Compare commits

..

639 Commits

Author SHA1 Message Date
complication
baebd1fdd2 * Update versions, package release 2009-01-24 23:57:39 +00:00
zzz
28cfd8cffe sv back in the updater 2009-01-22 17:36:03 +00:00
zzz
a4468219c7 sv take 4 2009-01-22 17:24:38 +00:00
zzz
70f07e5bc7 sv encoding take 3 2009-01-22 16:03:12 +00:00
zzz
173e8a0434 console css tweaks 2009-01-22 16:00:41 +00:00
zzz
72fd42ef9b -11 2009-01-17 17:35:14 +00:00
zzz
ba7dbf9064 propagate from branch 'i2p.i2p.zzz.test' (head d4e23b124489f9a3dd9410aa941e88823702b950)
to branch 'i2p.i2p' (head 7a54e1c58b8cf2ad43830ddec6d404229e3e6e60)
2009-01-17 17:33:17 +00:00
zzz
807f0665b1 tweak 2009-01-17 17:31:00 +00:00
zzz
416b0e4540 Prevent two NTCP Pumpers 2009-01-17 17:28:37 +00:00
zzz
011ded2ee4 -10 2009-01-14 17:06:52 +00:00
zzz
f9faf3c70d propagate from branch 'i2p.i2p.zzz.test' (head 4bd16d213231d7bd4373d4b57c449b358389f568)
to branch 'i2p.i2p' (head c7655ab1094ca15b4485ea2ac66085e87e28b0d6)
2009-01-14 17:04:35 +00:00
zzz
0ea532c72e reduce initial RTT to 8s 2009-01-14 13:50:44 +00:00
zzz
104cf8346e add .de thx echelon 2009-01-13 21:17:01 +00:00
zzz
3e7e5d6113 dont build sam tests by default 2009-01-13 19:54:07 +00:00
zzz
0275c5e13b crstrack 2009-01-13 19:53:35 +00:00
zzz
1c76d240e0 * i2psnark:
- Fix double completion message
      - Add crstrack
2009-01-13 19:52:45 +00:00
zzz
366da1b37c add b32 config for mosfet 2009-01-13 19:32:10 +00:00
zzz
bdcb625e6d fix rare NPE 2009-01-13 19:28:09 +00:00
zzz
8296723533 * HTTPClient: Fix per-tunnel settings for i2cp.gzip and i2ptunnel.httpclient.send* (thx tino) 2009-01-13 19:27:14 +00:00
zzz
957c809774 drop more syndie files 2009-01-12 16:28:36 +00:00
zzz
70b99cf4f9 prevent possible latency-measuring attack 2009-01-12 14:51:38 +00:00
zzz
05a6353142 .b32.i2p 2009-01-12 14:31:43 +00:00
zzz
85615b972b noobhelp 2009-01-12 05:21:16 +00:00
zzz
e3abea1ad2 add netdb links on tunnels.jsp 2009-01-11 15:25:23 +00:00
zzz
bc54908a22 cleanups using getProperty(String, int) 2009-01-10 22:34:07 +00:00
zzz
60bd9803f0 fix burst seconds display 2009-01-10 22:30:43 +00:00
zzz
c3360cc3d7 remove 1m fail column 2009-01-10 21:47:38 +00:00
zzz
aa71725159 -9 2009-01-08 21:00:08 +00:00
zzz
574713e608 propagate from branch 'i2p.i2p.zzz.test' (head 27dec7ffd064f6ecb40189c0438e4aee9f887a9c)
to branch 'i2p.i2p' (head 5aa9ccf6d6abec74c2d0d92ca02bc807463be93b)
2009-01-08 20:53:56 +00:00
zzz
0aaae0b0da robt4 2009-01-08 20:48:57 +00:00
zzz
ed34964747 reduce fast retx threshold to 2 2009-01-08 20:41:50 +00:00
zzz
7b758d89d0 * ExploreJob/SearchJob - more fixes:
- Disable ExploreKeySelectorJob completely, just have
        StartExplorersJob select a random key if queue is empty
      - Add netDb.alwaysQuery=[B64Hash] for debugging
      - Queue results of exploration for more exploration
      - Floodfills periodically shuffle their KBuckets, and
        FloodfillPeerSelector sorts more keys, so that
        exploration works well
2009-01-08 19:27:57 +00:00
zzz
1c7111eca0 alternate base32 check 2009-01-07 14:48:16 +00:00
zzz
831f09c91a fix corruption of update urls 2009-01-05 20:30:36 +00:00
zzz
4f836a20e1 * ExploreJob/SearchJob - fix brokenness:
- Give each search a minimum of time even at the end
      - Fix ExploreJob exclude peer list
      - Always add floodfills to exclude peer list
      - Don't queue keys for exploration or run ExploreJob
        if floodfill
      - Allow floodfills to return non-floodfills in
        a DSRM msg so exploration works
2009-01-05 15:21:00 +00:00
zzz
8faeaaa1ae Transport: Don't shitlist a peer if we are at our connection limit 2009-01-05 15:16:14 +00:00
zzz
7271289c1f Shitlist: Reduce max time to 30m (was 60m) 2009-01-05 15:13:42 +00:00
zzz
8421ae1ed4 * Streaming: Reduce default initial window size from 12 to 6,
to account for the MTU increase in the last release
2009-01-05 15:12:56 +00:00
zzz
d042c6b921 recognize robert 0.3 2009-01-05 15:11:36 +00:00
zzz
e2e4516a8f Fix display of outbound backup count 2009-01-05 15:11:00 +00:00
zzz
efc604a25c Remove readme_xx.html from updater 2009-01-05 15:06:56 +00:00
zzz
5c1864ed5e addressbook: Prevent Base32 hostnames 2009-01-05 15:06:29 +00:00
zzz
debf92fd9b history for prop., -8 2009-01-03 00:49:33 +00:00
zzz
9477b139be propagate from branch 'i2p.i2p.zzz.test' (head 014db28e7b42a25a02de0c0eee5f2fc57352e268)
to branch 'i2p.i2p' (head e4d9945a49c24434a8eaf34d142e033a3a6e0828)
2009-01-03 00:42:14 +00:00
zzz
53ce3c4802 sort torrents with a locale-based sort 2009-01-03 00:05:03 +00:00
zzz
d61af12867 clean up and fix the possibly broken browser launcher config 2009-01-02 20:09:20 +00:00
zzz
908c542b40 move buttons 2009-01-02 18:07:16 +00:00
zzz
ef998349cc require router.memoryUsed stat 2009-01-01 13:58:00 +00:00
zzz
44446d76e4 convert db to concurrent 2009-01-01 13:54:42 +00:00
zzz
a616a5f1c9 prep for upcoming torrent updater 2009-01-01 13:13:04 +00:00
zzz
c0b616e519 revert core version, -7 2009-01-01 12:45:33 +00:00
sponge
b4d3986006 router and core version bump 2008-12-31 07:53:30 +00:00
sponge
ba9108f937 bump revision to 0.0.3 2008-12-30 13:20:54 +00:00
sponge
161379f004 Removed debug line. 2008-12-30 10:29:39 +00:00
sponge
841feaedff Bugfix for getting Properties to actually work. 2008-12-30 07:52:04 +00:00
sponge
ba8de6c565 Spelling error correction. 2008-12-22 23:04:41 +00:00
zzz
d6148db455 * NetDb:
- Expire routers with introducers after 90m.
        This should improve reachability to firewalled routers
        by keeping introducer info current.
      - Expire routers with no addresses after 90m.
2008-12-21 14:43:09 +00:00
zzz
33b43f40b9 try again to kill the i2psnarkurl files 2008-12-20 02:33:57 +00:00
zzz
4336dc441e Remove spurious UDP warning on startup 2008-12-20 01:04:19 +00:00
zzz
2d86e7cf60 add router.memoryUsed stat 2008-12-20 01:00:53 +00:00
zzz
219e96d416 Remove apps/ bogobot jdom pants q rome stasher syndie 2008-12-15 21:54:52 +00:00
zzz
0c72fe7383 history for prop -5 2008-12-14 15:14:05 +00:00
zzz
369599fedd propagate from branch 'i2p.i2p.zzz.test' (head c021d3213ed91036828c43f1e93916e319d47bc1)
to branch 'i2p.i2p' (head f571e6566b12cd0ae93fd57157b849d5a963612f)
2008-12-14 15:10:12 +00:00
zzz
847c9dafce * I2CP, HostsTxtNamingService, I2PTunnel:
Implement Base32 Hash hostnames, via the naming service.
      Names are of the form [52-characters].i2p, where
      the 52 characters are the Base32 representation of our
      256-byte hash. The client requests a lookup of the hash
      via a brief I2CP session using new I2CP request/reply
      messages. The router looks up the leaseset for the hash
      to convert the hash to a dest. Convert the I2PTunnel
      'preview' links to use Base32 hostnames as a
      demonstration.
2008-12-14 15:03:11 +00:00
zzz
734818f651 * Transport:
- Cleanup max connections code
      - Add i2np.udp.maxConnections
      - Set max connections based on share bandwidth
      - Add haveCapacity() that can be used for connection
        throttling in the router
      - Reject IBGW/OBEP requests when near connection limit
      - Reduce idle timeout when near connection limit
    * Tunnel request handler:
      - Require tunnel.dropLoad* stats
      - Speed up request loop
2008-12-14 14:07:37 +00:00
zzz
dae6fd47d9 javadoc fixes 2008-12-13 18:07:20 +00:00
zzz
0956393cf3 add int getProperty(String prop, int default) 2008-12-10 16:32:26 +00:00
zzz
d16f187394 change restart/shutdown/update links to buttons 2008-12-10 16:25:09 +00:00
zzz
962a8f6f49 more splitting classes 2008-12-10 15:37:28 +00:00
sponge
9aa8707647 Prepended log LVL to messages, added INFO LVL 2008-12-08 22:34:45 +00:00
zzz
1fdd228a9d constructor fix 2008-12-08 16:38:46 +00:00
zzz
819d857550 Do not build tests 2008-12-08 15:03:45 +00:00
zzz
04fb12932f prop history, -4 2008-12-08 14:12:29 +00:00
zzz
703b6ed190 propagate from branch 'i2p.i2p.zzz.test' (head eac1d36c16cf82b0d98167c58e1562aa443ee5e5)
to branch 'i2p.i2p' (head b1fa07e8a4dabc26e731f7d486677abb165d975c)
2008-12-08 14:00:09 +00:00
zzz
bd6c63cc7e add findbugs target 2008-12-06 00:11:13 +00:00
zzz
7dbb13d6dc move atalk from core to apps 2008-12-05 20:31:54 +00:00
zzz
ebdc69cbc2 remove PRNG from summary bar 2008-12-05 14:52:15 +00:00
zzz
868fe90d7a increase max files to 256 2008-12-05 14:38:59 +00:00
sponge
9e39f34473 BOB: removed debugging (oops!)
BUMP: BOB to 00.00.02
BUMP router to -3
2008-12-05 10:12:10 +00:00
sponge
45ed744210 BUMP to -2 for bug reporting. 2008-12-05 09:55:53 +00:00
sponge
701904d119 BUGFIX: streaming lib blocking on a write() will now fail when the socket
is closed from under it.
Enhancement: BOB can now clear a destination in under 1 second with the above fix.
	BOB also will do a thread dump when something really aweful happens,
	so that developers/users can help in debugging.
2008-12-05 09:51:48 +00:00
zzz
dcf4bb595f split classes into their own files 2008-12-04 21:56:22 +00:00
zzz
e9f27c60dd avoid two NPEs on corrupt fragments 2008-12-04 00:09:52 +00:00
zzz
321f11c055 robert + xl 2008-12-03 23:38:13 +00:00
zzz
85cebc7992 * Transport:
- Fixes and cleanups when NTCP and/or UDP transports disabled
      - More TCP removal cleanup
      - Clean up bandwidth limiting, centralize defaults
      - Force burst to be >= limit
      - Increase default bw to 48/24, burst 64/32
2008-12-03 18:53:57 +00:00
zzz
8e5c4a3e22 error to warn 2008-12-03 16:55:48 +00:00
zzz
dff75de97a tweak 2008-12-03 14:46:37 +00:00
zzz
f1fd35265a enable blocklists by default 2008-12-03 14:26:39 +00:00
zzz
b73b3fc5ac * i2psnark:
- Add default i2psnark.config for new installs
      - Remove wishlist link
2008-12-03 01:49:19 +00:00
zzz
13d4ccf2e7 remove restart button if no wrapper 2008-12-02 19:07:58 +00:00
zzz
8c9ac941bf fix NPE on early shutdown 2008-12-02 16:28:29 +00:00
zzz
3fc698c7d3 disable eepsite webapps by default 2008-12-02 16:26:26 +00:00
zzz
15596c9230 add textareas to susidns 2008-12-02 16:25:43 +00:00
zzz
7fdbe9b87b post-0.6.5 netdb stats cleanup 2008-12-02 16:25:16 +00:00
zzz
5acc56c184 increase standalone to 128MB max mem 2008-12-02 16:23:54 +00:00
zzz
c524231c6d history for the propagate of the snark rewrite 2008-12-01 02:57:24 +00:00
zzz
5d4a7967cb propagate from branch 'i2p.i2p.zzz.i2psnark' (head 738b0ee2a3e938f83c8524d7ee1cbd66c83d7d56)
to branch 'i2p.i2p' (head 7bc276bf13158ca72d687031fdf5e9921efc5050)
2008-12-01 02:51:28 +00:00
complication
01101f9867 * Fix typos in news.xml 2008-12-01 01:07:22 +00:00
complication
c93ccd15eb * Update versions, package release, fix typo in comment 2008-12-01 00:23:53 +00:00
zzz
73280ab834 amiga->echelon 2008-11-28 18:08:15 +00:00
sponge
6a3c52b7fa Added verify command to check that a destination's BASE64 is correct for
external applications that need it.
2008-11-28 16:07:29 +00:00
dev
90983c8761 added inital version of a deploy script 2008-11-27 19:19:24 +00:00
zzz
daac598bde fix windows url launcher 2008-11-26 18:32:51 +00:00
dev
41d98acc95 minor style changes 2008-11-26 15:56:36 +00:00
dev
c8970c0fc6 changed some of the URL's 2008-11-26 15:20:00 +00:00
zzz
4e5825c648 * Cache DNS and negative DNS for 5m (was 1m and forever)
* Delay shitlist cleaner at startup
    * Strip wrapper properties from client config
    * Define multiple cert type
    * Prohibit negative maxSends in streaming
    * HTML fixup on configtunnels.jsp
    * Increase wrapper exit timeout from default 15s to 30s
2008-11-21 16:29:16 +00:00
zzz
93f0092437 propagate from branch 'i2p.i2p.zzz.test' (head fa1d7d3151cb0b03dde308766d3d350afda8f14a)
to branch 'i2p.i2p' (head 8cb6295e6a3492fd3b93366bfb0ebf231115fa85)
2008-11-20 15:53:30 +00:00
zzz
bad4c4a133 SAM: Convert from I2PThread to I2PAppThread so it won't
shutdown the whole router when ooming.
2008-11-20 14:59:55 +00:00
zzz
da9a4ce557 EepGet:
- Better handling of 504 gateway timeout
     (keep going up to limit of retry count rather
      than just one more partial fetch)
   - Add -t cmd line option for timeout
   - Better handling of 403, 409, 503 errors
   - Don't keep going after unknown return code
   - Don't delay before exiting after a failure
2008-11-20 14:14:13 +00:00
zzz
0ff8167425 i2psnark:
- Don't create SnarkManager instance until first call,
      so it doesn't create the i2psnark dir, read the config,
      etc., for single Snark instances.
    - Don't read i2psnark.config twice; fix setting
      i2psnark.dir
    - More Snark constructor changes for calling from router
    - Make max connections per torrent configurable
2008-11-18 02:18:23 +00:00
zzz
9ae589449d tweak 2008-11-16 19:12:58 +00:00
zzz
134764b154 i2psnark:
- Use new I2PAppThread that does not call global listeners on OOM,
      so that OOMing apps will not shutdown the whole router.
2008-11-16 17:24:08 +00:00
zzz
23699e46e5 i2psnark:
- Remove static instances of I2PSnarkUtil, ConnectionAcceptor,
      and PeerCoordinatorSet
    - Convert static classes in Snark to listeners
    - Fix Snark to work in single torrent mode again
    - Should now work with multiple single Snarks
2008-11-16 17:11:53 +00:00
zzz
fa23a7b066 i2psnark:
- Refactor to allow running a single Snark without a SnarkManager again,
    by moving some things from SnarkManager to I2PSnarkUtil,
    having Snark call completeListener callbacks,
    and having Storage call storageListener callbacks.
    This is in preparation for using Snark for router updates.
    Step 2 is to allow multiple I2PSnarkUtil instances.
  - Big rewrite of Storage to open file descriptors on demand, and
    close them when unused, so we can support large numbers of torrents.
2008-11-15 23:52:40 +00:00
zzz
de21a5ec48 drop old tcp transport and old tunnel build sources 2008-11-15 20:57:52 +00:00
zzz
b1a9dcf77e move dummy to his own file to help the build dependencies 2008-11-15 19:09:56 +00:00
zzz
15e7783477 handle missing fields in i2ptunnel edit pages better 2008-11-15 19:00:08 +00:00
zzz
afa17a8c04 * I2CP Compression:
- Add i2cp.gzip option (default true)
      - Don't bother compressing if really small
2008-11-15 15:03:19 +00:00
zzz
c7bb2e8f76 * build files:
- Don't die if depend not available
   - Only verify Jetty hash once
   - Add streaming lib tests to depends task
2008-11-14 14:48:08 +00:00
zzz
b4d299804b update history before propagate 2008-11-13 20:12:45 +00:00
zzz
77f5dd2d14 Fix blocklists with hashes only 2008-11-12 22:46:07 +00:00
zzz
c941d7bfa1 HTTPClient: Add config options to pass Via, Referer, and User-Agent through 2008-11-12 20:14:08 +00:00
zzz
049d6b2fa8 * Streaming:
- Add more info to Connection.toString() for debugging
      - Fix lifetimeMessages{Sent,Received} stats
      - Reduce RTT damping to 0.875 (was 0.9)
      - Add a stream.con.initialRTT.{in,out} stats
2008-11-12 20:10:39 +00:00
zzz
98038e9282 * Build files:
- Use the depend task with caching for more accurate dependencies
      - Make sure the routerconsole gets the latest router version
      - Fix addressbook repeated builds
2008-11-12 17:08:09 +00:00
zzz
6169904c76 oops remove extra stuff in IndexBean 2008-11-11 13:02:45 +00:00
zzz
04509f593a * Streaming: Enforce a minimum MTU of 512 2008-11-11 02:30:49 +00:00
zzz
875dd65dcb * I2PTunnel: Change "interactive" max window size to 16 (was 1) 2008-11-11 02:30:21 +00:00
zzz
b0ec6a0870 * Streaming - Fix several bugs and improve performance
when the initial data is larger than one MTU,
      e.g. HTTP GETs with large URLs, CGI params or cookies,
      or large HTTP POSTS:
      - Don't reject additional packets received without a
        send stream ID (i.e. sent before the SYN ACK was received)
      - Put unknown non-SYN packets on the SYN queue also
        so they won't be rejected
      - Reduce flusher delay to 250ms (was 500)
      - Flush unless window is full (was window is non-empty)
2008-11-10 20:30:14 +00:00
zzz
6ce2767514 * NetDb: Fix a deadlock caused by last checkin 2008-11-10 20:28:47 +00:00
zzz
5271838a14 -9 2008-11-09 16:18:45 +00:00
zzz
9ec45bbcf5 provide a link when starting a webapp 2008-11-09 16:10:59 +00:00
zzz
c9cef19a68 * Tunnel BuildHandler: add config router.participantOnly,
set to true to refuse OBEP and IBGW roles, should
      reduce connections significantly if set.
2008-11-09 16:08:24 +00:00
zzz
9f57be5f03 * Jetty: Add a I2PRequestLog class to log request dest hash 2008-11-09 16:05:13 +00:00
zzz
1793b05784 * NetDb: Don't drop routerInfos if we have connectivity issues or other problems 2008-11-09 16:02:44 +00:00
zzz
f95c324832 * configtunnels.jsp:
- Code cleanup
      - Add 4-hop option
      - Remove +/- 0-2 option
2008-11-09 15:59:35 +00:00
zzz
016c843ad6 * I2PTunnelHTTPServer: Put the requestor's dest hash
in the request headers
2008-11-09 15:57:58 +00:00
zzz
e52526b256 * NTCP: Lower idle timeout to 10m (was 15m) 2008-11-09 15:57:07 +00:00
zzz
7722ab5f6f * Routerconsole: Replace wtf msg w/ something nicer 2008-11-09 15:55:40 +00:00
zzz
c024398b93 Add some javadoc files 2008-11-09 15:54:04 +00:00
zzz
2e72ece384 * build.xml: Build speedups:
- Don't distclean in the updaterRouter target
      - Don't make prepUpdate and prepupdateSmall depend
        on distclean
      - Don't make susimail build always clean
      - Make pkg depend on distclean to be sure
      - Clean out more routerconsole and susidns files in 'ant clean'
      - i2ptunnel, routerconsole, susidns:
        Only build WEB-INF when necessary
      - systray: Only build jar when necessary
      - Don't build i2psnark standalone for the updater target
2008-11-09 15:46:08 +00:00
zzz
2b8d59d9f4 more override removals 2008-11-09 15:42:50 +00:00
dev
28b4c92241 should compile on 1.5 again now 2008-11-09 14:32:27 +00:00
dev
c9d9a83f73 finished core 2008-11-09 10:09:01 +00:00
dev
7bf57870d6 and again some more ;) 2008-11-09 09:49:54 +00:00
dev
d41b68438d and another bunch 2008-11-08 23:14:47 +00:00
dev
c634e5005d cleanup: annotated a bunch of files 2008-11-08 22:46:42 +00:00
dev
e0926b8ccd minor update to the checklist 2008-11-08 21:56:45 +00:00
dev
5ea7adb857 updated style of PrivateKeyFile to conform (more or less) to sun coding standards 2008-11-08 19:11:41 +00:00
zzz
bf12c5f9bf * Certificates:
- Add a signed Certificate type
      - Add a main() to PrivateKeyFile to generate
        Destinations with various Certificate types
      - Add a VerifiedDestination class to check Certificates
        of various types
      - Add a HashCash library from http://www.nettgryppa.com/code/
        (no distribution restrictions)
      - Allow non-null Certificates in addressbook
2008-11-02 22:13:11 +00:00
zzz
47d5e44b16 * Throttle: Reduce default max tunnels to 2000 (was 2500) 2008-11-02 21:53:17 +00:00
zzz
f6996c7d8b * NamingServices: Implement caching in the abstract class 2008-11-02 21:41:08 +00:00
zzz
fb7f4f2d11 * clients.config: Disable SAM and BOB by default for new installs 2008-11-02 21:39:32 +00:00
zzz
d89f97acd5 * I2PTunnel: Move some wayward stats to the I2PTunnel group 2008-11-02 21:38:49 +00:00
zzz
f3c9343c79 * NewsFetcher: Fix last updated time 2008-11-02 21:37:28 +00:00
zzz
16ec091209 * Streaming: Increase MTU to 1730 (was 960);
see ConnectionOptions.java for analysis
2008-11-02 21:36:52 +00:00
sponge
0b599c45ec Refactored code.
Piles of pedantic lock checks to ensure we don't get deadlocked, it's ugly.
2008-10-31 21:11:03 +00:00
sponge
7f3f6dfde3 Patches to (hoefully) fix deadlock in BOB and revision bumpped to B
SusiMail JavaDoc additions.
2008-10-30 15:04:16 +00:00
sponge
d736b75dc2 merge of '146998571b0b88243eb67af215b740f504fbcc50'
and 'ee93f3940b59255ddab5fa4aafd6f567f46783f7'
2008-10-29 09:00:13 +00:00
sponge
fa2f06b1d8 JavaDoc fixes 2008-10-29 08:59:56 +00:00
zzz
4212858409 fix english link in readme_nl.html 2008-10-28 19:07:39 +00:00
zzz
33221ce7fd More findbugs cleanup 2008-10-26 18:18:34 +00:00
zzz
fd5fcebae9 * NetDb:
- Fix behavior when router.isHidden=true
       - Delay StartExplorersJob for 10m at startup
       - More findbugs cleanups
    * netdb.jsp: Indicate if hidden
2008-10-26 18:16:18 +00:00
zzz
b743449715 * NetDb:
- Update dbLookup profile stats in FloodOnlySearchJob
         and FloodfillVerifyStoreJob
       - Fix response time store in profile in SearchJob
    * profiles.jsp: Don't override locale number format,
       clean up the response time output for floodfills
2008-10-26 18:12:36 +00:00
zzz
2a08fc7a34 * FloodfillMonitor:
- Fix ff count (we forgot ourselves)
       - Don't become ff if hidden
2008-10-26 18:08:20 +00:00
zzz
0c520de6e5 * HandleFloodfillDatabaseLookupMessageJob:
- Send back your routerinfo with the DSRM if not ff to
         spread the word that you aren't ff anymore
       - Fix behavior when router.isHidden=true
2008-10-26 18:05:51 +00:00
zzz
09b868e243 * Blocklist: Change logging from ERROR to WARN 2008-10-26 18:02:21 +00:00
zzz
83801c9feb * Stats:
- Remove unused tunnel.buildSuccess and tunnel.buildFailure
       - Remove tunnel.buildRequestTime and 5m rate stats from
         netDb, effective in next release
2008-10-26 18:00:49 +00:00
zzz
152f824779 * config.jsp: Add more help
* summary.jsp: Indicate if hidden
2008-10-26 17:24:11 +00:00
zzz
68256930b9 * UDP:
- Don't do peer tests when hidden
       - Don't offer to introduce when hidden
       - Don't continually rebuild routerInfo when hidden
       - Don't continually rebuild routerInfo when
         i2np.udp.internalPort is set but i2np.udp.port is not
       - Remove some unused functions
2008-10-26 17:20:19 +00:00
zzz
622951c794 * tunnels.jsp: Indicate if pool is dead 2008-10-26 17:18:07 +00:00
zzz
baa70299fc * I2Ping:
- Add -n count option
       - Add rtt output
       - Enhance help
       - Fix option handling
2008-10-26 17:15:59 +00:00
zzz
47856f312c * i2ptunnel/edit.jsp: Disable word wrap in textarea 2008-10-26 17:14:07 +00:00
zzz
b4c808918b * peers.jsp: Clean up 'Listening on' formatting 2008-10-26 17:11:12 +00:00
sponge
e6e4c60a25 BOB version bump to 0xA 2008-10-22 06:59:48 +00:00
sponge
2dc699b382 Better handling of listening sockets. 2008-10-22 06:57:07 +00:00
zzz
22454a06d4 UTF-8 readme_sv.html 2008-10-21 17:45:19 +00:00
zzz
0e0459f88a more findbugs 2008-10-19 22:36:18 +00:00
zzz
20effe3a7f Big findbugs cleanup 2008-10-19 22:09:14 +00:00
zzz
8a756a6e81 * FloodOnlySearchJob: Recover better if the floodfills
you know are no longer floodfill or are gone
2008-10-19 21:50:12 +00:00
zzz
a7e876da1e * FloodfillMonitor:
- Don't become ff if clock skew is high
       - Rebuild routerinfo immediately when ff status changes
2008-10-19 21:48:55 +00:00
zzz
06be4515e4 * ShellCommand: Fix main() 2008-10-19 21:46:04 +00:00
zzz
af630e9559 * configclients.jsp: Handle clients with no args 2008-10-19 21:45:04 +00:00
zzz
50c93e25c7 * Installer: Bump min JRE to 1.5 2008-10-19 21:43:56 +00:00
zzz
2d6007cf49 readme_sv.html 2008-10-19 21:42:56 +00:00
zzz
7aaed8e686 * Client: Prevent a race causing session reconnect 2008-10-19 21:41:07 +00:00
zzz
e2a1835142 readme_nl.html 2008-10-15 20:05:21 +00:00
zzz
078256da83 change to _de links 2008-10-14 17:53:16 +00:00
zzz
4f8d84e9e7 Add multilanguage support for index.jsp 2008-10-14 16:23:23 +00:00
zzz
ae967d6ef4 Disable word wrap in textareas 2008-10-14 15:46:21 +00:00
zzz
3b46b16038 Remove failing count from summary bar 2008-10-14 14:28:02 +00:00
zzz
25bf6e59bc Update install.txt files for 1.5 2008-10-14 14:26:40 +00:00
sponge
c4030f8dab Fixed one javadoc problem in snark.
This patch completes the javadoc fixups. Additions are pending.
2008-10-13 03:18:44 +00:00
sponge
e103f33c29 Addressbook javadoc fixes
Addressbook now JDK5
build.xml fixed to remove annoying javadoc warnings.
2008-10-12 17:07:21 +00:00
sponge
1c6b78a8da SAM davadoc cleanups
JDK5 compliance
2008-10-12 16:07:23 +00:00
sponge
8117d0465c BOB fixes: Default Properties work, files are properly closed. 2008-10-11 21:59:18 +00:00
sponge
0ff846deee Added package details for BOB 2008-10-11 16:50:55 +00:00
sponge
87a992bd3f Patched java docs to remove sam and bob from the SDK;
SAM and BOB are not part of the SDK in the first place.
2008-10-11 16:50:20 +00:00
sponge
41c38e64c3 Added JDK5 lint fixes
Streaming lib javadocs
2008-10-11 13:23:55 +00:00
sponge
ca5c15d4de Added more complete javadocs to ministreaming and cleaned up overrides so
the code is JDK5 compliant. There remains some unchecked warnings, but these
aren't important at this juncture.
2008-10-11 10:28:31 +00:00
sponge
f3f7537ec6 Set BOB source/target to JDK 5 (AKA 1.5)
Minor bugfixes/code cleanup on BOB
Add/Cleanup some documentation to streaming lib javadocs
2008-10-11 07:45:30 +00:00
zzz
855293d673 * Tunnels: Implement random discard to enforce share limit 2008-10-10 17:34:25 +00:00
zzz
4c2d4144d1 * i2psnark: Change default tunnel length from 1+1 to 2+0 2008-10-10 17:33:27 +00:00
zzz
387587b0b6 * Throttle: Change reject to BANDWIDTH from CRIT on shutdown
for improved anonymity
2008-10-10 17:30:35 +00:00
zzz
43e95a70d1 * configpeer.jsp: Table cleanup 2008-10-10 17:29:48 +00:00
zzz
ad56eb7220 * UDPPacketReader: Adjust logging 2008-10-10 17:29:18 +00:00
zzz
d2d32f0ad1 * peers.jsp: Change <,> to in,out for UDP 2008-10-10 17:28:23 +00:00
zzz
0428726e30 * Profiles: Reduce reject penalty in
capacity calculation to avoid a congestion collapse
2008-10-10 17:27:23 +00:00
zzz
2eb154c24c * Tunnel Tests: Add time for outbound delay, to avoid
congestion collapse
2008-10-10 17:26:44 +00:00
zzz
4ec82beec5 * build files: Change to source=1.5, target=1.5 2008-10-10 17:25:58 +00:00
sponge
224ebb16d4 Bugfixes for BOB, Important database locking to prevent thread collisions. 2008-10-09 11:58:00 +00:00
sponge
cb17fb8805 Made BOB 1.4 java compliant. 2008-10-08 16:40:07 +00:00
sponge
2c048d7465 Revision/history changes 2008-10-08 15:39:39 +00:00
sponge
00d537e5e4 Added new command to BOB, and made API a little better. 2008-10-08 15:28:06 +00:00
sponge
5eef43d239 BOB "option" added, next small push will have an API fix. 2008-10-08 14:57:02 +00:00
sponge
caaf0ccfc3 Additional BOB fixes.
Added BOB to clients.config and wrapper.config for new installs.
2008-10-08 14:28:35 +00:00
sponge
18d42ec925 A few fixes to make BOB a little more quiet,
there is possibly a little left, though.
2008-10-07 20:00:08 +00:00
sponge
872d2c48c9 Added demos for BOB 2008-10-07 19:43:43 +00:00
sponge
a3b9345ff1 Patch to reflect build version 2008-10-07 18:52:19 +00:00
sponge
eae67a44f0 merge of '07188d6eb4d52af5bdde5cbb23dc6facea726ad0'
and 'be6f83df49d5f766fd655b9ca0388bb30d68dfeb'
2008-10-07 18:50:53 +00:00
sponge
a988358ebb history.txt additions 2008-10-07 18:38:45 +00:00
sponge
bb32672c11 NEW BOB, a replacement for SAM, added It does have a different API. See it's java-doc. 2008-10-07 18:30:07 +00:00
complication
ae0a51669c * Update versions, package release 2008-10-06 13:28:34 +00:00
sponge
f1c4a85991 Code cleanup in I2PSocketManagerFull and I2PServerSocketFull
BUGFIX ConnectionHandler had a comparason bug that caused it to block when infact it was asked NOT to block
2008-10-06 09:28:59 +00:00
sponge
0a5eeed370 merge of '2f46bb4293a808d63ad2494aaebced5cf2227f52'
and '702d19f746dabc901ebadec705ce42950c124f55'
2008-10-04 18:41:55 +00:00
zzz
bf07a6a3c2 * checklist update
* i2psnark: Add codevoid link, remove mastertracker
    * hosts.txt: add echelon, codevoid
2008-09-29 11:49:09 +00:00
sponge
5913d9ee4a ADDED SimpleStore, cuz I forgot to add it 2008-09-28 16:36:59 +00:00
sponge
61749aaaa9 Added Simple true/false storage class to the utilities
Added socketSoTimeout
CHANGED RetransmissionTimer is now public
FIXED SimpleTimer has a way to be stopped, and reap it's children
CLEANUP A few javadoc additions, where I could figgure out bits
CLEANUP all code that needed to catch the timeout exception for socketSoTimeout
2008-09-27 22:59:22 +00:00
sponge
b0313bd6bf disapproval of revision '7ed18fd4c3a5430150a2d76bfe202bc491115974' 2008-09-27 16:00:06 +00:00
sponge
dd7d993631 Added Simple true/false storage class to the utilities
Added socketSoTimeout
CHANGED RetransmissionTimer is now public
FIXED SimpleTimer has a way to be stopped, and reap it's children
FIXED Lots of javadoc additions, where I could
CLEANUP all code that needed to catch the timeout exception for socketSoTimeout
2008-09-25 23:59:01 +00:00
sponge
ee2fd32a97 disapproval of revision 'bd09bb36a90e766b3a406d78055d427a6200dd41' 2008-09-25 23:31:57 +00:00
sponge
fa5c7219d3 Added {get,set}SOTimeout() to the ServerSocket API,
and fixed all the broken mainstream applications depending on it.
Fixed a grave bug in SimpleTimer.
Fixed Steraming Timer to be public.
Fixed a pile of JavaDoc comments, and reformatted the files I touched.
2008-09-25 06:55:04 +00:00
sponge
8d78a77a8c Allow SimplerTimer to die.
Still needs some methods to be able to reap it, and it's children.
2008-09-24 10:35:32 +00:00
zzz
52d38e0452 * config.jsp: Add some reachability help
* configpeer.jsp: Add blocklist info
    * help.jsp: Add link to German FAQ
    * tunnels.jsp: Fix inactive participating count
2008-09-23 18:48:59 +00:00
zzz
fbad8a1e8e * SearchReplyJob: Don't look up references to shitlisted peers 2008-09-23 18:47:30 +00:00
zzz
f49277087c * TunnelPeerSelector: Avoid a peer for 20s after a reject or timeout 2008-09-23 18:47:10 +00:00
zzz
e5c7b79cf5 * NetDb: Fix the totally broken "check new routers against blocklist"
code from 3 checkins ago
    * tunnels.jsp: Sort participating tunnels by usage, display rate
2008-09-20 14:08:02 +00:00
zzz
6b1224b23e 2008-09-19 zzz
* Tunnels:
      - Add missing message accounting for inbound gateways,
        we were underestimating participating traffic because of it,
        and the tunnels were classified "inactive"
      - Add participating tunnel role on tunnels.jsp
2008-09-19 01:03:57 +00:00
zzz
0bbc94f43c * Throttle:
- Correctly check inbound and outbound total bw limits separately
      - Fix up and actually use the tunnel.participatingMessageCount stat,
        favor it if lower than the total bw stat, so that
        client traffic isn't included for throttle decisions
      - Reduce min message count from 60 to 40
    * Tunnel Dispatcher:
      - Add tunnel.participatingBandwidth stat
      - Remove all 3h and 24h stats
2008-09-18 17:14:14 +00:00
zzz
7c083ed33b * logs.jsp: Remove unused connection log, cut wrapper log output in half
* configlogging.jsp: Increase box width
2008-09-15 16:23:47 +00:00
zzz
50f10e8cf1 * FloodOnlySearchJob:
- Ask non-floodfill peers if we don't know any floodfills
      - Lookup hashes in the DatabaseSearchReplyMessage if we
        don't know enough floodfills
2008-09-15 16:22:09 +00:00
zzz
69d9c054d8 * Tunnel Pool:
- Prevent excess zero-hop tunnels
      - Always wait before looping in BuildExecutor
2008-09-15 16:21:23 +00:00
zzz
fcfe4397c4 * NetDb: Check new routers against blocklist 2008-09-15 16:20:23 +00:00
zzz
e734a55872 * Router: Shutdown clients first
* Throttle:
      - Use 60s rather than 10m tunnel.participatingMessageCount stat
      - Fix a summary bar message
    * Tunnel Dispatcher: Update tunnel.participatingMessageCount
      every 20s, rather than at tunnel expiration, to maintain
      a more current stat
2008-09-15 16:19:08 +00:00
zzz
825af3e6c1 * HarvesterJob: Don't instantiate if disabled
* NetDb: Add netDb.exploreKeySet stat
    * netdb.jsp: Add parameter ?r=xxxxxx to view a single routerinfo,
      and ?r=. to view our own; change links on other pages too
2008-09-12 13:37:22 +00:00
zzz
cf54dd159d * Blocklist: Fix a log message format 2008-09-12 13:28:14 +00:00
zzz
6b1fb674ea * i2psnark:
- Add config i2psnark.linkPrefix to enable access to completed
        torrents from a different machine - examples:
           i2psnark.linkPrefix=file://///localserver/path/to/files/
           i2psnark.linkPrefix=http://localwebserver/path/
        Stop i2psnark, add to i2psnark.config, restart
      - Remove Galen and NickyB trackers
2008-09-12 13:27:07 +00:00
zzz
97366824d6 * Transport: Make 0.0.0.0/8 and 169.254.0.0/16 private 2008-09-12 13:25:51 +00:00
zzz
2ac5361937 fix compile error 2008-09-06 15:54:53 +00:00
zzz
9a2792e64c * EepGet command line: Fix byte counts after a failed resume
* UpdateHandler: Cleanup, clarify failure message
2008-09-06 13:52:46 +00:00
zzz
1091a289d2 * NTCP: Mark unreachable on outbound connection timeout 2008-09-06 13:49:31 +00:00
zzz
536f5d0c7b * Shitlist: Fix partial shitlisting (still unused though) 2008-09-06 13:48:57 +00:00
zzz
a3108ead4a * Throttle: Combine current and last bw measurement,
reduce default max tunnels to 2500 (was 3000)
2008-09-06 13:48:25 +00:00
zzz
808557d24f * Summary Bar: Warn if firewalled and floodfill 2008-09-06 13:47:56 +00:00
zzz
6501d403ab * Tunnel BuildHandler: Logging cleanup 2008-09-06 13:47:30 +00:00
zzz
ef328ed3cc * DataHelper: Prepare for 999 day uptime :) 2008-09-06 13:46:58 +00:00
zzz
62bf269c42 * Profiles: Penalize capacity when tunnel build request times out
* Tunnel BuildExecutor: Debug cleanup
2008-08-29 13:15:28 +00:00
zzz
ee4d68cf6a * Stats: Remove tunnel.Bps.* stats when the tunnel pool is closed 2008-08-29 13:13:45 +00:00
zzz
e064b0a0e1 * Shutdown: Call the shutdown hooks before the router shutdown
rather than after
2008-08-29 13:12:55 +00:00
zzz
c321251bb7 Add galen.i2p and tracker.mastertracker.i2p 2008-08-28 16:08:01 +00:00
zzz
896ba7ae1c * Floodfill Peer Selector: Prefer already-connected floodfill
peer for direct RouterInfo stores, to mimimize floodfill
      connections
    * Peer Profiles: Classify connected peers as "active",
      which will help improve the fast pool
    * Transport Manager: Add isEstablished(Hash)
2008-08-27 19:58:13 +00:00
zzz
2c48831604 ntcp reduce idle timeout 2008-08-27 19:56:06 +00:00
zzz
9d70a5293f netdb stats cleanup 2008-08-27 19:55:47 +00:00
complication
bf51741134 * Update versions, package release 2008-08-24 10:28:57 +00:00
zzz
33e8abfc3e * Persistent data store: Increase write limit from 300 to 600
so floodfill routers don't get backed up
2008-08-20 15:02:56 +00:00
zzz
258d01f0d9 * Blocklists: Handle blank lines and \r\n in blocklist.txt
* NTCP: Add connection limit, set by i2np.ntcp.maxConnections,
      default is 500 (very high for now)
2008-08-20 14:58:45 +00:00
zzz
49af13a3ca * i2psnark: Fix OOM vulnerability by checking incoming message length
(thanks devzero!)
2008-08-13 15:59:16 +00:00
zzz
719ba3f66f * Floodfill Peer Selector:
- Avoid peers whose netdb is old, or have a recent failed store,
        or are forever-shitlisted
2008-08-04 19:31:11 +00:00
zzz
9652db9623 * Blocklists:
- New, disabled by default, except for blocking of
        forever-shitlisted peers. See source for instructions
        and file format.
    * Transport - Reject peers from inbound connections:
      - Check IP against blocklist
      - Check router hash against forever-shitlist, then block IP
2008-07-30 03:59:18 +00:00
zzz
481af00bab -9 2008-07-16 15:05:56 +00:00
zzz
11d267bc9a * configpeer.jsp: New 2008-07-16 15:05:07 +00:00
zzz
40f0cb65a1 * SSU:
Don't proactively reconnect until 30m idle, so
        we don't lose introducer tags prematurely
2008-07-16 15:04:02 +00:00
zzz
2ba9929277 * PRNG: Move logging from wrapper to router log 2008-07-16 15:03:00 +00:00
zzz
616abba328 * i2psnark: Open completed files read-only the first time 2008-07-16 15:02:20 +00:00
Oldaris
14a6352d9a Corrected UTF-8 encoding 2008-07-16 14:44:17 +00:00
Oldaris
5782c42d25 Cleaned up all 'imports' in all applications, core and router. 2008-07-16 13:42:54 +00:00
dev
f261deaf16 made code more 1.5 compatible 2008-07-14 15:05:26 +00:00
zzz
5228543236 * SSU:
- Try to pick better introducers by checking shitlist,
        wasUnreachable list, failing list, and idle times
      - To keep introducer connections up and valid,
        periodically send a "ping" (a data packet with no data and no acks)
        to everybody that has been an introducer in the last two hours
      - Add a stat udp.receiveRelayRequestBadTag, make udp.receiveRelayRequest only for good ones
      - Remove some 60s and 5m stats, leave only the 10m ones
      - Narrow the range for the retransmit time after an allocation fail
      - Adjust some logging
2008-07-07 14:18:38 +00:00
zzz
e173a47e01 * Streaming lib - adjust some loggging, cleanup Connection.toString() 2008-07-07 14:18:15 +00:00
zzz
07b895a069 * Router console: Flag placeholder pages as noncacheable 2008-07-07 14:10:10 +00:00
zzz
4d8ffc85e2 * LoadTestManager: Don't instantiate, it's disabled 2008-07-07 14:09:16 +00:00
zzz
53e2e0d1c9 * KeyManager:
- Don't write router key backup when leaseSet keys are updated
      - Synchronize to prevent concurrent writes (thanks Galen!)
      - Backup keys every 7 days instead of every 5 minutes
2008-07-07 14:07:59 +00:00
zzz
e0dcf82697 * HTTP Proxy: Don't show jump links for unknown jump hosts 2008-07-07 14:07:14 +00:00
zzz
0cfac58adb * i2psnark:
- Repair corrupted files with wrong length rather than die
      - Register shutdown hook to properly shutdown torrents when
        the router shuts down, hopefully will reduce corruption
      - Add Galen tracker
      - Add a note about how to chane directory
2008-07-07 14:05:54 +00:00
zzz
2768bef991 * NTCP:
- Try to fix 100% CPU, caused perhaps by JVM NIO bug...
      - Fix failsafe stats
2008-06-30 03:14:32 +00:00
zzz
bae712ad96 * i2psnark:
- Fix NPE caused by race (thanks echelon!)
      - Add mastertracker, remove de-ebook
2008-06-30 03:09:20 +00:00
zzz
49cb4c13b3 * PersistentDataStore: More leaseSet code cleanup 2008-06-30 03:08:16 +00:00
zzz
28da17276c * configstats.jsp: Fix NPE when no stats checked (thanks nothome27!) 2008-06-30 03:07:52 +00:00
zzz
14099ace69 * SimpleTimer: Change congestion message from error to warn 2008-06-30 03:07:00 +00:00
zzz
9289799c97 * FloodfillMonitorJob: Change range from 5-7 to 4-6 2008-06-24 14:41:41 +00:00
zzz
f057666ac2 * PersistentDataStore: Don't try to remove nonexistent leaseSet files 2008-06-24 14:39:14 +00:00
zzz
a11b74b2d8 * NTCP: Remove getIsInbound(), duplicate of isInbound() 2008-06-24 14:38:09 +00:00
zzz
0e018c5b4d * Router console: add placeholder pages for i2psnark, i2ptunnel,
susidns, and susimail for use when the .wars are not running
2008-06-24 14:36:39 +00:00
zzz
107a90fa33 increase max window size to 128 2008-06-24 14:33:30 +00:00
dev
01259cc07d merge of '5c7631359fea237f6aa916acd4f76a8a00d519fb'
and '88d299913d4aeb0ef7e8adabb5c39255e9cca0d2'
2008-06-22 14:08:06 +00:00
dev
4d955f3be5 minor optimization in I2PDatagramDissector(only verfy signature once) 2008-06-22 14:07:30 +00:00
zzz
49e429c166 * PRNG: Add two stats
* Summary bar:
      - Display Warning for TCP private IP address
      - Display PRNG stats
2008-06-20 20:22:38 +00:00
zzz
53c5b1446a * OutNetMessage: Change cache logging from WARN to INFO 2008-06-20 20:21:21 +00:00
zzz
dc68ebbaeb * configclients.jsp: Add start button for clients and webapps. 2008-06-20 20:20:50 +00:00
zzz
f3d73a6c15 * configclients.jsp: Implement saves for clients and webapps. 2008-06-17 13:48:41 +00:00
zzz
91950a37f5 * Comm System: Add new STATUS_HOSED for use when UDP bind fails
* Summary bar: Display helpful errror message when UDP bind fails
    * UDP: Don't bid when UDP bind fails
2008-06-17 13:47:54 +00:00
zzz
a8c266402e * configclients.jsp: New. For both clients and webapps.
Saves are not yet implemented.
2008-06-16 12:31:14 +00:00
zzz
d78fb4df3c * RouterConsoleRunner: Use a new config file, webapps.config,
to control which .wars in webapps/ get run. Apps are enabled
      by default; disable by (e.g.) webapps.syndie.startOnLoad=false
      Config file is written if it does not exist.
      Implement methods for use by upcoming configclients.jsp.
2008-06-16 12:26:36 +00:00
zzz
fb5a8ee0d8 * Refactor LoadClientAppsJob.java, move some functions to new
ClientAppConfig.java, to make them easily available to
      a future configclients.jsp
2008-06-16 12:19:55 +00:00
zzz
7b81062816 * UDP: Prevent 100% CPU when UDP bind fails;
change bind fail message from ERROR to CRIT
2008-06-16 12:18:43 +00:00
zzz
c3a2adc97e minor updates 2008-06-13 17:19:42 +00:00
zzz
bff685f7ca * Throttle: Use BANDWIDTH rather than CRIT as the rejection reason at
startup, so peers don't list us as failing.
2008-06-10 14:05:55 +00:00
zzz
7e51c86c38 * Floodfill: Add new FloodfillMonitorJob, which tracks active
floodfills, and automatically enables/disables floodfill on
      Class O routers to maintain 5-7 total active floodfills
2008-06-10 13:37:27 +00:00
zzz
df069ec9d1 * NetDb Stats:
- Remove several more stats
      - Don't publish bw stats in first hour of uptime
      - Publish floodfill stats even if other stats are disabled
      - Changes not effective until 0.6.2.1 to provide cover.
2008-06-10 13:28:13 +00:00
zzz
eb3164d0e0 * graphs.jsp: Fix a bug where it tries to display the combined
bandwidth graph when it isn't available
2008-06-10 13:17:28 +00:00
zzz
5a69de3650 0.6.2-1 2008-06-09 14:12:09 +00:00
zzz
87b933fd3a propagate from branch 'i2p.i2p.i2p-0.6.2.1-pre' (head 8b23a248995e5c57ccef1c2620a47929f4b257cf)
to branch 'i2p.i2p' (head f65d1f225d8700ea812e1c3cbc0ee9e7a5bbaf98)
2008-06-09 14:00:50 +00:00
zzz
2404078bfa 2008-06-09 zzz
* Reachability: Restrict peers with no SSU address at all from inbound tunnels
    * News:
      - Add display of last updated and last checked time
        on index.jsp and configupdate.jsp
      - Add a function to get update version (unused for now)
    * config.jsp: Add another warning
2008-06-09 13:14:52 +00:00
zzz
6b33378a0a fix date in the xml 2008-06-08 17:37:13 +00:00
complication
c46c9b2b7c * Fix version in news.xml so it could be published 2008-06-07 21:46:33 +00:00
complication
acf22bf8fc * Write announcement and prepare for release 2008-06-07 20:34:07 +00:00
zzz
f3b8c73e96 * NetDb: Tweak some logging on lease problems
* Shitlist:
      - Add shitlistForever() and isShitlistedForever(), unused for now
      - Sort the HTML output by router hash
    * config.jsp: Add another warning
    * netdb.jsp:
      - Sort the lease HTML output by dest hash, local first
      - Sort the router HTML output by router hash
2008-06-07 17:44:13 +00:00
zzz
a8e625072b add de-ebook-archiv.i2p 2008-06-06 21:36:34 +00:00
zzz
88e26224c2 * LeaseSet:
- Sort the leases by expiration date in TunnelPool.locked_buildNewLeaseSet()
        to make later LeaseSet comparisons reliable. This cleans up the code too.
      - Fix broken old vs. new LeaseSet comparison
        in ClientConnectionRunner.requestLeaseSet(),
        so that we only sign and publish a new LeaseSet when it's really new.
        Should reduce outbound overhead both in LeaseSet publishing and LeaseSet bundling,
        and floodfill router load, since locked_buildNewLeaseSet() generates
        the same LeaseSet as before quite frequently, often just seconds apart.
2008-06-06 16:17:07 +00:00
zzz
db9db18bdf * LeaseSet - code cleanup:
- Add exception to enforce max # of leases = 6, should be plenty
      - Rewrite TunnelPool.locked_buildNewLeaseSet() so it doesn't add lots of
        leases and then immediately remove them again, triggering
        the new leaseSet size exception
      - Remove the now unused LeaseSet.removeLease(lease) and
        LeaseSet.removeLease(index)
      - Store first and last expiration for efficiency
2008-06-05 12:30:12 +00:00
zzz
9c06bb3fca * HTTP Proxy error pages: Don't say eepsites are 'temporarily' down since we don't know 2008-06-05 00:46:24 +00:00
zzz
8edfa746e5 * configtunnels.jsp: Add warnings for <= 0 and >= 4 hop configurations 2008-06-04 16:03:34 +00:00
zzz
5729b34f8b * Peer Profiles - Preparation for using bonuses:
- Use CapacityBonus rather than ReachablilityBonus in the Capacity calculation
      - Persist CapacityBonus rather than ReachabilityBonus
      - Include SpeedBonus in the Speed calculation
      - Prevent negative values in Speed and Capacity when using bonuses
      - Clean up SpeedCalculator.java
2008-06-04 15:06:55 +00:00
zzz
2f80f7fa63 Add some config files for a future small distribution 2008-06-04 14:54:05 +00:00
zzz
592e609291 .33-2001 2008-06-01 20:55:32 +00:00
zzz
3396a8813f * Add some compiler flexibility to two obscure SAM makefiles 2008-06-01 20:50:29 +00:00
zzz
6345e669bc * summary bar: Add a warning if you are firewalled and class O 2008-06-01 20:43:51 +00:00
zzz
74a5abbc11 * ProfileOrganizer: Restrict !isSelectable() (i.e. shitlisted) peers from the High Capacity tier,
not just the Fast tier, since we don't use them for tunnels anyway
2008-06-01 20:34:20 +00:00
zzz
19992b1d1b * Logging: Move common WARN output to DEBUG so we can ask users to
set the default log level to WARN without massive spewage
2008-06-01 20:24:43 +00:00
zzz
02e7a19f65 * i2psnark: Change displayed peer idents to match that shown by bytemonsoon 2008-06-01 20:17:48 +00:00
zzz
c6a697df57 * Client Apps: Add new parameter for clients.config,
clientApp.x.startOnLoad=false, to disable loading
        (for SAM for example). Defaults to true of course.
2008-06-01 20:16:17 +00:00
zzz
26bb479957 * summary bar: Hide ident, provide a tooltip and a link 2008-06-01 20:14:00 +00:00
zzz
0c42e7e4b2 make a nicer initialNews.xml, add clarification to config.jsp 2008-05-30 00:08:29 +00:00
zzz
699a62a9b9 Dont bid on private IP addresses in transports 2008-05-27 13:20:56 +00:00
zzz
ffc67d1e5a add a updaterRouter target, containing only i2p.jar and router.jar 2008-05-26 14:39:39 +00:00
zzz
2f72f5ca67 * Throttle: Set a default router.maxParticipatingTunnels = 3000 (was none)
* Stats: Add a fake uptime if not publishing stats, to get participating tunnels
    * build.xml:
      - Add an updateSmall target which includes only the essentials
      - Clean up the build file some 
      - Remove empty eepsite/ and subdirs from i2pupdate.zip
    * configtunnels.jsp: Add warning
    * i2psnark: Catch a bencode exception (bad peer from tracker) earlier
    * i2psnark-standalone: Fix exception http://forum.i2p/viewtopic.php?p=12217
2008-05-26 13:13:26 +00:00
dev
955e7823ad replaced jetty download-url 2008-05-22 20:52:56 +00:00
zzz
7e3800a5cb * Reachability:
- Call the previously unused profile.tunnelTestFailed()
        (redefined to include a probability argument)
        and severely downgrade a peer's capacity upon failures,
        depending on tunnel length and direction.
        This will help push unreachable and malicious peers
        out of the High Capacity tier.
      - Put recent fail rate on profiles.jsp
    * ProfileOrganizer: Logging cleanup
    * eepsite_index.html: Update add-host and jump links
    * HTTP Proxy: Remove trevorreznik jump server from list
2008-05-20 12:48:41 +00:00
dev
6c7691cecb updated history 2008-05-20 11:31:52 +00:00
dev
760c316486 merge of '883c453307272eee439471d4e9da1e120804dac1'
and 'c60598471c5f08b7d7e12e38d39f7a1d4c8ccf63'
2008-05-20 11:30:41 +00:00
dev
5d9d82879f implemented PrivateKeyFile(implements #3) 2008-05-20 11:30:03 +00:00
zzz
9b8772a470 * Throttle: Reject tunnels for first 20m uptime (was 10m)
* TunnelPeerSelectors:
       - Re-enable strict ordering of peers,
         based on XOR distance from a random hash
       - Restrict peers with uptime < 90m from tunnels (was 2h),
         which is really 60m due to rounding in netDb publishing.
    * i2psnark:
       - Limit max pipelined requests from a single peer to 128KB
         (was unlimited; i2p-bt default is 5 * 64KB)
       - Increase max uploaders per torrent to 6 (was 4)
       - Reduce max connections per torrent to 16 (was 24) to increase
         unchoke time and reduce memory consumption
       - Strictly enforce max connections per torrent
       - Choke more gradually when over BW limit
    * help.jsp: Add a link to the FAQ
    * peers.jsp: Fix UDP direction indicators
    * hosts.txt: Add update.postman.i2p
2008-05-18 21:45:54 +00:00
zzz
bc5d87e6f0 * i2psnark:
- Randomize the PeerCheckerTask start times to make global limiting
        work better
      - Calculate bw limits using 40s rather than 4m averages to make
        bw limiting work better
      - Change default bw limit from uplimit/3 to uplimit/2 due to
        overhead reduction from the leaseset bundling change
2008-05-12 13:53:11 +00:00
zzz
d81bff267a * Outbound message:
- Tweak the cache key for efficiency
2008-05-12 13:50:15 +00:00
zzz
042399f293 * Stats:
- Require two udp stats when stats.full=false, caused NPE on peers.jsp
2008-05-12 13:48:41 +00:00
zzz
5be7ea1fc5 * libjbigi:
- Add documentation on dynamic build option
      - Add two speed tests to the build script
      - Clean up the build script, make it easier to build dynamic
2008-05-12 13:47:15 +00:00
zzz
db34665bb1 * Update Handler:
- Add postman to the list
2008-05-12 13:46:23 +00:00
zzz
ed9a03ebc7 * Summary bar:
- Add messages when dropping tunnel requests due to load
2008-05-12 13:45:08 +00:00
zzz
619b5c0e45 * Update Handler:
- Add option to download and verify only
      - Add distinct error message if version check fails
2008-05-10 14:31:18 +00:00
zzz
4c2c5ca232 Simplify oldstats.jsp if no events in a stat 2008-05-10 14:28:37 +00:00
zzz
3a203c3018 Fix the hosed inNetPool.droppedDeliveryStatusDelay stat (caused by an SSU hack) 2008-05-10 14:27:49 +00:00
zzz
3e86ee9746 Dont write out the my.info file 2008-05-10 14:26:24 +00:00
dev
d0855e1fc6 added http://www.i2p2.i2p/_static/i2pupdate.sud as another update-site 2008-05-09 12:37:11 +00:00
zzz
0bde8a24e4 * Reachability:
- Restrict peers requiring introducers from inbound tunnels,
        since it's slow and unreliable... and many of them advertise
        NTCP, which seems unlikely to work
      - Provide warning on summary bar if firewalled with inbound NTCP enabled
    * Stats: Remove the bw.[send,recv]Bps[1,15]s stats unless
      log level net.i2p.router.transport.FIFOBandwidthLimiter >= WARN
      at startup (you didn't get any data unless you set the log level anyway)
    * oldstats.jsp: Don't put 2 decimal places on integer event counts
    * Remove the Internals link from the menu bar
    * i2psnark: Extend startup delay from 1 to 3 minutes
2008-05-07 16:23:54 +00:00
dev
4049ff5167 -2 2008-05-06 20:04:26 +00:00
dev
89389ccc13 added i2jump.i2p as jump-site 2008-05-06 19:44:35 +00:00
zzz
959e308578 Add router version to profiles.jsp 2008-05-05 16:26:15 +00:00
zzz
8d4cbd8556 I2PTunnel: Change default outproxy to false.i2p 2008-05-05 14:42:17 +00:00
zzz
99b9c93636 -1 2008-05-05 14:10:19 +00:00
zzz
47c666c582 * Summary bar:
- Add reachability status
      - Add participating tunnel acceptance status
    * Throttle: Reject tunnels for first 10m uptime
2008-05-05 14:07:40 +00:00
zzz
a3c330fd9d - Restrict <= .32 SSU-only peers from inbound tunnels,
since they don't know if they are unreachable
2008-05-05 14:04:41 +00:00
zzz
a6f3478db3 * Outbound message:
- Fix a couple of tunnel cache cleaning bugs
      - Cache based on source+dest pairs rather than just dest
      - Send the reply leaseSet only when necessary,
        rather than all the time (big savings in overhead)
      - Enable persistent lease selection again
      - Logging tweaks
2008-05-05 14:01:22 +00:00
zzz
b1af22a15e - Have SSU bid aggressively when it has less than 3 peers, so
we can determine our IP address and do peer testing.
        Otherwise a router may never determine its IP address or reachability status.
2008-05-05 13:57:54 +00:00
zzz
65ec41c48f NetDb Stats: Cleanup of commented out stats 2008-05-05 13:55:50 +00:00
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
jrandom
1c66543938 0.6.1.29 released 2007-08-24 00:33:28 +00:00
zzz
53ab3c472e 2007-08-13 zzz
* readme.html - Add inproxy.tino.i2p, replace search.i2p with eepsites.i2p,
      tweak the eepsite and troubleshooting sections
2007-08-13 19:42:59 +00:00
zzz
a4b221fa71 2007-08-11 zzz
* Add stats for individual tunnel rates (nice when graphed)
    * i2psnark: Fix outbound tunnel nickname
2007-08-11 20:48:14 +00:00
complication
e3e1d0842d 2007-08-05 Complication
* Update the sharing calculator on config.jsp
      and explain the trade-off even more thoroughly.
2007-08-06 03:35:42 +00:00
complication
99b5bf9609 2007-08-04 Complication
* Lower the threshold between the K and L bandwidth class,
      so that K is now < 12 KB/s, instead of <= 16 KB/s.
      Hopefully this lets people with 128 kbit/s (16 KB/s) upload lines
      participate in routing, if they keep the default share percentage.
2007-08-05 03:25:30 +00:00
zzz
da10fe0df7 (zzz) ask for bandwidth 2007-07-19 18:05:44 +00:00
zzz
9fd5ba7b2d 2007-07-16 zzz
* i2psnark: Add tooltip info for choked/uninterested
2007-07-16 21:15:51 +00:00
zzz
05b5df9d76 2007-07-16 zzz
* Make selection of graphed data configurable via configstats.jsp,
      remove most of the default graphs to save some memory
2007-07-16 20:47:57 +00:00
zzz
5c1dc79767 2007-07-15 zzz
* Add current values to graph legends
    * Fix up previous Rate fix to check for divide by zero
2007-07-15 18:34:33 +00:00
complication
4acd2996c5 2007-07-14 Complication
* Take the post-download routerInfo size check back out of ReseedHandler,
      since it wasn't helpful, and a lower limit caused false warnings.
    * Give EepGet ability to enforce a min/max HTTP response size.
    * Enforce a maximum response size of 8 MB when ReseedHandler
      downloads into a ByteArrayOutputStream.
    * Refactor ReseedHandler/ReseedRunner from static to ordinary classes,
      change invocation from RouterConsoleRunner accordingly.
    * Add an EepGet status listener to ReseedHandler to log causes of reseed failure,
      provide status reports to indicate the progress of reseeding.
    * Enable icon for default eepsite, and the index page
      of the router console (more later).
2007-07-15 00:56:18 +00:00
zzz
16fa6a89bc 2007-07-14 zzz
* Clean up graphs.jsp - set K=1024 where appropriate,
      output image sizes in html, catch ooms, other minor tweaks
    * Fix current event count truncation which fixes graphs with low
      60-sec event counts displaying high values
      (bw.* and router.* graphs for example were 1.5x too high)
      Affects all "events per period" (non-lifetime) counts.
2007-07-14 18:44:11 +00:00
zzz
2a72e8574b 2007-07-09 zzz
* i2psnark: give a better error message for a non-i2p torrent
2007-07-10 01:20:37 +00:00
zzz
d4a1bcf28f 2007-07-07 zzz
* Add auto-detect IP/Port to NTCP. When enabled on config.jsp,
      SSU will notify/restart NTCP when the external address changes.
      Now you can enable inbound TCP without a static IP or dyndns service.
2007-07-07 20:03:50 +00:00
zzz
409b71def5 2007-07-04 zzz
* Display calculated share bandwidth and remove load testing
      on config.jsp
2007-07-04 22:58:48 +00:00
zzz
2dc5fbda02 2007-07-01 zzz
* Replace broken option i2np.udp.alwaysPreferred with
      i2np.udp.preferred and adjust UDP bids; possible settings are
      "false" (default), "true", and "always".
      Default setting results in same behavior as before
      (NTCP is preferred unless it isn't established and UDP is established).
      Use to compare NTCP and UDP transports.
2007-07-01 22:07:52 +00:00
jrandom
71aaf03d09 2007-06-27 jrandom
* fix for a streaming lib bug that could leave a thread waiting
      indefinitely (thanks Complication!)
2007-06-28 01:51:16 +00:00
complication
30c99e630b 2007-06-16 Complication
* First pass on EepGet and ReseedHandler improvements,
      please avoid use on routers which matter!
    * Give EepGet ability of downloading into an OutputStream,
      such as the ByteArrayOutputStream of ReseedHandler.
    * Detect failure to reseed better, report it persistently
      and more verbosely, provide a link to logs
      and suggest manual reseed.
2007-06-16 23:15:49 +00:00
complication
445b39171a 2007-05-06 Complication
* spelling correction to history.txt
2007-05-06 20:02:04 +00:00
complication
571c2d6047 2007-05-06 Complication
* Fix the build.xml file, so the preppkg build target won't try copying files
      which became deprecated with the old Syndie (thank for alerting, itsu!)
2007-05-06 19:52:39 +00:00
zzz
42ff763933 (zzz) 4-10 2007-04-11 06:01:35 +00:00
zzz
727edc3ff9 (zzz) add 204 log link 2007-04-08 04:18:18 +00:00
zzz
82a4758a0a (zzz) 3-27 and 4-3 2007-04-05 06:11:21 +00:00
zzz
915914ebb3 2007-03-31 zzz
* Add trevorreznik jump server to the http proxy error page
    * Add anonymity to the trackers supporting details links in i2psnark
2007-03-31 21:50:51 +00:00
zzz
c438b56378 (zzz) 3-20 2007-03-25 22:58:18 +00:00
zzz
307ccfb1b4 2007-03-24 zzz
* Remove Syndie from build targets and navbar
2007-03-24 07:57:37 +00:00
zzz
34e23259b4 2007-03-22 zzz
* i2psnark tracker handling tweaks:
    -   Add link to tracker details page (Postman only for now, requires bytemonsoon patch)
    -   Add Base URL to tracker list configuration
    -   Web page links built from tracker list Base URLs
    -   Only build and sort tracker list once
    -   Add anonymityWeb tracker to default list
    -   Add tooltip info for TrackerErrs
    -   Stop torrent if not registered with tracker
    -   Mark temp files as delete on exit
2007-03-22 05:21:25 +00:00
zzz
036802d66a 2007-03-18 zzz
* i2psnark: Cleanup some handling of saved partial pieces
    * i2psnark: Put bit counting in Bitfield.java for efficiency
    * i2psnark: Save torrent completion state in i2psnark.config
2007-03-18 21:57:01 +00:00
zzz
6a7dbc8e3a (zzz) i2psnark: Save torrent completion status in i2psnark.config 2007-03-18 21:43:41 +00:00
zzz
cf4a9ffc27 (zzz) i2psnark: Put bit counting in Bitfield.java for efficiency 2007-03-18 21:28:28 +00:00
zzz
6ef4adf318 (zzz) i2psnark: Remove saved partial when halted, don't save partial when halted 2007-03-18 21:25:18 +00:00
zzz
f84c9bf3b1 (zzz) .28 news 2007-03-18 02:17:16 +00:00
jrandom
da0837bd58 ugh, jrandom sucks. 0.6.1.28 2007-03-18 01:47:59 +00:00
jrandom
9094a62273 oops 2007-03-17 21:19:37 +00:00
jrandom
026183a655 * 2007-03-17 0.6.1.2 released 2007-03-17 21:18:12 +00:00
zzz
b033c7945c (zzz) i2psnark: clarify that total uploader value is peers on UI. (thanks jadeSerpent) 2007-03-15 18:26:06 +00:00
zzz
0c2dcf0845 (zzz) 3-13 mtg 2007-03-15 08:21:35 +00:00
zzz
b6e597e5bf 2007-03-13 zzz
* i2psnark: Make max total uploaders configurable (thanks Amiga4000!)
2007-03-14 04:06:27 +00:00
jrandom
ae402baa71 2007-03-12 jrandom
* dodge a race on startup (thanks zzz!)
2007-03-12 18:19:57 +00:00
zzz
d6c8a4d9eb 2007-03-10 zzz
* Streaming lib: Change initial RTT deviation from RTT to RTT/2
      to reduce early RTO values
2007-03-10 08:45:27 +00:00
zzz
8e2849b7e5 2007-03-08 zzz
* i2psnark changes to improve upload performance:
    *  Implement total uploader limit (10)
    *  Don't timeout non-piece messages out
    *  Change chunk size to 32K (was 64K)
    *  Change request limit to 64K (was 256K)
    * i2psnark: Disconnect from seeds when complete
2007-03-08 18:55:17 +00:00
zzz
0aa0cd330f (zzz) take dynamic router keys off the config page 2007-03-07 21:05:21 +00:00
zzz
0960cafaf5 2007-03-07 zzz
* Streaming lib changes to improve upstream performance during congestion:
    *   Change min window size from 12 to 1
    *   Change max timeout from 10 to 45 sec
    *   Change initial timeout from 10 to 15 sec
    *   Change intial window size for i2psnark from 12 to 1
    *   Change slow start growth rate for i2psnark from 1/2 to 1
2007-03-07 05:11:45 +00:00
zzz
2088a28053 (zzz) Mar. 04 - More tweaks to the default eepsite start page to help
people start up the tunnel which is now stopped by default
2007-03-04 23:25:18 +00:00
zzz
a5c4ba3bff 2007-03-03 zzz
* Upgrade from Jetty 5.1.6 to 5.1.12 which fixes spaces in URL
    * Add a updaterWithJetty build target
2007-03-03 20:30:52 +00:00
zzz
1bbd2cf52e 2007-03-03 zzz
* Implement priority sending for NTCP
    * Disable trimForOverload() in tunnel BuildExecutor which
      was preventing tunnel builds when outbound traffic was high
      (i.e. most of the time when running i2psnark)
2007-03-03 20:11:05 +00:00
zzz
ce50efa60c (zzz) 02-28 i2psnark file reopen cleanup 2007-03-01 02:29:11 +00:00
zzz
a3c64a9ba3 (zzz) 02-28 add peer details to i2psnark web page 2007-03-01 02:22:14 +00:00
zzz
1447164a8a (zzz) 2-20 2007-02-24 09:15:29 +00:00
zzz
bc0bf8d7ff (zzz) Fix Syndie URL typo 2007-02-22 08:51:14 +00:00
zzz
9f346f488e (zzz) add links 2007-02-17 02:07:45 +00:00
zzz
760d7d9704 (zzz) 0.6.1.27 2007-02-16 19:35:09 +00:00
jrandom
77310e17d1 * 2007-02-15 0.6.1.27 released
2007-02-15  jrandom
    * Limit the whispering floodfill sends to at most 3 randomly
      chosen from the known floodfill peers
2007-02-15 23:25:04 +00:00
jrandom
e54b964929 2007-02-14 jrandom
* Don't filter out KICK and H(ide oper status) IRC messages
      (thanks Takk and postman!)
2007-02-14 21:35:43 +00:00
jrandom
809f3e847b 2007-02-13 jrandom
* Tell our peers about who we know in the floodfill netDb every
      6 hours or so, mitigating the situation where peers lose track
      of floodfill routers.
    * Disable the Syndie updater (people should use the new Syndie,
      not this one)
    * Disable the eepsite tunnel by default
2007-02-14 04:33:36 +00:00
zzz
f4beebe60d (zzz) 02-13 2007-02-14 03:04:11 +00:00
jrandom
827e427f0b added trac.i2p 2007-02-12 10:26:21 +00:00
zzz
c02125511d (zzz) 02-06 2007-02-08 18:51:58 +00:00
zzz
1aa1069b6f (zzz) 01-30 2007-02-02 02:50:43 +00:00
zzz
91d281077d 2007-01-30 zzz
* i2psnark: Don't hold _snarks lock while checking a snark,
      so web page is responsive at startup
2007-01-30 08:58:19 +00:00
zzz
f339dec024 2007-01-29 zzz
* i2psnark: Add NickyB tracker
2007-01-30 04:05:21 +00:00
zzz
2aeef44f8d 2007-01-28 zzz
* i2psnark: Don't hold sendQueue lock while flushing output,
      to make everything run smoother
2007-01-29 04:03:36 +00:00
zzz
0fd41a9490 2007-01-27 zzz
* i2psnark: Fix orphaned Snark reader tasks leading to OOMs
2007-01-28 02:30:05 +00:00
complication
58f10d14b2 2007-01-20 Complication
* Drop overlooked comment
2007-01-21 03:49:41 +00:00
complication
46ca42ddf8 2007-01-20 Complication
* Modify ReseedHandler to query the "i2p.reseedURL" property from I2PAppContext
      instead of System, so setting a reseed URL in advanced configuration has effect.
    * Clean out obsolete reseed code from ConfigNetHandler.
2007-01-21 03:35:49 +00:00
zzz
e6e6d6f4ee 2007-01-20 zzz
* Improve performance by not reading in the whole
      piece from disk for each request. A huge memory savings
      on 1MB torrents with many peers.
2007-01-21 01:43:31 +00:00
zzz
8a87df605b 2007-01-20 zzz
* i2psnark: More choking rotation tweaks
    * Improve performance by not reading in the whole
      piece from disk for each request. A huge memory savings
      on 1MB torrents with many peers.
2007-01-21 00:35:09 +00:00
zzz
8ca085bceb (zzz) 1/16 2007-01-19 03:04:49 +00:00
zzz
df47587db0 * Add new HTTP Proxy error message for non-http protocols 2007-01-18 01:42:13 +00:00
zzz
d705e0ad04 2007-01-17 zzz
* Add note on Syndie index.html steering people to new Syndie
2007-01-17 05:13:27 +00:00
zzz
40d209dd7c 2007-01-17 zzz
* i2psnark: Fix crash when autostart off and
      tcrrent started manually
2007-01-16 06:20:23 +00:00
zzz
7f2a0457bf 2007-01-16 zzz
* i2psnark: Fix bug caused by last i2psnark checkin
      (ConnectionAcceptor not started)
    * Don't start PeerCoordinator, ConnectionAcceptor,
      and TrackerClient unless starting torrent
2007-01-16 04:47:58 +00:00
jrandom
f4749f2483 2007-01-15 jrandom
* small guard against unnecessary streaming lib reset packets
      (thanks Complication!)
2007-01-15 06:35:59 +00:00
zzz
9c42830076 2007-01-15 zzz
* i2psnark: Add 'Stop All' link on web page
    * Add some links to trackers and forum on web page
    * Don't start tunnel if 'Autostart' unchecked
    * Fix torrent restart bug by reopening file descriptors
2007-01-15 04:36:03 +00:00
zzz
53ba6c2a64 2007-01-14 zzz
* i2psnark: Improvements for torrents with > 4 leechers:
      choke based on upload rate when seeding, and
      be smarter and fairer about rotating choked peers.
    * Handle two common i2psnark OOM situations rather
      than shutting down the whole thing.
    * Fix reporting to tracker of remaining bytes for
      torrents > 4GB (but ByteMonsoon still has a bug)
2007-01-14 19:49:33 +00:00
zzz
61b3f21f69 (zzz) 01-09 2007-01-13 01:15:04 +00:00
zzz
506fd5f889 (zzz) Jan. 2 2007-01-03 03:19:06 +00:00
zzz
d538f888b4 (zzz) 12-19,12-26 2006-12-28 09:11:30 +00:00
jrandom
976c5fdd47 new syndie httpserv 2006-12-16 22:31:07 +00:00
zzz
b63f3437f2 (zzz) 12-12 mtg 2006-12-13 06:40:15 +00:00
zzz
e760f2e538 (zzz) 12/5 mtg 2006-12-06 02:52:13 +00:00
zzz
17c8fca779 (zzz) 11-28 mtg 2006-11-29 01:37:18 +00:00
zzz
87fda382c3 (zzz) 11/14 and 11/21 mtgs 2006-11-22 02:31:23 +00:00
zzz
1e404cd7ac 2006-10-29 zzz
* i2psnark: Fix and enable generation of multifile torrents,
      print error if no tracker selected at create-torrent,
      fix stopping a torrent that hasn't started successfully,
      add eBook and GayTorrents trackers to form,
      web page formatting tweaks
2006-11-10 01:44:35 +00:00
zzz
098f99d806 (zzz) 11/7 mtg 2006-11-10 01:34:54 +00:00
zzz
da93f96035 (zzz) 10/31 mtg 2006-11-02 02:39:07 +00:00
complication
ead39cc87e 2006-10-29 Complication
* Ensure we get NTP samples from more diverse sources
      (0.pool.ntp.org, 1.pool.ntp.org, etc)
    * Discard median-based peer skew calculator as framed average works,
      and adjusting its percentage can make it behave median-like
    * Require more data points (from at least 20 peers)
      before considering a peer skew measurement reliable
2006-10-29 19:29:50 +00:00
zzz
e4e3c44459 (zzz) 10/24 2006-10-25 08:22:09 +00:00
zzz
af151e32e5 (zzz) 10/17 mtg 2006-10-21 08:22:24 +00:00
jrandom
12819a2a17 added mtn.i2p 2006-10-15 02:10:36 +00:00
jrandom
87eedff254 0.6.1.26 2006-10-09 05:10:22 +00:00
jrandom
4c59cd7621 * 2006-10-10 0.6.1.26 released
2006-10-10  jrandom
    * Removed the status display from the console, as its more confusing
      than informative (though the content is still displayed in the HTML)
2006-10-09 01:44:47 +00:00
complication
ef707e7956 2006-10-08 Complication
* Update comment to reflect current status
2006-10-08 23:10:58 +00:00
complication
73cf3fb299 2006-10-08 Complication
* Add a framed average peer clock skew calculator
    * Add config property "router.clockOffsetSanityCheck" to determine
      if NTP-suggested clock offsets get sanity checked (default "true")
    * Reject NTP-suggested clock offsets if they'd increase peer clock skew
      by more than 5 seconds, or make it more than 20 seconds total
    * Decrease log level in getMedianPeerClockSkew()
2006-10-08 22:52:59 +00:00
zzz
80b0c97d72 (zzz) 10/3 status notes 2006-10-04 19:41:09 +00:00
zzz
5cf85c1d7b (zzz)
* i2psnark: Second try at synchronization fix - synch addRequest()
      completely rather than just portions of it and requestNextPiece()
2006-09-29 23:54:17 +00:00
jrandom
c14e52ceb5 2006-09-27 jrandom
* added HMAC-SHA256
    * properly use CRLF with EepPost
    * suppress jbigi/jcpuid messages if jbigi.dontLog/jcpuid.dontLog is set
    * PBE session key generation (with 1000 rounds of SHA256)
    * misc SDK helper functions
2006-09-27 06:00:33 +00:00
complication
32a579e480 2006-09-26 Complication
* Take back another inadverent logging change in NTCPConnection
2006-09-27 04:44:13 +00:00
complication
0a240a4436 2006-09-26 Complication
* Take back an accidental log level change
2006-09-27 04:31:34 +00:00
complication
9325b806e4 2006-09-26 Complication
* Subclass from Clock a RouterClock which can access router transports,
      with the goal of developing it to second-guess NTP results
    * Make transports report clock skew in seconds
    * Adjust renderStatusHTML() methods accordingly
    * Show average for NTCP clock skews too
    * Give transports a getClockSkews() method to report clock skews
    * Give transport manager a getClockSkews() method to aggregate results
    * Give comm system facade a getMedianPeerClockSkew() method which RouterClock calls
      (to observe results, add "net.i2p.router.transport.CommSystemFacadeImpl=WARN" to
logging)
    * Extra explicitness in NTCP classes to denote unit of time.
    * Fix some places in NTCPConnection where milliseconds and seconds were confused
2006-09-27 04:02:13 +00:00
zzz
ef2e24ea11 (zzz)
* i2psnark: Paranoid copy before writing pieces,
      recheck files on completion, redownload bad pieces
    * i2psnark: Don't contact tracker as often when seeding
2006-09-26 03:11:39 +00:00
zzz
373934c6e0 (zzz)
* i2psnark: Add some synchronization to prevent rare problem
      after restoring orphan piece
2006-09-24 18:30:22 +00:00
zzz
e8e8bac694 (zzz)
* i2psnark: Eliminate duplicate requests caused by i2p-bt's
      rapid choke/unchokes
    * i2psnark: Truncate long TrackerErr messages on web page
2006-09-20 22:39:24 +00:00
zzz
23e8a558c2 (zzz)
* i2psnark: Implement retransmission of requests. This
      eliminates one cause of complete stalls with a peer.
      This problem is common on torrents with a small number of
      active peers where there are no choke/unchokes to kickstart things.
2006-09-16 21:07:28 +00:00
complication
46f2645834 2006-09-14 Complication
* news.xml update
2006-09-14 03:16:53 +00:00
zzz
2329439034 (zzz)
* i2psnark: Fix restoral of partial pieces broken by last patch
2006-09-14 02:37:32 +00:00
zzz
6d400368b9 (zzz) changelog date fix 2006-09-13 23:24:14 +00:00
zzz
26c13b40fe (zzz)
* i2psnark: Mark a peer's requests as unrequested on disconnect,
      preventing premature end game
    * i2psnark: Randomize selection of next piece during end game
    * i2psnark: Don't restore a partial piece to a peer that is already working on it
    * i2psnark: strip ".torrent" on web page
    * i2psnark: Limit piece size in generated torrent to 1MB max
2006-09-13 23:02:07 +00:00
zzz
9fd0e95fe8 (zzz) 9/12 status 2006-09-13 17:34:58 +00:00
zzz
7e21f2c92b (zzz)
* i2psnark: Add "Stalled" indication and stat totals on web page
2006-09-10 01:55:37 +00:00
zzz
c9d8e796c6 (zzz)
* i2psnark: Fix bug where new peers would always be set to "interested"
      regardless of actual interest
    * i2psnark: Reduce max piece size from 10MB to 1MB; larger may have severe
      memory and efficiency problems
2006-09-09 22:15:05 +00:00
zzz
e7203f5d46 (zzz) 0.6.1.25 2006-09-09 21:19:49 +00:00
jrandom
22d76a1b64 * 2006-09-09 0.6.1.25 released 2006-09-09 17:46:21 +00:00
jrandom
0903dc46c6 2006-09-08 jrandom
* Tweak the PRNG logging so it only displays error messages if there are
      problems
    * Disable dynamic router keys for the time being, as they don't offer
      meaningful security, may hurt the router, and makes it harder to
      determine the network health.  The code to restart on SSU IP change is
      still enabled however.
    * Disable tunnel load testing, leaning back on the tiered selection for
      the time being.
    * Spattering of bugfixes
2006-09-09 01:41:57 +00:00
zzz
0f56ec8078 (zzz) oops remove duplicate 2006-09-07 23:26:53 +00:00
zzz
70ee1df2bf (zzz)
* i2psnark: Increase output timeout from 2 min to 4 min
    * i2psnark: Orphan debug msg cleanup
    * i2psnark: More web rate report cleanup
2006-09-07 23:22:12 +00:00
zzz
61a6a29bec cCVS: ---------------------------------------------------------------------- 2006-09-07 23:03:18 +00:00
zzz
678f7d8f72 (zzz)
* i2psnark: Implement basic partial-piece saves across connections
    * i2psnark: Implement keep-alive sending. This will keep non-i2psnark clients
      from dropping us for inactivity but also renders the 2-minute transmit-inactivity
      code in i2psnark ineffective. Will have to research why there is transmit but
      not receive inactivity code. With the current connection limit of 24 peers
      we aren't in any danger of keeping out new peers by keeping inactive ones.
    * i2psnark: Increase CHECK_PERIOD from 20 to 40 since nothing happens in 20 seconds
    * i2psnark: Fix dropped chunk handling
    * i2psnark: Web rate report cleanup
2006-09-06 06:32:53 +00:00
zzz
b92ee364bc (zzz)
* i2psnark: Report cleared trackerErr immediately
    * i2psnark: Add trackerErr reporting after previous success; retry more quickly
    * i2psnark: Set up new connections more quickly
    * i2psnark: Don't delay tracker fetch when setting up lots of connections
    * i2psnark: Reduce MAX_UPLOADERS from 12 to 4
2006-09-04 08:26:21 +00:00
zzz
aef19fcd38 (zzz) i2psnark: enable pipelining, set tunnel length default to 1 + 0-1 2006-09-04 06:01:53 +00:00
zzz
3b01df1d2c (zzz) Add rate reporting to i2psnark 2006-09-03 09:12:22 +00:00
complication
4aed23b198 2006-09-03 Complication
* Limit form size in SusiDNS to avoid exceeding a POST size limit on postback
    * Print messages about addressbook size to give better overview
    * Enable delete function in published addressbook
2006-09-03 06:37:46 +00:00
complication
03e8875c27 2006-08-21 Complication
* Fix error reporting discrepancy (thanks for helping notice, yojoe!)
2006-08-21 05:55:33 +00:00
complication
48921a0875 2006-08-03 Complication
* news.xml update
2006-08-04 00:49:40 +00:00
jrandom
633fabb09e 2006-08-03 jrandom
* Decrease the recently modified tunnel building timeout, though keep
      the scaling on their processing
2006-08-03 22:34:24 +00:00
jrandom
bc42c26d94 2006-07-31 jrandom
* Increase the tunnel building timeout
    * Avoid a rare race (thanks bar!)
    * Fix the bandwidth capacity publishing code to factor in share percentage
      and outbound throttling (oops)
2006-08-01 02:26:52 +00:00
complication
3c09ca3359 2006-07-29 Complication
* Treat NTP responses from unexpected stratums like failures
2006-07-30 05:08:20 +00:00
zzz
1e9e7dd345 (zzz) 0.6.1.24 2006-07-29 23:02:57 +00:00
jrandom
034803add7 * 2006-07-28 0.6.1.24 released 2006-07-29 18:03:14 +00:00
jrandom
b25bb053bb 2006-07-28 jrandom
* Don't try to reverify too many netDb entries at once (thanks
      cervantes and Complication!)
2006-07-29 04:41:15 +00:00
jrandom
9bd0c79441 2006-07-28 jrandom
* Actually fix the threading deadlock issue in the netDb (removing
      the synchronized access to individual kbuckets while validating
      individual entries) (thanks cervantes, postman, frosk, et al!)
2006-07-29 01:11:50 +00:00
jrandom
06b8670410 * 2006-07-27 0.6.1.23 released 2006-07-28 03:34:59 +00:00
jrandom
6577ae499f 2006-07-27 jrandom
* Cut down NTCP connection establishments once we know the peer is skewed
      (rather than wait for full establishment before verifying)
    * Removed a lock on the stats framework when accessing rates, which
      shouldn't be a problem, assuming rates are created (pretty much) all at
      once and merely updated during the lifetime of the jvm.
2006-07-27 23:40:00 +00:00
jrandom
54bc5485ec oops, thanks bar! 2006-07-27 07:06:55 +00:00
jrandom
84b741ac98 2006-07-27 jrandom
* Further NTCP write status cleanup
    * Handle more oddly-timed NTCP disconnections (thanks bar!)
2006-07-27 06:20:25 +00:00
jrandom
c48c419d74 quick prng workaround 2006-07-27 01:34:31 +00:00
jrandom
fb2e795add 2006-07-26 jrandom
* When dropping a netDb router reference, only accept newer
      references as part of the update check
    * If we have been up for a while, don't accept really old
      router references (published 2 or more days ago)
    * Drop router references once they are no longer valid, even if
      they were allowed in due to the lax restrictions on startup
2006-07-27 01:04:59 +00:00
jrandom
ec215777ec 2006-07-26 jrandom
* When dropping a netDb router reference, only accept newer
      references as part of the update check
    * If we have been up for a while, don't accept really old
      router references (published 2 or more days ago)
    * Drop router references once they are no longer valid, even if
      they were allowed in due to the lax restrictions on startup
2006-07-27 00:56:49 +00:00
jrandom
d4e0f27c56 2006-07-26 jrandom
* Every time we create a new router identity, add an entry to the
      new "identlog.txt" text file in the I2P install directory.  For
      debugging purposes, publish the count of how many identities the
      router has cycled through, though not the identities itself.
    * Cleaned up the way the multitransport shitlisting worked, and
      added per-transport shitlists
    * When dropping a router reference locally, first fire a netDb
      lookup for the entry
    * Take the peer selection filters into account when organizing the
      profiles (thanks Complication!)
    * Avoid some obvious configuration errors for the NTCP transport
      (invalid ports, "null" ip, etc)
    * Deal with some small NTCP bugs found in the wild (unresolveable
      hosts, strange network discons, etc)
    * Send our netDb info to peers we have direct NTCP connections to
      after each 6-12 hours of connection uptime
    * Clean up the NTCP reading and writing queue logic to avoid some
      potential delays
    * Allow people to specify the IP that the SSU transport binds on
      locally, via the advanced config "i2np.udp.bindInterface=1.2.3.4"
2006-07-26 06:36:18 +00:00
complication
e1c686baa6 2006-07-18 Complication
* URL and date fix in news.xml
2006-07-18 23:35:54 +00:00
jrandom
d57af1aef4 remove 1.5ism 2006-07-18 20:20:08 +00:00
jrandom
a52dd57215 * 2006-07-18 0.6.1.22 released
2006-07-18  jrandom
    * Add a failsafe to the NTCP transport to make sure we keep
      pumping writes when we should.
    * Properly reallow 16-32KBps routers in the default config
      (thanks Complication!)
2006-07-18 20:08:00 +00:00
complication
65138357d3 2006-07-16 Complication
* Collect tunnel build agree/reject/expire statistics
      for each bandwidth tier of peers (and peers of unknown tiers,
      even if those shouldn't exist)
2006-07-16 17:20:46 +00:00
jrandom
f6320696dd 2006-07-14 jrandom
* Improve the multitransport shitlisting (thanks Complication!)
    * Allow routers with a capacity of 16-32KBps to be used in tunnels under
      the default configuration (thanks for the stats Complication!)
    * Properly allow older router references to load on startup
      (thanks bar, Complication, et al!)
    * Add a new "i2p.alwaysAllowReseed" advanced config property, though
      hopefully today's changes should make this unnecessary (thanks void!)
    * Improved NTCP buffering
    * Close NTCP connections if we are too backlogged when writing to them
2006-07-14 18:08:44 +00:00
jrandom
900d8a2026 oops, test method. thanks cervantes 2006-07-07 19:04:24 +00:00
jrandom
ccc9a87e8c unnecessary 2006-07-07 18:59:16 +00:00
jrandom
208634e5de 2006-07-04 jrandom
* New NIO-based tcp transport (NTCP), enabled by default for outbound
      connections only.  Those who configure their NAT/firewall to allow
      inbound connections and specify the external host and port
      (dyndns/etc is ok) on /config.jsp can receive inbound connections.
      SSU is still enabled for use by default for all users as a fallback.
    * Substantial bugfix to the tunnel gateway processing to transfer
      messages sequentially instead of interleaved
    * Renamed GNU/crypto classes to avoid name clashes with kaffe and other
      GNU/Classpath based JVMs
    * Adjust the Fortuna PRNG's pooling system to reduce contention on
      refill with a background thread to refill the output buffer
    * Add per-transport support for the shitlist
    * Add a new async pumped tunnel gateway to reduce tunnel dispatcher
      contention
2006-07-04 21:17:44 +00:00
complication
3d07205c9d 2006-07-01 Complication
* Ensure that the I2PTunnel web interface won't update tunnel settings
      for shared clients when a non-shared client is modified
      (thanks for spotting, BarkerJr!)
2006-07-01 22:44:34 +00:00
zzz
f0a424a93f (zzz) .21, 6-13 mtg 2006-06-15 22:15:09 +00:00
cervantes
f9b59ee07d 2006-06-14 cervantes
* Small tweak to I2PTunnel CSS, so it looks better with desktops
      that use Bitstream Vera fonts @ 96 dpi
2006-06-14 05:24:34 +00:00
jrandom
b92b9d2618 * 2006-06-14 0.6.1.21 released 2006-06-14 02:17:40 +00:00
jrandom
a3db9429a7 2006-06-13 jrandom
* Use a minimum uptime of 2 hours, not 4 (oops)
2006-06-13 23:29:51 +00:00
jrandom
291a5c9578 2006-06-13 jrandom
* Cut down the proactive rejections due to queue size - if we are
      at the point of having decrypted the request off the queue, might
      as well let it through, rather than waste that decryption
2006-06-13 09:38:48 +00:00
jrandom
0a3281c279 2006-06-11 Kloug
* Bugfix to the I2PTunnel IRC filter to support multiple concurrent
      outstanding pings/pongs
2006-06-11 19:48:37 +00:00
jrandom
23f30ba576 2006-06-10 jrandom
* Further reduction in proactive rejections
2006-06-10 20:14:57 +00:00
jrandom
f3de85c4de 2006-06-09 jrandom
* Don't let the pending tunnel request queue grow beyond reason
      (letting things sit for up to 30s when they fail after 10s
      seems a bit... off)
2006-06-10 00:34:44 +00:00
jrandom
a3a4888e0b 2006-06-08 jrandom
* Be more conservative in the proactive rejections
2006-06-09 01:02:40 +00:00
jrandom
6fd7881f8e thanks bar 2006-06-05 06:41:11 +00:00
complication
381f716769 2006-06-04 Complication
* Stop sending a blank line before USER in susimail.
      Seemed to break in rare cases, thanks for reporting, Brachtus!
2006-06-05 01:33:03 +00:00
993 changed files with 32695 additions and 62941 deletions

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<project name="echoclient" default="default" basedir=".">
<description>Builds, tests, and runs the project echoclient.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="echoclient-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@@ -0,0 +1,5 @@
#!/bin/bash
(
cd dist
java -jar echoclient.jar main 37338 testclient $1
)

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

View File

@@ -0,0 +1,629 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="echoclient-impl">
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="" name="sourcepath"/>
<element name="customize" optional="true"/>
<sequential>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="${run.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<j2seproject3:depend/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,8 @@
build.xml.data.CRC32=8ce3cee9
build.xml.script.CRC32=d1de2df3
build.xml.stylesheet.CRC32=be360661
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=8ce3cee9
nbproject/build-impl.xml.script.CRC32=22d1fbbb
nbproject/build-impl.xml.stylesheet.CRC32=487672f9

View File

@@ -0,0 +1,2 @@
jaxws.endorsed.dir=/usr/local/netbeans-6.1/java2/modules/ext/jaxws21/api
user.properties.file=/root/.netbeans/6.1/build.properties

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/1">
<file>file:/root/NetBeansProjects/BOB/Demos/echo/echoclient/src/net/i2p/BOB/Demos/echo/echoclient/Main.java</file>
</open-files>
</project-private>

View File

@@ -0,0 +1,60 @@
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/echoclient.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.BOB.jar=../../../dist/BOB.jar
includes=**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=net.i2p.BOB.Demos.echo.echoclient.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>echoclient</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@@ -0,0 +1,201 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB.Demos.echo.echoclient;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author sponge
*/
public class Main {
public static String Lread(InputStream in) throws IOException {
String S;
int b;
char c;
S = new String();
while(true) {
b = in.read();
if(b == 13) {
//skip CR
continue;
}
if(b < 20 || b > 126) {
// exit on anything not legal
break;
}
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
S = new String(S + c);
}
return S;
}
/**
* Check for "ERROR" and if so, throw RuntimeException
* @param line
* @throws java.lang.RuntimeException
*/
static void checkline(String line) throws RuntimeException {
System.out.println(line); // print status
if(line.startsWith("ERROR")) {
throw new RuntimeException(line);
}
}
static void wrtxt(OutputStream CMDout, String s) throws IOException {
CMDout.write(s.getBytes());
CMDout.write('\n');
CMDout.flush();
}
static void setupconn(String[] args) throws UnknownHostException, IOException, RuntimeException {
String line;
Socket CMDsock = new Socket("localhost", 0xB0B);
InputStream CMDin = CMDsock.getInputStream();
OutputStream CMDout = CMDsock.getOutputStream();
// setup the tunnel.
line = Lread(CMDin);
System.out.println(line); // print the banner
line = Lread(CMDin);
System.out.println(line); // print initial status, should always be "OK"
try {
wrtxt(CMDout, "status " + args[2]);
line = Lread(CMDin); // get the status of this nickname, if it's an error, create it
checkline(line);
} catch(RuntimeException rte) {
wrtxt(CMDout, "setnick " + args[2]);
line = Lread(CMDin); // create a new nickname
checkline(line);
wrtxt(CMDout, "newkeys");
line = Lread(CMDin); // set up new keys
checkline(line);
wrtxt(CMDout, "inport " + args[1]);
line = Lread(CMDin); // set the port we connect in on
checkline(line);
}
wrtxt(CMDout, "getnick " + args[2]);
line = Lread(CMDin); // Set to our nick
try {
checkline(line);
} catch(RuntimeException rte) {
System.out.println("Continuing on existing tunnel..");
return;
}
wrtxt(CMDout, "start");
line = Lread(CMDin); // an error here is OK
System.out.println(line); // print status
CMDsock.close(); // we no longer need this particular socket
}
static void deleteconn(String[] args) throws UnknownHostException, IOException, RuntimeException {
String line;
// Wait for things to flush
try {
Thread.sleep(10000);
} catch(InterruptedException ex) {
// nop
}
Socket CMDsock = new Socket("localhost", 0xB0B);
InputStream CMDin = CMDsock.getInputStream();
OutputStream CMDout = CMDsock.getOutputStream();
// delete the tunnel.
line = Lread(CMDin);
System.out.println(line); // print the banner
line = Lread(CMDin);
System.out.println(line); // print initial status, should always be "OK"
wrtxt(CMDout, "getnick " + args[2]); // Set to our nick
line = Lread(CMDin);
checkline(line);
wrtxt(CMDout, "stop");
line = Lread(CMDin);
checkline(line);
try {
Thread.sleep(2000); //sleep for 2000 ms (Two seconds)
} catch(Exception e) {
// nop
}
wrtxt(CMDout, "clear");
line = Lread(CMDin);
while(line.startsWith("ERROR")) {
wrtxt(CMDout, "clear");
line = Lread(CMDin);
}
System.out.println(line); // print status
CMDsock.close(); // we no longer need this particular socket
}
static void chatter(String[] args) throws UnknownHostException, IOException, RuntimeException {
String line;
Socket sock = new Socket("localhost", Integer.parseInt(args[1]));
InputStream in = sock.getInputStream();
OutputStreamWriter out = new OutputStreamWriter(sock.getOutputStream());
out.write(args[3] + "\n"); // send out the i2p address to connect to
out.flush();
System.out.println("Connecting to " + args[3]);
line = Lread(in); // get server greeting
System.out.println("Got " + line); // show user
out.write("Test complete.\n"); // send something back
out.flush(); // make sure it's sent.
sock.close(); // done.
}
/**
*
* @param args tunnelport tunnelnickname I2Pdestkey
*/
public static void main(String[] args) {
// I'm lazy, and want to exit on any failures.
try {
setupconn(args); // talk to BOB, set up an outbound port
chatter(args); // talk over the connection
} catch(UnknownHostException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
try {
deleteconn(args);
} catch(UnknownHostException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(RuntimeException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<project name="echoserver" default="default" basedir=".">
<description>Builds, tests, and runs the project echoserver.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="echoserver-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

View File

@@ -0,0 +1,629 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="echoserver-impl">
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="" name="sourcepath"/>
<element name="customize" optional="true"/>
<sequential>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="${run.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<j2seproject3:depend/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,8 @@
build.xml.data.CRC32=4ce39738
build.xml.script.CRC32=c1deb82c
build.xml.stylesheet.CRC32=be360661
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=4ce39738
nbproject/build-impl.xml.script.CRC32=555cdd2d
nbproject/build-impl.xml.stylesheet.CRC32=487672f9

View File

@@ -0,0 +1,2 @@
jaxws.endorsed.dir=/usr/local/netbeans-6.1/java2/modules/ext/jaxws21/api
user.properties.file=/root/.netbeans/6.1/build.properties

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/1">
<file>file:/root/NetBeansProjects/BOB/Demos/echo/echoserver/src/net/i2p/BOB/Demos/echo/echoserver/Main.java</file>
</open-files>
</project-private>

View File

@@ -0,0 +1,60 @@
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/echoserver.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.BOB.jar=../../../dist/BOB.jar
includes=**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=net.i2p.BOB.Demos.echo.echoserver.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>echoserver</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@@ -0,0 +1,4 @@
(
cd dist
java -jar echoserver.jar main 37337 testserver
)

View File

@@ -0,0 +1,197 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB.Demos.echo.echoserver;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author sponge
*/
public class Main {
public static String Lread(InputStream in) throws IOException {
String S;
int b;
char c;
S = new String();
while(true) {
b = in.read();
if(b < 20) {
break;
}
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
S = new String(S + c);
}
return S;
}
/**
* Check for "ERROR" and if so, throw RuntimeException
* @param line
* @throws java.lang.RuntimeException
*/
static void checkline(String line) throws RuntimeException {
System.out.println(line); // print status
if(line.startsWith("ERROR")) {
throw new RuntimeException(line);
}
}
static void wrtxt(OutputStream CMDout, String s) throws IOException {
CMDout.write(s.getBytes());
CMDout.write('\n');
CMDout.flush();
}
static void setupconn(String[] args) throws UnknownHostException, IOException, RuntimeException {
String line;
Socket CMDsock = new Socket("localhost", 0xB0B);
InputStream CMDin = CMDsock.getInputStream();
OutputStream CMDout = CMDsock.getOutputStream();
// setup the tunnel.
line = Lread(CMDin);
System.out.println(line); // print the banner
line = Lread(CMDin);
System.out.println(line); // print initial status, should always be "OK"
try {
wrtxt(CMDout, "status " + args[2]);
line =Lread(CMDin); // get the status of this nickname, if it's an error, create it
checkline(line);
} catch(RuntimeException rte) {
wrtxt(CMDout, "setnick " + args[2]);
line =Lread(CMDin); // create a new nickname
checkline(line);
wrtxt(CMDout, "newkeys ");
line =Lread(CMDin); // set up new keys
checkline(line);
wrtxt(CMDout, "outport " + args[1]);
line = Lread(CMDin); // set the port we connect out on
checkline(line);
}
wrtxt(CMDout, "getnick " + args[2]);
line = Lread(CMDin); // Set to our nick
checkline(line);
wrtxt(CMDout, "start ");
line = Lread(CMDin); // an error here is OK
System.out.println(line); // print status
CMDsock.close(); // we no longer need this particular socket
}
static void deleteconn(String[] args) throws UnknownHostException, IOException, RuntimeException {
String line;
Socket CMDsock = new Socket("localhost", 0xB0B);
InputStream CMDin = CMDsock.getInputStream();
OutputStream CMDout = CMDsock.getOutputStream();
// delete the tunnel.
line = Lread(CMDin);
System.out.println(line); // print the banner
line = Lread(CMDin);
System.out.println(line); // print initial status, should always be "OK"
wrtxt(CMDout, "getnick " + args[2]); // Set to our nick
line = Lread(CMDin);
checkline(line);
wrtxt(CMDout, "stop");
line = Lread(CMDin);
checkline(line);
try {
Thread.sleep(2000); //sleep for 2000 ms (Two seconds)
} catch(Exception e) {
// nop
}
wrtxt(CMDout, "clear");
line = Lread(CMDin);
while(line.startsWith("ERROR")) {
wrtxt(CMDout, "clear");
line = Lread(CMDin);
}
System.out.println(line); // print status
CMDsock.close(); // we no longer need this particular socket
}
static void chatter(Socket sock) throws UnknownHostException, IOException, RuntimeException {
String line;
InputStream in = sock.getInputStream();
OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(sock.getOutputStream()));
line = Lread(in); // get remote I2P address
System.out.println("Connect from: " + line); // show user
out.write("Hello, You are connecting from " + line + "\n"); // send greeting
out.flush(); // make sure it's sent.
line = Lread(in); // get test text from client
System.out.println("Got "+line); // show user
sock.close(); // done.
}
private static void serverlistener(String[] args) throws UnknownHostException, IOException, RuntimeException {
ServerSocket listener = new ServerSocket(Integer.parseInt(args[1]), 10, InetAddress.getByName("localhost"));
Socket server;
while(true) {
server = listener.accept();
chatter(server);
}
}
/**
*
* @param args tunnelport tunnelnickname
*/
public static void main(String[] args) {
// I'm lazy, and want to exit on any failures.
try {
setupconn(args); // talk to BOB, set up an inbound port
serverlistener(args); // talk over the connection
} catch(UnknownHostException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
try {
deleteconn(args);
} catch(UnknownHostException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch(RuntimeException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

14
apps/BOB/bob.config Normal file
View File

@@ -0,0 +1,14 @@
#bob.config
#Tue Dec 30 00:00:00 UTC 2008
# Please leave this file here for testing.
# Thank you,
# Sponge
i2cp.tcp.port=7654
BOB.host=localhost
inbound.lengthVariance=0
i2cp.messageReliability=BestEffort
BOB.port=45067
outbound.length=1
inbound.length=1
outbound.lengthVariance=0
i2cp.tcp.host=localhost

74
apps/BOB/build.xml Normal file
View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="BOB" default="default" basedir=".">
<description>Builds, tests, and runs the project BOB.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="BOB-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

3
apps/BOB/manifest.mf Normal file
View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

View File

@@ -0,0 +1,642 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="BOB-impl">
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="" name="sourcepath"/>
<element name="customize" optional="true"/>
<sequential>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target depends="-init-debug-args" name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
<condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
<os family="windows"/>
</condition>
<condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
<isset property="debug.transport"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="${run.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
<target depends="init" name="-check-automatic-build">
<available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
</target>
<target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
<antcall target="clean"/>
</target>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<j2seproject3:depend/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,8 @@
build.xml.data.CRC32=209349b6
build.xml.script.CRC32=403e69e6
build.xml.stylesheet.CRC32=958a1d3e
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=209349b6
nbproject/build-impl.xml.script.CRC32=75fac64c
nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5

View File

@@ -0,0 +1,7 @@
compile.on.save=false
do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
jaxws.endorsed.dir=/usr/local/netbeans-6.5/java2/modules/ext/jaxws21/api:/usr/local/netbeans-6.5/ide10/modules/ext/jaxb/api
user.properties.file=/root/.netbeans/6.5/build.properties

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
</project-private>

View File

@@ -0,0 +1,107 @@
application.title=BOB
application.vendor=root
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=false
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=8
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=8
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/BOB.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.core.jar=../i2p.i2p/core/dist/core.jar
file.reference.i2p.jar=../../bob/i2p/i2p.i2p/build/i2p.jar
file.reference.i2p.jar-1=../../core/java/build/i2p.jar
file.reference.i2p.jar-2=../i2p.i2p/core/java/build/i2p.jar
file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar
file.reference.java-src=../i2p.i2p/core/java/src/
file.reference.jbigi.jar=../../bob/i2p/i2p.i2p/build/jbigi.jar
file.reference.mstreaming.jar=../../bob/i2p/i2p.i2p/build/mstreaming.jar
file.reference.mstreaming.jar-1=../ministreaming/java/build/mstreaming.jar
file.reference.NetBeansProjects-i2p.i2p=../i2p.i2p/
file.reference.streaming.jar=../../bob/i2p/i2p.i2p/build/streaming.jar
file.reference.streaming.jar-1=../streaming/java/build/streaming.jar
file.reference.wrapper-freebsd=../../installer/lib/wrapper/freebsd/
file.reference.wrapper-linux=../../installer/lib/wrapper/linux/
file.reference.wrapper-linux64=../../installer/lib/wrapper/linux64/
file.reference.wrapper-macosx=../../installer/lib/wrapper/macosx/
file.reference.wrapper-solaris=../../installer/lib/wrapper/solaris/
file.reference.wrapper-win32=../../installer/lib/wrapper/win32/
file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar
file.reference.wrapper.jar-1=../../installer/lib/wrapper/freebsd/wrapper.jar
file.reference.wrapper.jar-2=../../installer/lib/wrapper/linux64/wrapper.jar
file.reference.wrapper.jar-3=../../installer/lib/wrapper/macosx/wrapper.jar
file.reference.wrapper.jar-4=../../installer/lib/wrapper/solaris/wrapper.jar
file.reference.wrapper.jar-5=../../installer/lib/wrapper/win32/wrapper.jar
includes=**
jar.compress=false
javac.classpath=\
${file.reference.i2p.jar-1}:\
${file.reference.i2ptunnel.jar}:\
${file.reference.mstreaming.jar-1}:\
${file.reference.streaming.jar-1}:\
${file.reference.wrapper.jar-1}:\
${file.reference.wrapper.jar}:\
${file.reference.wrapper.jar-2}:\
${file.reference.wrapper.jar-3}:\
${file.reference.wrapper.jar-4}:\
${file.reference.wrapper.jar-5}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
jnlp.codebase.type=local
jnlp.codebase.url=file:/root/NetBeansProjects/i2p.i2p/apps/BOB/dist/
jnlp.descriptor=application
jnlp.enabled=false
jnlp.offline-allowed=false
jnlp.signed=false
main.class=net.i2p.BOB.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>BOB</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@@ -0,0 +1,238 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import net.i2p.client.I2PClient;
import net.i2p.client.streaming.RetransmissionTimer;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
/**
* <span style="font-size:8px;font-family:courier;color:#EEEEEE;background-color:#000000">
* ################################################################################<br>
* ############################.#..........#..#..........##########################<br>
* #######################......................................###################<br>
* ####################...........................#.......#........################<br>
* #################..................##...................#.........##############<br>
* ###############................###...####.....#..###.....#.........#############<br>
* #############...........###..#..###...#####...###.##........#.......############<br>
* ###########................#......##...#####...##..##.......#..#........########<br>
* ##########.........................#....##.##..#...##.....................######<br>
* #########...................................#....#.........................#####<br>
* ########.........................................#...............#..........####<br>
* ########.........................................#..........#######..........###<br>
* #######.................................................############..........##<br>
* #######..........................................####################.........##<br>
* #######............####################......########################.........##<br>
* ######.............###############################################.##.........##<br>
* ######............################################################..##........##<br>
* ######............################################################..##........##<br>
* ######.............##############################################..##.........##<br>
* ######............##############################################...##..........#<br>
* ######............#..###########################################...##..........#<br>
* ######.............#############################################....#..........#<br>
* #######...........###############################################..##.........##<br>
* #######...........#####.#.#.#.########################.....#.####...##........##<br>
* ######............#..............##################.................##.........#<br>
* ######................####.........###############........#####......##........#<br>
* ######..............####..#.........############.......##.#.######...##.......##<br>
* ######.................#.####.........########...........##....###...##.......##<br>
* #######....#....###...................#######...............#...###..##.......##<br>
* #######.........###..###.....###.......######.##.#####.........####..##.......##<br>
* #######.....#...##############.........############......###########.###......##<br>
* #######....##...##########.......##...##############......#.############.....###<br>
* ########....#..########......######...##################################....####<br>
* ########....##.####################...##################################....####<br>
* ########..#.##..###################..##################################..#..####<br>
* ##########..###..#################...##################################...#.####<br>
* #########....##...##############....########..#####.################.##..#.#####<br>
* ############.##....##########.......#########.###.......###########..#.#########<br>
* ###############.....#######...#.......########.....##.....######.....###########<br>
* ###############......###....##..........##.......######....#.........#.#########<br>
* ##############............##..................##########..............##########<br>
* ##############..............................##########..#.............##########<br>
* ###############.......##..................#####..............####....###########<br>
* ###############.......#####.......#.............####.....#######.....###########<br>
* ################...#...####......##################.....########....############<br>
* ################...##..#####.........####.##.....#....##########....############<br>
* ##################..##..####...........#####.#....############.....#############<br>
* ##################......#####.................################....##############<br>
* ###################.....####..........##########..###########....###############<br>
* ####################..#..#..........................########.....###############<br>
* #####################.##.......###.................########....#################<br>
* ######################.........#.......#.##.###############....#################<br>
* #############.#######...............#####################....###################<br>
* ###..#.....##...####..........#.....####################....####################<br>
* ####......##........................##################....######################<br>
* #.##...###..............###.........###############......#######################<br>
* #...###..##............######...........................########################<br>
* ##.......###..........##########....#...#...........############################<br>
* ##.........##.......############################################################<br>
* ###........##.....##############################################################<br>
* ####.............###############################################################<br>
* ######.........#################################################################<br>
* #########....###################################################################<br>
* ################################################################################<br>
* </span>
* BOB, main command socket listener, launches the command parser engine.
*
* @author sponge
*/
public class BOB {
private final static Log _log = new Log(BOB.class);
public final static String PROP_CONFIG_LOCATION = "BOB.config";
public final static String PROP_BOB_PORT = "BOB.port";
public final static String PROP_BOB_HOST = "BOB.host";
private static int maxConnections = 0;
private static NamedDB database;
private static Properties props = new Properties();
/**
* Log a warning
*
* @param arg
*/
public static void info(String arg) {
System.out.println("INFO:" + arg);
_log.info(arg);
}
/**
* Log a warning
*
* @param arg
*/
public static void warn(String arg) {
System.out.println("WARNING:" + arg);
_log.warn(arg);
}
/**
* Log an error
*
* @param arg
*/
public static void error(String arg) {
System.out.println("ERROR: " + arg);
_log.error(arg);
}
/**
* Listen for incoming connections and handle them
*
* @param args
*/
public static void main(String[] args) {
database = new NamedDB();
int i = 0;
boolean save = false;
// Set up all defaults to be passed forward to other threads.
// Re-reading the config file in each thread is pretty damn stupid.
// I2PClient client = I2PClientFactory.createClient();
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config");
// This is here just to ensure there is no interference with our threadgroups.
SimpleTimer Y = RetransmissionTimer.getInstance();
i = Y.hashCode();
{
try {
FileInputStream fi = new FileInputStream(configLocation);
props.load(fi);
fi.close();
} catch(FileNotFoundException fnfe) {
warn("Unable to load up the BOB config file " + configLocation + ", Using defaults.");
warn(fnfe.toString());
save = true;
} catch(IOException ioe) {
warn("IOException on BOB config file " + configLocation + ", using defaults.");
warn(ioe.toString());
}
}
// Global router and client API configurations that are missing are set to defaults here.
if(!props.containsKey(I2PClient.PROP_TCP_HOST)) {
props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
}
if(!props.containsKey(I2PClient.PROP_TCP_PORT)) {
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
}
if(!props.containsKey(I2PClient.PROP_RELIABILITY)) {
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
}
if(!props.containsKey(PROP_BOB_PORT)) {
props.setProperty(PROP_BOB_PORT, "2827"); // 0xB0B
}
if(!props.containsKey("inbound.length")) {
props.setProperty("inbound.length", "1");
}
if(!props.containsKey("outbound.length")) {
props.setProperty("outbound.length", "1");
}
if(!props.containsKey("inbound.lengthVariance")) {
props.setProperty("inbound.lengthVariance", "0");
}
if(!props.containsKey("outbound.lengthVariance")) {
props.setProperty("outbound.lengthVariance", "0");
}
if(!props.containsKey(PROP_BOB_HOST)) {
props.setProperty(PROP_BOB_HOST, "localhost");
}
if(save) {
try {
warn("Writing new defaults file " + configLocation);
FileOutputStream fo = new FileOutputStream(configLocation);
props.store(fo, configLocation);
fo.close();
} catch(IOException ioe) {
error("IOException on BOB config file " + configLocation + ", " + ioe);
}
}
try {
info("BOB is now running.");
ServerSocket listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
Socket server;
while((i++ < maxConnections) || (maxConnections == 0)) {
//DoCMDS connection;
server = listener.accept();
DoCMDS conn_c = new DoCMDS(server, props, database, _log);
Thread t = new Thread(conn_c);
t.start();
}
} catch(IOException ioe) {
error("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import net.i2p.I2PException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.util.Log;
/**
* Listen on I2P and connect to TCP
*
* @author sponge
*/
public class I2Plistener implements Runnable {
private NamedDB info, database;
private Log _log;
private int tgwatch;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
/**
* Constructor
* @param S
* @param info
* @param database
* @param _log
*/
I2Plistener(I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
this.database = database;
this.info = info;
this._log = _log;
this.socketManager = S;
serverSocket = this.socketManager.getServerSocket();
tgwatch = 1;
}
/**
* Simply listen on I2P port, and thread connections
*
*/
public void run() {
boolean g = false;
I2PSocket sessSocket = null;
serverSocket.setSoTimeout(100);
database.getReadLock();
info.getReadLock();
if(info.exists("INPORT")) {
tgwatch = 2;
}
info.releaseReadLock();
database.releaseReadLock();
boolean spin = true;
while(spin) {
database.getReadLock();
info.getReadLock();
spin = info.get("RUNNING").equals(Boolean.TRUE);
info.releaseReadLock();
database.releaseReadLock();
try {
try {
sessSocket = serverSocket.accept();
g = true;
} catch(ConnectException ce) {
g = false;
} catch(SocketTimeoutException ste) {
g = false;
}
if(g) {
g = false;
// toss the connection to a new thread.
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database);
Thread t = new Thread(conn_c, "BOBI2PtoTCP");
t.start();
}
} catch(I2PException e) {
// System.out.println("Exception " + e);
}
}
// System.out.println("I2Plistener: Close");
try {
serverSocket.close();
} catch(I2PException e) {
// nop
}
// need to kill off the socket manager too.
I2PSession session = socketManager.getSession();
if(session != null) {
// System.out.println("I2Plistener: destroySession");
try {
session.destroySession();
} catch(I2PSessionException ex) {
// nop
}
}
// System.out.println("I2Plistener: Waiting for children");
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch(Exception e) {
// nop
}
}
// System.out.println("I2Plistener: Done.");
}
}

View File

@@ -0,0 +1,144 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import net.i2p.client.streaming.I2PSocket;
/**
* Process I2P->TCP
*
* @author sponge
*/
public class I2PtoTCP implements Runnable {
private I2PSocket I2P;
private NamedDB info, database;
private Socket sock;
/**
* Constructor
*
* @param I2Psock
* @param info
* @param database
*/
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB database) {
this.I2P = I2Psock;
this.info = info;
this.database = database;
}
private void rlock() throws Exception {
database.getReadLock();
info.getReadLock();
}
private void runlock() throws Exception {
database.releaseReadLock();
info.releaseReadLock();
}
/**
* I2P stream to TCP stream thread starter
*
*/
public void run() {
String host;
int port;
boolean tell;
die: {
try {
try {
rlock();
} catch(Exception e) {
break die;
}
try {
host = info.get("OUTHOST").toString();
port = Integer.parseInt(info.get("OUTPORT").toString());
tell = info.get("QUIET").equals(Boolean.FALSE);
} catch(Exception e) {
runlock();
break die;
}
try {
runlock();
} catch(Exception e) {
break die;
}
sock = new Socket(host, port);
// make readers/writers
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
InputStream Iin = I2P.getInputStream();
OutputStream Iout = I2P.getOutputStream();
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
if(tell) {
// tell who is connecting
out.write(I2P.getPeerDestination().toBase64().getBytes());
out.write(10); // nl
out.flush(); // not really needed, but...
}
// setup to cross the streams
TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P
TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app
Thread t = new Thread(conn_c, "TCPioA");
Thread q = new Thread(conn_a, "TCPioB");
// Fire!
t.start();
q.start();
while(t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
try {
Thread.sleep(10); //sleep for 10 ms
} catch(InterruptedException e) {
// nop
}
}
// System.out.println("I2PtoTCP: Going away...");
} catch(Exception e) {
// System.out.println("I2PtoTCP: Owch! damn!");
break die;
}
} // die
try {
// System.out.println("I2PtoTCP: Close I2P");
I2P.close();
} catch(Exception e) {
tell = false;
}
//System.out.println("I2PtoTCP: Closed I2P");
try {
// System.out.println("I2PtoTCP: Close sock");
sock.close();
} catch(Exception e) {
tell = false;
}
// System.out.println("I2PtoTCP: Done");
}
}

View File

@@ -0,0 +1,56 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.util.Enumeration;
import java.util.Properties;
/**
* Sets of "friendly" utilities to make life easier.
* Any "Lifted" code will apear here, and credits given.
* It's better to "Lift" a small chunk of "free" code than add in piles of
* code we don't need, and don't want.
*
* @author sponge
*/
public class Lifted {
/**
* Copy a set of properties from one Property to another.
* Lifted from Apache Derby code svn repository.
* Liscenced as follows:
* http://svn.apache.org/repos/asf/db/derby/code/trunk/LICENSE
*
* @param src_prop Source set of properties to copy from.
* @param dest_prop Dest Properties to copy into.
*
**/
public static void copyProperties(Properties src_prop, Properties dest_prop) {
for (Enumeration propertyNames = src_prop.propertyNames();
propertyNames.hasMoreElements();) {
Object key = propertyNames.nextElement();
dest_prop.put(key, src_prop.get(key));
}
}
}

View File

@@ -0,0 +1,276 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Properties;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.util.Log;
import org.tanukisoftware.wrapper.WrapperManager;
/**
*
* Multiplex listeners for TCP and I2P
*
* @author sponge
*/
public class MUXlisten implements Runnable {
private NamedDB database, info;
private Log _log;
private I2PSocketManager socketManager;
private ByteArrayInputStream prikey;
private ThreadGroup tg;
private String N;
private ServerSocket listener;
private int backlog = 50; // should this be more? less?
boolean go_out;
boolean come_in;
/**
* Constructor Will fail if INPORT is occupied.
*
* @param info
* @param database
* @param _log
* @throws net.i2p.I2PException
* @throws java.io.IOException
*/
MUXlisten(NamedDB database, NamedDB info, Log _log) throws I2PException, IOException, RuntimeException {
int port = 0;
InetAddress host = null;
this.tg = null;
this.database = database;
this.info = info;
this._log = _log;
this.database.getReadLock();
this.info.getReadLock();
N = this.info.get("NICKNAME").toString();
prikey = new ByteArrayInputStream((byte[])info.get("KEYS"));
// Make a new copy so that anything else won't muck with our database.
Properties R = (Properties)info.get("PROPERTIES");
Properties Q = new Properties();
Lifted.copyProperties(R, Q);
this.database.releaseReadLock();
this.info.releaseReadLock();
this.database.getReadLock();
this.info.getReadLock();
this.go_out = info.exists("OUTPORT");
this.come_in = info.exists("INPORT");
if(this.come_in) {
port = Integer.parseInt(info.get("INPORT").toString());
host = InetAddress.getByName(info.get("INHOST").toString());
}
this.database.releaseReadLock();
this.info.releaseReadLock();
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
if(this.come_in) {
this.listener = new ServerSocket(port, backlog, host);
}
// Everything is OK as far as we can tell.
this.database.getWriteLock();
this.info.getWriteLock();
this.info.add("STARTING", Boolean.TRUE);
this.info.releaseWriteLock();
this.database.releaseWriteLock();
}
private void rlock() throws Exception {
database.getReadLock();
info.getReadLock();
}
private void runlock() throws Exception {
database.releaseReadLock();
info.releaseReadLock();
}
private void wlock() throws Exception {
database.getWriteLock();
info.getWriteLock();
}
private void wunlock() throws Exception {
info.releaseWriteLock();
database.releaseWriteLock();
}
/**
* MUX sockets, fire off a thread to connect, get destination info, and do I/O
*
*/
public void run() {
try {
wlock();
try {
info.add("RUNNING", Boolean.TRUE);
info.add("STARTING", Boolean.FALSE);
} catch(Exception e) {
wunlock();
return;
}
} catch(Exception e) {
return;
}
try {
wunlock();
} catch(Exception e) {
return;
}
quit: {
try {
tg = new ThreadGroup(N);
die: {
// toss the connections to a new threads.
// will wrap with TCP and UDP when UDP works
if(go_out) {
// I2P -> TCP
I2Plistener conn = new I2Plistener(socketManager, info, database, _log);
Thread t = new Thread(tg, conn, "BOBI2Plistener " + N);
t.start();
}
if(come_in) {
// TCP -> I2P
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log);
Thread q = new Thread(tg, conn, "BOBTCPlistener" + N);
q.start();
}
boolean spin = true;
while(spin) {
try {
Thread.sleep(1000); //sleep for 1000 ms (One second)
} catch(InterruptedException e) {
// nop
}
try {
rlock();
try {
spin = info.get("STOPPING").equals(Boolean.FALSE);
} catch(Exception e) {
runlock();
break die;
}
} catch(Exception e) {
break die;
}
try {
runlock();
} catch(Exception e) {
break die;
}
}
try {
wlock();
try {
info.add("RUNNING", Boolean.FALSE);
} catch(Exception e) {
wunlock();
break die;
}
} catch(Exception e) {
break die;
}
try {
wunlock();
} catch(Exception e) {
break die;
}
} // die
// wait for child threads and thread groups to die
// System.out.println("MUXlisten: waiting for children");
while(tg.activeCount() + tg.activeGroupCount() != 0) {
tg.interrupt(); // unwedge any blocking threads.
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch(InterruptedException ex) {
// nop
}
}
tg.destroy();
// Zap reference to the ThreadGroup so the JVM can GC it.
tg = null;
} catch(Exception e) {
// System.out.println("MUXlisten: Caught an exception" + e);
break quit;
}
} // quit
// This is here to catch when something fucks up REALLY bad.
if(tg != null) {
System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!");
System.out.println("BOB: MUXlisten: Please email the following dump to sponge@mail.i2p");
WrapperManager.requestThreadDump();
System.out.println("BOB: MUXlisten: Something fucked up REALLY bad!");
System.out.println("BOB: MUXlisten: Please email the above dump to sponge@mail.i2p");
}
// zero out everything, just incase.
try {
socketManager.destroySocketManager();
} catch(Exception e) {
// nop
}
try {
wlock();
try {
info.add("STARTING", Boolean.FALSE);
info.add("STOPPING", Boolean.FALSE);
info.add("RUNNING", Boolean.FALSE);
} catch(Exception e) {
wunlock();
return;
}
wunlock();
} catch(Exception e) {
}
// This is here to catch when something fucks up REALLY bad.
if(tg != null) {
while(tg.activeCount() + tg.activeGroupCount() != 0) {
tg.interrupt(); // unwedge any blocking threads.
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch(InterruptedException ex) {
// nop
}
}
tg.destroy();
// Zap reference to the ThreadGroup so the JVM can GC it.
tg = null;
}
}
}

View File

@@ -0,0 +1,46 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import net.i2p.client.streaming.RetransmissionTimer;
import net.i2p.util.SimpleTimer;
/**
* Start from command line
*
* @author sponge
*
*/
public class Main {
/**
* @param args the command line arguments, these are not used yet
*/
public static void main(String[] args) {
// THINK THINK THINK THINK THINK THINK
SimpleTimer Y = RetransmissionTimer.getInstance();
BOB.main(args);
Y.removeSimpleTimer();
}
}

View File

@@ -0,0 +1,195 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
/**
* Internal database to relate nicknames to options to values
*
* @author sponge
*/
public class NamedDB {
private volatile Object[][] data;
private volatile int index, writersWaiting, readers;
/**
* make initial NULL object
*
*/
public NamedDB() {
this.data = new Object[1][2];
this.index = this.writersWaiting = this.readers = 0;
}
synchronized public void getReadLock() {
while((writersWaiting != 0)) {
try {
wait();
} catch(InterruptedException ie) {
}
}
readers++;
}
synchronized public void releaseReadLock() {
readers--;
notifyAll();
}
synchronized public void getWriteLock() {
writersWaiting++;
while(readers != 0 && writersWaiting != 1 ) {
try {
wait();
} catch(InterruptedException ie) {
}
}
}
synchronized public void releaseWriteLock() {
writersWaiting--;
notifyAll();
}
/**
* Find objects in the array, returns it's index or throws exception
* @param key
* @return an objects index
* @throws ArrayIndexOutOfBoundsException when key does not exist
*/
public int idx(Object key) throws ArrayIndexOutOfBoundsException {
for(int i = 0; i < index; i++) {
if(key.equals(data[i][0])) {
return i;
}
}
throw new ArrayIndexOutOfBoundsException("Can't locate key for index");
}
/**
* Delete an object from array if it exists
*
* @param key
*/
public void kill(Object key) {
int i, j, k, l;
Object[][] olddata;
int didsomething = 0;
try {
k = idx(key);
} catch(ArrayIndexOutOfBoundsException b) {
return;
}
olddata = new Object[index + 2][2];
// copy to olddata, skipping 'k'
for(i = 0 , l = 0; l < index; i++, l++) {
if(i == k) {
l++;
didsomething++;
}
for(j = 0; j < 2; j++) {
olddata[i][j] = data[l][j];
}
}
index -= didsomething;
data = olddata;
}
/**
* Add object to the array, deletes the old one if it exists
*
* @param key
* @param val
*/
public void add(Object key, Object val) {
Object[][] olddata;
int i, j;
i = 0;
kill(key);
olddata = new Object[index + 2][2];
// copy to olddata
for(i = 0; i < index; i++) {
for(j = 0; j < 2; j++) {
olddata[i][j] = data[i][j];
}
}
data = olddata;
data[index++] = new Object[] {key, val};
}
/**
* Get the object, and return it, throws RuntimeException
*
* @param key
* @return Object
* @throws java.lang.RuntimeException
*/
public Object get(Object key) throws RuntimeException {
for(int i = 0; i < index; i++) {
if(key.equals(data[i][0])) {
return data[i][1];
}
}
throw new RuntimeException("Key not found");
}
/**
* returns true if an object exists, else returns false
*
* @param key
* @return true if an object exists, else returns false
*/
public boolean exists(Object key) {
for(int i = 0; i < index; i++) {
if(key.equals(data[i][0])) {
return true;
}
}
return false;
}
/**
*
* @param i index
* @return an indexed Object
* @throws java.lang.RuntimeException
*/
public Object getnext(int i) throws RuntimeException {
if(i < index && i > -1) {
return data[i][1];
}
throw new RuntimeException("No more data");
}
/**
* @return the count of how many objects
*/
public int getcount() {
return index;
}
}

View File

@@ -0,0 +1,105 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Shove data from one stream to the other.
*
* @author sponge
*/
public class TCPio implements Runnable {
private InputStream Ain;
private OutputStream Aout;
private NamedDB info, database;
/**
* Constructor
*
* @param Ain
* @param Aout
* @param info
* @param database
*/
TCPio(InputStream Ain, OutputStream Aout, NamedDB info, NamedDB database) {
this.Ain = Ain;
this.Aout = Aout;
this.info = info;
this.database = database;
}
/**
* Copy from source to destination...
* and yes, we are totally OK to block here on writes,
* The OS has buffers, and I intend to use them.
*
*/
public void run() {
int b;
byte a[] = new byte[1];
boolean spin = true;
try {
while(spin) {
database.getReadLock();
info.getReadLock();
spin = info.get("RUNNING").equals(Boolean.TRUE);
info.releaseReadLock();
database.releaseReadLock();
b = Ain.read(a, 0, 1);
// System.out.println(info.get("NICKNAME").toString() + " " + b);
if(b > 0) {
Aout.write(a, 0, b);
} else if(b == 0) {
Thread.yield(); // this should act like a mini sleep.
if(Ain.available() == 0) {
try {
// Thread.yield();
Thread.sleep(10);
} catch(InterruptedException ex) {
}
}
} else {
/* according to the specs:
*
* The total number of bytes read into the buffer,
* or -1 if there is no more data because the end of
* the stream has been reached.
*
*/
// System.out.println("TCPio: End Of Stream");
return;
}
}
// System.out.println("TCPio: RUNNING = false");
} catch(Exception e) {
// Eject!!! Eject!!!
// System.out.println("TCPio: Caught an exception " + e);
return;
}
// System.out.println("TCPio: Leaving.");
}
}

View File

@@ -0,0 +1,147 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.util.Log;
/**
* Listen on TCP port and connect to I2P
*
* @author sponge
*/
public class TCPlistener implements Runnable {
private NamedDB info, database;
private Log _log;
private int tgwatch;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private ServerSocket listener;
/**
* Constructor
* @param S
* @param info
* @param database
* @param _log
*/
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
this.database = database;
this.info = info;
this._log = _log;
this.socketManager = S;
this.listener = listener;
tgwatch = 1;
}
/**
* Simply listen on TCP port, and thread connections
*
*/
public void run() {
boolean g = false;
boolean spin = true;
database.getReadLock();
info.getReadLock();
if(info.exists("OUTPORT")) {
tgwatch = 2;
}
try {
Socket server = new Socket();
listener.setSoTimeout(1000);
info.releaseReadLock();
database.releaseReadLock();
while(spin) {
database.getReadLock();
info.getReadLock();
spin = info.get("RUNNING").equals(Boolean.TRUE);
info.releaseReadLock();
database.releaseReadLock();
try {
server = listener.accept();
g = true;
} catch(SocketTimeoutException ste) {
g = false;
}
if(g) {
// toss the connection to a new thread.
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database);
Thread t = new Thread(conn_c, "BOBTCPtoI2P");
t.start();
g = false;
}
}
//System.out.println("TCPlistener: destroySession");
listener.close();
} catch(IOException ioe) {
try {
listener.close();
} catch(IOException e) {
}
// Fatal failure, cause a stop event
database.getReadLock();
info.getReadLock();
spin = info.get("RUNNING").equals(Boolean.TRUE);
info.releaseReadLock();
database.releaseReadLock();
if(spin) {
database.getWriteLock();
info.getWriteLock();
info.add("STOPPING", new Boolean(true));
info.add("RUNNING", new Boolean(false));
info.releaseWriteLock();
database.releaseWriteLock();
}
}
// need to kill off the socket manager too.
I2PSession session = socketManager.getSession();
if(session != null) {
try {
session.destroySession();
} catch(I2PSessionException ex) {
// nop
}
}
//System.out.println("TCPlistener: Waiting for children");
while(Thread.activeCount() > tgwatch) { // wait for all threads in our threadgroup to finish
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch(Exception e) {
// nop
}
}
//System.out.println("TCPlistener: Done.");
}
}

View File

@@ -0,0 +1,186 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
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 net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnel;
/**
*
* Process TCP->I2P
*
* @author sponge
*/
public class TCPtoI2P implements Runnable {
private I2PSocket I2P;
private NamedDB info, database;
private Socket sock;
private I2PSocketManager socketManager;
/**
* This is a more forgiving readline,
* it works on unbuffered streams
*
* @param in
* @return line of text as a String
* @throws Exception
*/
private static String lnRead(InputStream in) throws Exception {
String S;
int b;
char c;
S = new String();
while(true) {
b = in.read();
if(b == 13) {
//skip CR
continue;
}
if(b < 20 || b > 126) {
// exit on anything not legal
break;
}
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
S = new String(S + c);
}
return S;
}
/**
* Constructor
* @param i2p
* @param socket
* @param info
* @param database
*/
TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database) {
this.sock = socket;
this.info = info;
this.database = database;
this.socketManager = i2p;
}
/**
* Print an error message to out
*
* @param e
* @param out
* @throws java.io.IOException
*/
private void Emsg(String e, OutputStream out) throws IOException {
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
out.write("ERROR".concat(e).getBytes());
out.write(13); // cr
out.flush();
}
/**
* TCP stream to I2P stream thread starter
*/
public void run() {
String line, input;
try {
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
try {
line = lnRead(in);
input = line.toLowerCase();
Destination dest = null;
if(input.endsWith(".i2p")) {
dest = I2PTunnel.destFromName(input);
line = dest.toBase64();
}
dest = new Destination();
dest.fromBase64(line);
try {
// get a client socket
I2P = socketManager.connect(dest);
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
// make readers/writers
InputStream Iin = I2P.getInputStream();
OutputStream Iout = I2P.getOutputStream();
// setup to cross the streams
TCPio conn_c = new TCPio(in, Iout, info, database); // app -> I2P
TCPio conn_a = new TCPio(Iin, out, info, database); // I2P -> app
Thread t = new Thread(conn_c, "TCPioA");
Thread q = new Thread(conn_a, "TCPioB");
// Fire!
t.start();
q.start();
while(t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
try {
Thread.sleep(10); //sleep for 10 ms
} catch(InterruptedException e) {
// nop
}
}
// System.out.println("TCPtoI2P: Going away...");
} catch(I2PException e) {
Emsg("ERROR " + e.toString(), out);
} catch(ConnectException e) {
Emsg("ERROR " + e.toString(), out);
} catch(NoRouteToHostException e) {
Emsg("ERROR " + e.toString(), out);
} catch(InterruptedIOException e) {
Emsg("ERROR " + e.toString(), out);
}
} catch(Exception e) {
Emsg("ERROR " + e.toString(), out);
}
} catch(IOException ioe) {
}
try {
// System.out.println("TCPtoI2P: Close I2P");
I2P.close();
} catch(Exception e) {
}
try {
// System.out.println("TCPtoI2P: Close sock");
sock.close();
} catch(Exception e) {
}
// System.out.println("TCPtoI2P: Done.");
}
}

View File

@@ -0,0 +1,144 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
* http://sam.zoy.org/wtfpl/
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
*/
package net.i2p.BOB;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.I2PSessionListener;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**
* UDP IO on I2P
*
* FIX ME: Untested, and incomplete!
* I have no personal need to UDP yet,
* however alot of p2p apps pretty much demand it.
* The skeletal frame is here, just needs to be finished.
*
* @author sponge
*/
public class UDPIOthread implements I2PSessionListener, Runnable {
private NamedDB info;
private Log _log;
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private I2PSession _session;
private Destination _peerDestination;
private boolean up;
/**
* Constructor
* @param info
* @param _log
* @param socket
* @param _session
*/
UDPIOthread(NamedDB info, Log _log, Socket socket, I2PSession _session) {
this.info = info;
this._log = _log;
this.socket = socket;
this._session = _session;
}
/**
*
*/
public void run() {
byte data[] = new byte[1024];
up = true;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
while(up) {
int c = in.read(data);
// Note: could do a loopback test here with a wrapper.
boolean ok = _session.sendMessage(_peerDestination, data, 0, c);
if(!ok) {
up = false; // Is this the right thing to do??
}
}
} catch(IOException ioe) {
_log.error("Error running", ioe);
} catch(I2PSessionException ise) {
_log.error("Error communicating", ise);
// } catch(DataFormatException dfe) {
// _log.error("Peer destination file is not valid", dfe);
} finally {
if(_session != null) {
try {
_session.destroySession();
} catch(I2PSessionException ise) {
// ignored
}
}
}
}
/**
*
* @param session
* @param msgId
* @param size
*/
public void messageAvailable(I2PSession session, int msgId, long size) {
// _log.debug("Message available: id = " + msgId + " size = " + size);
try {
byte msg[] = session.receiveMessage(msgId);
out.write(msg);
out.flush();
} catch(I2PSessionException ise) {
up = false;
} catch(IOException ioe) {
up = false;
}
}
// Great, can these be used to kill ourselves.
/** required by {@link I2PSessionListener I2PSessionListener} to notify of disconnect */
public void disconnected(I2PSession session) {
_log.debug("Disconnected");
// up = false;
}
/** required by {@link I2PSessionListener I2PSessionListener} to notify of error */
public void errorOccurred(I2PSession session, String message, Throwable error) {
_log.debug("Error occurred: " + message, error);
// up = false;
}
/** required by {@link I2PSessionListener I2PSessionListener} to notify of abuse */
public void reportAbuse(I2PSession session, int severity) {
_log.debug("Abuse reported of severity " + severity);
// up = false;
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
<p>BOB, the Basic Open Bridge, allows TCP applications to talk over I2P.</p>
</body>
</html>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<project name="addressbook" default="war" basedir=".">
<property name="src" value="java/src/addressbook"/>
<property name="src" value="java/src"/>
<property name="build" value="build"/>
<property name="dist" location="dist"/>
<property name="jar" value="addressbook.jar"/>
@@ -19,8 +19,24 @@
<target name="distclean" depends="clean" />
<target name="compile" depends="init">
<javac debug="true" deprecation="on" source="1.3" target="1.3"
<condition property="depend.available">
<typefound name="depend" />
</condition>
<target name="depend" if="depend.available">
<depend
cache="../../build"
srcdir="${src}"
destdir="${build}" >
<!-- Depend on classes instead of jars where available -->
<classpath>
<pathelement location="../../core/java/build/obj" />
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
</classpath>
</depend>
</target>
<target name="compile" depends="init, depend">
<javac debug="true" deprecation="on" source="1.5" target="1.5"
srcdir="${src}" destdir="${build}">
<classpath>
<pathelement location="../../core/java/build/i2p.jar" />
@@ -37,7 +53,7 @@
</jar>
</target>
<target name="war" depends="compile">
<target name="war" depends="compile" unless="war.uptodate">
<mkdir dir="${dist}/tmp"/>
<mkdir dir="${dist}/tmp/WEB-INF"/>
<mkdir dir="${dist}/tmp/WEB-INF/classes"/>
@@ -48,4 +64,8 @@
<delete dir="${dist}/tmp"/>
</target>
<uptodate property="war.uptodate" targetfile="${dist}/${war}">
<srcfiles dir= "." includes="${build}/**/*.class, web.xml"/>
</uptodate>
</project>

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

@@ -21,11 +21,11 @@
package addressbook;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.util.EepGet;
@@ -57,7 +57,7 @@ public class AddressBook {
this.addresses = addresses;
}
/**
/*
* Construct an AddressBook from the contents of the file at url. If the
* remote file cannot be read, construct an empty AddressBook
*
@@ -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,28 @@ public class AddressBook {
}
new File("addressbook.tmp").delete();
}
*/
static final long MAX_SUB_SIZE = 3 * 1024 * 1024l; //about 5,000 hosts
/**
* 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.
* @param proxyHost hostname of proxy
* @param proxyPort port number of proxy
*/
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) {
@@ -147,10 +154,50 @@ public class AddressBook {
*
* @return A String representing the contents of the AddressBook.
*/
@Override
public String toString() {
return this.addresses.toString();
}
private static final int MIN_DEST_LENGTH = 516;
private static final int MAX_DEST_LENGTH = MIN_DEST_LENGTH + 100; // longer than any known cert type for now
/**
* 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 &&
// Base32 spoofing (52chars.i2p)
(! (host.length() == 56 && host.substring(0,52).replaceAll("[a-z2-7]", "").length() == 0)) &&
// ... or maybe we do Base32 this way ...
(! host.equals("b32.i2p")) &&
(! host.endsWith(".b32.i2p")) &&
// 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() == MIN_DEST_LENGTH && dest.endsWith("AAAA")) ||
(dest.length() > MIN_DEST_LENGTH && dest.length() <= MAX_DEST_LENGTH)) &&
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
@@ -159,6 +206,7 @@ public class AddressBook {
*
* @param other
* An AddressBook to merge with.
* @param overwrite True to overwrite
* @param log
* The log to write messages about new addresses or conflicts to.
*/
@@ -169,7 +217,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 +232,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

@@ -21,12 +21,19 @@
package addressbook;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Utility class providing methods to parse and write files in config file
@@ -60,6 +67,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 +85,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();
}
@@ -99,7 +107,11 @@ public class ConfigParser {
FileInputStream fileStream = new FileInputStream(file);
BufferedReader input = new BufferedReader(new InputStreamReader(
fileStream));
return ConfigParser.parse(input);
Map rv = ConfigParser.parse(input);
try {
fileStream.close();
} catch (IOException ioe) {}
return rv;
}
/**
@@ -130,7 +142,7 @@ public class ConfigParser {
* cannot be read, map.
*/
public static Map parse(File file, Map map) {
Map result = new HashMap();
Map result;
try {
result = ConfigParser.parse(file);
} catch (IOException exp) {
@@ -180,7 +192,11 @@ public class ConfigParser {
FileInputStream fileStream = new FileInputStream(file);
BufferedReader input = new BufferedReader(new InputStreamReader(
fileStream));
return ConfigParser.parseSubscriptions(input);
List rv = ConfigParser.parseSubscriptions(input);
try {
fileStream.close();
} catch (IOException ioe) {}
return rv;
}
/**
@@ -205,13 +221,12 @@ public class ConfigParser {
*
* @param file
* A File to attempt to parse.
* @param string
* A List to use as the default, if file fails.
* @param list list of files to parse
* @return A List consisting of one element for each line in file, or if
* file cannot be read, list.
*/
public static List parseSubscriptions(File file, List list) {
List result = new LinkedList();
List result;
try {
result = ConfigParser.parseSubscriptions(file);
} catch (IOException exp) {
@@ -301,4 +316,4 @@ public class ConfigParser {
new FileWriter(file, false)));
}
}
}

View File

@@ -21,12 +21,12 @@
package addressbook;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Main class of addressbook. Performs updates, and runs the main loop.
@@ -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
@@ -124,7 +125,6 @@ public class Daemon {
public void run(String[] args) {
String settingsLocation = "config.txt";
Map settings = new HashMap();
String home;
if (args.length > 0) {
home = args[0];
@@ -156,10 +156,11 @@ public class Daemon {
File settingsFile = new File(homeFile, settingsLocation);
settings = ConfigParser.parse(settingsFile, defaultSettings);
Map settings = ConfigParser.parse(settingsFile, defaultSettings);
// wait
try {
Thread.currentThread().sleep(5*60*1000);
Thread.sleep(5*60*1000);
// Static method, and redundent Thread.currentThread().sleep(5*60*1000);
} catch (InterruptedException ie) {}
while (true) {

View File

@@ -43,6 +43,7 @@ public class DaemonThread extends Thread {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
//try {
// Thread.sleep(5 * 60 * 1000);

View File

@@ -54,14 +54,17 @@ public class Log {
* A String containing a message to append to the log.
*/
public void append(String entry) {
BufferedWriter bw = null;
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(this.file,
bw = new BufferedWriter(new FileWriter(this.file,
true));
String timestamp = new Date().toString();
bw.write(timestamp + " -- " + entry);
bw.newLine();
bw.close();
} catch (IOException exp) {
} finally {
if (bw != null)
try { bw.close(); } catch (IOException ioe) {}
}
}
@@ -73,4 +76,4 @@ public class Log {
public File getFile() {
return this.file;
}
}
}

View File

@@ -22,10 +22,10 @@
package addressbook;
import javax.servlet.GenericServlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* A wrapper for addressbook to allow it to be started as a web application.
@@ -44,6 +44,7 @@ public class Servlet extends GenericServlet {
/* (non-Javadoc)
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
*/
@Override
public void init(ServletConfig config) {
try {
super.init(config);

View File

@@ -41,6 +41,8 @@ public class SubscriptionIterator implements Iterator {
*
* @param subscriptions
* List of Subscription objects that represent address books.
* @param proxyHost proxy hostname
* @param proxyPort proxt port number
*/
public SubscriptionIterator(List subscriptions, String proxyHost, int proxyPort) {
this.subIterator = subscriptions.iterator();

View File

@@ -21,13 +21,13 @@
package addressbook;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* A list of Subscriptions loaded from a file.
@@ -60,6 +60,9 @@ public class SubscriptionList {
* @param lastModifiedFile
* A file containg the last-modified headers used for conditional
* GET. The file is in the format "url=leastmodified".
* @param defaultSubs default subscription file
* @param proxyHost proxy hostname
* @param proxyPort proxy port number
*/
public SubscriptionList(File locationsFile, File etagsFile,
File lastModifiedFile, List defaultSubs, String proxyHost,

View File

@@ -41,24 +41,34 @@ import net.i2p.util.Log;
public class ATalk implements I2PSessionListener, Runnable {
/** logging hook - status messages are piped to this */
private final static Log _log = new Log(ATalk.class);
/** platform independent newline */
private final static String NL = System.getProperty("line.separator");
/** the current session */
private I2PSession _session;
/** who am i */
private Destination _myDestination;
/** who are you? */
private Destination _peerDestination;
/** location of my secret key file */
private String _myKeyFile;
/** location of their public key */
private String _theirDestinationFile;
/** where the application reads input from. currently set to standard input */
private BufferedReader _in;
/** where the application sends output to. currently set to standard output */
private BufferedWriter _out;
/** string that messages must begin with to be treated as files */
private final static String FILE_COMMAND = ".file: ";
/** the, erm, manual */
private final static String MANUAL = "ATalk: Anonymous Talk, a demo program for the Invisible Internet Project SDK"
+ NL
@@ -84,7 +94,9 @@ public class ATalk implements I2PSessionListener, Runnable {
+ NL
+ "To end the talk session, enter a period on a line by itself and hit return"
+ NL;
public final static String PROP_CONFIG_LOCATION = "configFile";
private static final SimpleDateFormat _fmt = new SimpleDateFormat("hh:mm:ss.SSS");
/** Construct the talk engine, but don't connect yet */
@@ -111,11 +123,12 @@ public class ATalk implements I2PSessionListener, Runnable {
_log.warn("Unable to load up the ATalk config file " + configLocation);
}
// Provide any router or client API configuration here.
if (!props.containsKey(I2PClient.PROP_TCP_HOST)) props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
if (!props.containsKey(I2PClient.PROP_TCP_PORT)) props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
if (!props.containsKey(I2PClient.PROP_TCP_HOST))
props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
if (!props.containsKey(I2PClient.PROP_TCP_PORT))
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
if (!props.containsKey(I2PClient.PROP_RELIABILITY))
props.setProperty(I2PClient.PROP_RELIABILITY,
I2PClient.PROP_RELIABILITY_BEST_EFFORT);
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
_session = client.createSession(new FileInputStream(myFile), props);
_session.setSessionListener(this);
_session.connect();
@@ -364,4 +377,5 @@ public class ATalk implements I2PSessionListener, Runnable {
public void reportAbuse(I2PSession session, int severity) {
_log.debug("Abuse reported of severity " + severity);
}
}
}

View File

@@ -1,349 +0,0 @@
/*
* bogobot - A simple join/part stats logger bot for I2P IRC.
*
* Bogobot.java
* 2004 The I2P Project
* http://www.i2p.net
* This code is public domain.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Properties;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.jibble.pircbot.PircBot;
import org.jibble.pircbot.User;
/**
* TODO 0.5 Add multi-server capability.
*
* @author hypercubus, oOo
* @version 0.4
*/
public class Bogobot extends PircBot {
private static final String INTERVAL_DAILY = "daily";
private static final String INTERVAL_MONTHLY = "monthly";
private static final String INTERVAL_WEEKLY = "weekly";
private boolean _isIntentionalDisconnect = false;
private long _lastUserlistCommandTimestamp = 0;
private Logger _logger = Logger.getLogger(Bogobot.class);
private int _currentAutoRoundTripTag = 0;
private long _lastAutoRoundTripSentTime = 0;
private Timer _tickTimer;
private String _configFile;
private String _botPrimaryNick;
private String _botSecondaryNick;
private String _botNickservPassword;
private String _botUsername;
private String _ownerPrimaryNick;
private String _ownerSecondaryNick;
private String _botShutdownPassword;
private String _ircChannel;
private String _ircServer;
private int _ircServerPort;
private boolean _isLoggerEnabled;
private String _loggedHostnamePattern;
private boolean _isUserlistCommandEnabled;
private String _logFilePrefix;
private String _logFileRotationInterval;
private long _commandAntiFloodInterval;
private String _userlistCommandTrigger;
private boolean _isRoundTripDelayEnabled;
private int _roundTripDelayPeriod;
class BogobotTickTask extends TimerTask {
private Bogobot _caller;
public BogobotTickTask(Bogobot caller) {
_caller = caller;
}
public void run() {
_caller.onTick();
}
}
private void loadConfigFile(String configFileName) {
_configFile = configFileName;
Properties config = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(configFileName);
config.load(fis);
} catch (IOException ioe) {
System.err.println("Error loading configuration file");
System.exit(2);
} finally {
if (fis != null) try {
fis.close();
} catch (IOException ioe) { // nop
}
}
_botPrimaryNick = config.getProperty("botPrimaryNick", "somebot");
_botSecondaryNick = config.getProperty("botSecondaryNick", "somebot_");
_botNickservPassword = config.getProperty("botNickservPassword", "");
_botUsername = config.getProperty("botUsername", "somebot");
_ownerPrimaryNick = config.getProperty("ownerPrimaryNick", "somenick");
_ownerSecondaryNick = config.getProperty("ownerSecondaryNick", "somenick_");
_botShutdownPassword = config.getProperty("botShutdownPassword", "take off eh");
_ircChannel = config.getProperty("ircChannel", "#i2p-chat");
_ircServer = config.getProperty("ircServer", "irc.postman.i2p");
_ircServerPort = Integer.parseInt(config.getProperty("ircServerPort", "6668"));
_isLoggerEnabled = Boolean.valueOf(config.getProperty("isLoggerEnabled", "true")).booleanValue();
_loggedHostnamePattern = config.getProperty("loggedHostnamePattern", "");
_logFilePrefix = config.getProperty("logFilePrefix", "irc.postman.i2p.i2p-chat");
_logFileRotationInterval = config.getProperty("logFileRotationInterval", INTERVAL_DAILY);
_isRoundTripDelayEnabled = Boolean.valueOf(config.getProperty("isRoundTripDelayEnabled", "false")).booleanValue();
_roundTripDelayPeriod = Integer.parseInt(config.getProperty("roundTripDelayPeriod", "300"));
_isUserlistCommandEnabled = Boolean.valueOf(config.getProperty("isUserlistCommandEnabled", "true")).booleanValue();
_userlistCommandTrigger = config.getProperty("userlistCommandTrigger", "!who");
_commandAntiFloodInterval = Long.parseLong(config.getProperty("commandAntiFloodInterval", "60"));
}
public Bogobot(String configFileName) {
loadConfigFile(configFileName);
this.setName(_botPrimaryNick);
this.setLogin(_botUsername);
_tickTimer = new Timer();
_tickTimer.scheduleAtFixedRate(new BogobotTickTask(this), 1000, 10 * 1000);
}
public static void main(String[] args) {
Bogobot bogobot;
if (args.length > 1) {
System.err.println("Too many arguments, the only allowed parameter is configuration file name");
System.exit(3);
}
if (args.length == 1) {
bogobot = new Bogobot(args[0]);
} else {
bogobot = new Bogobot("bogobot.config");
}
bogobot.setVerbose(true);
if (bogobot._isLoggerEnabled)
bogobot.initLogger();
bogobot.connectToServer();
}
protected void onTick() {
// Tick about once every ten seconds
if (this.isConnected() && _isRoundTripDelayEnabled) {
if( ( (System.currentTimeMillis() - _lastAutoRoundTripSentTime) >= (_roundTripDelayPeriod * 1000) ) && (this.getOutgoingQueueSize() == 0) ) {
// Connected, sending queue is empty and last RoundTrip is more then 5 minutes old -> Send a new one
_currentAutoRoundTripTag ++;
_lastAutoRoundTripSentTime = System.currentTimeMillis();
sendNotice(this.getNick(),"ROUNDTRIP " + _currentAutoRoundTripTag);
}
}
}
protected void onDisconnect() {
if (_isIntentionalDisconnect)
System.exit(0);
if (_isLoggerEnabled)
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " *** (Lost connection)");
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// No worries.
}
connectToServer();
}
protected void onJoin(String channel, String sender, String login, String hostname) {
if (_isLoggerEnabled) {
if (sender.equals(this.getName())) {
_logger.info(System.currentTimeMillis() + " joins *** " + _botPrimaryNick + " ***");
} else {
String prependedHostname = "@" + hostname;
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
_logger.info(System.currentTimeMillis() + " joins " + sender);
}
}
}
}
protected void onMessage(String channel, String sender, String login, String hostname, String message) {
message = message.replaceFirst("<.+?> ", "");
if (_isUserlistCommandEnabled && message.equals(_userlistCommandTrigger)) {
if (System.currentTimeMillis() - _lastUserlistCommandTimestamp < _commandAntiFloodInterval * 1000)
return;
Object[] users = getUsers(_ircChannel);
String output = "Userlist for " + _ircChannel + ": ";
for (int i = 0; i < users.length; i++)
output += "[" + ((User) users[i]).getNick() + "] ";
sendMessage(_ircChannel, output);
_lastUserlistCommandTimestamp = System.currentTimeMillis();
}
}
protected void onPart(String channel, String sender, String login, String hostname) {
if (_isLoggerEnabled) {
if (sender.equals(this.getName())) {
_logger.info(System.currentTimeMillis() + " parts *** " + _botPrimaryNick + " ***");
} else {
String prependedHostname = "@" + hostname;
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
_logger.info(System.currentTimeMillis() + " parts " + sender);
}
}
}
}
protected void onPrivateMessage(String sender, String login, String hostname, String message) {
/*
* Nobody else except the bot's owner can shut it down, unless of
* course the owner's nick isn't registered and someone's spoofing it.
*/
if ((sender.equals(_ownerPrimaryNick) || sender.equals(_ownerSecondaryNick)) && message.equals(_botShutdownPassword)) {
if (_isLoggerEnabled)
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " ***");
_isIntentionalDisconnect = true;
disconnect();
}
}
protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
String prependedHostname = "@" + sourceHostname;
if (sourceNick.equals(_botPrimaryNick))
changeNick(_botPrimaryNick);
if (_isLoggerEnabled) {
if (prependedHostname.endsWith(_loggedHostnamePattern)) {
_logger.info(System.currentTimeMillis() + " quits " + sourceNick + " " + reason);
}
}
}
private void connectToServer() {
int loginAttempts = 0;
while (true) {
try {
connect(_ircServer, _ircServerPort);
break;
} catch (NickAlreadyInUseException e) {
if (loginAttempts == 1) {
System.out.println("Sorry, the primary and secondary bot nicks are already taken. Exiting.");
System.exit(1);
}
loginAttempts++;
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// Hmph.
}
if (getName().equals(_botPrimaryNick))
setName(_botSecondaryNick);
else
setName(_botPrimaryNick);
continue;
} catch (IOException e) {
System.out.println("Error during login: ");
e.printStackTrace();
System.exit(1);
} catch (IrcException e) {
System.out.println("Error during login: ");
e.printStackTrace();
System.exit(1);
}
}
joinChannel(_ircChannel);
}
protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {
if (sourceNick.equals("NickServ") && (notice.indexOf("/msg NickServ IDENTIFY") >= 0) && (_botNickservPassword != "")) {
sendRawLineViaQueue("NICKSERV IDENTIFY " + _botNickservPassword);
}
if (sourceNick.equals(getNick()) && notice.equals( "ROUNDTRIP " + _currentAutoRoundTripTag)) {
int delay = (int)((System.currentTimeMillis() - _lastAutoRoundTripSentTime) / 100);
// sendMessage(_ircChannel, "Round-trip delay = " + (delay / 10.0f) + " seconds");
if (_isLoggerEnabled)
_logger.info(System.currentTimeMillis() + " roundtrip " + delay);
}
}
private void initLogger() {
String logFilePath = "logs" + File.separator + _logFilePrefix;
DailyRollingFileAppender rollingFileAppender = null;
if (!(new File("logs").exists()))
(new File("logs")).mkdirs();
try {
if (_logFileRotationInterval.equals("monthly"))
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM'.log'");
else if (_logFileRotationInterval.equals("weekly"))
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-ww'.log'");
else
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM-dd'.log'");
rollingFileAppender.setThreshold(Level.INFO);
_logger.addAppender(rollingFileAppender);
} catch (IOException ex) {
System.out.println("Error: Couldn't create or open an existing log file. Exiting.");
System.exit(1);
}
}
}

View File

@@ -1,353 +0,0 @@
/*
* bogoparser - A simple logfile analyzer for bogobot.
*
* Bogoparser.java
* 2004 The I2P Project
* http://www.i2p.net
* This code is public domain.
*/
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author hypercubus
* @version 0.4
*/
public class Bogoparser {
private static void displayUsageAndExit() {
System.out.println("\r\nUsage:\r\n\r\n java Bogoparser [--by-duration] <logfile>\r\n");
System.exit(1);
}
public static void main(String[] args) {
Bogoparser bogoparser;
if (args.length < 1 || args.length > 2)
displayUsageAndExit();
if (args.length == 2) {
if (!args[0].equals("--by-duration"))
displayUsageAndExit();
bogoparser = new Bogoparser(args[1], true);
}
if (args.length == 1)
bogoparser = new Bogoparser(args[0], false);
}
private Bogoparser(String logfile, boolean sortByDuration) {
ArrayList sortedSessions;
if (sortByDuration) {
sortedSessions = sortSessionsByDuration(calculateSessionDurations(sortSessionsByTime(readLogfile(logfile))));
formatAndOutputByDuration(sortedSessions);
} else {
sortedSessions = calculateSessionDurations(sortSessionsByQuitReason(sortSessionsByNick(sortSessionsByTime(readLogfile(logfile)))));
formatAndOutput(sortedSessions);
}
}
private ArrayList calculateSessionDurations(ArrayList sortedSessionsByQuitReasonOrDuration) {
ArrayList calculatedSessionDurations = new ArrayList();
for (int i = 0; i+1 < sortedSessionsByQuitReasonOrDuration.size(); i += 2) {
String joinsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i);
String[] joinsEntryFields = joinsEntry.split(" ");
String quitsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i+1);
Pattern p = Pattern.compile("^([^ ]+) [^ ]+ ([^ ]+) (.*)$");
Matcher m = p.matcher(quitsEntry);
if (m.matches()) {
String currentJoinTime = joinsEntryFields[0];
String currentNick = m.group(2);
String currentQuitReason = m.group(3);
String currentQuitTime = m.group(1);
long joinsTimeInMilliseconds;
long quitsTimeInMilliseconds;
long sessionLengthInMilliseconds;
joinsTimeInMilliseconds = Long.parseLong(currentJoinTime);
quitsTimeInMilliseconds = Long.parseLong(currentQuitTime);
sessionLengthInMilliseconds = quitsTimeInMilliseconds - joinsTimeInMilliseconds;
String hours = "" + sessionLengthInMilliseconds/1000/60/60;
String minutes = "" + (sessionLengthInMilliseconds/1000/60)%60;
if (hours.length() < 2)
hours = "0" + hours;
if (hours.length() < 3)
hours = "0" + hours;
if (minutes.length() < 2)
minutes = "0" + minutes;
int columnPadding = 19-currentNick.length();
String columnPaddingString = " ";
for (int j = 0; j < columnPadding; j++)
columnPaddingString = columnPaddingString + " ";
calculatedSessionDurations.add(sessionLengthInMilliseconds + " " + currentNick + columnPaddingString + " online " + hours + " hours " + minutes + " minutes " + currentQuitReason);
} else {
System.out.println("\r\nError: Unexpected entry in logfile: " + quitsEntry);
System.exit(1);
}
}
return calculatedSessionDurations;
}
private void formatAndOutput(ArrayList sortedSessions) {
String quitReason = null;
for (int i = 0; i < sortedSessions.size(); i++) {
String entry = (String) sortedSessions.get(i);
Pattern p = Pattern.compile("^[\\d]+ ([^ ]+ +online [\\d]+ hours [\\d]+ minutes) (.*)$");
Matcher m = p.matcher(entry);
if (m.matches()) {
if (quitReason == null) {
quitReason = m.group(2);
System.out.println("\r\nQUIT: " + ((m.group(2).equals("")) ? "No Reason Given" : quitReason) + "\r\n");
}
String tempQuitReason = m.group(2);
String tempSession = m.group(1);
if (tempQuitReason.equals(quitReason)) {
System.out.println(" " + tempSession);
} else {
quitReason = null;
i -= 1;
continue;
}
} else {
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
System.exit(1);
}
}
System.out.println("\r\n");
}
private void formatAndOutputByDuration(ArrayList sortedSessions) {
System.out.println("\r\n");
for (int i = 0; i < sortedSessions.size(); i++) {
String[] columns = ((String) sortedSessions.get(i)).split(" ", 2);
System.out.println(columns[1]);
}
System.out.println("\r\n");
}
private ArrayList readLogfile(String logfile) {
ArrayList log = new ArrayList();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(logfile)));
for (String line; (line = in.readLine()) != null; )
log.add(line);
in.close();
} catch (FileNotFoundException e) {
System.out.println("\r\nError: Can't find logfile '" + logfile + "'.\r\n");
System.exit(1);
} catch (IOException e) {
System.out.println("\r\nError: Can't read logfile '" + logfile + "'.\r\n");
System.exit(1);
}
return log;
}
/*
* Performs an odd-even transposition sort.
*/
private ArrayList sortSessionsByDuration(ArrayList calculatedSessionDurations) {
for (int i = 0; i < calculatedSessionDurations.size()/2; i++) {
for (int j = 0; j+1 < calculatedSessionDurations.size(); j += 2) {
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
long currentDuration = Long.parseLong(currentDurationString[0]);
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
long nextDuration = Long.parseLong(nextDurationString[0]);
if (currentDuration > nextDuration) {
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
calculatedSessionDurations.remove(j+2);
}
}
for (int j = 1; j+1 < calculatedSessionDurations.size(); j += 2) {
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
long currentDuration = Long.parseLong(currentDurationString[0]);
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
long nextDuration = Long.parseLong(nextDurationString[0]);
if (currentDuration > nextDuration) {
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
calculatedSessionDurations.remove(j+2);
}
}
}
return calculatedSessionDurations;
}
private ArrayList sortSessionsByNick(ArrayList sortedSessionsByTime) {
ArrayList sortedSessionsByNick = new ArrayList();
while (sortedSessionsByTime.size() != 0) {
String entry = (String) sortedSessionsByTime.get(0);
String[] entryFields = entry.split(" ");
String currentNick = entryFields[2];
sortedSessionsByNick.add(entry);
sortedSessionsByNick.add(sortedSessionsByTime.get(1));
sortedSessionsByTime.remove(0);
sortedSessionsByTime.remove(0);
for (int i = 0; i+1 < sortedSessionsByTime.size(); i += 2) {
String nextEntry = (String) sortedSessionsByTime.get(i);
String[] nextEntryFields = nextEntry.split(" ");
if (nextEntryFields[2].equals(currentNick)) {
sortedSessionsByNick.add(nextEntry);
sortedSessionsByNick.add(sortedSessionsByTime.get(i+1));
sortedSessionsByTime.remove(i);
sortedSessionsByTime.remove(i);
i -= 2;
}
}
}
return sortedSessionsByNick;
}
private ArrayList sortSessionsByQuitReason(ArrayList sortedSessionsByNick) {
ArrayList sortedSessionsByQuitReason = new ArrayList();
while (sortedSessionsByNick.size() != 0) {
String entry = (String) sortedSessionsByNick.get(1);
Pattern p = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
Matcher m = p.matcher(entry);
if (m.matches()) {
String currentQuitReason = m.group(1);
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(0));
sortedSessionsByQuitReason.add(entry);
sortedSessionsByNick.remove(0);
sortedSessionsByNick.remove(0);
for (int i = 0; i+1 < sortedSessionsByNick.size(); i += 2) {
String nextEntry = (String) sortedSessionsByNick.get(i+1);
Pattern p2 = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
Matcher m2 = p2.matcher(nextEntry);
if (m2.matches()) {
String nextQuitReason = m2.group(1);
if (nextQuitReason.equals(currentQuitReason)) {
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(i));
sortedSessionsByQuitReason.add(nextEntry);
sortedSessionsByNick.remove(i);
sortedSessionsByNick.remove(i);
i -= 2;
}
} else {
System.out.println("\r\nError: Unexpected entry in logfile: " + nextEntry);
System.exit(1);
}
}
} else {
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
System.exit(1);
}
}
return sortedSessionsByQuitReason;
}
/**
* Sessions terminated with "parts" messages instead of "quits" are filtered
* out.
*/
private ArrayList sortSessionsByTime(ArrayList log) {
ArrayList sortedSessionsByTime = new ArrayList();
mainLoop:
while (log.size() > 0) {
String entry = (String) log.get(0);
String[] entryFields = entry.split(" ");
if (entryFields[1].equals("quits") && !entryFields[1].equals("joins")) {
/*
* Discard entry. The specified log either doesn't contain
* the corresponding "joins" time for this quit entry or the
* entry is a "parts" or unknown message, and in both cases
* the entry's data is useless.
*/
log.remove(0);
continue;
}
for (int i = 1; i < log.size(); i++) { // Find corresponding "quits" entry.
String tempEntry = (String) log.get(i);
String[] tempEntryFields = tempEntry.split(" ");
if (tempEntryFields[2].equals(entryFields[2])) { // Check if the nick fields for the two entries match.
if (!tempEntryFields[1].equals("quits")) {
if (tempEntryFields[1].equals("joins")) { // Don't discard a subsequent "joins" entry.
log.remove(0);
continue mainLoop;
}
log.remove(i);
continue;
}
sortedSessionsByTime.add(entry);
sortedSessionsByTime.add(tempEntry);
log.remove(i);
break;
}
}
/*
* Discard "joins" entry. The specified log doesn't contain the
* corresponding "quits" time for this entry so the entry's
* data is useless.
*/
log.remove(0);
}
return sortedSessionsByTime;
}
}

View File

@@ -1,48 +0,0 @@
/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation. For more information on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/

View File

@@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -1 +0,0 @@
java -cp .;log4j-1.2.8.jar;pircbot.jar Bogobot

View File

@@ -1,101 +0,0 @@
#####
# Bogobot user configuration
#####
###
# The bot's nick and backup nick. You will probably want to register these with
# the IRC server's NickServ.(a NickServ interface is forthcoming).
#
botPrimaryNick=somebot
botSecondaryNick=somebot_
###
# The bot's password required by Nickserv service's identify command.
# You have to register the nickname yourself first, the bot will not.
#
botNickservPassword=
###
# The bot's username. Appears in the whois replies
#
botUsername=somebot
#####
# The bot owner's nick and backup nick. One of these must match the owner's
# currently-used nick or else remote shutdown will not be possible. You will
# probably want to register these with the IRC server's NickServ.
#
ownerPrimaryNick=somenick
ownerSecondaryNick=somenick_
###
# The bot will disconnect and shut down when sent this password via private
# message (aka query) from either of the owner nicks specified above. DO NOT USE
# THIS DEFAULT VALUE!
#
botShutdownPassword=take off eh
###
# The server, channel, and port the bot will connect to.
#
ircChannel=#i2p-chat
ircServer=irc.duck.i2p
ircServerPort=6668
###
# Set to "true" to enable logging, else "false" (but don't use quotation marks).
#
isLoggerEnabled=true
###
# Restrict logging of joins and parts on the user hostname.
# Leave empty to log all of them
# Prepend with a @ for a perfect match
# Otherwise, specify the required end of the user hostname
#
loggedHostnamePattern=@free.duck.i2p
###
# The prefix to be used for the filenames of logs.
#
logFilePrefix=irc.duck.i2p.i2p-chat
###
# How often the logs should be rotated. Either "daily", "weekly", or "monthly"
# (but don't use quotation marks).
#
logFileRotationInterval=daily
###
# Set to "true" to enable the regular round-trip delay computation,
# else "false" (but don't use quotation marks).
#
isRoundTripDelayEnabled=false
###
# How often should the round-trip delay be recorded.
# (in seconds)
#
roundTripDelayPeriod=300
###
# Set to "true" to enable the userlist command, else "false" (but don't use
# quotation marks).
#
isUserlistCommandEnabled=true
###
# The userlist trigger command to listen for. It is a good idea to prefix
# triggers with some non-alphanumeric character in order to avoid accidental
# trigger use during normal channel conversation. In most cases you will
# probably want to choose a unique trigger here that no other bots in the
# channel will respond to.
#
userlistCommandTrigger=!who
###
# The number of seconds to rest after replying to a userlist command issued by
# a user in the channel. The bot will ignore subsequent userlist commands during
# this period. This helps prevent flooding.
#
commandAntiFloodInterval=60

View File

@@ -1,2 +0,0 @@
#!/bin/sh
java -cp .:log4j-1.2.8.jar:pircbot.jar Bogobot

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ********************************************************** -->
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
<!-- -->
<!-- build-eclipse.xml -->
<!-- 2004 The I2P Project -->
<!-- http://www.i2p.net -->
<!-- This code is public domain. -->
<!-- -->
<!-- authors: hypercubus, oOo -->
<!-- version 0.4 -->
<!-- ********************************************************** -->
<project basedir="." default="dist" name="Bogobot">
<!-- init:
Create distribution directory if missing and initialize time stamp for
archive naming -->
<target name="init">
<mkdir dir="dist" />
<tstamp>
<format pattern="yyyy-MM-dd" property="DSTAMP" />
</tstamp>
</target>
<!-- dist.bin:
Create the binary distribution archive -->
<target depends="init" description="Create the binary distribution archive" name="dist.bin">
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
</zip>
</target>
<!-- dist.source:
Create the source distribution archive -->
<target depends="init" description="Create the source distribution archive" name="dist.source">
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
</zip>
</target>
<!-- dist:
Create both the binary and source distribution archives -->
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
<echo message="Successfully created binary and source distribution archives in directory &apos;dist&apos;." />
</target>
<!-- clean:
Delete all class files and temporary directories -->
<target description="Delete all class files and temporary directories" name="clean">
<delete>
<fileset dir="${basedir}" includes="**/*.class" />
</delete>
<echo message="Clean successful." />
</target>
</project>

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ********************************************************** -->
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
<!-- -->
<!-- build.xml -->
<!-- 2004 The I2P Project -->
<!-- http://www.i2p.net -->
<!-- This code is public domain. -->
<!-- -->
<!-- authors: hypercubus, oOo -->
<!-- version 0.4 -->
<!-- ********************************************************** -->
<project basedir="." default="compile" name="Bogobot">
<!-- init:
Create distribution directory if missing and initialize time stamp for
archive naming -->
<target name="init">
<mkdir dir="dist" />
<tstamp>
<format pattern="yyyy-MM-dd" property="DSTAMP" />
</tstamp>
</target>
<!-- compile:
Compile source code -->
<target depends="init" description="Compile source code" name="compile">
<javac classpath="${basedir};log4j-1.2.8.jar;pircbot.jar" source="1.4" srcdir="." />
</target>
<!-- dist.bin:
Create the binary distribution archive -->
<target depends="init,compile" description="Create the binary distribution archive" name="dist.bin">
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.class Bogobot$BogobotTickTask.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
</zip>
</target>
<!-- dist.source:
Create the source distribution archive -->
<target depends="init" description="Create the source distribution archive" name="dist.source">
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
<zipfileset dir="${basedir}" includes="bogobot.bat bogobot.config Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
</zip>
</target>
<!-- dist:
Create both the binary and source distribution archives -->
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
<echo message="Successfully created binary and source distribution archives in directory &apos;dist&apos;." />
</target>
<!-- clean:
Delete all class files and temporary directories -->
<target description="Delete all class files and temporary directories" name="clean">
<delete>
<fileset dir="${basedir}" includes="**/*.class" />
</delete>
<echo message="Clean successful." />
</target>
</project>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
i2psnark.dir=i2psnark

View File

@@ -7,14 +7,32 @@
<ant dir="../../streaming/java/" target="build" />
<!-- streaming will build ministreaming and core -->
</target>
<target name="compile">
<condition property="depend.available">
<typefound name="depend" />
</condition>
<target name="depend" if="depend.available">
<depend
cache="../../../build"
srcdir="./src"
destdir="./build/obj" >
<!-- Depend on classes instead of jars where available -->
<classpath>
<pathelement location="../../../core/java/build/obj" />
<pathelement location="../../../router/java/build/obj" />
<pathelement location="../../ministreaming/java/build/obj" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
</classpath>
</depend>
</target>
<target name="compile" depends="depend">
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
srcdir="./src"
debug="true" deprecation="on" source="1.3" target="1.3"
debug="true" deprecation="on" source="1.5" target="1.5"
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">
@@ -36,7 +54,7 @@
</zip>
</target>
<target name="standalone_prep" depends="war">
<javac debug="true" deprecation="on" source="1.3" target="1.3"
<javac debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build" srcdir="src/" includes="org/klomp/snark/web/RunStandalone.java" >
<classpath>
<pathelement location="../../jetty/jettylib/commons-logging.jar" />

View File

@@ -20,9 +20,6 @@
package org.klomp.snark;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
/**
* Container of a byte array representing set and unset bits.
@@ -32,6 +29,7 @@ public class BitField
private final byte[] bitfield;
private final int size;
private int count;
/**
* Creates a new BitField that represents <code>size</code> unset bits.
@@ -41,6 +39,7 @@ public class BitField
this.size = size;
int arraysize = ((size-1)/8)+1;
bitfield = new byte[arraysize];
this.count = 0;
}
/**
@@ -60,6 +59,11 @@ public class BitField
// XXX - More correct would be to check that unused bits are
// cleared or clear them explicitly ourselves.
System.arraycopy(bitfield, 0, this.bitfield, 0, arraysize);
this.count = 0;
for (int i = 0; i < size; i++)
if (get(i))
this.count++;
}
/**
@@ -95,7 +99,10 @@ public class BitField
throw new IndexOutOfBoundsException(Integer.toString(bit));
int index = bit/8;
int mask = 128 >> (bit % 8);
bitfield[index] |= mask;
if ((bitfield[index] & mask) == 0) {
count++;
bitfield[index] |= mask;
}
}
/**
@@ -114,6 +121,22 @@ public class BitField
return (bitfield[index] & mask) != 0;
}
/**
* Return the number of set bits.
*/
public int count()
{
return count;
}
/**
* Return true if all bits are set.
*/
public boolean complete()
{
return count >= size;
}
public String toString()
{
// Not very efficient
@@ -129,4 +152,5 @@ public class BitField
return sb.toString();
}
}

View File

@@ -20,13 +20,15 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
@@ -34,17 +36,16 @@ import net.i2p.util.Log;
*/
public class ConnectionAcceptor implements Runnable
{
private static final ConnectionAcceptor _instance = new ConnectionAcceptor();
public static final ConnectionAcceptor instance() { return _instance; }
private Log _log = new Log(ConnectionAcceptor.class);
private I2PServerSocket serverSocket;
private PeerAcceptor peeracceptor;
private Thread thread;
private I2PSnarkUtil _util;
private boolean stop;
private boolean socketChanged;
private ConnectionAcceptor() {}
public ConnectionAcceptor(I2PSnarkUtil util) { _util = util; }
public synchronized void startAccepting(PeerCoordinatorSet set, I2PServerSocket socket) {
if (serverSocket != socket) {
@@ -54,29 +55,30 @@ public class ConnectionAcceptor implements Runnable
stop = false;
socketChanged = true;
if (thread == null) {
thread = new I2PThread(this, "I2PSnark acceptor");
thread = new I2PAppThread(this, "I2PSnark acceptor");
thread.setDaemon(true);
thread.start();
}
}
}
public ConnectionAcceptor(I2PServerSocket serverSocket,
public ConnectionAcceptor(I2PSnarkUtil util, I2PServerSocket serverSocket,
PeerAcceptor peeracceptor)
{
this.serverSocket = serverSocket;
this.peeracceptor = peeracceptor;
_util = util;
socketChanged = false;
stop = false;
thread = new I2PThread(this, "I2PSnark acceptor");
thread = new I2PAppThread(this, "I2PSnark acceptor");
thread.setDaemon(true);
thread.start();
}
public void halt()
{
if (true) throw new RuntimeException("wtf");
if (stop) return;
stop = true;
I2PServerSocket ss = serverSocket;
@@ -93,7 +95,7 @@ public class ConnectionAcceptor implements Runnable
}
public void restart() {
serverSocket = I2PSnarkUtil.instance().getServerSocket();
serverSocket = _util.getServerSocket();
socketChanged = true;
Thread t = thread;
if (t != null)
@@ -114,10 +116,12 @@ public class ConnectionAcceptor implements Runnable
socketChanged = false;
}
while ( (serverSocket == null) && (!stop)) {
serverSocket = I2PSnarkUtil.instance().getServerSocket();
serverSocket = _util.getServerSocket();
if (serverSocket == null)
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
}
if(stop)
break;
try
{
I2PSocket socket = serverSocket.accept();
@@ -125,27 +129,27 @@ public class ConnectionAcceptor implements Runnable
if (socketChanged) {
continue;
} else {
I2PServerSocket ss = I2PSnarkUtil.instance().getServerSocket();
I2PServerSocket ss = _util.getServerSocket();
if (ss != serverSocket) {
serverSocket = ss;
socketChanged = true;
}
}
} else {
Thread t = new I2PThread(new Handler(socket), "Connection-" + socket);
Thread t = new I2PAppThread(new Handler(socket), "Connection-" + socket);
t.start();
}
}
catch (I2PException ioe)
{
if (!socketChanged) {
Snark.debug("Error while accepting: " + ioe, Snark.ERROR);
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
stop = true;
}
}
catch (IOException ioe)
{
Snark.debug("Error while accepting: " + ioe, Snark.ERROR);
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
stop = true;
}
}
@@ -157,7 +161,6 @@ public class ConnectionAcceptor implements Runnable
}
catch (I2PException ignored) { }
throw new RuntimeException("wtf");
}
private class Handler implements Runnable {

View File

@@ -30,4 +30,8 @@ public interface CoordinatorListener
* Called when the PeerCoordinator notices a change in the state of a peer.
*/
void peerChange(PeerCoordinator coordinator, Peer peer);
public boolean overUploadLimit(int uploaders);
public boolean overUpBWLimit();
public boolean overUpBWLimit(long total);
}

View File

@@ -1,28 +1,40 @@
package org.klomp.snark;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.util.EepGet;
import net.i2p.client.I2PSession;
import net.i2p.data.*;
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.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.EepGet;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
import java.io.*;
import java.util.*;
/**
* I2P specific helpers for I2PSnark
* We use this class as a sort of context for i2psnark
* so we can run multiple instances of single Snarks
* (but not multiple SnarkManagers, it is still static)
*/
public class I2PSnarkUtil {
private I2PAppContext _context;
private Log _log;
private static I2PSnarkUtil _instance = new I2PSnarkUtil();
public static I2PSnarkUtil instance() { return _instance; }
private boolean _shouldProxy;
private String _proxyHost;
@@ -33,15 +45,28 @@ public class I2PSnarkUtil {
private I2PSocketManager _manager;
private boolean _configured;
private Set _shitlist;
private int _maxUploaders;
private int _maxUpBW;
private int _maxConnections;
private I2PSnarkUtil() {
_context = I2PAppContext.getGlobalContext();
public static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
public static final boolean 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 DEFAULT_MAX_UP_BW = 8; //KBps
public static final int MAX_CONNECTIONS = 16; // per torrent
public I2PSnarkUtil(I2PAppContext ctx) {
_context = ctx;
_log = _context.logManager().getLog(Snark.class);
_opts = new HashMap();
setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", 7654, null);
_shitlist = new HashSet(64);
_configured = false;
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
_maxUpBW = DEFAULT_MAX_UP_BW;
_maxConnections = MAX_CONNECTIONS;
}
/**
@@ -65,24 +90,44 @@ public class I2PSnarkUtil {
public boolean configured() { return _configured; }
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
_i2cpHost = i2cpHost;
_i2cpPort = i2cpPort;
if (i2cpHost != null)
_i2cpHost = i2cpHost;
if (i2cpPort > 0)
_i2cpPort = i2cpPort;
if (opts != null)
_opts.putAll(opts);
_configured = true;
}
public void setMaxUploaders(int limit) {
_maxUploaders = limit;
_configured = true;
}
public void setMaxUpBW(int limit) {
_maxUpBW = limit;
_configured = true;
}
public void setMaxConnections(int limit) {
_maxConnections = limit;
_configured = true;
}
public String getI2CPHost() { return _i2cpHost; }
public int getI2CPPort() { return _i2cpPort; }
public Map getI2CPOptions() { return _opts; }
public String getEepProxyHost() { return _proxyHost; }
public int getEepProxyPort() { return _proxyPort; }
public boolean getEepProxySet() { return _shouldProxy; }
public int getMaxUploaders() { return _maxUploaders; }
public int getMaxUpBW() { return _maxUpBW; }
public int getMaxConnections() { return _maxConnections; }
/**
* 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) {
@@ -93,10 +138,16 @@ public class I2PSnarkUtil {
}
if (opts.getProperty("inbound.nickname") == null)
opts.setProperty("inbound.nickname", "I2PSnark");
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)
opts.setProperty("i2p.streaming.slowStartGrowthRateFactor", "1");
//if (opts.getProperty("i2p.streaming.writeTimeout") == null)
// opts.setProperty("i2p.streaming.writeTimeout", "90000");
//if (opts.getProperty("i2p.streaming.readTimeout") == null)
@@ -146,22 +197,26 @@ 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 {
out = File.createTempFile("i2psnark", "url", new File("."));
} catch (IOException ioe) {
ioe.printStackTrace();
out.delete();
if (out != null)
out.delete();
return null;
}
out.deleteOnExit();
String fetchURL = url;
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;
@@ -181,6 +236,8 @@ public class I2PSnarkUtil {
}
String getOurIPString() {
if (_manager == null)
return "unknown";
I2PSession sess = _manager.getSession();
if (sess != null) {
Destination dest = sess.getMyDestination();
@@ -189,18 +246,17 @@ public class I2PSnarkUtil {
}
return "unknown";
}
Destination getDestination(String ip) {
/** Base64 only - static (no naming service) */
static Destination getDestinationFromBase64(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) {
if (ip.length() < 520)
return null;
}
try {
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
} catch (DataFormatException dfe) {
return null;
}
} else {
try {
@@ -211,19 +267,85 @@ public class I2PSnarkUtil {
}
}
/** Base64 Hash or Hash.i2p or name.i2p using naming service */
Destination getDestination(String ip) {
if (ip == null) return null;
if (ip.endsWith(".i2p")) {
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 {
return new Destination(ip);
} catch (DataFormatException dfe) {
return null;
}
}
}
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 + "]");
return rv;
}
public String getOpenTrackerString() {
String rv = (String) _opts.get(PROP_OPENTRACKERS);
if (rv == null)
return DEFAULT_OPENTRACKERS;
return rv;
}
/** 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;
}
public boolean shouldUseOpenTrackers() {
String rv = (String) _opts.get(PROP_USE_OPENTRACKERS);
if (rv == null)
return DEFAULT_USE_OPENTRACKERS;
return Boolean.valueOf(rv).booleanValue();
}
/** hook between snark's logger and an i2p log */
void debug(String msg, int snarkDebugLevel) {
debug(msg, snarkDebugLevel, null);
}
void debug(String msg, int snarkDebugLevel, Throwable t) {
if (t instanceof OutOfMemoryError) {
try { Thread.sleep(100); } catch (InterruptedException ie) {}

View File

@@ -22,20 +22,22 @@ package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import org.klomp.snark.bencode.*;
import net.i2p.crypto.SHA1;
import net.i2p.data.Base64;
import net.i2p.util.Log;
import net.i2p.crypto.SHA1;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.BEncoder;
import org.klomp.snark.bencode.InvalidBEncodingException;
/**
* Note: this class is buggy, as it doesn't propogate custom meta fields into the bencoded
@@ -406,7 +408,7 @@ public class MetaInfo
info.put("name", name);
if (name_utf8 != null)
info.put("name.utf-8", name_utf8);
info.put("piece length", new Integer(piece_length));
info.put("piece length", Integer.valueOf(piece_length));
info.put("pieces", piece_hashes);
if (files == null)
info.put("length", new Long(length));
@@ -432,9 +434,10 @@ public class MetaInfo
Map info = createInfoMap();
StringBuffer buf = new StringBuffer(128);
buf.append("info: ");
for (Iterator iter = info.keySet().iterator(); iter.hasNext(); ) {
String key = (String)iter.next();
Object val = info.get(key);
for (Iterator iter = info.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String key = (String)entry.getKey();
Object val = entry.getValue();
buf.append(key).append('=');
if (val instanceof byte[])
buf.append(Base64.encode((byte[])val, true));

View File

@@ -20,15 +20,15 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;
import org.klomp.snark.bencode.*;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
public class Peer implements Comparable
@@ -54,6 +54,10 @@ public class Peer implements Comparable
private boolean deregister = true;
private static long __id;
private long _id;
final static long CHECK_PERIOD = PeerCoordinator.CHECK_PERIOD; // 40 seconds
final static int RATE_DEPTH = PeerCoordinator.RATE_DEPTH; // make following arrays RATE_DEPTH long
private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
/**
* Creates a disconnected peer given a PeerID, your own id and the
@@ -110,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.
*/
@@ -161,7 +173,7 @@ public class Peer implements Comparable
* If the given BitField is non-null it is send to the peer as first
* message.
*/
public void runConnection(PeerListener listener, BitField bitfield)
public void runConnection(I2PSnarkUtil util, PeerListener listener, BitField bitfield)
{
if (state != null)
throw new IllegalStateException("Peer already started");
@@ -172,7 +184,7 @@ public class Peer implements Comparable
// Do we need to handshake?
if (din == null)
{
sock = I2PSnarkUtil.instance().connect(peerID);
sock = util.connect(peerID);
_log.debug("Connected to " + peerID + ": " + sock);
if ((sock == null) || (sock.isClosed())) {
throw new IOException("Unable to reach " + peerID);
@@ -318,6 +330,14 @@ public class Peer implements Comparable
PeerState s = state;
if (s != null)
{
// try to save partial piece
if (this.deregister) {
PeerListener p = s.listener;
if (p != null) {
p.savePeerPartial(s);
p.markUnrequested(this);
}
}
state = null;
PeerConnectionIn in = s.in;
@@ -449,13 +469,105 @@ 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";
}
}
/**
* Send keepalive
*/
public void keepAlive()
{
PeerState s = state;
if (s != null)
s.keepAlive();
}
/**
* Retransmit outstanding requests if necessary
*/
public void retransmitRequests()
{
PeerState s = state;
if (s != null)
s.retransmitRequests();
}
/**
* Return how much the peer has
*/
public int completed()
{
PeerState s = state;
if (s == null || s.bitfield == null)
return 0;
return s.bitfield.count();
}
/**
* Return if a peer is a seeder
*/
public boolean isCompleted()
{
PeerState s = state;
if (s == null || s.bitfield == null)
return false;
return s.bitfield.complete();
}
/**
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
*/
public void setRateHistory(long up, long down)
{
setRate(up, uploaded_old);
setRate(down, downloaded_old);
}
private void setRate(long val, long array[])
{
synchronized(array) {
for (int i = RATE_DEPTH-1; i > 0; i--)
array[i] = array[i-1];
array[0] = val;
}
}
/**
* Returns the 4-minute-average rate in Bps
*/
public long getUploadRate()
{
return getRate(uploaded_old);
}
public long getDownloadRate()
{
return getRate(downloaded_old);
}
private long getRate(long array[])
{
long rate = 0;
int i = 0;
synchronized(array) {
for ( ; i < RATE_DEPTH; i++){
if (array[i] < 0)
break;
rate += array[i];
}
}
if (i == 0)
return 0;
return rate / (i * CHECK_PERIOD / 1000);
}
}

View File

@@ -20,8 +20,12 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
import java.util.Iterator;
import net.i2p.client.streaming.I2PSocket;

View File

@@ -20,7 +20,11 @@
package org.klomp.snark;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.TimerTask;
/**
* TimerTask that checks for good/bad up/downloader. Works together
@@ -28,19 +32,34 @@ import java.util.*;
*/
class PeerCheckerTask extends TimerTask
{
private final long KILOPERSECOND = 1024*(PeerCoordinator.CHECK_PERIOD/1000);
private static final long KILOPERSECOND = 1024*(PeerCoordinator.CHECK_PERIOD/1000);
private final PeerCoordinator coordinator;
public I2PSnarkUtil _util;
PeerCheckerTask(PeerCoordinator coordinator)
PeerCheckerTask(I2PSnarkUtil util, PeerCoordinator coordinator)
{
_util = util;
this.coordinator = coordinator;
}
private Random random = new Random();
public void run()
{
synchronized(coordinator.peers)
{
Iterator it = coordinator.peers.iterator();
if ((!it.hasNext()) || coordinator.halted()) {
coordinator.peerCount = 0;
coordinator.interestedAndChoking = 0;
coordinator.setRateHistory(0, 0);
coordinator.uploaders = 0;
if (coordinator.halted())
cancel();
return;
}
// Calculate total uploading and worst downloader.
long worstdownload = Long.MAX_VALUE;
Peer worstDownloader = null;
@@ -48,10 +67,7 @@ class PeerCheckerTask extends TimerTask
int peers = 0;
int uploaders = 0;
int downloaders = 0;
int interested = 0;
int interesting = 0;
int choking = 0;
int choked = 0;
int removedCount = 0;
long uploaded = 0;
long downloaded = 0;
@@ -59,8 +75,8 @@ class PeerCheckerTask extends TimerTask
// Keep track of peers we remove now,
// we will add them back to the end of the list.
List removed = new ArrayList();
Iterator it = coordinator.peers.iterator();
int uploadLimit = coordinator.allowedUploaders();
boolean overBWLimit = coordinator.overUpBWLimit();
while (it.hasNext())
{
Peer peer = (Peer)it.next();
@@ -80,48 +96,43 @@ class PeerCheckerTask extends TimerTask
uploaders++;
if (!peer.isChoked() && peer.isInteresting())
downloaders++;
if (peer.isInterested())
interested++;
if (peer.isInteresting())
interesting++;
if (peer.isChoking())
choking++;
if (peer.isChoked())
choked++;
// XXX - We should calculate the up/download rate a bit
// more intelligently
long upload = peer.getUploaded();
uploaded += upload;
long download = peer.getDownloaded();
downloaded += download;
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);
}
_util.debug(peer + ":", Snark.DEBUG);
_util.debug(" ul: " + upload/KILOPERSECOND
+ " dl: " + download/KILOPERSECOND
+ " i: " + peer.isInterested()
+ " I: " + peer.isInteresting()
+ " c: " + peer.isChoking()
+ " C: " + peer.isChoked(),
Snark.DEBUG);
// Choke half of them rather than all so it isn't so drastic...
// unless this torrent is over the limit all by itself.
boolean overBWLimitChoke = upload > 0 &&
((overBWLimit && random.nextBoolean()) ||
(coordinator.overUpBWLimit(uploaded)));
// 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 >= PeerCoordinator.MAX_UPLOADERS
&& interested > PeerCoordinator.MAX_UPLOADERS
if (((coordinator.uploaders == uploadLimit
&& coordinator.interestedAndChoking > 0)
|| coordinator.uploaders > uploadLimit
|| overBWLimitChoke)
&& !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);
_util.debug("Choke uninterested peer: " + peer,
Snark.INFO);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -130,14 +141,40 @@ class PeerCheckerTask extends TimerTask
it.remove();
removed.add(peer);
}
else if (peer.isChoked())
else if (overBWLimitChoke)
{
// If they are choking us make someone else a downloader
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke choking peer: " + peer, Snark.DEBUG);
_util.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer,
Snark.INFO);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
removedCount++;
// Put it at the back of the list for fairness, even though we won't be unchoking this time
it.remove();
removed.add(peer);
}
else if (peer.isInteresting() && peer.isChoked())
{
// If they are choking us make someone else a downloader
_util.debug("Choke choking peer: " + peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
removedCount++;
// Put it at the back of the list
it.remove();
removed.add(peer);
}
else if (!peer.isInteresting() && !coordinator.completed())
{
// If they aren't interesting make someone else a downloader
_util.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
removedCount++;
// Put it at the back of the list
it.remove();
@@ -148,41 +185,51 @@ 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);
_util.debug("Choke downloader that doesn't deliver:"
+ peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
removedCount++;
// Put it at the back of the list
it.remove();
removed.add(peer);
}
else if (!peer.isChoking() && download < worstdownload)
else if (peer.isInteresting() && !peer.isChoked() &&
download < worstdownload)
{
// Make sure download is good if we are uploading
worstdownload = download;
worstDownloader = peer;
}
else if (upload < worstdownload && coordinator.completed())
{
// Make sure upload is good if we are seeding
worstdownload = upload;
worstDownloader = peer;
}
}
peer.retransmitRequests();
peer.keepAlive();
}
// Resync actual uploaders value
// (can shift a bit by disconnecting peers)
coordinator.uploaders = uploaders;
// Remove the worst downloader if needed.
if (uploaders >= PeerCoordinator.MAX_UPLOADERS
&& interested > PeerCoordinator.MAX_UPLOADERS
// Remove the worst downloader if needed. (uploader if seeding)
if (((uploaders == uploadLimit
&& coordinator.interestedAndChoking > 0)
|| uploaders > uploadLimit)
&& worstDownloader != null)
{
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke worst downloader: " + worstDownloader,
Snark.DEBUG);
_util.debug("Choke worst downloader: " + worstDownloader,
Snark.DEBUG);
worstDownloader.setChoking(true);
coordinator.uploaders--;
removedCount++;
// Put it at the back of the list
coordinator.peers.remove(worstDownloader);
@@ -191,14 +238,21 @@ class PeerCheckerTask extends TimerTask
}
// Optimistically unchoke a peer
coordinator.unchokePeer();
if ((!overBWLimit) && !coordinator.overUpBWLimit(uploaded))
coordinator.unchokePeer();
// Put peers back at the end of the list that we removed earlier.
coordinator.peers.addAll(removed);
coordinator.peerCount = coordinator.peers.size();
coordinator.interestedAndChoking += removedCount;
// store the rates
coordinator.setRateHistory(uploaded, downloaded);
// close out unused files, but we don't need to do it every time
if (random.nextInt(4) == 0)
coordinator.getStorage().cleanRAFs();
}
if (coordinator.halted()) {
cancel();
}
}
}

View File

@@ -20,9 +20,8 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.util.*;
import java.io.DataInputStream;
import java.io.IOException;
import net.i2p.util.Log;
@@ -33,12 +32,15 @@ class PeerConnectionIn implements Runnable
private final DataInputStream din;
private Thread thread;
private boolean quit;
private volatile boolean quit;
long lastRcvd;
public PeerConnectionIn(Peer peer, DataInputStream din)
{
this.peer = peer;
this.din = din;
lastRcvd = System.currentTimeMillis();
quit = false;
}
@@ -51,6 +53,13 @@ class PeerConnectionIn implements Runnable
Thread t = thread;
if (t != null)
t.interrupt();
if (din != null) {
try {
din.close();
} catch (IOException ioe) {
_log.warn("Error closing the stream from " + peer, ioe);
}
}
}
public void run()
@@ -68,8 +77,12 @@ class PeerConnectionIn implements Runnable
// Wait till we hear something...
// The length of a complete message in bytes.
// The biggest is the piece message, for which the length is the
// request size (32K) plus 9. (we could also check if Storage.MAX_PIECES / 8
// in the bitfield message is bigger but it's currently 5000/8 = 625 so don't bother)
int i = din.readInt();
if (i < 0)
lastRcvd = System.currentTimeMillis();
if (i < 0 || i > PeerState.PARTSIZE + 9)
throw new IOException("Unexpected length prefix: " + i);
if (i == 0)

View File

@@ -20,11 +20,13 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.util.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
@@ -56,7 +58,7 @@ class PeerConnectionOut implements Runnable
}
public void startup() {
thread = new I2PThread(this, "Snark sender " + _id + ": " + peer);
thread = new I2PAppThread(this, "Snark sender " + _id + ": " + peer);
thread.start();
}
@@ -72,6 +74,16 @@ class PeerConnectionOut implements Runnable
{
Message m = null;
PeerState state = null;
boolean shouldFlush;
synchronized(sendQueue)
{
shouldFlush = !quit && peer.isConnected() && sendQueue.isEmpty();
}
if (shouldFlush)
// Make sure everything will reach the other side.
// flush while not holding lock, could take a long time
dout.flush();
synchronized(sendQueue)
{
while (!quit && peer.isConnected() && sendQueue.isEmpty())
@@ -79,7 +91,8 @@ class PeerConnectionOut implements Runnable
try
{
// Make sure everything will reach the other side.
dout.flush();
// don't flush while holding lock, could take a long time
// dout.flush();
// Wait till more data arrives.
sendQueue.wait(60*1000);
@@ -197,10 +210,12 @@ class PeerConnectionOut implements Runnable
/**
* Adds a message to the sendQueue and notifies the method waiting
* on the sendQueue to change.
* If a PIECE message only, add a timeout.
*/
private void addMessage(Message m)
{
SimpleTimer.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT);
if (m.type == Message.PIECE)
SimpleTimer.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT);
synchronized(sendQueue)
{
sendQueue.add(m);
@@ -259,7 +274,13 @@ class PeerConnectionOut implements Runnable
{
Message m = new Message();
m.type = Message.KEEP_ALIVE;
addMessage(m);
// addMessage(m);
synchronized(sendQueue)
{
if(sendQueue.isEmpty())
sendQueue.add(m);
sendQueue.notifyAll();
}
}
void sendChoke(boolean choke)
@@ -318,6 +339,23 @@ class PeerConnectionOut implements Runnable
addMessage(m);
}
/** reransmit requests not received in 7m */
private static final int REQ_TIMEOUT = (2 * SEND_TIMEOUT) + (60 * 1000);
void retransmitRequests(List requests)
{
long now = System.currentTimeMillis();
Iterator it = requests.iterator();
while (it.hasNext())
{
Request req = (Request)it.next();
if(now > req.sendTime + REQ_TIMEOUT) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Retransmit request " + req + " to peer " + peer);
sendRequest(req);
}
}
}
void sendRequests(List requests)
{
Iterator it = requests.iterator();
@@ -330,12 +368,47 @@ class PeerConnectionOut implements Runnable
void sendRequest(Request req)
{
// Check for duplicate requests to deal with fibrillating i2p-bt
// (multiple choke/unchokes received cause duplicate requests in the queue)
synchronized(sendQueue)
{
Iterator it = sendQueue.iterator();
while (it.hasNext())
{
Message m = (Message)it.next();
if (m.type == Message.REQUEST && m.piece == req.piece &&
m.begin == req.off && m.length == req.len)
{
if (_log.shouldLog(Log.DEBUG))
_log.debug("Discarding duplicate request " + req + " to peer " + peer);
return;
}
}
}
Message m = new Message();
m.type = Message.REQUEST;
m.piece = req.piece;
m.begin = req.off;
m.length = req.len;
addMessage(m);
req.sendTime = System.currentTimeMillis();
}
// Used by PeerState to limit pipelined requests
int queuedBytes()
{
int total = 0;
synchronized(sendQueue)
{
Iterator it = sendQueue.iterator();
while (it.hasNext())
{
Message m = (Message)it.next();
if (m.type == Message.PIECE)
total += m.length;
}
}
return total;
}
void sendPiece(int piece, int begin, int length, byte[] bytes)
@@ -346,7 +419,7 @@ class PeerConnectionOut implements Runnable
m.begin = begin;
m.length = length;
m.data = bytes;
m.off = begin;
m.off = 0;
m.len = length;
addMessage(m);
}

View File

@@ -20,10 +20,16 @@
package org.klomp.snark;
import java.util.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
@@ -37,19 +43,22 @@ public class PeerCoordinator implements PeerListener
final Snark snark;
// package local for access by CheckDownLoadersTask
final static long CHECK_PERIOD = 20*1000; // 20 seconds
final static int MAX_CONNECTIONS = 24;
final static int MAX_UPLOADERS = 12; // i2p: might as well balance it out
final static long CHECK_PERIOD = 40*1000; // 40 seconds
final static int MAX_UPLOADERS = 6;
// Approximation of the number of current uploaders.
// Resynced by PeerChecker once in a while.
int uploaders = 0;
int interestedAndChoking = 0;
// final static int MAX_DOWNLOADERS = MAX_CONNECTIONS;
// int downloaders = 0;
private long uploaded;
private long downloaded;
final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long
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();
@@ -62,24 +71,38 @@ public class PeerCoordinator implements PeerListener
private final byte[] id;
// Some random wanted pieces
private final List wantedPieces;
private List wantedPieces;
private boolean halted = false;
private final CoordinatorListener listener;
public I2PSnarkUtil _util;
public String trackerProblems = null;
public int trackerSeenPeers = 0;
public PeerCoordinator(byte[] id, MetaInfo metainfo, Storage storage,
public PeerCoordinator(I2PSnarkUtil util, byte[] id, MetaInfo metainfo, Storage storage,
CoordinatorListener listener, Snark torrent)
{
_util = util;
this.id = id;
this.metainfo = metainfo;
this.storage = storage;
this.listener = listener;
this.snark = torrent;
setWantedPieces();
// Install a timer to check the uploaders.
// Randomize the first start time so multiple tasks are spread out,
// this will help the behavior with global limits
Random r = new Random();
timer.schedule(new PeerCheckerTask(_util, this), (CHECK_PERIOD / 2) + r.nextInt((int) CHECK_PERIOD), CHECK_PERIOD);
}
// only called externally from Storage after the double-check fails
public void setWantedPieces()
{
// Make a list of pieces
wantedPieces = new ArrayList();
BitField bitfield = storage.getBitField();
@@ -87,14 +110,20 @@ public class PeerCoordinator implements PeerListener
if (!bitfield.get(i))
wantedPieces.add(new Piece(i));
Collections.shuffle(wantedPieces);
// Install a timer to check the uploaders.
timer.schedule(new PeerCheckerTask(this), CHECK_PERIOD, CHECK_PERIOD);
}
public Storage getStorage() { return storage; }
public CoordinatorListener getListener() { return listener; }
// for web page detailed stats
public List peerList()
{
synchronized(peers)
{
return new ArrayList(peers);
}
}
public byte[] getID()
{
return id;
@@ -123,7 +152,7 @@ public class PeerCoordinator implements PeerListener
public long getLeft()
{
// XXX - Only an approximation.
return storage.needed() * metainfo.getPieceLength(0);
return ((long) storage.needed()) * metainfo.getPieceLength(0);
}
/**
@@ -142,6 +171,62 @@ public class PeerCoordinator implements PeerListener
return downloaded;
}
/**
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
*/
public void setRateHistory(long up, long down)
{
setRate(up, uploaded_old);
setRate(down, downloaded_old);
}
private static void setRate(long val, long array[])
{
synchronized(array) {
for (int i = RATE_DEPTH-1; i > 0; i--)
array[i] = array[i-1];
array[0] = val;
}
}
/**
* Returns the 4-minute-average rate in Bps
*/
public long getDownloadRate()
{
return getRate(downloaded_old);
}
public long getUploadRate()
{
return getRate(uploaded_old);
}
public long getCurrentUploadRate()
{
// no need to synchronize, only one value
long r = uploaded_old[0];
if (r <= 0)
return 0;
return (r * 1000) / CHECK_PERIOD;
}
private long getRate(long array[])
{
long rate = 0;
int i = 0;
synchronized(array) {
for ( ; i < RATE_DEPTH; i++) {
if (array[i] < 0)
break;
rate += array[i];
}
}
if (i == 0)
return 0;
return rate / (i * CHECK_PERIOD / 1000);
}
public MetaInfo getMetaInfo()
{
return metainfo;
@@ -151,7 +236,7 @@ public class PeerCoordinator implements PeerListener
{
synchronized(peers)
{
return !halted && peers.size() < MAX_CONNECTIONS;
return !halted && peers.size() < _util.getMaxConnections();
}
}
@@ -177,6 +262,8 @@ public class PeerCoordinator implements PeerListener
peer.disconnect();
removePeerFromPieces(peer);
}
// delete any saved orphan partial piece
savedRequest = null;
}
public void connected(Peer peer)
@@ -191,8 +278,10 @@ public class PeerCoordinator implements PeerListener
synchronized(peers)
{
Peer old = peerIDInList(peer.getPeerID(), peers);
if ( (old != null) && (old.getInactiveTime() > 2*60*1000) ) {
// idle for 2 minutes, kill the old con
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);
toDisconnect = old;
old = null;
@@ -201,8 +290,17 @@ public class PeerCoordinator implements PeerListener
{
if (_log.shouldLog(Log.WARN))
_log.warn("Already connected to: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
// toDisconnect = peer to get out of synchronized(peers)
peer.disconnect(false); // Don't deregister this connection/peer.
}
// This is already checked in addPeer() but we could have gone over the limit since then
else if (peers.size() >= _util.getMaxConnections())
{
if (_log.shouldLog(Log.WARN))
_log.warn("Already at MAX_CONNECTIONS in connected() with peer: " + peer);
// toDisconnect = peer to get out of synchronized(peers)
peer.disconnect(false);
}
else
{
if (_log.shouldLog(Log.INFO))
@@ -224,6 +322,7 @@ public class PeerCoordinator implements PeerListener
}
}
// caller must synchronize on peers
private static Peer peerIDInList(PeerID pid, List peers)
{
Iterator it = peers.iterator();
@@ -235,18 +334,26 @@ public class PeerCoordinator implements PeerListener
return null;
}
public void addPeer(final Peer peer)
// returns true if actual attempt to add peer occurs
public boolean addPeer(final Peer peer)
{
if (halted)
{
peer.disconnect(false);
return;
return false;
}
boolean need_more;
int peersize = 0;
synchronized(peers)
{
need_more = !peer.isConnected() && peers.size() < MAX_CONNECTIONS;
peersize = peers.size();
// This isn't a strict limit, as we may have several pending connections;
// thus there is an additional check in connected()
need_more = (!peer.isConnected()) && peersize < _util.getMaxConnections();
// Check if we already have this peer before we build the connection
Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
}
if (need_more)
@@ -260,20 +367,21 @@ public class PeerCoordinator implements PeerListener
{
public void run()
{
peer.runConnection(listener, bitfield);
peer.runConnection(_util, listener, bitfield);
}
};
String threadName = peer.toString();
new I2PThread(r, threadName).start();
}
else
if (_log.shouldLog(Log.DEBUG)) {
if (peer.isConnected())
_log.info("Add peer already connected: " + peer);
else
_log.info("MAX_CONNECTIONS = " + MAX_CONNECTIONS
+ " not accepting extra peer: " + peer);
new I2PAppThread(r, threadName).start();
return true;
}
if (_log.shouldLog(Log.DEBUG)) {
if (peer.isConnected())
_log.info("Add peer already connected: " + peer);
else
_log.info("Connections: " + peersize + "/" + _util.getMaxConnections()
+ " not accepting extra peer: " + peer);
}
return false;
}
@@ -285,34 +393,40 @@ public class PeerCoordinator implements PeerListener
// other peer that are interested, but are choking us.
List interested = new LinkedList();
synchronized (peers) {
int count = 0;
int unchokedCount = 0;
int maxUploaders = allowedUploaders();
Iterator it = peers.iterator();
while (it.hasNext())
{
Peer peer = (Peer)it.next();
boolean remove = false;
if (uploaders < MAX_UPLOADERS
&& peer.isChoking()
&& peer.isInterested())
if (peer.isChoking() && peer.isInterested())
{
if (!peer.isChoked())
interested.add(0, peer);
else
interested.add(peer);
count++;
if (uploaders < maxUploaders)
{
if (!peer.isChoked())
interested.add(unchokedCount++, peer);
else
interested.add(peer);
}
}
}
while (uploaders < MAX_UPLOADERS && interested.size() > 0)
while (uploaders < maxUploaders && interested.size() > 0)
{
Peer peer = (Peer)interested.remove(0);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Unchoke: " + peer);
peer.setChoking(false);
uploaders++;
count--;
// Put peer back at the end of the list.
peers.remove(peer);
peers.add(peer);
peerCount = peers.size();
}
interestedAndChoking = count;
}
}
@@ -351,9 +465,10 @@ public class PeerCoordinator implements PeerListener
{
Piece p = (Piece)it.next();
int i = p.getId();
if (bitfield.get(i))
if (bitfield.get(i)) {
p.addPeer(peer);
return true;
}
}
}
return false;
@@ -392,6 +507,8 @@ public class PeerCoordinator implements PeerListener
//Only request a piece we've requested before if there's no other choice.
if (piece == null) {
// let's not all get on the same piece
Collections.shuffle(requested);
Iterator it2 = requested.iterator();
while (piece == null && it2.hasNext())
{
@@ -403,9 +520,17 @@ public class PeerCoordinator implements PeerListener
}
if (piece == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("nothing to even rerequest from " + peer + ": requested = " + requested
+ " wanted = " + wantedPieces + " peerHas = " + havePieces);
_log.warn("nothing to even rerequest from " + peer + ": requested = " + requested);
// _log.warn("nothing to even rerequest from " + peer + ": requested = " + requested
// + " wanted = " + wantedPieces + " peerHas = " + havePieces);
return -1; //If we still can't find a piece we want, so be it.
} else {
// Should be a lot smarter here - limit # of parallel attempts and
// share blocks rather than starting from 0 with each peer.
// This is where the flaws of the snark data model are really exposed.
// Could also randomize within the duplicate set rather than strict rarest-first
if (_log.shouldLog(Log.DEBUG))
_log.debug("parallel request (end game?) for " + peer + ": piece = " + piece);
}
}
piece.setRequested(true);
@@ -417,14 +542,14 @@ public class PeerCoordinator implements PeerListener
* Returns a byte array containing the requested piece or null of
* the piece is unknown.
*/
public byte[] gotRequest(Peer peer, int piece)
public byte[] gotRequest(Peer peer, int piece, int off, int len)
{
if (halted)
return null;
try
{
return storage.getPiece(piece);
return storage.getPiece(piece, off, len);
}
catch (IOException ioe)
{
@@ -504,14 +629,27 @@ public class PeerCoordinator implements PeerListener
}
// Announce to the world we have it!
// Disconnect from other seeders when we get the last piece
synchronized(peers)
{
List toDisconnect = new ArrayList();
Iterator it = peers.iterator();
while (it.hasNext())
{
Peer p = (Peer)it.next();
if (p.isConnected())
p.have(piece);
{
if (completed() && p.isCompleted())
toDisconnect.add(p);
else
p.have(piece);
}
}
it = toDisconnect.iterator();
while (it.hasNext())
{
Peer p = (Peer)it.next();
p.disconnect(true);
}
}
@@ -533,7 +671,7 @@ public class PeerCoordinator implements PeerListener
{
synchronized(peers)
{
if (uploaders < MAX_UPLOADERS)
if (uploaders < allowedUploaders())
{
if(peer.isChoking())
{
@@ -582,4 +720,155 @@ public class PeerCoordinator implements PeerListener
}
}
}
/** Simple method to save a partial piece on peer disconnection
* and hopefully restart it later.
* Only one partial piece is saved at a time.
* Replace it if a new one is bigger or the old one is too old.
* Storage method is private so we can expand to save multiple partials
* if we wish.
*/
private Request savedRequest = null;
private long savedRequestTime = 0;
public void savePeerPartial(PeerState state)
{
if (halted)
return;
Request req = state.getPartialRequest();
if (req == null)
return;
if (savedRequest == null ||
req.off > savedRequest.off ||
System.currentTimeMillis() > savedRequestTime + (15 * 60 * 1000)) {
if (savedRequest == null || (req.piece != savedRequest.piece && req.off != savedRequest.off)) {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(" Saving orphaned partial piece " + req);
if (savedRequest != null)
_log.debug(" (Discarding previously saved orphan) " + savedRequest);
}
}
savedRequest = req;
savedRequestTime = System.currentTimeMillis();
} else {
if (req.piece != savedRequest.piece)
if (_log.shouldLog(Log.DEBUG))
_log.debug(" Discarding orphaned partial piece " + req);
}
}
/** Return partial piece if it's still wanted and peer has it.
*/
public Request getPeerPartial(BitField havePieces) {
if (savedRequest == null)
return null;
if (! havePieces.get(savedRequest.piece)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer doesn't have orphaned piece " + savedRequest);
return null;
}
synchronized(wantedPieces)
{
for(Iterator iter = wantedPieces.iterator(); iter.hasNext(); ) {
Piece piece = (Piece)iter.next();
if (piece.getId() == savedRequest.piece) {
Request req = savedRequest;
piece.setRequested(true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Restoring orphaned partial piece " + req);
savedRequest = null;
return req;
}
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("We no longer want orphaned piece " + savedRequest);
savedRequest = null;
return null;
}
/** Clear the requested flag for a piece if the peer
** is the only one requesting it
*/
private void markUnrequestedIfOnlyOne(Peer peer, int piece)
{
// see if anybody else is requesting
synchronized (peers)
{
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer p = (Peer)it.next();
if (p.equals(peer))
continue;
if (p.state == null)
continue;
int[] arr = p.state.getRequestedPieces();
for (int i = 0; arr[i] >= 0; i++)
if(arr[i] == piece) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Another peer is requesting piece " + piece);
return;
}
}
}
// nobody is, so mark unrequested
synchronized(wantedPieces)
{
Iterator it = wantedPieces.iterator();
while (it.hasNext()) {
Piece p = (Piece)it.next();
if (p.getId() == piece) {
p.setRequested(false);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Removing from request list piece " + piece);
return;
}
}
}
}
/** Mark a peer's requested pieces unrequested when it is disconnected
** Once for each piece
** This is enough trouble, maybe would be easier just to regenerate
** the requested list from scratch instead.
*/
public void markUnrequested(Peer peer)
{
if (halted || peer.state == null)
return;
int[] arr = peer.state.getRequestedPieces();
for (int i = 0; arr[i] >= 0; i++)
markUnrequestedIfOnlyOne(peer, arr[i]);
}
/** Return number of allowed uploaders for this torrent.
** Check with Snark to see if we are over the total upload limit.
*/
public int allowedUploaders()
{
if (listener != null && listener.overUploadLimit(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()
{
if (listener != null)
return listener.overUpBWLimit();
return false;
}
public boolean overUpBWLimit(long total)
{
if (listener != null)
return listener.overUpBWLimit(total * 1000 / CHECK_PERIOD);
return false;
}
}

View File

@@ -1,6 +1,9 @@
package org.klomp.snark;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Hmm, any guesses as to what this is? Used by the multitorrent functionality
@@ -9,11 +12,9 @@ import java.util.*;
* from it there too)
*/
public class PeerCoordinatorSet {
private static final PeerCoordinatorSet _instance = new PeerCoordinatorSet();
public static final PeerCoordinatorSet instance() { return _instance; }
private Set _coordinators;
private PeerCoordinatorSet() {
public PeerCoordinatorSet() {
_coordinators = new HashSet();
}

View File

@@ -21,15 +21,15 @@
package org.klomp.snark;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import org.klomp.snark.bencode.*;
import net.i2p.data.Base64;
import net.i2p.data.Destination;
import net.i2p.data.DataFormatException;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
public class PeerID implements Comparable
{
@@ -72,7 +72,7 @@ public class PeerID implements Comparable
bevalue = (BEValue)m.get("ip");
if (bevalue == null)
throw new InvalidBEncodingException("ip missing");
address = I2PSnarkUtil.instance().getDestination(bevalue.getString());
address = I2PSnarkUtil.getDestinationFromBase64(bevalue.getString());
if (address == null)
throw new InvalidBEncodingException("Invalid destination [" + bevalue.getString() + "]");
@@ -167,7 +167,9 @@ public class PeerID implements Comparable
}
/**
* Returns the String "id@address" where id is the base64 encoded id.
* Returns the String "id@address" where id is the base64 encoded id
* and address is the base64 dest (was the base64 hash of the dest) which
* should match what the bytemonsoon tracker reports on its web pages.
*/
public String toString()
{
@@ -178,7 +180,7 @@ public class PeerID implements Comparable
break;
}
}
return Base64.encode(id, nonZero, id.length-nonZero).substring(0,4) + "@" + address.calculateHash().toBase64().substring(0,6);
return Base64.encode(id, nonZero, id.length-nonZero).substring(0,4) + "@" + address.toBase64().substring(0,6);
}
/**

View File

@@ -107,11 +107,13 @@ public interface PeerListener
*
* @param peer the Peer that wants the piece.
* @param piece the piece number requested.
* @param off byte offset into the piece.
* @param len length of the chunk requested.
*
* @return a byte array containing the piece or null when the piece
* is not available (which is a protocol error).
*/
byte[] gotRequest(Peer peer, int piece);
byte[] gotRequest(Peer peer, int piece, int off, int len);
/**
* Called when a (partial) piece has been downloaded from the peer.
@@ -142,4 +144,29 @@ public interface PeerListener
* we are no longer interested in the peer.
*/
int wantPiece(Peer peer, BitField bitfield);
/**
* Called when the peer has disconnected and the peer task may have a partially
* downloaded piece that the PeerCoordinator can save
*
* @param state the PeerState for the peer
*/
void savePeerPartial(PeerState state);
/**
* Called when a peer has connected and there may be a partially
* downloaded piece that the coordinatorator can give the peer task
*
* @param havePieces the have-pieces bitmask for the peer
*
* @return request (contains the partial data and valid length)
*/
Request getPeerPartial(BitField havePieces);
/** Mark a peer's requested pieces unrequested when it is disconnected
* This prevents premature end game
*
* @param peer the peer that is disconnecting
*/
void markUnrequested(Peer peer);
}

View File

@@ -20,7 +20,8 @@
package org.klomp.snark;
import java.util.*;
import java.util.Iterator;
import java.util.TimerTask;
/**
* TimerTask that monitors the peers and total up/download speeds.
@@ -29,7 +30,7 @@ import java.util.*;
class PeerMonitorTask extends TimerTask
{
final static long MONITOR_PERIOD = 10 * 1000; // Ten seconds.
private final long KILOPERSECOND = 1024 * (MONITOR_PERIOD / 1000);
private static final long KILOPERSECOND = 1024 * (MONITOR_PERIOD / 1000);
private final PeerCoordinator coordinator;

View File

@@ -23,8 +23,6 @@ package org.klomp.snark;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import net.i2p.util.Log;
@@ -62,8 +60,10 @@ class PeerState
// If we have te resend outstanding requests (true after we got choked).
private boolean resend = false;
private final static int MAX_PIPELINE = 1;
private final static int PARTSIZE = 64*1024; // default was 16K, i2p-bt uses 64KB
private final static int MAX_PIPELINE = 2; // this is for outbound requests
private final static int MAX_PIPELINE_BYTES = 128*1024; // this is for inbound requests
public final static int PARTSIZE = 32*1024; // Snark was 16K, i2p-bt uses 64KB
private final static int MAX_PARTSIZE = 64*1024; // Don't let anybody request more than this
PeerState(Peer peer, PeerListener listener, MetaInfo metainfo,
PeerConnectionIn in, PeerConnectionOut out)
@@ -173,7 +173,7 @@ class PeerState
|| begin < 0
|| begin > metainfo.getPieceLength(piece)
|| length <= 0
|| length > 4*PARTSIZE)
|| length > MAX_PARTSIZE)
{
// XXX - Protocol error -> disconnect?
if (_log.shouldLog(Log.WARN))
@@ -184,7 +184,16 @@ class PeerState
return;
}
byte[] pieceBytes = listener.gotRequest(peer, piece);
// Limit total pipelined requests to MAX_PIPELINE bytes
// to conserve memory and prevent DOS
if (out.queuedBytes() + length > MAX_PIPELINE_BYTES)
{
if (_log.shouldLog(Log.WARN))
_log.warn("Discarding request over pipeline limit from " + peer);
return;
}
byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length);
if (pieceBytes == null)
{
// XXX - Protocol error-> diconnect?
@@ -194,7 +203,7 @@ class PeerState
}
// More sanity checks
if (begin >= pieceBytes.length || begin + length > pieceBytes.length)
if (length != pieceBytes.length)
{
// XXX - Protocol error-> disconnect?
if (_log.shouldLog(Log.WARN))
@@ -221,6 +230,10 @@ class PeerState
listener.uploaded(peer, size);
}
// This is used to flag that we have to back up from the firstOutstandingRequest
// when calculating how far we've gotten
Request pendingRequest = null;
/**
* Called when a partial piece request has been handled by
* PeerConnectionIn.
@@ -231,6 +244,8 @@ class PeerState
downloaded += size;
listener.downloaded(peer, size);
pendingRequest = null;
// Last chunk needed for this piece?
if (getFirstOutstandingRequest(req.piece) == -1)
{
@@ -318,14 +333,8 @@ class PeerState
{
Request dropReq = (Request)outstandingRequests.remove(0);
outstandingRequests.add(dropReq);
// We used to rerequest the missing chunks but that mostly
// just confuses the other side. So now we just keep
// waiting for them. They will be rerequested when we get
// choked/unchoked again.
/*
if (!choked)
if (!choked)
out.sendRequest(dropReq);
*/
if (_log.shouldLog(Log.WARN))
_log.warn("dropped " + dropReq + " with peer " + peer);
}
@@ -336,10 +345,58 @@ class PeerState
// Request more if necessary to keep the pipeline filled.
addRequest();
pendingRequest = req;
return req;
}
// get longest partial piece
Request getPartialRequest()
{
Request req = null;
for (int i = 0; i < outstandingRequests.size(); i++) {
Request r1 = (Request)outstandingRequests.get(i);
int j = getFirstOutstandingRequest(r1.piece);
if (j == -1)
continue;
Request r2 = (Request)outstandingRequests.get(j);
if (r2.off > 0 && ((req == null) || (r2.off > req.off)))
req = r2;
}
if (pendingRequest != null && req != null && pendingRequest.off < req.off) {
if (pendingRequest.off != 0)
req = pendingRequest;
else
req = null;
}
return req;
}
// return array of pieces terminated by -1
// remove most duplicates
// but still could be some duplicates, not guaranteed
int[] getRequestedPieces()
{
int size = outstandingRequests.size();
int[] arr = new int[size+2];
int pc = -1;
int pos = 0;
if (pendingRequest != null) {
pc = pendingRequest.piece;
arr[pos++] = pc;
}
Request req = null;
for (int i = 0; i < size; i++) {
Request r1 = (Request)outstandingRequests.get(i);
if (pc != r1.piece) {
pc = r1.piece;
arr[pos++] = pc;
}
}
arr[pos] = -1;
return(arr);
}
void cancelMessage(int piece, int begin, int length)
{
if (_log.shouldLog(Log.DEBUG))
@@ -414,16 +471,12 @@ class PeerState
/**
* Adds a new request to the outstanding requests list.
*/
private void addRequest()
synchronized private void addRequest()
{
boolean more_pieces = true;
while (more_pieces)
{
synchronized(this)
{
more_pieces = outstandingRequests.size() < MAX_PIPELINE;
}
more_pieces = outstandingRequests.size() < MAX_PIPELINE;
// We want something and we don't have outstanding requests?
if (more_pieces && lastRequest == null)
more_pieces = requestNextPiece();
@@ -431,19 +484,14 @@ class PeerState
{
int pieceLength;
boolean isLastChunk;
synchronized(this)
{
pieceLength = metainfo.getPieceLength(lastRequest.piece);
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
}
pieceLength = metainfo.getPieceLength(lastRequest.piece);
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
// Last part of a piece?
if (isLastChunk)
more_pieces = requestNextPiece();
else
{
synchronized(this)
{
int nextPiece = lastRequest.piece;
int nextBegin = lastRequest.off + PARTSIZE;
byte[] bs = lastRequest.bs;
@@ -456,7 +504,6 @@ class PeerState
if (!choked)
out.sendRequest(req);
lastRequest = req;
}
}
}
}
@@ -472,16 +519,41 @@ class PeerState
// Check that we already know what the other side has.
if (bitfield != null)
{
// Check for adopting an orphaned partial piece
Request r = listener.getPeerPartial(bitfield);
if (r != null) {
// Check that r not already in outstandingRequests
int[] arr = getRequestedPieces();
boolean found = false;
for (int i = 0; arr[i] >= 0; i++) {
if (arr[i] == r.piece) {
found = true;
break;
}
}
if (!found) {
outstandingRequests.add(r);
if (!choked)
out.sendRequest(r);
lastRequest = r;
return true;
}
}
int nextPiece = listener.wantPiece(peer, bitfield);
if (_log.shouldLog(Log.DEBUG))
_log.debug(peer + " want piece " + nextPiece);
synchronized(this)
{
if (nextPiece != -1
&& (lastRequest == null || lastRequest.piece != nextPiece))
{
int piece_length = metainfo.getPieceLength(nextPiece);
byte[] bs = new byte[piece_length];
//Catch a common place for OOMs esp. on 1MB pieces
byte[] bs;
try {
bs = new byte[piece_length];
} catch (OutOfMemoryError oom) {
_log.warn("Out of memory, can't request piece " + nextPiece, oom);
return false;
}
int length = Math.min(piece_length, PARTSIZE);
Request req = new Request(nextPiece, bs, 0, length);
@@ -491,7 +563,6 @@ class PeerState
lastRequest = req;
return true;
}
}
}
return false;
@@ -523,4 +594,15 @@ class PeerState
out.sendChoke(choke);
}
}
void keepAlive()
{
out.sendAlive();
}
synchronized void retransmitRequests()
{
if (interesting && !choked)
out.retransmitRequests(outstandingRequests);
}
}

View File

@@ -1,8 +1,8 @@
package org.klomp.snark;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class Piece implements Comparable {

View File

@@ -29,6 +29,7 @@ class Request
final byte[] bs;
final int off;
final int len;
long sendTime;
/**
* Creates a new Request.

View File

@@ -20,17 +20,29 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.util.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import org.klomp.snark.bencode.*;
import net.i2p.data.Destination;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.I2PAppContext;
import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.data.Destination;
import net.i2p.util.I2PThread;
import org.klomp.snark.bencode.BDecoder;
/**
* Main Snark program startup class.
*
@@ -63,7 +75,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;
@@ -93,7 +105,7 @@ public class Snark
public void outOfMemory(OutOfMemoryError err) {
try {
err.printStackTrace();
I2PSnarkUtil.instance().debug("OOM in the snark", Snark.ERROR, err);
System.out.println("OOM in the snark" + err);
} catch (Throwable t) {
System.out.println("OOM in the OOM");
}
@@ -216,7 +228,7 @@ public class Snark
}
catch(IOException ioe)
{
debug("ERROR while reading stdin: " + ioe, ERROR);
System.out.println("ERROR while reading stdin: " + ioe);
}
// Explicit shutdown.
@@ -225,6 +237,7 @@ public class Snark
}
}
public static final String PROP_MAX_CONNECTIONS = "i2psnark.maxConnections";
public String torrent;
public MetaInfo meta;
public Storage storage;
@@ -234,19 +247,60 @@ public class Snark
public String rootDataDir = ".";
public CompleteListener completeListener;
public boolean stopped;
byte[] id;
public I2PSnarkUtil _util;
private PeerCoordinatorSet _peerCoordinatorSet;
Snark(String torrent, String ip, int user_port,
/** from main() via parseArguments() single torrent */
Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener) {
this(torrent, ip, user_port, slistener, clistener, true, ".");
this(util, torrent, ip, user_port, slistener, clistener, null, null, null, true, ".");
}
Snark(String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener, boolean start, String rootDir)
/** single torrent - via router */
public Snark(I2PAppContext ctx, Properties opts, String torrent,
StorageListener slistener, boolean start, String rootDir) {
this(new I2PSnarkUtil(ctx), torrent, null, -1, slistener, null, null, null, null, false, rootDir);
String host = opts.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST);
int port = 0;
String s = opts.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_PORT);
if (s != null) {
try {
port = Integer.parseInt(s);
} catch (NumberFormatException nfe) {}
}
_util.setI2CPConfig(host, port, opts);
s = opts.getProperty(SnarkManager.PROP_UPBW_MAX);
if (s != null) {
try {
int v = Integer.parseInt(s);
_util.setMaxUpBW(v);
} catch (NumberFormatException nfe) {}
}
s = opts.getProperty(PROP_MAX_CONNECTIONS);
if (s != null) {
try {
int v = Integer.parseInt(s);
_util.setMaxConnections(v);
} catch (NumberFormatException nfe) {}
}
if (start)
this.startTorrent();
}
/** multitorrent */
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener,
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
ConnectionAcceptor connectionAcceptor, boolean start, String rootDir)
{
if (slistener == null)
slistener = this;
if (clistener == null)
clistener = this;
completeListener = complistener;
_util = util;
_peerCoordinatorSet = peerCoordinatorSet;
acceptor = connectionAcceptor;
this.torrent = torrent;
this.rootDataDir = rootDir;
@@ -268,7 +322,7 @@ public class Snark
// zeros bytes, then three bytes filled with snark and then
// sixteen random bytes.
byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
byte[] id = new byte[20];
id = new byte[20];
Random random = new Random();
int i;
for (i = 0; i < 9; i++)
@@ -279,33 +333,39 @@ public class Snark
while (i < 20)
id[i++] = (byte)random.nextInt(256);
Snark.debug("My peer id: " + PeerID.idencode(id), Snark.INFO);
debug("My peer id: " + PeerID.idencode(id), Snark.INFO);
int port;
IOException lastException = null;
boolean ok = I2PSnarkUtil.instance().connect();
/*
* Don't start a tunnel if the torrent isn't going to be started.
* If we are starting,
* startTorrent() will force a connect.
*
boolean ok = util.connect();
if (!ok) fatal("Unable to connect to I2P");
I2PServerSocket serversocket = I2PSnarkUtil.instance().getServerSocket();
I2PServerSocket serversocket = util.getServerSocket();
if (serversocket == null)
fatal("Unable to listen for I2P connections");
else {
Destination d = serversocket.getManager().getSession().getMyDestination();
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
}
*/
// Figure out what the torrent argument represents.
meta = null;
File f = null;
InputStream in = null;
try
{
InputStream in = null;
f = new File(torrent);
if (f.exists())
in = new FileInputStream(f);
else
{
activity = "Getting torrent";
File torrentFile = I2PSnarkUtil.instance().get(torrent);
File torrentFile = _util.get(torrent, 3);
if (torrentFile == null) {
fatal("Unable to fetch " + torrent);
if (false) return; // never reached - fatal(..) throws
@@ -329,7 +389,7 @@ public class Snark
/*
{
// Try to create a new metainfo file
Snark.debug
debug
("Trying to create metainfo torrent for '" + torrent + "'",
NOTICE);
try
@@ -348,8 +408,11 @@ public class Snark
*/
else
fatal("Cannot open '" + torrent + "'", ioe);
}
} finally {
if (in != null)
try { in.close(); } catch (IOException ioe) {}
}
debug(meta.toString(), INFO);
// When the metainfo torrent was created from an existing file/dir
@@ -359,8 +422,17 @@ public class Snark
try
{
activity = "Checking storage";
storage = new Storage(meta, slistener);
storage.check(rootDataDir);
storage = new Storage(_util, meta, slistener);
if (completeListener != null) {
storage.check(rootDataDir,
completeListener.getSavedTorrentTime(this),
completeListener.getSavedTorrentBitField(this));
} else {
storage.check(rootDataDir);
}
// have to figure out when to reopen
// if (!start)
// storage.close();
}
catch (IOException ioe)
{
@@ -371,14 +443,19 @@ public class Snark
}
}
/*
* see comment above
*
activity = "Collecting pieces";
coordinator = new PeerCoordinator(id, meta, storage, clistener, this);
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
set.add(coordinator);
ConnectionAcceptor acceptor = ConnectionAcceptor.instance();
acceptor.startAccepting(set, serversocket);
trackerclient = new TrackerClient(meta, coordinator);
*/
if (start)
startTorrent();
}
@@ -386,23 +463,63 @@ public class Snark
* Start up contacting peers and querying the tracker
*/
public void startTorrent() {
boolean ok = _util.connect();
if (!ok) fatal("Unable to connect to I2P");
if (coordinator == null) {
I2PServerSocket serversocket = _util.getServerSocket();
if (serversocket == null)
fatal("Unable to listen for I2P connections");
else {
Destination d = serversocket.getManager().getSession().getMyDestination();
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
}
debug("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient", NOTICE);
activity = "Collecting pieces";
coordinator = new PeerCoordinator(_util, id, meta, storage, this, this);
if (_peerCoordinatorSet != null) {
// multitorrent
_peerCoordinatorSet.add(coordinator);
if (acceptor != null) {
acceptor.startAccepting(_peerCoordinatorSet, serversocket);
} else {
// error
}
} else {
// single torrent
acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
}
trackerclient = new TrackerClient(_util, meta, coordinator);
}
stopped = false;
boolean coordinatorChanged = false;
if (coordinator.halted()) {
// ok, we have already started and stopped, but the coordinator seems a bit annoying to
// restart safely, so lets build a new one to replace the old
PeerCoordinatorSet set = PeerCoordinatorSet.instance();
set.remove(coordinator);
PeerCoordinator newCoord = new PeerCoordinator(coordinator.getID(), coordinator.getMetaInfo(),
if (_peerCoordinatorSet != null)
_peerCoordinatorSet.remove(coordinator);
PeerCoordinator newCoord = new PeerCoordinator(_util, coordinator.getID(), coordinator.getMetaInfo(),
coordinator.getStorage(), coordinator.getListener(), this);
set.add(newCoord);
if (_peerCoordinatorSet != null)
_peerCoordinatorSet.add(newCoord);
coordinator = newCoord;
coordinatorChanged = true;
}
if (!trackerclient.started() && !coordinatorChanged) {
trackerclient.start();
} else if (trackerclient.halted() || coordinatorChanged) {
TrackerClient newClient = new TrackerClient(coordinator.getMetaInfo(), coordinator);
try
{
storage.reopen(rootDataDir);
}
catch (IOException ioe)
{
try { storage.close(); } catch (IOException ioee) {
ioee.printStackTrace();
}
fatal("Could not reopen storage", ioe);
}
TrackerClient newClient = new TrackerClient(_util, coordinator.getMetaInfo(), coordinator);
if (!trackerclient.halted())
trackerclient.halt();
trackerclient = newClient;
@@ -422,15 +539,20 @@ public class Snark
pc.halt();
Storage st = storage;
if (st != null) {
boolean changed = storage.changed;
try {
storage.close();
} catch (IOException ioe) {
System.out.println("Error closing " + torrent);
ioe.printStackTrace();
}
if (changed && completeListener != null)
completeListener.updateStatus(this);
}
if (pc != null)
PeerCoordinatorSet.instance().remove(pc);
if (pc != null && _peerCoordinatorSet != null)
_peerCoordinatorSet.remove(pc);
if (_peerCoordinatorSet == null)
_util.disconnect();
}
static Snark parseArguments(String[] args)
@@ -452,11 +574,13 @@ public class Snark
String ip = null;
String torrent = null;
boolean configured = I2PSnarkUtil.instance().configured();
I2PSnarkUtil util = new I2PSnarkUtil(I2PAppContext.getGlobalContext());
boolean configured = util.configured();
int i = 0;
while (i < args.length)
{
/*
if (args[i].equals("--debug"))
{
debug = INFO;
@@ -477,7 +601,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");
@@ -501,7 +625,7 @@ public class Snark
String proxyHost = args[i+1];
String proxyPort = args[i+2];
if (!configured)
I2PSnarkUtil.instance().setProxy(proxyHost, Integer.parseInt(proxyPort));
util.setProxy(proxyHost, Integer.parseInt(proxyPort));
i += 3;
}
else if (args[i].equals("--i2cp"))
@@ -523,7 +647,7 @@ public class Snark
}
}
if (!configured)
I2PSnarkUtil.instance().setI2CPConfig(i2cpHost, Integer.parseInt(i2cpPort), opts);
util.setI2CPConfig(i2cpHost, Integer.parseInt(i2cpPort), opts);
i += 3 + (opts != null ? 1 : 0);
}
else
@@ -540,7 +664,7 @@ public class Snark
else
usage("Need exactly one <url>, <file> or <dir>.");
return new Snark(torrent, ip, user_port, slistener, clistener);
return new Snark(util, torrent, ip, user_port, slistener, clistener);
}
private static void usage(String s)
@@ -607,7 +731,7 @@ public class Snark
*/
public void fatal(String s, Throwable t)
{
I2PSnarkUtil.instance().debug(s, ERROR, t);
_util.debug(s, ERROR, t);
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
//if (debug >= INFO && t != null)
// t.printStackTrace();
@@ -618,13 +742,12 @@ public class Snark
/**
* Show debug info if debug is true.
*/
public static void debug(String s, int level)
private void debug(String s, int level)
{
I2PSnarkUtil.instance().debug(s, level, null);
//if (debug >= level)
// System.out.println(s);
_util.debug(s, level, null);
}
/** coordinatorListener */
public void peerChange(PeerCoordinator coordinator, Peer peer)
{
// System.out.println(peer.toString());
@@ -663,7 +786,7 @@ public class Snark
{
// Use the MetaInfo from the storage since our own might not
// yet be setup correctly.
MetaInfo meta = storage.getMetaInfo();
//MetaInfo meta = storage.getMetaInfo();
//if (meta != null)
// System.out.print("Checking existing "
// + meta.getPieces()
@@ -671,7 +794,7 @@ public class Snark
checking = true;
}
if (!checking)
Snark.debug("Got " + (checked ? "" : "BAD ") + "piece: " + num,
debug("Got " + (checked ? "" : "BAD ") + "piece: " + num,
Snark.INFO);
}
@@ -682,17 +805,24 @@ public class Snark
allChecked = true;
checking = false;
if (storage.changed && completeListener != null)
completeListener.updateStatus(this);
}
public void storageCompleted(Storage storage)
{
Snark.debug("Completely received " + torrent, Snark.INFO);
debug("Completely received " + torrent, Snark.INFO);
//storage.close();
//System.out.println("Completely received: " + torrent);
if (completeListener != null)
completeListener.torrentComplete(this);
}
public void setWantedPieces(Storage storage)
{
coordinator.setWantedPieces();
}
public void shutdown()
{
// Should not be necessary since all non-deamon threads should
@@ -702,5 +832,47 @@ public class Snark
public interface CompleteListener {
public void torrentComplete(Snark snark);
public void updateStatus(Snark snark);
// not really listeners but the easiest way to get back to an optional SnarkManager
public long getSavedTorrentTime(Snark snark);
public BitField getSavedTorrentBitField(Snark snark);
}
/** Maintain a configurable total uploader cap
* coordinatorListener
*/
final static int MIN_TOTAL_UPLOADERS = 4;
final static int MAX_TOTAL_UPLOADERS = 10;
public boolean overUploadLimit(int uploaders) {
if (_peerCoordinatorSet == null || uploaders <= 0)
return false;
int totalUploaders = 0;
for (Iterator iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = (PeerCoordinator)iter.next();
if (!c.halted())
totalUploaders += c.uploaders;
}
int limit = _util.getMaxUploaders();
// debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
return totalUploaders > limit;
}
public boolean overUpBWLimit() {
if (_peerCoordinatorSet == null)
return false;
long total = 0;
for (Iterator iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = (PeerCoordinator)iter.next();
if (!c.halted())
total += c.getCurrentUploadRate();
}
long limit = 1024l * _util.getMaxUpBW();
debug("Total up bw: " + total + " Limit: " + limit, Snark.WARNING);
return total > limit;
}
public boolean overUpBWLimit(long total) {
long limit = 1024l * _util.getMaxUpBW();
return total > limit;
}
}

View File

@@ -1,10 +1,25 @@
package org.klomp.snark;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.I2PThread;
import net.i2p.router.RouterContext;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
@@ -16,35 +31,63 @@ public class SnarkManager implements Snark.CompleteListener {
/** map of (canonical) filename to Snark instance (unsynchronized) */
private Map _snarks;
private String _configFile;
private Object _addSnarkLock;
private String _configFile = "i2psnark.config";
private Properties _config;
private I2PAppContext _context;
private Log _log;
private List _messages;
private I2PSnarkUtil _util;
private PeerCoordinatorSet _peerCoordinatorSet;
private ConnectionAcceptor _connectionAcceptor;
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions";
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_LINK_PREFIX = "i2psnark.linkPrefix";
public static final String DEFAULT_LINK_PREFIX = "file:///";
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();
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(SnarkManager.class);
_messages = new ArrayList(16);
loadConfig("i2psnark.config");
_util = new I2PSnarkUtil(_context);
loadConfig(null);
}
/** Caller _must_ call loadConfig(file) before this if setting new values
* for i2cp host/port or i2psnark.dir
*/
public void start() {
_peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util);
int minutes = getStartupDelayMinutes();
_messages.add("Starting up torrents in " + minutes + (minutes == 1 ? " minute" : " minutes"));
I2PThread monitor = new I2PThread(new DirMonitor(), "Snark DirMonitor");
_messages.add("Adding torrents in " + minutes + (minutes == 1 ? " minute" : " minutes"));
I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor");
monitor.setDaemon(true);
monitor.start();
if (_context instanceof RouterContext)
((RouterContext)_context).router().addShutdownTask(new SnarkManagerShutdown());
}
/** hook to I2PSnarkUtil for the servlet */
public I2PSnarkUtil util() { return _util; }
private static final int MAX_MESSAGES = 5;
public void addMessage(String message) {
synchronized (_messages) {
@@ -66,7 +109,10 @@ public class SnarkManager implements Snark.CompleteListener {
public boolean shouldAutoStart() {
return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue();
}
private int getStartupDelayMinutes() { return 1; }
public String linkPrefix() {
return _config.getProperty(PROP_LINK_PREFIX, DEFAULT_LINK_PREFIX + getDataDir().getAbsolutePath() + File.separatorChar);
}
private int getStartupDelayMinutes() { return 3; }
public File getDataDir() {
String dir = _config.getProperty(PROP_DIR);
if ( (dir == null) || (dir.trim().length() <= 0) )
@@ -74,27 +120,44 @@ public class SnarkManager implements Snark.CompleteListener {
return new File(dir);
}
/** null to set initial defaults */
public void loadConfig(String filename) {
_configFile = filename;
if (_config == null)
_config = new Properties();
File cfg = new File(filename);
if (cfg.exists()) {
try {
DataHelper.loadProps(_config, cfg);
} catch (IOException ioe) {
_log.error("Error loading I2PSnark config '" + filename + "'", ioe);
}
if (filename != null) {
_configFile = filename;
File cfg = new File(filename);
if (cfg.exists()) {
try {
DataHelper.loadProps(_config, cfg);
} catch (IOException ioe) {
_log.error("Error loading I2PSnark config '" + filename + "'", ioe);
}
}
}
// now add sane defaults
if (!_config.containsKey(PROP_I2CP_HOST))
_config.setProperty(PROP_I2CP_HOST, "localhost");
if (!_config.containsKey(PROP_I2CP_PORT))
_config.setProperty(PROP_I2CP_PORT, "7654");
if (!_config.containsKey(PROP_I2CP_OPTS))
_config.setProperty(PROP_I2CP_OPTS, "inbound.length=2 inbound.lengthVariance=0 outbound.length=2 outbound.lengthVariance=0");
if (!_config.containsKey(PROP_EEP_HOST))
_config.setProperty(PROP_EEP_HOST, "localhost");
if (!_config.containsKey(PROP_EEP_PORT))
_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)) {
try {
if (_context instanceof RouterContext)
_config.setProperty(PROP_UPBW_MAX, "" + (((RouterContext)_context).bandwidthLimiter().getOutboundKBytesPerSecond() / 2));
else
_config.setProperty(PROP_UPBW_MAX, "" + DEFAULT_MAX_UP_BW);
} catch (NoClassDefFoundError ncdfe) {
_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))
@@ -117,14 +180,16 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
if (i2cpHost != null) {
I2PSnarkUtil.instance().setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts);
_util.setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts);
_log.debug("Configuring with I2CP options " + i2cpOpts);
}
//I2PSnarkUtil.instance().setI2CPConfig("66.111.51.110", 7654, new Properties());
String eepHost = _config.getProperty(PROP_EEP_HOST);
int eepPort = getInt(PROP_EEP_PORT, 4444);
if (eepHost != null)
I2PSnarkUtil.instance().setProxy(eepHost, eepPort);
_util.setProxy(eepHost, eepPort);
_util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
getDataDir().mkdirs();
}
@@ -140,24 +205,53 @@ 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 eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) {
boolean changed = false;
if (eepHost != null) {
int port = I2PSnarkUtil.instance().getEepProxyPort();
int port = _util.getEepProxyPort();
try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {}
String host = I2PSnarkUtil.instance().getEepProxyHost();
String host = _util.getEepProxyHost();
if ( (eepHost.trim().length() > 0) && (port > 0) &&
((!host.equals(eepHost) || (port != I2PSnarkUtil.instance().getEepProxyPort()) )) ) {
I2PSnarkUtil.instance().setProxy(eepHost, port);
((!host.equals(eepHost) || (port != _util.getEepProxyPort()) )) ) {
_util.setProxy(eepHost, port);
changed = true;
_config.setProperty(PROP_EEP_HOST, eepHost);
_config.setProperty(PROP_EEP_PORT, eepPort+"");
addMessage("EepProxy location changed to " + eepHost + ":" + port);
}
}
if (upLimit != null) {
int limit = _util.getMaxUploaders();
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
if ( limit != _util.getMaxUploaders()) {
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
_util.setMaxUploaders(limit);
changed = true;
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit);
addMessage("Total uploaders limit changed to " + limit);
} else {
addMessage("Minimum total uploaders limit is " + Snark.MIN_TOTAL_UPLOADERS);
}
}
}
if (upBW != null) {
int limit = _util.getMaxUpBW();
try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {}
if ( limit != _util.getMaxUpBW()) {
if ( limit >= MIN_UP_BW ) {
_util.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();
int oldI2CPPort = _util.getI2CPPort();
String oldI2CPHost = _util.getI2CPHost();
int port = oldI2CPPort;
try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {}
String host = oldI2CPHost;
@@ -183,7 +277,7 @@ public class SnarkManager implements Snark.CompleteListener {
if ( (i2cpHost.trim().length() > 0) && (port > 0) &&
((!host.equals(i2cpHost) ||
(port != I2PSnarkUtil.instance().getI2CPPort()) ||
(port != _util.getI2CPPort()) ||
(!oldOpts.equals(opts)))) ) {
boolean snarksActive = false;
Set names = listTorrentFiles();
@@ -199,19 +293,19 @@ public class SnarkManager implements Snark.CompleteListener {
_log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts
+ "] oldOpts [" + oldOpts + "]");
} else {
if (I2PSnarkUtil.instance().connected()) {
I2PSnarkUtil.instance().disconnect();
if (_util.connected()) {
_util.disconnect();
addMessage("Disconnecting old I2CP destination");
}
Properties p = new Properties();
p.putAll(opts);
addMessage("I2CP settings changed to " + i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")");
I2PSnarkUtil.instance().setI2CPConfig(i2cpHost, port, p);
boolean ok = I2PSnarkUtil.instance().connect();
_util.setI2CPConfig(i2cpHost, port, p);
boolean ok = _util.connect();
if (!ok) {
addMessage("Unable to connect with the new settings, reverting to the old I2CP settings");
I2PSnarkUtil.instance().setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts);
ok = I2PSnarkUtil.instance().connect();
_util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts);
ok = _util.connect();
if (!ok)
addMessage("Unable to reconnect with the old settings!");
} else {
@@ -239,6 +333,18 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage("Adjusted autostart to " + autoStart);
changed = true;
}
if (_util.shouldUseOpenTrackers() != useOpenTrackers) {
_config.setProperty(I2PSnarkUtil.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(_util.getOpenTrackerString())) {
_config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim());
addMessage("Open Tracker list changed - torrent restart required to take effect");
changed = true;
}
}
if (changed) {
saveConfig();
} else {
@@ -248,7 +354,9 @@ public class SnarkManager implements Snark.CompleteListener {
public void saveConfig() {
try {
DataHelper.storeProps(_config, new File(_configFile));
synchronized (_configFile) {
DataHelper.storeProps(_config, new File(_configFile));
}
} catch (IOException ioe) {
addMessage("Unable to save the config to '" + _configFile + "'");
}
@@ -257,7 +365,7 @@ public class SnarkManager implements Snark.CompleteListener {
public Properties getConfig() { return _config; }
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
private static final int MAX_FILES_PER_TORRENT = 128;
private static final int MAX_FILES_PER_TORRENT = 256;
/** set of filenames that we are dealing with */
public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } }
@@ -267,9 +375,9 @@ public class SnarkManager implements Snark.CompleteListener {
public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } }
public void addTorrent(String filename) { addTorrent(filename, false); }
public void addTorrent(String filename, boolean dontAutoStart) {
if (!I2PSnarkUtil.instance().connected()) {
if ((!dontAutoStart) && !_util.connected()) {
addMessage("Connecting to I2P");
boolean ok = I2PSnarkUtil.instance().connect();
boolean ok = _util.connect();
if (!ok) {
addMessage("Error connecting to I2P - check your I2CP settings");
return;
@@ -287,7 +395,16 @@ public class SnarkManager implements Snark.CompleteListener {
Snark torrent = null;
synchronized (_snarks) {
torrent = (Snark)_snarks.get(filename);
if (torrent == null) {
}
// don't hold the _snarks lock while verifying the torrent
if (torrent == null) {
synchronized (_addSnarkLock) {
// double-check
synchronized (_snarks) {
if(_snarks.get(filename) != null)
return;
}
FileInputStream fis = null;
try {
fis = new FileInputStream(sfile);
@@ -301,9 +418,13 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage(rejectMessage);
return;
} else {
torrent = new Snark(filename, null, -1, null, null, false, dataDir.getPath());
torrent = new Snark(_util, filename, null, -1, null, null, this,
_peerCoordinatorSet, _connectionAcceptor,
false, dataDir.getPath());
torrent.completeListener = this;
_snarks.put(filename, torrent);
synchronized (_snarks) {
_snarks.put(filename, torrent);
}
}
} catch (IOException ioe) {
addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage());
@@ -313,9 +434,9 @@ public class SnarkManager implements Snark.CompleteListener {
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
} else {
return;
}
} else {
return;
}
// ok, snark created, now lets start it up or configure it further
File f = new File(filename);
@@ -327,14 +448,106 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
/**
* Get the timestamp for a torrent from the config file
*/
public long getSavedTorrentTime(Snark snark) {
MetaInfo metainfo = snark.meta;
byte[] ih = metainfo.getInfoHash();
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
if (time == null)
return 0;
int comma = time.indexOf(',');
if (comma <= 0)
return 0;
time = time.substring(0, comma);
try { return Long.parseLong(time); } catch (NumberFormatException nfe) {}
return 0;
}
/**
* Get the saved bitfield for a torrent from the config file.
* Convert "." to a full bitfield.
*/
public BitField getSavedTorrentBitField(Snark snark) {
MetaInfo metainfo = snark.meta;
byte[] ih = metainfo.getInfoHash();
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
if (bf == null)
return null;
int comma = bf.indexOf(',');
if (comma <= 0)
return null;
bf = bf.substring(comma + 1).trim();
int len = metainfo.getPieces();
if (bf.equals(".")) {
BitField bitfield = new BitField(len);
for (int i = 0; i < len; i++)
bitfield.set(i);
return bitfield;
}
byte[] bitfield = Base64.decode(bf);
if (bitfield == null)
return null;
if (bitfield.length * 8 < len)
return null;
return new BitField(bitfield, len);
}
/**
* Save the completion status of a torrent and the current time in the config file
* in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield".
* The config file property key is appended with the Base64 of the infohash,
* with the '=' changed to '$' since a key can't contain '='.
* The time is a standard long converted to string.
* The status is either a bitfield converted to Base64 or "." for a completed
* torrent to save space in the config file and in memory.
*/
public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) {
byte[] ih = metainfo.getInfoHash();
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
String now = "" + System.currentTimeMillis();
String bfs;
if (bitfield.complete()) {
bfs = ".";
} else {
byte[] bf = bitfield.getFieldBytes();
bfs = Base64.encode(bf);
}
_config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs);
saveConfig();
}
/**
* Remove the status of a torrent from the config file.
* This may help the config file from growing too big.
*/
public void removeTorrentStatus(MetaInfo metainfo) {
byte[] ih = metainfo.getInfoHash();
String infohash = Base64.encode(ih);
infohash = infohash.replace('=', '$');
_config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
saveConfig();
}
private String locked_validateTorrent(MetaInfo info) throws IOException {
String announce = info.getAnnounce();
// basic validation of url
if ((!announce.startsWith("http://")) ||
(announce.indexOf(".i2p/") < 0))
return "Non-i2p tracker in " + info.getName() + ", deleting it";
List files = info.getFiles();
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it";
} else if (info.getPieces() <= 0) {
return "No pieces in " + info.getName() + "? deleting it";
} else if (info.getPieceLength(0) > 10*1024*1024) {
return "Pieces are too large in " + info.getName() + " (" + info.getPieceLength(0)/1024 + "KB, deleting it";
} else if (info.getPieceLength(0) > 1*1024*1024) {
return "Pieces are too large in " + info.getName() + " (" + info.getPieceLength(0)/1024 + "KB), deleting it";
} else if (info.getTotalLength() > 10*1024*1024*1024l) {
System.out.println("torrent info: " + info.toString());
List lengths = info.getLengths();
@@ -376,7 +589,7 @@ public class SnarkManager implements Snark.CompleteListener {
if (remaining == 0) {
// should we disconnect/reconnect here (taking care to deal with the other thread's
// I2PServerSocket.accept() call properly?)
////I2PSnarkUtil.instance().
////_util.
}
if (!wasStopped)
addMessage("Torrent stopped: '" + sfile.getName() + "'");
@@ -392,6 +605,8 @@ public class SnarkManager implements Snark.CompleteListener {
if (torrent != null) {
File torrentFile = new File(filename);
torrentFile.delete();
if (torrent.storage != null)
removeTorrentStatus(torrent.storage.getMetaInfo());
addMessage("Torrent removed: '" + torrentFile.getName() + "'");
}
}
@@ -418,11 +633,17 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
/** two listeners */
public void torrentComplete(Snark snark) {
File f = new File(snark.torrent);
long len = snark.meta.getTotalLength();
addMessage("Download complete of " + f.getName()
+ (len < 5*1024*1024 ? " (size: " + (len/1024) + "KB)" : " (size: " + (len/(1024*1024l)) + "MB)"));
updateStatus(snark);
}
public void updateStatus(Snark snark) {
saveTorrentStatus(snark.meta, snark.storage.getBitField());
}
private void monitorTorrents(File dir) {
@@ -444,10 +665,9 @@ public class SnarkManager implements Snark.CompleteListener {
if (existingNames.contains(foundNames.get(i))) {
// already known. noop
} else {
if (I2PSnarkUtil.instance().connect())
addTorrent((String)foundNames.get(i));
else
if (shouldAutoStart() && !_util.connect())
addMessage("Unable to connect to I2P");
addTorrent((String)foundNames.get(i), !shouldAutoStart());
}
}
// now lets see which ones have been removed...
@@ -463,22 +683,33 @@ public class SnarkManager implements Snark.CompleteListener {
}
private static final String DEFAULT_TRACKERS[] = {
"Postman's tracker", "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"
, "Orion's tracker", "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"
"Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/"
// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
, "welterde", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/"
// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/"
, "crstrack", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/"
};
/** comma delimited list of name=announceURL for the trackers to be displayed */
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
/** unordered map of announceURL to name */
private static Map trackerMap = null;
/** sorted map of name to announceURL=baseURL */
public Map getTrackers() {
HashMap rv = new HashMap();
if (trackerMap != null) // only do this once, can't be updated while running
return trackerMap;
Map rv = new TreeMap();
String trackers = _config.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) )
trackers = _context.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) ) {
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2)
rv.put(DEFAULT_TRACKERS[i+1], DEFAULT_TRACKERS[i]);
rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]);
} else {
StringTokenizer tok = new StringTokenizer(trackers, ",");
while (tok.hasMoreTokens()) {
@@ -489,11 +720,12 @@ public class SnarkManager implements Snark.CompleteListener {
String name = pair.substring(0, split).trim();
String url = pair.substring(split+1).trim();
if ( (name.length() > 0) && (url.length() > 0) )
rv.put(url, name);
rv.put(name, url);
}
}
return rv;
trackerMap = rv;
return trackerMap;
}
private static class TorrentFilenameFilter implements FilenameFilter {
@@ -503,4 +735,15 @@ public class SnarkManager implements Snark.CompleteListener {
return (name != null) && (name.endsWith(".torrent"));
}
}
public class SnarkManagerShutdown extends I2PAppThread {
public void run() {
Set names = listTorrentFiles();
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
Snark snark = getTorrent((String)iter.next());
if ( (snark != null) && (!snark.stopped) )
snark.stopTorrent();
}
}
}
}

View File

@@ -22,12 +22,12 @@ package org.klomp.snark;
import java.io.IOException;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
/**
* Makes sure everything ends correctly when shutting down.
*/
public class SnarkShutdown extends I2PThread
public class SnarkShutdown extends I2PAppThread
{
private final Storage storage;
private final PeerCoordinator coordinator;
@@ -51,21 +51,21 @@ public class SnarkShutdown extends I2PThread
public void run()
{
Snark.debug("Shutting down...", Snark.NOTICE);
//Snark.debug("Shutting down...", Snark.NOTICE);
Snark.debug("Halting ConnectionAcceptor...", Snark.INFO);
//Snark.debug("Halting ConnectionAcceptor...", Snark.INFO);
if (acceptor != null)
acceptor.halt();
Snark.debug("Halting TrackerClient...", Snark.INFO);
//Snark.debug("Halting TrackerClient...", Snark.INFO);
if (trackerclient != null)
trackerclient.halt();
Snark.debug("Halting PeerCoordinator...", Snark.INFO);
//Snark.debug("Halting PeerCoordinator...", Snark.INFO);
if (coordinator != null)
coordinator.halt();
Snark.debug("Closing Storage...", Snark.INFO);
//Snark.debug("Closing Storage...", Snark.INFO);
if (storage != null)
{
try
@@ -74,7 +74,7 @@ public class SnarkShutdown extends I2PThread
}
catch(IOException ioe)
{
I2PSnarkUtil.instance().debug("Couldn't properly close storage", Snark.ERROR, ioe);
//I2PSnarkUtil.instance().debug("Couldn't properly close storage", Snark.ERROR, ioe);
throw new RuntimeException("b0rking");
}
}
@@ -82,7 +82,7 @@ public class SnarkShutdown extends I2PThread
// XXX - Should actually wait till done...
try
{
Snark.debug("Waiting 5 seconds...", Snark.INFO);
//Snark.debug("Waiting 5 seconds...", Snark.INFO);
Thread.sleep(5*1000);
}
catch (InterruptedException ie) { /* ignored */ }

View File

@@ -20,10 +20,6 @@
package org.klomp.snark;
import java.security.Provider;
import java.security.Security;
import org.klomp.snark.bencode.*;
/**
* Main snark startup class for staticly linking with gcj.

View File

@@ -20,10 +20,13 @@
package org.klomp.snark;
import java.io.*;
import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import net.i2p.crypto.SHA1;
@@ -36,18 +39,25 @@ public class Storage
private long[] lengths;
private RandomAccessFile[] rafs;
private String[] names;
private Object[] RAFlock; // lock on RAF access
private long[] RAFtime; // when was RAF last accessed, or 0 if closed
private File[] RAFfile; // File to make it easier to reopen
private final StorageListener listener;
private I2PSnarkUtil _util;
private final BitField bitfield; // BitField to represent the pieces
private BitField bitfield; // BitField to represent the pieces
private int needed; // Number of pieces needed
private boolean _probablyComplete; // use this to decide whether to open files RO
// XXX - Not always set correctly
int piece_size;
int pieces;
boolean changed;
/** The default piece size. */
private static int MIN_PIECE_SIZE = 256*1024;
private static int MAX_PIECE_SIZE = 1024*1024;
/** The maximum number of pieces in a torrent. */
private static long MAX_PIECES = 100*1024/20;
@@ -57,12 +67,14 @@ public class Storage
*
* @exception IOException when creating and/or checking files fails.
*/
public Storage(MetaInfo metainfo, StorageListener listener)
public Storage(I2PSnarkUtil util, MetaInfo metainfo, StorageListener listener)
throws IOException
{
_util = util;
this.metainfo = metainfo;
this.listener = listener;
needed = metainfo.getPieces();
_probablyComplete = false;
bitfield = new BitField(needed);
}
@@ -71,11 +83,11 @@ public class Storage
* with an appropriate MetaInfo file as can be announced on the
* given announce String location.
*/
public Storage(File baseFile, String announce, StorageListener listener)
public Storage(I2PSnarkUtil util, File baseFile, String announce, StorageListener listener)
throws IOException
{
_util = util;
this.listener = listener;
// Create names, rafs and lengths arrays.
getFiles(baseFile);
@@ -90,7 +102,7 @@ public class Storage
piece_size = MIN_PIECE_SIZE;
pieces = (int) ((total - 1)/piece_size) + 1;
while (pieces > MAX_PIECES)
while (pieces > MAX_PIECES && piece_size < MAX_PIECE_SIZE)
{
piece_size = piece_size*2;
pieces = (int) ((total - 1)/piece_size) +1;
@@ -115,8 +127,8 @@ public class Storage
files.add(file);
}
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;
@@ -128,16 +140,18 @@ public class Storage
}
// Creates piece hases for a new storage.
// Creates piece hashes for a new storage.
// This does NOT create the files, just the hashes
public void create() throws IOException
{
if (true) {
// if (true) {
fast_digestCreate();
} else {
orig_digestCreate();
}
// } else {
// orig_digestCreate();
// }
}
/*
private void orig_digestCreate() throws IOException {
// Calculate piece_hashes
MessageDigest digest = null;
@@ -155,7 +169,7 @@ public class Storage
byte[] piece = new byte[piece_size];
for (int i = 0; i < pieces; i++)
{
int length = getUncheckedPiece(i, piece, 0);
int length = getUncheckedPiece(i, piece);
digest.update(piece, 0, length);
byte[] hash = digest.digest();
for (int j = 0; j < 20; j++)
@@ -173,6 +187,7 @@ public class Storage
// Reannounce to force recalculating the info_hash.
metainfo = metainfo.reannounce(metainfo.getAnnounce());
}
*/
private void fast_digestCreate() throws IOException {
// Calculate piece_hashes
@@ -183,21 +198,15 @@ public class Storage
byte[] piece = new byte[piece_size];
for (int i = 0; i < pieces; i++)
{
int length = getUncheckedPiece(i, piece, 0);
int length = getUncheckedPiece(i, piece);
digest.update(piece, 0, length);
byte[] hash = digest.digest();
for (int j = 0; j < 20; j++)
piece_hashes[20 * i + j] = hash[j];
bitfield.set(i);
if (listener != null)
listener.storageChecked(this, i, true);
}
if (listener != null)
listener.storageAllChecked(this);
// Reannounce to force recalculating the info_hash.
metainfo = metainfo.reannounce(metainfo.getAnnounce());
}
@@ -211,6 +220,9 @@ public class Storage
names = new String[size];
lengths = new long[size];
rafs = new RandomAccessFile[size];
RAFlock = new Object[size];
RAFtime = new long[size];
RAFfile = new File[size];
int i = 0;
Iterator it = files.iterator();
@@ -218,13 +230,16 @@ public class Storage
{
File f = (File)it.next();
names[i] = f.getPath();
if (base.isDirectory() && names[i].startsWith(base.getPath()))
names[i] = names[i].substring(base.getPath().length() + 1);
lengths[i] = f.length();
rafs[i] = new RandomAccessFile(f, "r");
RAFlock[i] = new Object();
RAFfile[i] = f;
i++;
}
}
private static void addFiles(List l, File f)
private void addFiles(List l, File f)
{
if (!f.isDirectory())
l.add(f);
@@ -233,7 +248,7 @@ public class Storage
File[] files = f.listFiles();
if (files == null)
{
Snark.debug("WARNING: Skipping '" + f
_util.debug("WARNING: Skipping '" + f
+ "' not a normal file.", Snark.WARNING);
return;
}
@@ -279,31 +294,44 @@ public class Storage
* Creates (and/or checks) all files from the metainfo file list.
*/
public void check(String rootDir) throws IOException
{
check(rootDir, 0, null);
}
/** use a saved bitfield and timestamp from a config file */
public void check(String rootDir, long savedTime, BitField savedBitField) throws IOException
{
File base = new File(rootDir, filterName(metainfo.getName()));
boolean useSavedBitField = savedTime > 0 && savedBitField != null;
List files = metainfo.getFiles();
if (files == null)
{
// Create base as file.
Snark.debug("Creating/Checking file: " + base, Snark.NOTICE);
_util.debug("Creating/Checking file: " + base, Snark.NOTICE);
if (!base.createNewFile() && !base.exists())
throw new IOException("Could not create file " + base);
lengths = new long[1];
rafs = new RandomAccessFile[1];
names = new String[1];
RAFlock = new Object[1];
RAFtime = new long[1];
RAFfile = new File[1];
lengths[0] = metainfo.getTotalLength();
if (base.exists() && !base.canWrite()) // hope we can get away with this, if we are only seeding...
rafs[0] = new RandomAccessFile(base, "r");
else
rafs[0] = new RandomAccessFile(base, "rw");
RAFlock[0] = new Object();
RAFfile[0] = base;
if (useSavedBitField) {
long lm = base.lastModified();
if (lm <= 0 || lm > savedTime)
useSavedBitField = false;
}
names[0] = base.getName();
}
else
{
// Create base as dir.
Snark.debug("Creating/Checking directory: " + base, Snark.NOTICE);
_util.debug("Creating/Checking directory: " + base, Snark.NOTICE);
if (!base.mkdir() && !base.isDirectory())
throw new IOException("Could not create directory " + base);
@@ -313,15 +341,21 @@ public class Storage
lengths = new long[size];
rafs = new RandomAccessFile[size];
names = new String[size];
RAFlock = new Object[size];
RAFtime = new long[size];
RAFfile = new File[size];
for (int i = 0; i < size; i++)
{
File f = createFileFromNames(base, (List)files.get(i));
lengths[i] = ((Long)ls.get(i)).longValue();
RAFlock[i] = new Object();
RAFfile[i] = f;
total += lengths[i];
if (f.exists() && !f.canWrite()) // see above re: only seeding
rafs[i] = new RandomAccessFile(f, "r");
else
rafs[i] = new RandomAccessFile(f, "rw");
if (useSavedBitField) {
long lm = base.lastModified();
if (lm <= 0 || lm > savedTime)
useSavedBitField = false;
}
names[i] = f.getName();
}
@@ -331,13 +365,60 @@ public class Storage
throw new IOException("File lengths do not add up "
+ total + " != " + metalength);
}
checkCreateFiles();
if (useSavedBitField) {
bitfield = savedBitField;
needed = metainfo.getPieces() - bitfield.count();
_probablyComplete = complete();
_util.debug("Found saved state and files unchanged, skipping check", Snark.NOTICE);
} else {
// the following sets the needed variable
changed = true;
checkCreateFiles();
}
if (complete())
_util.debug("Torrent is complete", Snark.NOTICE);
else
_util.debug("Still need " + needed + " out of " + metainfo.getPieces() + " pieces", Snark.NOTICE);
}
/**
* Reopen the file descriptors for a restart
* Do existence check but no length check or data reverification
*/
public void reopen(String rootDir) throws IOException
{
File base = new File(rootDir, filterName(metainfo.getName()));
List files = metainfo.getFiles();
if (files == null)
{
// Reopen base as file.
_util.debug("Reopening file: " + base, Snark.NOTICE);
if (!base.exists())
throw new IOException("Could not reopen file " + base);
}
else
{
// Reopen base as dir.
_util.debug("Reopening directory: " + base, Snark.NOTICE);
if (!base.isDirectory())
throw new IOException("Could not reopen directory " + base);
int size = files.size();
for (int i = 0; i < size; i++)
{
File f = getFileFromNames(base, (List)files.get(i));
if (!f.exists())
throw new IOException("Could not reopen file " + f);
}
}
}
/**
* 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, '_');
@@ -369,27 +450,55 @@ public class Storage
return f;
}
public static File getFileFromNames(File base, List names)
{
Iterator it = names.iterator();
while (it.hasNext())
{
String name = filterName((String)it.next());
base = new File(base, name);
}
return base;
}
/**
* This is called at the beginning, and at presumed completion,
* so we have to be careful about locking.
*/
private void checkCreateFiles() throws IOException
{
// Whether we are resuming or not,
// if any of the files already exists we assume we are resuming.
boolean resume = false;
_probablyComplete = true;
needed = metainfo.getPieces();
// Make sure all files are available and of correct length
for (int i = 0; i < rafs.length; i++)
{
long length = rafs[i].length();
if(length == lengths[i])
long length = RAFfile[i].length();
if(RAFfile[i].exists() && length == lengths[i])
{
if (listener != null)
listener.storageAllocated(this, length);
resume = true; // XXX Could dynamicly check
}
else if (length == 0)
allocateFile(i);
else
throw new IOException("File '" + names[i]
+ "' exists, but has wrong length");
else if (length == 0) {
changed = true;
synchronized(RAFlock[i]) {
allocateFile(i);
}
} else {
_util.debug("File '" + names[i] + "' exists, but has wrong length - repairing corruption", Snark.ERROR);
changed = true;
_probablyComplete = false; // to force RW
synchronized(RAFlock[i]) {
checkRAF(i);
rafs[i].setLength(lengths[i]);
}
// will be closed below
}
}
// Check which pieces match and which don't
@@ -399,7 +508,7 @@ public class Storage
byte[] piece = new byte[metainfo.getPieceLength(0)];
for (int i = 0; i < pieces; i++)
{
int length = getUncheckedPiece(i, piece, 0);
int length = getUncheckedPiece(i, piece);
boolean correctHash = metainfo.checkPiece(i, piece, 0, length);
if (correctHash)
{
@@ -412,6 +521,17 @@ public class Storage
}
}
_probablyComplete = complete();
// close all the files so we don't end up with a zillion open ones;
// we will reopen as needed
for (int i = 0; i < rafs.length; i++) {
synchronized(RAFlock[i]) {
try {
closeRAF(i);
} catch (IOException ioe) {}
}
}
if (listener != null) {
listener.storageAllChecked(this);
if (needed <= 0)
@@ -421,6 +541,8 @@ public class Storage
private void allocateFile(int nr) throws IOException
{
// caller synchronized
openRAF(nr, false); // RW
// XXX - Is this the best way to make sure we have enough space for
// the whole file?
listener.storageCreateFile(this, names[nr], lengths[nr]);
@@ -435,6 +557,7 @@ public class Storage
}
int size = (int)(lengths[nr] - i*ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
// caller will close rafs[nr]
if (listener != null)
listener.storageAllocated(this, size);
}
@@ -450,28 +573,35 @@ public class Storage
for (int i = 0; i < rafs.length; i++)
{
try {
synchronized(rafs[i])
{
rafs[i].close();
}
synchronized(RAFlock[i]) {
closeRAF(i);
}
} catch (IOException ioe) {
I2PSnarkUtil.instance().debug("Error closing " + rafs[i], Snark.ERROR, ioe);
_util.debug("Error closing " + RAFfile[i], Snark.ERROR, ioe);
// gobble gobble
}
}
changed = false;
}
/**
* Returns a byte array containing the requested piece or null if
* Returns a byte array containing a portion of the requested piece or null if
* the storage doesn't contain the piece yet.
*/
public byte[] getPiece(int piece) throws IOException
public byte[] getPiece(int piece, int off, int len) throws IOException
{
if (!bitfield.get(piece))
return null;
byte[] bs = new byte[metainfo.getPieceLength(piece)];
getUncheckedPiece(piece, bs, 0);
//Catch a common place for OOMs esp. on 1MB pieces
byte[] bs;
try {
bs = new byte[len];
} catch (OutOfMemoryError oom) {
_util.debug("Out of memory, can't honor request for piece " + piece, Snark.WARNING, oom);
return null;
}
getUncheckedPiece(piece, bs, off, len);
return bs;
}
@@ -482,10 +612,11 @@ public class Storage
* matches), otherwise false.
* @exception IOException when some storage related error occurs.
*/
public boolean putPiece(int piece, byte[] bs) throws IOException
public boolean putPiece(int piece, byte[] ba) throws IOException
{
// First check if the piece is correct.
// If we were paranoia we could copy the array first.
// Copy the array first to be paranoid.
byte[] bs = (byte[]) ba.clone();
int length = bs.length;
boolean correctHash = metainfo.checkPiece(piece, bs, 0, length);
if (listener != null)
@@ -493,17 +624,10 @@ public class Storage
if (!correctHash)
return false;
boolean complete;
synchronized(bitfield)
{
if (bitfield.get(piece))
return true; // No need to store twice.
else
{
bitfield.set(piece);
needed--;
complete = needed == 0;
}
}
// Early typecast, avoid possibly overflowing a temp integer
@@ -523,8 +647,9 @@ public class Storage
{
int need = length - written;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized(rafs[i])
synchronized(RAFlock[i])
{
checkRAF(i);
rafs[i].seek(start);
rafs[i].write(bs, off + written, len);
}
@@ -537,24 +662,60 @@ public class Storage
}
}
changed = true;
// do this after the write, so we know it succeeded, and we don't set the
// needed count to zero, which would cause checkRAF() to open the file readonly.
boolean complete = false;
synchronized(bitfield)
{
if (!bitfield.get(piece))
{
bitfield.set(piece);
needed--;
complete = needed == 0;
}
}
if (complete) {
listener.storageCompleted(this);
// do we also need to close all of the files and reopen
// them readonly?
// Do a complete check to be sure.
// Temporarily resets the 'needed' variable and 'bitfield', then call
// checkCreateFiles() which will set 'needed' and 'bitfield'
// and also call listener.storageCompleted() if the double-check
// was successful.
// Todo: set a listener variable so the web shows "checking" and don't
// have the user panic when completed amount goes to zero temporarily?
needed = metainfo.getPieces();
bitfield = new BitField(needed);
checkCreateFiles();
if (needed > 0) {
if (listener != null)
listener.setWantedPieces(this);
_util.debug("WARNING: Not really done, missing " + needed
+ " pieces", Snark.WARNING);
}
}
return true;
}
private int getUncheckedPiece(int piece, byte[] bs, int off)
private int getUncheckedPiece(int piece, byte[] bs)
throws IOException
{
return getUncheckedPiece(piece, bs, 0, metainfo.getPieceLength(piece));
}
private int getUncheckedPiece(int piece, byte[] bs, int off, int length)
throws IOException
{
// XXX - copy/paste code from putPiece().
// Early typecast, avoid possibly overflowing a temp integer
long start = (long) piece * (long) metainfo.getPieceLength(0);
long start = ((long) piece * (long) metainfo.getPieceLength(0)) + off;
int length = metainfo.getPieceLength(piece);
int i = 0;
long raflen = lengths[i];
while (start > raflen)
@@ -569,10 +730,11 @@ public class Storage
{
int need = length - read;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized(rafs[i])
synchronized(RAFlock[i])
{
checkRAF(i);
rafs[i].seek(start);
rafs[i].readFully(bs, off + read, len);
rafs[i].readFully(bs, read, len);
}
read += len;
if (need - len > 0)
@@ -585,4 +747,59 @@ public class Storage
return length;
}
/**
* Close unused RAFs - call periodically
*/
private static final long RAFCloseDelay = 7*60*1000;
public void cleanRAFs() {
long cutoff = System.currentTimeMillis() - RAFCloseDelay;
for (int i = 0; i < RAFlock.length; i++) {
synchronized(RAFlock[i]) {
if (RAFtime[i] > 0 && RAFtime[i] < cutoff) {
try {
closeRAF(i);
} catch (IOException ioe) {}
}
}
}
}
/*
* For each of the following,
* caller must synchronize on RAFlock[i]
* ... except at the beginning if you're careful
*/
/**
* This must be called before using the RAF to ensure it is open
*/
private void checkRAF(int i) throws IOException {
if (RAFtime[i] > 0) {
RAFtime[i] = System.currentTimeMillis();
return;
}
openRAF(i);
}
private void openRAF(int i) throws IOException {
openRAF(i, _probablyComplete);
}
private void openRAF(int i, boolean readonly) throws IOException {
rafs[i] = new RandomAccessFile(RAFfile[i], (readonly || !RAFfile[i].canWrite()) ? "r" : "rw");
RAFtime[i] = System.currentTimeMillis();
}
/**
* Can be called even if not open
*/
private void closeRAF(int i) throws IOException {
RAFtime[i] = 0;
if (rafs[i] == null)
return;
rafs[i].close();
rafs[i] = null;
}
}

View File

@@ -55,4 +55,10 @@ public interface StorageListener
*
*/
void storageCompleted(Storage storage);
/** Reset the peer's wanted pieces table
* Call after the storage double-check fails
*
*/
void setWantedPieces(Storage storage);
}

View File

@@ -20,12 +20,18 @@
package org.klomp.snark;
import java.io.*;
import java.net.*;
import java.util.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.klomp.snark.bencode.*;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
@@ -34,16 +40,24 @@ import net.i2p.util.Log;
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class TrackerClient extends I2PThread
public class TrackerClient extends I2PAppThread
{
private static final Log _log = new Log(TrackerClient.class);
private static final String NO_EVENT = "";
private static final String STARTED_EVENT = "started";
private static final String COMPLETED_EVENT = "completed";
private static final String STOPPED_EVENT = "stopped";
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
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 I2PSnarkUtil _util;
private final MetaInfo meta;
private final PeerCoordinator coordinator;
private final int port;
@@ -51,13 +65,13 @@ 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)
public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator)
{
// Set unique name.
super("TrackerClient-" + urlencode(coordinator.getID()));
_util = util;
this.meta = meta;
this.coordinator = coordinator;
@@ -86,90 +100,94 @@ public class TrackerClient extends I2PThread
}
private boolean verifyConnected() {
while (!stop && !I2PSnarkUtil.instance().connected()) {
boolean ok = I2PSnarkUtil.instance().connect();
while (!stop && !_util.connected()) {
boolean ok = _util.connect();
if (!ok) {
try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
}
}
return !stop && I2PSnarkUtil.instance().connected();
return !stop && _util.connected();
}
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 = _util.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 = _util.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();
boolean completed = (left == 0);
int sleptTime = 0;
try
{
if (!verifyConnected()) return;
boolean started = false;
while (!started)
{
try
{
// Send start.
TrackerInfo info = doRequest(announce, infoHash, peerID,
uploaded, downloaded, left,
STARTED_EVENT);
Set peers = info.getPeers();
coordinator.trackerSeenPeers = peers.size();
if (!completed) {
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer cur = (Peer)it.next();
coordinator.addPeer(cur);
int delay = 3000;
int c = ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
try { Thread.sleep(delay * c); } catch (InterruptedException ie) {}
}
}
started = true;
coordinator.trackerProblems = null;
}
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 (!started && !stop)
{
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...
int delay = SLEEP*60*1000 + r.nextInt(120*1000);
Thread.sleep(delay);
// Sleep the minimum interval for all the trackers, but 60s minimum
// except for the first time...
int delay;
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);
}
catch(InterruptedException interrupt)
{
@@ -195,19 +213,37 @@ public class TrackerClient extends I2PThread
else
event = NO_EVENT;
// *** loop once for each tracker
// Only do a request when necessary.
if (event == COMPLETED_EVENT
|| coordinator.needPeers()
|| System.currentTimeMillis() > lastRequestTime + interval)
sleptTime = 0;
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)
@@ -216,26 +252,57 @@ public class TrackerClient extends I2PThread
Iterator it = ordered.iterator();
while (it.hasNext()) {
Peer cur = (Peer)it.next();
coordinator.addPeer(cur);
int delay = 3000;
int c = ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
try { Thread.sleep(delay * c); } catch (InterruptedException ie) {}
// only delay if we actually make an attempt to add peer
if(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) {}
}
}
}
}
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
Snark.debug
_util.debug
("WARNING: Could not contact tracker at '"
+ announce + "': " + ioe, Snark.WARNING);
+ 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)
_util.debug(" Retrying in one minute...", Snark.DEBUG);
} // *** end of while loop
} // try
catch (Throwable t)
{
I2PSnarkUtil.instance().debug("TrackerClient: " + t, Snark.ERROR, t);
_util.debug("TrackerClient: " + t, Snark.ERROR, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError)t;
}
@@ -243,33 +310,39 @@ 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
+ "&ip=" + I2PSnarkUtil.instance().getOurIPString() + ".i2p"
+ "&ip=" + _util.getOurIPString() + ".i2p"
+ "&uploaded=" + uploaded
+ "&downloaded=" + downloaded
+ "&left=" + left
+ ((event != NO_EVENT) ? ("&event=" + event) : "");
if (Snark.debug >= Snark.INFO)
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
File fetched = I2PSnarkUtil.instance().get(s);
tr.lastRequestTime = System.currentTimeMillis();
File fetched = _util.get(s);
if (fetched == null) {
throw new IOException("Error fetching " + s);
}
@@ -280,15 +353,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();
_util.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) {}
@@ -300,7 +371,7 @@ public class TrackerClient extends I2PThread
* Very lazy byte[] to URL encoder. Just encodes everything, even
* "normal" chars.
*/
static String urlencode(byte[] bs)
public static String urlencode(byte[] bs)
{
StringBuffer sb = new StringBuffer(bs.length*3);
for (int i = 0; i < bs.length; i++)
@@ -314,4 +385,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

@@ -22,14 +22,15 @@ package org.klomp.snark;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import org.klomp.snark.bencode.*;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
public class TrackerInfo
{
@@ -95,7 +96,14 @@ public class TrackerInfo
Iterator it = l.iterator();
while (it.hasNext())
{
PeerID peerID = new PeerID(((BEValue)it.next()).getMap());
PeerID peerID;
try {
peerID = new PeerID(((BEValue)it.next()).getMap());
} catch (InvalidBEncodingException ibe) {
// don't let one bad entry spoil the whole list
//Snark.debug("Discarding peer from list: " + ibe, Snark.ERROR);
continue;
}
peers.add(new Peer(peerID, my_id, metainfo));
}

View File

@@ -20,20 +20,16 @@
package org.klomp.snark.bencode;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.EOFException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Decodes a bencoded stream to <code>BEValue</code>s.

View File

@@ -21,7 +21,6 @@
package org.klomp.snark.bencode;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

View File

@@ -20,11 +20,9 @@
package org.klomp.snark.bencode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

View File

@@ -1,20 +1,39 @@
package org.klomp.snark.web;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServlet;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PThread;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import org.klomp.snark.*;
import org.klomp.snark.I2PSnarkUtil;
import org.klomp.snark.MetaInfo;
import org.klomp.snark.Peer;
import org.klomp.snark.Snark;
import org.klomp.snark.SnarkManager;
import org.klomp.snark.Storage;
import org.klomp.snark.TrackerClient;
/**
*
@@ -37,28 +56,57 @@ public class I2PSnarkServlet extends HttpServlet {
if ( (configFile == null) || (configFile.trim().length() <= 0) )
configFile = "i2psnark.config";
_manager.loadConfig(configFile);
_manager.start();
}
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
long stats[] = {0,0,0,0};
String nonce = req.getParameter("nonce");
if ( (nonce != null) && (nonce.equals(String.valueOf(_nonce))) )
processRequest(req);
String peerParam = req.getParameter("p");
String peerString;
if (peerParam == null) {
peerString = "";
} else {
peerString = "?p=" + peerParam;
}
PrintWriter out = resp.getWriter();
out.write(HEADER_BEGIN);
// we want it to go to the base URI so we don't refresh with some funky action= value
out.write("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + "\">\n");
out.write("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + peerString + "\">\n");
out.write(HEADER);
out.write("<table border=\"0\" width=\"100%\">\n");
out.write("<tr><td width=\"5%\" class=\"snarkTitle\" valign=\"top\" align=\"left\">");
out.write("<tr><td width=\"20%\" class=\"snarkTitle\" valign=\"top\" align=\"left\">");
out.write("I2PSnark<br />\n");
out.write("<a href=\"" + req.getRequestURI() + "\" class=\"snarkRefresh\">Refresh</a>\n");
out.write("</td><td width=\"95%\" class=\"snarkMessages\" valign=\"top\" align=\"left\"><pre>");
out.write("<table border=\"0\" width=\"100%\">\n");
out.write("<tr><td><a href=\"" + req.getRequestURI() + peerString + "\" class=\"snarkRefresh\">Refresh</a>\n");
out.write("<td><a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\">Forum</a>\n");
int count = 0;
Map trackers = _manager.getTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String name = (String)entry.getKey();
String baseURL = (String)entry.getValue();
int e = baseURL.indexOf('=');
if (e < 0)
continue;
baseURL = baseURL.substring(e + 1);
if (count++ % 2 == 0)
out.write("<tr>");
out.write("<td><a href=\"" + baseURL + "\" class=\"snarkRefresh\">" + name + "</a>\n");
}
if (count % 2 == 1)
out.write("<td>&nbsp;\n");
out.write("</table>\n");
out.write("</td><td width=\"80%\" class=\"snarkMessages\" valign=\"top\" align=\"left\"><pre>");
List msgs = _manager.getMessages();
for (int i = msgs.size()-1; i >= 0; i--) {
String msg = (String)msgs.get(i);
@@ -66,19 +114,46 @@ public class I2PSnarkServlet extends HttpServlet {
}
out.write("</pre></td></tr></table>\n");
out.write(TABLE_HEADER);
List snarks = getSortedSnarks(req);
String uri = req.getRequestURI();
out.write(TABLE_HEADER);
if (_manager.util().connected() && snarks.size() > 0) {
if (peerParam != null)
out.write("(<a href=\"" + req.getRequestURI() + "\">Hide Peers</a>)<br />\n");
else
out.write("(<a href=\"" + req.getRequestURI() + "?p=1" + "\">Show Peers</a>)<br />\n");
}
out.write(TABLE_HEADER2);
out.write("<th align=\"left\" valign=\"top\">");
if (_manager.util().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);
displaySnark(out, snark, uri, i);
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);
} else if (snarks.size() > 1) {
out.write(TABLE_TOTAL);
out.write(" <th align=\"right\" valign=\"top\">" + formatSize(stats[0]) + "</th>\n" +
" <th align=\"right\" valign=\"top\">" + formatSize(stats[1]) + "</th>\n" +
" <th align=\"right\" valign=\"top\">" + formatSize(stats[2]) + "ps</th>\n" +
" <th align=\"right\" valign=\"top\">" + formatSize(stats[3]) + "ps</th>\n" +
" <th>&nbsp;</th></tr>\n" +
"</tfoot>\n");
}
out.write(TABLE_FOOTER);
writeAddForm(out, req);
if (true) // seeding needs to register the torrent first, so we can't start it automatically (boo, hiss)
writeSeedForm(out, req);
@@ -127,7 +202,7 @@ public class I2PSnarkServlet extends HttpServlet {
}
} else if ( (newURL != null) && (newURL.trim().length() > "http://.i2p/".length()) ) {
_manager.addMessage("Fetching " + newURL);
I2PThread fetch = new I2PThread(new FetchAndAdd(_manager, newURL), "Fetch and add");
I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add");
fetch.start();
} else {
// no file or URL specified
@@ -198,23 +273,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;
}
@@ -230,7 +313,11 @@ public class I2PSnarkServlet extends HttpServlet {
String i2cpHost = req.getParameter("i2cpHost");
String i2cpPort = req.getParameter("i2cpPort");
String i2cpOpts = req.getParameter("i2cpOpts");
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts);
String upLimit = req.getParameter("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) {
@@ -240,36 +327,60 @@ public class I2PSnarkServlet extends HttpServlet {
if ( (announceURLOther != null) && (announceURLOther.trim().length() > "http://.i2p/announce".length()) )
announceURL = announceURLOther;
if (baseFile.exists() && baseFile.isFile()) {
if (announceURL == null || announceURL.length() <= 0)
_manager.addMessage("Error creating torrent - you must select a tracker");
else if (baseFile.exists()) {
try {
Storage s = new Storage(baseFile, announceURL, null);
Storage s = new Storage(_manager.util(), 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());
}
} else if (baseFile.exists()) {
_manager.addMessage("I2PSnark doesn't yet support creating multifile torrents");
} else {
_manager.addMessage("Cannot create a torrent for the nonexistant data: " + baseFile.getAbsolutePath());
_manager.addMessage("Cannot create a torrent for the nonexistent data: " + baseFile.getAbsolutePath());
}
}
} else if ("StopAll".equals(action)) {
_manager.addMessage("Stopping all torrents and closing the I2P tunnel");
List snarks = getSortedSnarks(req);
for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i);
if (!snark.stopped)
_manager.stopTorrent(snark.torrent, false);
}
if (_manager.util().connected()) {
_manager.util().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();
}
}
}
private List getSortedSnarks(HttpServletRequest req) {
Set files = _manager.listTorrentFiles();
TreeSet fileNames = new TreeSet(files); // sorts it alphabetically
TreeSet fileNames = new TreeSet(Collator.getInstance()); // sorts it alphabetically
fileNames.addAll(files);
ArrayList rv = new ArrayList(fileNames.size());
for (Iterator iter = fileNames.iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
@@ -279,12 +390,16 @@ public class I2PSnarkServlet extends HttpServlet {
}
return rv;
}
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60;
private void displaySnark(PrintWriter out, Snark snark, String uri, int row) throws IOException {
private static final int MAX_DISPLAYED_ERROR_LENGTH = 40;
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
int i = filename.lastIndexOf(".torrent");
if (i > 0)
filename = filename.substring(0, i);
if (filename.length() > MAX_DISPLAYED_FILENAME_LENGTH)
filename = filename.substring(0, MAX_DISPLAYED_FILENAME_LENGTH) + "...";
long total = snark.meta.getTotalLength();
@@ -292,32 +407,78 @@ public class I2PSnarkServlet extends HttpServlet {
long remaining = (long) snark.storage.needed() * (long) snark.meta.getPieceLength(0);
if (remaining > total)
remaining = total;
int totalBps = 4096; // should probably grab this from the snark...
long remainingSeconds = remaining / totalBps;
long uploaded = snark.coordinator.getUploaded();
long downBps = 0;
long upBps = 0;
if (snark.coordinator != null) {
downBps = snark.coordinator.getDownloadRate();
upBps = snark.coordinator.getUploadRate();
}
long remainingSeconds;
if (downBps > 0)
remainingSeconds = remaining / downBps;
else
remainingSeconds = -1;
boolean isRunning = !snark.stopped;
long uploaded = 0;
if (snark.coordinator != null) {
uploaded = snark.coordinator.getUploaded();
stats[0] += snark.coordinator.getDownloaded();
}
stats[1] += uploaded;
if (isRunning) {
stats[2] += downBps;
stats[3] += upBps;
}
boolean isValid = snark.meta != null;
boolean singleFile = snark.meta.getFiles() == null;
String err = snark.coordinator.trackerProblems;
int curPeers = snark.coordinator.getPeerCount();
int knownPeers = snark.coordinator.trackerSeenPeers;
String err = null;
int curPeers = 0;
int knownPeers = 0;
if (snark.coordinator != null) {
err = snark.coordinator.trackerProblems;
curPeers = snark.coordinator.getPeerCount();
knownPeers = snark.coordinator.trackerSeenPeers;
}
String statusString = "Unknown";
if (err != null) {
if (isRunning)
statusString = "TrackerErr (" + curPeers + "/" + knownPeers + " peers)";
else
statusString = "TrackerErr (" + err + ")";
if (isRunning && curPeers > 0 && !showPeers)
statusString = "<a title=\"" + err + "\">TrackerErr</a> (" +
curPeers + "/" + knownPeers +
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
else if (isRunning)
statusString = "<a title=\"" + err + "\">TrackerErr (" + curPeers + "/" + knownPeers + " peers)";
else {
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "...";
statusString = "TrackerErr<br />(" + err + ")";
}
} else if (remaining <= 0) {
if (isRunning)
if (isRunning && curPeers > 0 && !showPeers)
statusString = "Seeding (" +
curPeers + "/" + knownPeers +
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
else if (isRunning)
statusString = "Seeding (" + curPeers + "/" + knownPeers + " peers)";
else
statusString = "Complete";
} else {
if (isRunning)
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
statusString = "OK (" +
curPeers + "/" + knownPeers +
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
else if (isRunning && curPeers > 0 && downBps > 0)
statusString = "OK (" + curPeers + "/" + knownPeers + " peers)";
else if (isRunning && curPeers > 0 && !showPeers)
statusString = "Stalled (" +
curPeers + "/" + knownPeers +
" <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">peers</a>)";
else if (isRunning && curPeers > 0)
statusString = "Stalled (" + curPeers + "/" + knownPeers + " peers)";
else if (isRunning)
statusString = "No Peers (0/" + knownPeers + ")";
else
statusString = "Stopped";
}
@@ -329,45 +490,152 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentName " + rowClass + "\">");
if (remaining == 0)
out.write("<a href=\"file:///" + _manager.getDataDir().getAbsolutePath() + File.separatorChar + snark.meta.getName()
out.write("<a href=\"" + _manager.linkPrefix() + snark.meta.getName()
+ "\" title=\"Download the completed file\">");
out.write(filename);
if (remaining == 0)
out.write("</a>");
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0) {
out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB
// lets hold off on the ETA until we have rates sorted...
//out.write(" (eta " + DataHelper.formatDuration(remainingSeconds*1000) + ")"); // (eta 6h)
} else {
out.write(formatSize(total)); // 3GB
// temporarily hardcoded for postman and anonymity, requires bytemonsoon patch for lookup by info_hash
String announce = snark.meta.getAnnounce();
if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr")) {
Map trackers = _manager.getTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String name = (String)entry.getKey();
String baseURL = (String)entry.getValue();
if (!baseURL.startsWith(announce))
continue;
int e = baseURL.indexOf('=');
if (e < 0)
continue;
baseURL = baseURL.substring(e + 1);
out.write("&nbsp;&nbsp;&nbsp;(<a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash=");
out.write(TrackerClient.urlencode(snark.meta.getInfoHash()));
out.write("\" title=\"" + name + " Tracker\">Details</a>)");
break;
}
}
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentUploaded " + rowClass
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
if(isRunning && remainingSeconds > 0)
out.write(DataHelper.formatDuration(remainingSeconds*1000)); // (eta 6h)
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0)
out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB
else
out.write(formatSize(total)); // 3GB
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentUploaded " + rowClass
+ "\">" + formatSize(uploaded) + "</td>\n\t");
//out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentRate\">");
//out.write("n/a"); //2KBps/12KBps/4KBps
//out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentRate\">");
if(isRunning && remaining > 0)
out.write(formatSize(downBps) + "ps");
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentRate\">");
if(isRunning)
out.write(formatSize(upBps) + "ps");
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"left\" class=\"snarkTorrentAction " + rowClass + "\">");
String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash());
if (showPeers)
parameters = parameters + "&p=1";
if (isRunning) {
out.write("<a href=\"" + uri + "?action=Stop&nonce=" + _nonce
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
out.write("<a href=\"" + uri + "?action=Stop" + parameters
+ "\" title=\"Stop the torrent\">Stop</a>");
} else {
if (isValid)
out.write("<a href=\"" + uri + "?action=Start&nonce=" + _nonce
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
out.write("<a href=\"" + uri + "?action=Start" + parameters
+ "\" title=\"Start the torrent\">Start</a> ");
out.write("<a href=\"" + uri + "?action=Remove&nonce=" + _nonce
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
out.write("<a href=\"" + uri + "?action=Remove" + parameters
+ "\" title=\"Remove the torrent from the active list, deleting the .torrent file\">Remove</a><br />");
out.write("<a href=\"" + uri + "?action=Delete&nonce=" + _nonce
+ "&torrent=" + Base64.encode(snark.meta.getInfoHash())
out.write("<a href=\"" + uri + "?action=Delete" + parameters
+ "\" title=\"Delete the .torrent file and the associated data file(s)\">Delete</a> ");
}
out.write("</td>\n</tr>\n");
if(showPeers && isRunning && curPeers > 0) {
List peers = snark.coordinator.peerList();
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer peer = (Peer)it.next();
if (!peer.isConnected())
continue;
out.write("<tr class=\"" + rowClass + "\">");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
String ch = peer.toString().substring(0, 4);
String client;
if ("AwMD".equals(ch))
client = "I2PSnark";
else if ("BFJT".equals(ch))
client = "I2PRufus";
else if ("TTMt".equals(ch))
client = "I2P-BT";
else if ("LUFa".equals(ch))
client = "Azureus";
else if ("CwsL".equals(ch))
client = "I2PSnarkXL";
else if ("AUZV".equals(ch) || "AkZV".equals(ch) || "A0ZV".equals(ch))
client = "Robert";
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");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
float pct = (float) (100.0 * (float) peer.completed() / snark.meta.getPieces());
if (pct == 100.0)
out.write("<font size=-1>Seed</font>");
else {
String ps = String.valueOf(pct);
if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write("<font size=-1>" + ps + "%</font>");
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
if (remaining > 0) {
if (peer.isInteresting() && !peer.isChoked()) {
out.write("<font color=#008000>");
out.write("<font size=-1>" + formatSize(peer.getDownloadRate()) + "ps</font></font>");
} else {
out.write("<font color=#a00000><font size=-1><a title=\"");
if (!peer.isInteresting())
out.write("Uninteresting\">");
else
out.write("Choked\">");
out.write(formatSize(peer.getDownloadRate()) + "ps</a></font></font>");
}
}
out.write("</td>\n\t");
out.write("<td valign=\"top\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
if (pct != 100.0) {
if (peer.isInterested() && !peer.isChoking()) {
out.write("<font color=#008000>");
out.write("<font size=-1>" + formatSize(peer.getUploadRate()) + "ps</font></font>");
} else {
out.write("<font color=#a00000><font size=-1><a title=\"");
if (!peer.isInterested())
out.write("Uninterested\">");
else
out.write("Choking\">");
out.write(formatSize(peer.getUploadRate()) + "ps</a></font></font>");
}
}
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>");
}
}
}
private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException {
@@ -381,7 +649,8 @@ public class I2PSnarkServlet extends HttpServlet {
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" />\n");
out.write("From URL&nbsp;: <input type=\"text\" name=\"newURL\" size=\"50\" value=\"" + newURL + "\" /> \n");
out.write("<span class=\"snarkConfigTitle\">Add Torrent:</span><br />\n");
out.write("From URL&nbsp;: <input type=\"text\" name=\"newURL\" size=\"80\" value=\"" + newURL + "\" /> \n");
// not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve)
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br />\n");
out.write("<input type=\"submit\" value=\"Add torrent\" name=\"action\" /><br />\n");
@@ -396,21 +665,25 @@ public class I2PSnarkServlet extends HttpServlet {
if (baseFile == null)
baseFile = "";
out.write("<span class=\"snarkNewTorrent\">\n");
out.write("<span class=\"snarkNewTorrent\"><hr />\n");
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" />\n");
out.write("<span class=\"snarkConfigTitle\">Create Torrent:</span><br />\n");
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br />\n");
out.write("Data to seed: " + _manager.getDataDir().getAbsolutePath() + File.separatorChar
+ "<input type=\"text\" name=\"baseFile\" size=\"20\" value=\"" + baseFile
+ "\" title=\"File to seed (must be within the specified path)\" /><br />\n");
out.write("Tracker: <select name=\"announceURL\"><option value=\"\">Select a tracker</option>\n");
Map trackers = sort(_manager.getTrackers());
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
String announceURL = (String)trackers.get(name);
// we inject whitespace in sort(...) to guarantee uniqueness, but we can strip it off here
out.write("\t<option value=\"" + announceURL + "\">" + name.trim() + "</option>\n");
Map trackers = _manager.getTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String name = (String)entry.getKey();
String announceURL = (String)entry.getValue();
int e = announceURL.indexOf('=');
if (e > 0)
announceURL = announceURL.substring(0, e);
out.write("\t<option value=\"" + announceURL + "\">" + name + "</option>\n");
}
out.write("</select>\n");
out.write("or <input type=\"text\" name=\"announceURLOther\" size=\"50\" value=\"http://\" " +
@@ -419,36 +692,27 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("</form>\n</span>\n");
}
private Map sort(Map trackers) {
TreeMap rv = new TreeMap();
for (Iterator iter = trackers.keySet().iterator(); iter.hasNext(); ) {
String url = (String)iter.next();
String name = (String)trackers.get(url);
while (rv.containsKey(name))
name = name + " ";
rv.put(name, url);
}
return rv;
}
private void writeConfigForm(PrintWriter out, HttpServletRequest req) throws IOException {
String uri = req.getRequestURI();
String dataDir = _manager.getDataDir().getAbsolutePath();
boolean autoStart = _manager.shouldAutoStart();
int seedPct = 0;
boolean useOpenTrackers = _manager.util().shouldUseOpenTrackers();
String openTrackers = _manager.util().getOpenTrackerString();
//int seedPct = 0;
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
out.write("<span class=\"snarkConfig\"><hr />\n");
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" />\n");
out.write("<span class=\"snarkConfigTitle\">Configuration:</span><br />\n");
out.write("Data directory: <input type=\"text\" size=\"40\" name=\"dataDir\" value=\"" + dataDir + "\" ");
out.write("title=\"Directory to store torrents and data\" disabled=\"true\" /><br />\n");
out.write("title=\"Directory to store torrents and data\" disabled=\"true\" /> <i>(Edit i2psnark.config and restart to change)</i><br />\n");
out.write("Auto start: <input type=\"checkbox\" name=\"autoStart\" value=\"true\" "
+ (autoStart ? "checked " : "")
+ "title=\"If true, automatically start torrents that are added\" />");
//Auto add: <input type="checkbox" name="autoAdd" value="true" title="If true, automatically add torrents that are found in the data directory" />
//Auto stop: <input type="checkbox" name="autoStop" value="true" title="If true, automatically stop torrents that are removed from the data directory" />
//out.write("<br />\n");
/*
out.write("Seed percentage: <select name=\"seedPct\" disabled=\"true\" >\n\t");
if (seedPct <= 0)
out.write("<option value=\"0\" selected=\"true\">Unlimited</option>\n\t");
@@ -463,39 +727,52 @@ public class I2PSnarkServlet extends HttpServlet {
else
out.write("<option value=\"150\">150%</option>\n\t");
out.write("</select><br />\n");
*/
out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\""
+ _manager.util().getMaxUploaders() + "\" size=\"3\" maxlength=\"3\" /> peers<br />\n");
out.write("Up bandwidth limit: <input type=\"text\" name=\"upBW\" value=\""
+ _manager.util().getMaxUpBW() + "\" size=\"3\" maxlength=\"3\" /> KBps <i>(Router Up BW / 2 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\" /> ");
+ _manager.util().getEepProxyHost() + "\" size=\"15\" /> ");
out.write("port: <input type=\"text\" name=\"eepPort\" value=\""
+ I2PSnarkUtil.instance().getEepProxyPort() + "\" size=\"5\" /><br />\n");
+ _manager.util().getEepProxyPort() + "\" size=\"5\" maxlength=\"5\" /><br />\n");
out.write("I2CP host: <input type=\"text\" name=\"i2cpHost\" value=\""
+ I2PSnarkUtil.instance().getI2CPHost() + "\" size=\"15\" /> ");
+ _manager.util().getI2CPHost() + "\" size=\"15\" /> ");
out.write("port: <input type=\"text\" name=\"i2cpPort\" value=\"" +
+ I2PSnarkUtil.instance().getI2CPPort() + "\" size=\"5\" /> <br />\n");
+ _manager.util().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(); ) {
String key = (String)iter.next();
String val = (String)options.get(key);
Map options = new TreeMap(_manager.util().getI2CPOptions());
for (Iterator iter = options.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String key = (String)entry.getKey();
String val = (String)entry.getValue();
opts.append(key).append('=').append(val).append(' ');
}
out.write("I2CP opts: <input type=\"text\" name=\"i2cpOpts\" size=\"40\" value=\""
out.write("I2CP opts: <input type=\"text\" name=\"i2cpOpts\" size=\"80\" value=\""
+ opts.toString() + "\" /><br />\n");
out.write("<input type=\"submit\" value=\"Save configuration\" name=\"action\" />\n");
out.write("</span>\n");
out.write("</form>\n");
}
// rounding makes us look faster :)
private String formatSize(long bytes) {
if (bytes < 5*1024)
return bytes + "B";
else if (bytes < 5*1024*1024)
return (bytes/1024) + "KB";
return ((bytes + 512)/1024) + "KB";
else if (bytes < 5*1024*1024*1024l)
return (bytes/(1024*1024)) + "MB";
return ((bytes + 512*1024)/(1024*1024)) + "MB";
else
return (bytes/(1024*1024*1024)) + "GB";
return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "GB";
}
private static final String HEADER_BEGIN = "<html>\n" +
@@ -540,7 +817,10 @@ public class I2PSnarkServlet extends HttpServlet {
"}\n" +
"th {\n" +
" background-color: #C7D5D5;\n" +
" margin: 0px 0px 0px 0px;\n" +
" padding: 0px 7px 0px 3px;\n" +
"}\n" +
"td {\n" +
" padding: 0px 7px 0px 3px;\n" +
"}\n" +
".snarkTorrentEven {\n" +
" background-color: #E7E7E7;\n" +
@@ -550,8 +830,6 @@ public class I2PSnarkServlet extends HttpServlet {
"}\n" +
".snarkNewTorrent {\n" +
" font-size: 10pt;\n" +
" font-family: monospace;\n" +
" background-color: #ADAE9;\n" +
"}\n" +
".snarkAddInfo {\n" +
" font-size: 10pt;\n" +
@@ -568,19 +846,26 @@ public class I2PSnarkServlet extends HttpServlet {
"<body>\n";
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\">\n" +
private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" cellpadding=\"0 10px\">\n" +
"<thead>\n" +
"<tr><th align=\"left\" valign=\"top\">Status</th>\n" +
"<tr><th align=\"left\" valign=\"top\">Status \n";
private static final String TABLE_HEADER2 = "</th>\n" +
" <th align=\"left\" valign=\"top\">Torrent</th>\n" +
" <th align=\"left\" valign=\"top\">Downloaded</th>\n" +
" <th align=\"left\" valign=\"top\">Uploaded</th>\n" +
//" <th align=\"left\" valign=\"top\">Rate</th>\n" +
" <th>&nbsp;</th></tr>\n" +
"</thead>\n";
" <th align=\"right\" valign=\"top\">ETA</th>\n" +
" <th align=\"right\" valign=\"top\">Downloaded</th>\n" +
" <th align=\"right\" valign=\"top\">Uploaded</th>\n" +
" <th align=\"right\" valign=\"top\">Down Rate</th>\n" +
" <th align=\"right\" valign=\"top\">Up Rate</th>\n";
private static final String TABLE_TOTAL = "<tfoot>\n" +
"<tr><th align=\"left\" valign=\"top\">Totals</th>\n" +
" <th>&nbsp;</th>\n" +
" <th>&nbsp;</th>\n";
private static final String TABLE_EMPTY = "<tr class=\"snarkTorrentEven\">" +
"<td class=\"snarkTorrentEven\" align=\"left\"" +
" valign=\"top\" colspan=\"5\">No torrents</td></tr>\n";
" valign=\"top\" colspan=\"8\">No torrents</td></tr>\n";
private static final String TABLE_FOOTER = "</table>\n";
@@ -597,7 +882,8 @@ class FetchAndAdd implements Runnable {
}
public void run() {
_url = _url.trim();
File file = I2PSnarkUtil.instance().get(_url, false);
// 3 retries
File file = _manager.util().get(_url, false, 3);
try {
if ( (file != null) && (file.exists()) && (file.length() > 0) ) {
_manager.addMessage("Torrent fetched from " + _url);

View File

@@ -3,6 +3,7 @@ package org.klomp.snark.web;
import java.io.File;
import net.i2p.util.FileUtil;
import org.mortbay.jetty.Server;
public class RunStandalone {

View File

@@ -7,12 +7,27 @@
<ant dir="../../jetty/" target="build" />
<!-- ministreaming will build core -->
</target>
<target name="compile">
<condition property="depend.available">
<typefound name="depend" />
</condition>
<target name="depend" if="depend.available">
<depend
cache="../../../build"
srcdir="./src"
destdir="./build/obj" >
<!-- Depend on classes instead of jars where available -->
<classpath>
<pathelement location="../../../core/java/build/obj" />
<pathelement location="../../ministreaming/java/build/obj" />
</classpath>
</depend>
</target>
<target name="compile" depends="depend">
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
srcdir="./src"
debug="true" deprecation="on" source="1.3" target="1.3"
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
classpath="../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar" />
</target>
@@ -30,7 +45,7 @@
basedir="../jsp/" excludes="web.xml, *.java, *.jsp">
</war>
</target>
<target name="precompilejsp">
<target name="precompilejsp" unless="precompilejsp.uptodate">
<delete dir="../jsp/WEB-INF/" />
<delete file="../jsp/web-fragment.xml" />
<delete file="../jsp/web-out.xml" />
@@ -56,7 +71,7 @@
<arg value="-webapp" />
<arg value="../jsp/" />
</java>
<javac debug="true" deprecation="on" source="1.3" target="1.3"
<javac debug="true" deprecation="on" source="1.5" target="1.5"
destdir="../jsp/WEB-INF/classes/" srcdir="../jsp/WEB-INF/classes" includes="**/*.java">
<classpath>
<pathelement location="../../jetty/jettylib/jasper-runtime.jar" />
@@ -72,6 +87,11 @@
<replacefilter token="&lt;!-- precompiled servlets --&gt;" value="${jspc.web.fragment}" />
</replace>
</target>
<uptodate property="precompilejsp.uptodate" targetfile="../jsp/web-out.xml">
<srcfiles dir= "../jsp" includes="*.jsp, *.html, web.xml"/>
</uptodate>
<target name="javadoc">
<mkdir dir="./build" />
<mkdir dir="./build/javadoc" />
@@ -84,6 +104,9 @@
</target>
<target name="clean">
<delete dir="./build" />
<delete dir="../jsp/WEB-INF/" />
<delete file="../jsp/web-fragment.xml" />
<delete file="../jsp/web-out.xml" />
</target>
<target name="cleandep" depends="clean">
<!-- ministreaming will clean core -->

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