forked from I2P_Developers/i2p.i2p
Compare commits
1133 Commits
i2p_0_6_0_
...
i2p-0.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baebd1fdd2 | ||
| 28cfd8cffe | |||
| a4468219c7 | |||
| 70f07e5bc7 | |||
| 173e8a0434 | |||
| 72fd42ef9b | |||
| ba7dbf9064 | |||
| 807f0665b1 | |||
| 416b0e4540 | |||
| 011ded2ee4 | |||
| f9faf3c70d | |||
| 0ea532c72e | |||
| 104cf8346e | |||
| 3e7e5d6113 | |||
| 0275c5e13b | |||
| 1c76d240e0 | |||
| 366da1b37c | |||
| bdcb625e6d | |||
| 8296723533 | |||
| 957c809774 | |||
| 70b99cf4f9 | |||
| 05a6353142 | |||
| 85615b972b | |||
| e3abea1ad2 | |||
| bc54908a22 | |||
| 60bd9803f0 | |||
| c3360cc3d7 | |||
| aa71725159 | |||
| 574713e608 | |||
| 0aaae0b0da | |||
| ed34964747 | |||
| 7b758d89d0 | |||
| 1c7111eca0 | |||
| 831f09c91a | |||
| 4f836a20e1 | |||
| 8faeaaa1ae | |||
| 7271289c1f | |||
| 8421ae1ed4 | |||
| d042c6b921 | |||
| e2e4516a8f | |||
| efc604a25c | |||
| 5c1864ed5e | |||
| debf92fd9b | |||
| 9477b139be | |||
| 53ce3c4802 | |||
| d61af12867 | |||
| 908c542b40 | |||
| ef998349cc | |||
| 44446d76e4 | |||
| a616a5f1c9 | |||
| c0b616e519 | |||
|
|
b4d3986006 | ||
|
|
ba9108f937 | ||
|
|
161379f004 | ||
|
|
841feaedff | ||
|
|
ba8de6c565 | ||
| d6148db455 | |||
| 33b43f40b9 | |||
| 4336dc441e | |||
| 2d86e7cf60 | |||
| 219e96d416 | |||
| 0c72fe7383 | |||
| 369599fedd | |||
| 847c9dafce | |||
| 734818f651 | |||
| dae6fd47d9 | |||
| 0956393cf3 | |||
| d16f187394 | |||
| 962a8f6f49 | |||
|
|
9aa8707647 | ||
| 1fdd228a9d | |||
| 819d857550 | |||
| 04fb12932f | |||
| 703b6ed190 | |||
| bd6c63cc7e | |||
| 7dbb13d6dc | |||
| ebdc69cbc2 | |||
| 868fe90d7a | |||
|
|
9e39f34473 | ||
|
|
45ed744210 | ||
|
|
701904d119 | ||
| dcf4bb595f | |||
| e9f27c60dd | |||
| 321f11c055 | |||
| 85cebc7992 | |||
| 8e5c4a3e22 | |||
| dff75de97a | |||
| f1fd35265a | |||
| b73b3fc5ac | |||
| 13d4ccf2e7 | |||
| 8c9ac941bf | |||
| 3fc698c7d3 | |||
| 15596c9230 | |||
| 7fdbe9b87b | |||
| 5acc56c184 | |||
| c524231c6d | |||
| 5d4a7967cb | |||
|
|
01101f9867 | ||
|
|
c93ccd15eb | ||
| 73280ab834 | |||
|
|
6a3c52b7fa | ||
|
|
90983c8761 | ||
| daac598bde | |||
|
|
41d98acc95 | ||
|
|
c8970c0fc6 | ||
| 4e5825c648 | |||
| 93f0092437 | |||
| bad4c4a133 | |||
| da9a4ce557 | |||
| 0ff8167425 | |||
| 9ae589449d | |||
| 134764b154 | |||
| 23699e46e5 | |||
| fa23a7b066 | |||
| de21a5ec48 | |||
| b1a9dcf77e | |||
| 15e7783477 | |||
| afa17a8c04 | |||
| c7bb2e8f76 | |||
| b4d299804b | |||
| 77f5dd2d14 | |||
| c941d7bfa1 | |||
| 049d6b2fa8 | |||
| 98038e9282 | |||
| 6169904c76 | |||
| 04509f593a | |||
| 875dd65dcb | |||
| b0ec6a0870 | |||
| 6ce2767514 | |||
| 5271838a14 | |||
| 9ec45bbcf5 | |||
| c9cef19a68 | |||
| 9f57be5f03 | |||
| 1793b05784 | |||
| f95c324832 | |||
| 016c843ad6 | |||
| e52526b256 | |||
| 7722ab5f6f | |||
| c024398b93 | |||
| 2e72ece384 | |||
| 2b8d59d9f4 | |||
|
|
28b4c92241 | ||
|
|
c9d9a83f73 | ||
|
|
7bf57870d6 | ||
|
|
d41b68438d | ||
|
|
c634e5005d | ||
|
|
e0926b8ccd | ||
|
|
5ea7adb857 | ||
| bf12c5f9bf | |||
| 47d5e44b16 | |||
| f6996c7d8b | |||
| fb7f4f2d11 | |||
| d89f97acd5 | |||
| f3c9343c79 | |||
| 16ec091209 | |||
|
|
0b599c45ec | ||
|
|
7f3f6dfde3 | ||
|
|
d736b75dc2 | ||
|
|
fa2f06b1d8 | ||
| 4212858409 | |||
| 33221ce7fd | |||
| fd5fcebae9 | |||
| b743449715 | |||
| 2a08fc7a34 | |||
| 0c520de6e5 | |||
| 09b868e243 | |||
| 83801c9feb | |||
| 152f824779 | |||
| 68256930b9 | |||
| 622951c794 | |||
| baa70299fc | |||
| 47856f312c | |||
| b4c808918b | |||
|
|
e6e4c60a25 | ||
|
|
2dc699b382 | ||
| 22454a06d4 | |||
| 0e0459f88a | |||
| 20effe3a7f | |||
| 8a756a6e81 | |||
| a7e876da1e | |||
| 06be4515e4 | |||
| af630e9559 | |||
| 50c93e25c7 | |||
| 2d6007cf49 | |||
| 7aaed8e686 | |||
| e2a1835142 | |||
| 078256da83 | |||
| 4f8d84e9e7 | |||
| ae967d6ef4 | |||
| 3b46b16038 | |||
| 25bf6e59bc | |||
|
|
c4030f8dab | ||
|
|
e103f33c29 | ||
|
|
1c6b78a8da | ||
|
|
8117d0465c | ||
|
|
0ff846deee | ||
|
|
87a992bd3f | ||
|
|
41c38e64c3 | ||
|
|
ca5c15d4de | ||
|
|
f3f7537ec6 | ||
| 855293d673 | |||
| 4c2d4144d1 | |||
| 387587b0b6 | |||
| 43e95a70d1 | |||
| ad56eb7220 | |||
| d2d32f0ad1 | |||
| 0428726e30 | |||
| 2eb154c24c | |||
| 4ec82beec5 | |||
|
|
224ebb16d4 | ||
|
|
cb17fb8805 | ||
|
|
2c048d7465 | ||
|
|
00d537e5e4 | ||
|
|
5eef43d239 | ||
|
|
caaf0ccfc3 | ||
|
|
18d42ec925 | ||
|
|
872d2c48c9 | ||
|
|
a3b9345ff1 | ||
|
|
eae67a44f0 | ||
|
|
a988358ebb | ||
|
|
bb32672c11 | ||
|
|
ae0a51669c | ||
|
|
f1c4a85991 | ||
|
|
0a5eeed370 | ||
| bf07a6a3c2 | |||
|
|
5913d9ee4a | ||
|
|
61749aaaa9 | ||
|
|
b0313bd6bf | ||
|
|
dd7d993631 | ||
|
|
ee2fd32a97 | ||
|
|
fa5c7219d3 | ||
|
|
8d78a77a8c | ||
| 52d38e0452 | |||
| fbad8a1e8e | |||
| f49277087c | |||
| e5c7b79cf5 | |||
| 6b1224b23e | |||
| 0bbc94f43c | |||
| 7c083ed33b | |||
| 50f10e8cf1 | |||
| 69d9c054d8 | |||
| fcfe4397c4 | |||
| e734a55872 | |||
| 825af3e6c1 | |||
| cf54dd159d | |||
| 6b1fb674ea | |||
| 97366824d6 | |||
| 2ac5361937 | |||
| 9a2792e64c | |||
| 1091a289d2 | |||
| 536f5d0c7b | |||
| a3108ead4a | |||
| 808557d24f | |||
| 6501d403ab | |||
| ef328ed3cc | |||
| 62bf269c42 | |||
| ee4d68cf6a | |||
| e064b0a0e1 | |||
| c321251bb7 | |||
| 896ba7ae1c | |||
| 2c48831604 | |||
| 9d70a5293f | |||
|
|
bf51741134 | ||
| 33e8abfc3e | |||
| 258d01f0d9 | |||
| 49af13a3ca | |||
| 719ba3f66f | |||
| 9652db9623 | |||
| 481af00bab | |||
| 11d267bc9a | |||
| 40f0cb65a1 | |||
| 2ba9929277 | |||
| 616abba328 | |||
|
|
14a6352d9a | ||
|
|
5782c42d25 | ||
|
|
f261deaf16 | ||
| 5228543236 | |||
| e173a47e01 | |||
| 07b895a069 | |||
| 4d8ffc85e2 | |||
| 53e2e0d1c9 | |||
| e0dcf82697 | |||
| 0cfac58adb | |||
| 2768bef991 | |||
| bae712ad96 | |||
| 49cb4c13b3 | |||
| 28da17276c | |||
| 14099ace69 | |||
| 9289799c97 | |||
| f057666ac2 | |||
| a11b74b2d8 | |||
| 0e018c5b4d | |||
| 107a90fa33 | |||
|
|
01259cc07d | ||
|
|
4d955f3be5 | ||
| 49e429c166 | |||
| 53c5b1446a | |||
| dc68ebbaeb | |||
| f3d73a6c15 | |||
| 91950a37f5 | |||
| a8c266402e | |||
| d78fb4df3c | |||
| fb5a8ee0d8 | |||
| 7b81062816 | |||
| c3a2adc97e | |||
| bff685f7ca | |||
| 7e51c86c38 | |||
| df069ec9d1 | |||
| eb3164d0e0 | |||
| 5a69de3650 | |||
| 87b933fd3a | |||
| 2404078bfa | |||
| 6b33378a0a | |||
|
|
c46c9b2b7c | ||
|
|
acf22bf8fc | ||
| f3b8c73e96 | |||
| a8e625072b | |||
| 88e26224c2 | |||
| db9db18bdf | |||
| 9c06bb3fca | |||
| 8edfa746e5 | |||
| 5729b34f8b | |||
| 2f80f7fa63 | |||
| 592e609291 | |||
| 3396a8813f | |||
| 6345e669bc | |||
| 74a5abbc11 | |||
| 19992b1d1b | |||
| 02e7a19f65 | |||
| c6a697df57 | |||
| 26bb479957 | |||
| 0c42e7e4b2 | |||
| 699a62a9b9 | |||
| ffc67d1e5a | |||
| 2f72f5ca67 | |||
|
|
955e7823ad | ||
| 7e3800a5cb | |||
|
|
6c7691cecb | ||
|
|
760c316486 | ||
|
|
5d9d82879f | ||
| 9b8772a470 | |||
| bc5d87e6f0 | |||
| d81bff267a | |||
| 042399f293 | |||
| 5be7ea1fc5 | |||
| db34665bb1 | |||
| ed9a03ebc7 | |||
| 619b5c0e45 | |||
| 4c2c5ca232 | |||
| 3a203c3018 | |||
| 3e86ee9746 | |||
|
|
d0855e1fc6 | ||
| 0bde8a24e4 | |||
|
|
4049ff5167 | ||
|
|
89389ccc13 | ||
| 959e308578 | |||
| 8d4cbd8556 | |||
| 99b9c93636 | |||
| 47c666c582 | |||
| a3c330fd9d | |||
| a6f3478db3 | |||
| b1af22a15e | |||
| 65ec41c48f | |||
| aebf16add7 | |||
| 1de0563c94 | |||
|
|
c6059b9d85 | ||
|
|
f68c9242a9 | ||
| 51838ba051 | |||
| cf50b7eac1 | |||
| 2edd84e088 | |||
| 5ba1e458c6 | |||
| 0b600669c7 | |||
|
|
215eb14d38 | ||
| 20ff2f5bdc | |||
| edc02e5efa | |||
| d57356f807 | |||
| a7a6c75ac5 | |||
| b9e2def552 | |||
| 4d7417401c | |||
| 40a9e959e8 | |||
| 42bbb4a9ff | |||
| 9500a55532 | |||
| 0556f15068 | |||
| 6e981874a5 | |||
| 8886d61caa | |||
| b6fe81a982 | |||
| e7cdb965ba | |||
| 4fa4357bf1 | |||
| 46307c60d4 | |||
| e6a0c2f4f0 | |||
| cb41bf6023 | |||
| d23c8a8331 | |||
| b1beb46ca2 | |||
|
|
6606c83cb2 | ||
| 5998f5c9bd | |||
| cffcbe5f94 | |||
| 0c75725f5e | |||
| 5ef325408c | |||
| d957712e88 | |||
| 9233c2ed4c | |||
| 7ad54eb749 | |||
| 5740e20c62 | |||
| 0a9114fc2f | |||
| 71ddfa42e1 | |||
| 1ecb84f3fb | |||
| c46b06fb81 | |||
| a7397879aa | |||
| 9b86da7ce5 | |||
| c68977ca8c | |||
| bc7bd628db | |||
| bc7ab39131 | |||
| 100163e03b | |||
| 49c02f13b2 | |||
| 40f072e25e | |||
| 918b1acb8f | |||
| bc16078e3f | |||
| 4a8dbd0634 | |||
| 38c0184f95 | |||
| 68829ddb99 | |||
| 19089bd6a7 | |||
| 69cc0afd1b | |||
| d2f3a262db | |||
|
|
c1703b872d | ||
|
|
f7b0e8181b | ||
| 43f2695901 | |||
|
|
ea0d4ffd7f | ||
|
|
0ed29573a7 | ||
| 1365d3e3b9 | |||
| 40befb5a92 | |||
| 9c16eec361 | |||
| 093c69637d | |||
| 134ec7acea | |||
|
|
0802a5ae40 | ||
|
|
14ddfb360f | ||
|
|
78ad831028 | ||
| 22f1684262 | |||
| 83f51b4a66 | |||
| 9c28de0704 | |||
| c69fda2298 | |||
| cabb22331b | |||
|
|
5b3aca29a8 | ||
|
|
f35cbf59d8 | ||
|
|
a96119d09b | ||
|
|
2711294aee | ||
|
|
f838b1828b | ||
|
|
fbf6282c1a | ||
|
|
5195a5c1fc | ||
|
|
62b18b18b5 | ||
|
|
7c8f519b35 | ||
|
|
d6fb979616 | ||
|
|
f568d21969 | ||
|
|
7fe9d590f5 | ||
|
|
0a1240ebfd | ||
|
|
4e68f2a157 | ||
|
|
e9bd6907d1 | ||
|
|
b20495c39f | ||
|
|
0ecbc4c27b | ||
|
|
4d5b1d4c3f | ||
|
|
17b719f3f7 | ||
|
|
979a3e98d8 | ||
|
|
c6a1112f0a | ||
|
|
4ebcc95d9f | ||
|
|
7e59ce27fa | ||
|
|
22345a264e | ||
|
|
03739996da | ||
|
|
819a72d4f6 | ||
|
|
e480931e20 | ||
|
|
3f01d0a69e | ||
|
|
f67f47f0cd | ||
|
|
5ad6ee60eb | ||
|
|
5accba6cdc | ||
|
|
313e1704df | ||
|
|
cf4d2b17c9 | ||
|
|
9145eedc35 | ||
|
|
b772179077 | ||
|
|
9054a196ce | ||
|
|
d28a96ac7d | ||
|
|
9c73f80ac3 | ||
|
|
20c46cff04 | ||
|
|
f332513755 | ||
|
|
cb69a66498 | ||
|
|
1c66543938 | ||
|
|
53ab3c472e | ||
|
|
a4b221fa71 | ||
|
|
e3e1d0842d | ||
|
|
99b5bf9609 | ||
|
|
da10fe0df7 | ||
|
|
9fd5ba7b2d | ||
|
|
05b5df9d76 | ||
|
|
5c1dc79767 | ||
|
|
4acd2996c5 | ||
|
|
16fa6a89bc | ||
|
|
2a72e8574b | ||
|
|
d4a1bcf28f | ||
|
|
409b71def5 | ||
|
|
2dc5fbda02 | ||
|
|
71aaf03d09 | ||
|
|
30c99e630b | ||
|
|
445b39171a | ||
|
|
571c2d6047 | ||
|
|
42ff763933 | ||
|
|
727edc3ff9 | ||
|
|
82a4758a0a | ||
|
|
915914ebb3 | ||
|
|
c438b56378 | ||
|
|
307ccfb1b4 | ||
|
|
34e23259b4 | ||
|
|
036802d66a | ||
|
|
6a7dbc8e3a | ||
|
|
cf4a9ffc27 | ||
|
|
6ef4adf318 | ||
|
|
f84c9bf3b1 | ||
|
|
da0837bd58 | ||
|
|
9094a62273 | ||
|
|
026183a655 | ||
|
|
b033c7945c | ||
|
|
0c2dcf0845 | ||
|
|
b6e597e5bf | ||
|
|
ae402baa71 | ||
|
|
d6c8a4d9eb | ||
|
|
8e2849b7e5 | ||
|
|
0aa0cd330f | ||
|
|
0960cafaf5 | ||
|
|
2088a28053 | ||
|
|
a5c4ba3bff | ||
|
|
1bbd2cf52e | ||
|
|
ce50efa60c | ||
|
|
a3c64a9ba3 | ||
|
|
1447164a8a | ||
|
|
bc0bf8d7ff | ||
|
|
9f346f488e | ||
|
|
760d7d9704 | ||
|
|
77310e17d1 | ||
|
|
e54b964929 | ||
|
|
809f3e847b | ||
|
|
f4beebe60d | ||
|
|
827e427f0b | ||
|
|
c02125511d | ||
|
|
1aa1069b6f | ||
|
|
91d281077d | ||
|
|
f339dec024 | ||
|
|
2aeef44f8d | ||
|
|
0fd41a9490 | ||
|
|
58f10d14b2 | ||
|
|
46ca42ddf8 | ||
|
|
e6e6d6f4ee | ||
|
|
8a87df605b | ||
|
|
8ca085bceb | ||
|
|
df47587db0 | ||
|
|
d705e0ad04 | ||
|
|
40d209dd7c | ||
|
|
7f2a0457bf | ||
|
|
f4749f2483 | ||
|
|
9c42830076 | ||
|
|
53ba6c2a64 | ||
|
|
61b3f21f69 | ||
|
|
506fd5f889 | ||
|
|
d538f888b4 | ||
|
|
976c5fdd47 | ||
|
|
b63f3437f2 | ||
|
|
e760f2e538 | ||
|
|
17c8fca779 | ||
|
|
87fda382c3 | ||
|
|
1e404cd7ac | ||
|
|
098f99d806 | ||
|
|
da93f96035 | ||
|
|
ead39cc87e | ||
|
|
e4e3c44459 | ||
|
|
af151e32e5 | ||
|
|
12819a2a17 | ||
|
|
87eedff254 | ||
|
|
4c59cd7621 | ||
|
|
ef707e7956 | ||
|
|
73cf3fb299 | ||
|
|
80b0c97d72 | ||
|
|
5cf85c1d7b | ||
|
|
c14e52ceb5 | ||
|
|
32a579e480 | ||
|
|
0a240a4436 | ||
|
|
9325b806e4 | ||
|
|
ef2e24ea11 | ||
|
|
373934c6e0 | ||
|
|
e8e8bac694 | ||
|
|
23e8a558c2 | ||
|
|
46f2645834 | ||
|
|
2329439034 | ||
|
|
6d400368b9 | ||
|
|
26c13b40fe | ||
|
|
9fd0e95fe8 | ||
|
|
7e21f2c92b | ||
|
|
c9d8e796c6 | ||
|
|
e7203f5d46 | ||
|
|
22d76a1b64 | ||
|
|
0903dc46c6 | ||
|
|
0f56ec8078 | ||
|
|
70ee1df2bf | ||
|
|
61a6a29bec | ||
|
|
678f7d8f72 | ||
|
|
b92ee364bc | ||
|
|
aef19fcd38 | ||
|
|
3b01df1d2c | ||
|
|
4aed23b198 | ||
|
|
03e8875c27 | ||
|
|
48921a0875 | ||
|
|
633fabb09e | ||
|
|
bc42c26d94 | ||
|
|
3c09ca3359 | ||
|
|
1e9e7dd345 | ||
|
|
034803add7 | ||
|
|
b25bb053bb | ||
|
|
9bd0c79441 | ||
|
|
06b8670410 | ||
|
|
6577ae499f | ||
|
|
54bc5485ec | ||
|
|
84b741ac98 | ||
|
|
c48c419d74 | ||
|
|
fb2e795add | ||
|
|
ec215777ec | ||
|
|
d4e0f27c56 | ||
|
|
e1c686baa6 | ||
|
|
d57af1aef4 | ||
|
|
a52dd57215 | ||
|
|
65138357d3 | ||
|
|
f6320696dd | ||
|
|
900d8a2026 | ||
|
|
ccc9a87e8c | ||
|
|
208634e5de | ||
|
|
3d07205c9d | ||
|
|
f0a424a93f | ||
|
|
f9b59ee07d | ||
|
|
b92b9d2618 | ||
|
|
a3db9429a7 | ||
|
|
291a5c9578 | ||
|
|
0a3281c279 | ||
|
|
23f30ba576 | ||
|
|
f3de85c4de | ||
|
|
a3a4888e0b | ||
|
|
6fd7881f8e | ||
|
|
381f716769 | ||
|
|
f2078e1523 | ||
|
|
f2fb87c88b | ||
|
|
fcbea19478 | ||
|
|
92f25bd4fa | ||
|
|
85c2c11217 | ||
|
|
de1ca4aea4 | ||
|
|
a0f865fb99 | ||
|
|
2c3fea5605 | ||
|
|
ba1d88b5c9 | ||
|
|
2ad715c668 | ||
|
|
5f17557e54 | ||
|
|
2ad5a6f907 | ||
|
|
0920462060 | ||
|
|
870e94e184 | ||
|
|
6b0d507644 | ||
|
|
70cf9e4ca7 | ||
|
|
2a3974c71d | ||
|
|
46ac9292e8 | ||
|
|
4307097472 | ||
|
|
ed3fdaf4f1 | ||
|
|
378a9a8f5c | ||
|
|
4ef6180455 | ||
|
|
d4970e23c0 | ||
|
|
0c9f165016 | ||
|
|
be3a899ecb | ||
|
|
7a6a749004 | ||
|
|
17271ee3f0 | ||
|
|
99bcfa90df | ||
|
|
eb36e993c1 | ||
|
|
e5eca5fa45 | ||
|
|
8cba2f4236 | ||
|
|
40d5ed31ac | ||
|
|
181275fe35 | ||
|
|
23d8c01ce7 | ||
|
|
de83944486 | ||
|
|
90cd7ff23a | ||
|
|
8d0a9b4ccd | ||
|
|
230d4cd23f | ||
|
|
e9b6fcc0a4 | ||
|
|
8fcb871409 | ||
|
|
83bef43fd5 | ||
|
|
b4fc6ca31b | ||
|
|
ab3f1b708d | ||
|
|
c76402a160 | ||
|
|
a50c73aa5e | ||
|
|
5aa66795d2 | ||
|
|
ac3c2d2b15 | ||
|
|
072a45e5ce | ||
|
|
1ab14e52d2 | ||
|
|
9a820961a2 | ||
|
|
764149aef3 | ||
|
|
1b3ad31bff | ||
|
|
15e6c27c04 | ||
|
|
8b707e569f | ||
|
|
e4c4b24c61 | ||
|
|
031636e607 | ||
|
|
b5c0d77c69 | ||
|
|
d489caa88c | ||
|
|
2a24029acf | ||
|
|
c5aab8c750 | ||
|
|
343748111a | ||
|
|
c5ddfabfe9 | ||
|
|
1ef33906ed | ||
|
|
f3849a22ad | ||
|
|
b03ff21d3b | ||
|
|
52094b10c9 | ||
|
|
fc927efaa3 | ||
|
|
65dc803fb7 | ||
|
|
349adf6690 | ||
|
|
2c843fd818 | ||
|
|
863b511cde | ||
|
|
c417e7c237 | ||
|
|
1822c0d7d8 | ||
|
|
94c1c32b51 | ||
|
|
deb35f4af4 | ||
|
|
883150f943 | ||
|
|
717d1b97b2 | ||
|
|
e62135eacc | ||
|
|
2c6d953359 | ||
|
|
2b79e2df3f | ||
|
|
fab6e421b8 | ||
|
|
589cbd675a | ||
|
|
c486f5980a | ||
|
|
eee21aa301 | ||
|
|
a2854cf6f6 | ||
|
|
62b7cf64da | ||
|
|
7b2a435aad | ||
|
|
3d8d21e543 | ||
|
|
8b7958cff2 | ||
|
|
7bb792836d | ||
|
|
03f509ca54 | ||
|
|
5f05631936 | ||
|
|
5cfedd4c8b | ||
|
|
269fec64a5 | ||
|
|
f63c6f4717 | ||
|
|
b4c495531a | ||
|
|
9990126e3e | ||
|
|
ac8436a8eb | ||
|
|
dee79dfb1c | ||
|
|
9b4e6f475d | ||
|
|
7672ba23d1 | ||
|
|
4b77ddedcc | ||
|
|
222af6c090 | ||
|
|
8e879cb646 | ||
|
|
65975df1be | ||
|
|
c94de2fbb5 | ||
|
|
5aa335740a | ||
|
|
1202751359 | ||
|
|
34fcf53d87 | ||
|
|
9ddc632b9f | ||
|
|
941b65eb32 | ||
|
|
8c9167464b | ||
|
|
5b94965983 | ||
|
|
3226ea5bf6 | ||
|
|
84a24784e4 | ||
|
|
71d3fa6b8c | ||
|
|
9e00dbaafd | ||
|
|
2e9e0c64d4 | ||
|
|
fde3f1ce7d | ||
|
|
321c560648 | ||
|
|
d2ddca7d64 | ||
|
|
fb17e70f12 | ||
|
|
79f934fe17 | ||
|
|
3d76df6af3 | ||
|
|
d5c36f7f4e | ||
|
|
41ac628744 | ||
|
|
41e5e1a094 | ||
|
|
74edc3fa7d | ||
|
|
3a26218b5a | ||
|
|
687abd9427 | ||
|
|
113fbc1df3 | ||
|
|
1374ea0ea1 | ||
|
|
424e55d3b2 | ||
|
|
fde4f579f4 | ||
|
|
2d651a41f0 | ||
|
|
1eebd5463f | ||
|
|
f22601b477 | ||
|
|
ab8e11657f | ||
|
|
17eb7fa983 | ||
|
|
d1134f9704 | ||
|
|
13fe45b489 | ||
|
|
cd235e5902 | ||
|
|
b727d868fb | ||
|
|
cd2609b34a | ||
|
|
a12ede096a | ||
|
|
eb3442823e | ||
|
|
211f37c207 | ||
|
|
d60d0923c0 | ||
|
|
0448203ede | ||
|
|
00c97dbf92 | ||
|
|
d07342e3e3 | ||
|
|
205d8de281 | ||
|
|
a638301b5c | ||
|
|
4f51ad492b | ||
|
|
c3a9f72d41 | ||
|
|
79476d3609 | ||
|
|
97a206fcda | ||
|
|
f783e65a4c | ||
|
|
dbd1f65864 | ||
|
|
5c78d8108f | ||
|
|
1b273bdf43 | ||
|
|
934f4082f1 | ||
|
|
002aed145f | ||
|
|
1ca27ffd39 | ||
|
|
66e6dbec33 | ||
|
|
894caaa63c | ||
|
|
97dae94b46 | ||
|
|
c00488afeb | ||
|
|
23723b56ca | ||
|
|
76f89ac93c | ||
|
|
0f8611e465 | ||
|
|
8e87ae08fb | ||
|
|
5b1a6391f3 | ||
|
|
728f177473 | ||
|
|
1d0d0d9c69 | ||
|
|
9b7e5d1817 | ||
|
|
dc0485b526 | ||
|
|
784d465d17 | ||
|
|
327089c9d1 | ||
|
|
148dd99c86 | ||
|
|
98277d3b64 | ||
|
|
702e5a5eab | ||
|
|
54c91731c0 | ||
|
|
3bfc109476 | ||
|
|
3989638f2d | ||
|
|
4a65fd4f46 | ||
|
|
d525c49d45 | ||
|
|
c287bace0f | ||
|
|
ee0951b5b2 | ||
|
|
1eb3ae5e1b | ||
|
|
7d234b1978 | ||
|
|
6f424fa751 | ||
|
|
7726bd1a5c | ||
|
|
2a922098d6 | ||
|
|
3ec92c8b62 | ||
|
|
b37bb9372e | ||
|
|
369b6930e5 | ||
|
|
5033a22a9b | ||
|
|
6e5114a4c2 | ||
|
|
77c818a0b1 | ||
|
|
7ac673cea4 | ||
|
|
e5fa7e0ae4 | ||
|
|
ab4f3008cb | ||
|
|
f738a02760 | ||
|
|
7d64ecb628 | ||
|
|
7beacff028 | ||
|
|
952bcc696a | ||
|
|
19bba048f2 | ||
|
|
5966fcf5ff | ||
|
|
fbd7feee61 | ||
|
|
5faca98176 | ||
|
|
99951bf815 | ||
|
|
024b1a04e2 | ||
|
|
a4cc18df76 | ||
|
|
fef578973a | ||
|
|
35b75a7300 | ||
|
|
1c6c397913 | ||
|
|
c96965d364 | ||
|
|
12900ca709 | ||
|
|
f5b829a124 | ||
|
|
f62a6d3ce6 | ||
|
|
3d18bf870b | ||
|
|
d8071296eb | ||
|
|
c66e3256aa | ||
|
|
686742a67b | ||
|
|
cdf94295f3 | ||
|
|
fbf1705c4e | ||
|
|
453ecc4208 | ||
|
|
d1f2b447ac | ||
|
|
70c4560f02 | ||
|
|
9089fdd2d5 | ||
|
|
ef82cc4f20 | ||
|
|
f2c2a5b386 | ||
|
|
fc858bc950 | ||
|
|
dbb4b3d0c2 | ||
|
|
2b841ad667 | ||
|
|
5e094b43b3 | ||
|
|
33d57dd545 | ||
|
|
61f75b5f09 | ||
|
|
3f65e53592 | ||
|
|
99ae3ee459 | ||
|
|
f7236d7d58 | ||
|
|
5182008b38 | ||
|
|
9d030327e6 | ||
|
|
a15c90d2cc | ||
|
|
84c2a713e1 | ||
|
|
7db9ce6e5b | ||
|
|
da42f5717b | ||
|
|
5241953e5d | ||
|
|
b1a5f61ba2 | ||
|
|
024a5a1ad4 | ||
|
|
b031de5404 | ||
|
|
dceac73951 | ||
|
|
8f95143488 | ||
|
|
a8f3043aae | ||
|
|
6c91b2d4a9 | ||
|
|
ddd438de35 | ||
|
|
16fd46db2b | ||
|
|
1159c155a4 | ||
|
|
30b4e2aa2a | ||
|
|
ae46fa2e6d | ||
|
|
9fc34895c9 | ||
|
|
08be4c7b3d | ||
|
|
7443457af4 | ||
|
|
979a4cfb69 | ||
|
|
ed285871bf | ||
|
|
8c70b8b32a | ||
|
|
14134694d7 | ||
|
|
807d2d3509 | ||
|
|
b222cd43f4 | ||
|
|
7f6aa327f2 | ||
|
|
49564a3878 | ||
|
|
12ddaff0ce | ||
|
|
a8ea239dcc | ||
|
|
ca391097a9 | ||
|
|
4297edc88f | ||
|
|
6de4673e9e | ||
|
|
f6979c811f | ||
|
|
bd86483204 | ||
|
|
53cf03cec6 | ||
|
|
e284a8878b | ||
|
|
14cd469c6d | ||
|
|
9050d7c218 | ||
|
|
0ad18cd0ba | ||
|
|
ca0af146b7 | ||
|
|
a2d2b031f4 | ||
|
|
2f36912ac0 | ||
|
|
53e32c8e64 | ||
|
|
10dde610dc | ||
|
|
f7c2ae9a3b | ||
|
|
ac3b88b9e9 | ||
|
|
60124cdcdc | ||
|
|
e7d2281772 | ||
|
|
52ace2d695 | ||
|
|
b5a25801b4 | ||
|
|
3fc0558810 | ||
|
|
bd9c6ff463 | ||
|
|
a0c822af96 | ||
|
|
4de302101d | ||
|
|
84383c3dab | ||
|
|
a94abb13a4 | ||
|
|
ad59ab691b | ||
|
|
ee9ac31c8b | ||
|
|
788998307a | ||
|
|
2f8a2879bb | ||
|
|
c7b9525d2c | ||
|
|
3fbc6f41af | ||
|
|
6534c84578 | ||
|
|
3816c79193 | ||
|
|
8458e4e0af | ||
|
|
0b9e4967a0 | ||
|
|
05e2da7c22 | ||
|
|
13bda1f6d7 | ||
|
|
ea22c73a73 | ||
|
|
aa5f1cb18d | ||
|
|
ab9c6d59cf | ||
|
|
76655d01d0 | ||
|
|
138f7d3b8d | ||
|
|
df4b998a6a | ||
|
|
2d70103f88 | ||
|
|
731e26e7d6 | ||
|
|
f9d3b157f0 | ||
|
|
12775c416d | ||
|
|
2ca4e63216 | ||
|
|
918d8f851f | ||
|
|
20ea680ff0 | ||
|
|
cabb607211 | ||
|
|
00a4761b5e | ||
|
|
3516701272 | ||
|
|
c4d785667a | ||
|
|
123e0ba589 | ||
|
|
197237aa32 | ||
|
|
f30dc2b480 | ||
|
|
d4ff34eacb | ||
|
|
978769a05d | ||
|
|
993c70f600 | ||
|
|
5dfa9ad7f6 | ||
|
|
f282fe3854 | ||
|
|
9297564555 | ||
|
|
e7ad516685 | ||
|
|
ad574c8504 | ||
|
|
38617fe0a7 | ||
|
|
cdee5b2c31 | ||
|
|
7f6e65c76f | ||
|
|
4dd628dbc8 | ||
|
|
3b5b48ad8a | ||
|
|
c4cac3f3f1 | ||
|
|
4a49e98c31 | ||
|
|
0c0e269e72 | ||
|
|
70b6f97abe | ||
|
|
0013677b83 | ||
|
|
a98ceda64d | ||
|
|
91ea1d0395 | ||
|
|
4aa65c3bb3 | ||
|
|
0a1f59940a | ||
|
|
f540dc798b | ||
|
|
30f6f26a68 | ||
|
|
ea3bf3ffc8 | ||
|
|
831d5ac70c | ||
|
|
1962867ad9 | ||
|
|
6019a03029 | ||
|
|
df5736f571 | ||
|
|
9a73c6defe | ||
|
|
9dfa87ba47 | ||
|
|
934a269753 | ||
|
|
1c0dfc242b | ||
|
|
3bc3e5d47e | ||
|
|
55869af2cc | ||
|
|
9f336dd05b | ||
|
|
411ca5e6c3 | ||
|
|
c528e4db03 | ||
|
|
848ead7683 | ||
|
|
1b8419b9b5 | ||
|
|
900420719e | ||
|
|
ef7d1ba964 | ||
|
|
ab1654c784 | ||
|
|
24bad8e4bb | ||
|
|
f6d8200bc8 | ||
|
|
aef33548b3 | ||
|
|
56ecdcce82 | ||
|
|
b9b59ff95f | ||
|
|
aa9dd3e5c6 | ||
|
|
30bd659149 | ||
|
|
3286ca49c8 | ||
|
|
7700d12178 | ||
|
|
557b7e3f2e | ||
|
|
3e1e9146e1 | ||
|
|
40d8d1aac1 | ||
|
|
1457b8efba | ||
|
|
3821e80ac8 | ||
|
|
d40bb459ea | ||
|
|
edf04f07c9 | ||
|
|
2bdea23986 | ||
|
|
6be0c4b694 | ||
|
|
2a272f465c | ||
|
|
a8ecd32b45 | ||
|
|
20c42a175d | ||
|
|
d6c3ffde87 | ||
|
|
177e0ae6a3 | ||
|
|
dab1b4d256 | ||
|
|
3aba12631b | ||
|
|
cfee6430d4 | ||
|
|
6b96df1cec | ||
|
|
deecfa5047 | ||
|
|
6ca3f01038 | ||
|
|
d89f589f2b | ||
|
|
8c1895e04f | ||
|
|
c3d0132a98 | ||
|
|
d955279d17 | ||
|
|
76266dce0d | ||
|
|
5694206b35 | ||
|
|
4293a18726 | ||
|
|
9865af4174 | ||
|
|
c8c109093d | ||
|
|
b5784d6025 | ||
|
|
31bdb8909a | ||
|
|
ee921c22ae | ||
|
|
172ffd0434 | ||
|
|
d9b4406c09 | ||
|
|
8ac0e85df4 | ||
|
|
249ccd5e3c | ||
|
|
727d76d43e | ||
|
|
44770b7c07 | ||
|
|
b5d571c75f | ||
|
|
da56d83716 | ||
|
|
f777e213ce | ||
|
|
79906f5a7d | ||
|
|
54074e76b5 | ||
|
|
c2ea8db683 | ||
|
|
744671a518 | ||
|
|
7f5b127bbc | ||
|
|
89eff0c628 | ||
|
|
177aeebb1c | ||
|
|
e0e6bde4a5 | ||
|
|
e6b145716f | ||
|
|
f958342704 | ||
|
|
5a1f738505 | ||
|
|
8147cdf40c | ||
|
|
6afc64ac39 | ||
|
|
61b8e3598b | ||
|
|
3bb445ff40 | ||
|
|
59a8037599 | ||
|
|
09cb5fad59 | ||
|
|
ee8e45ecf7 | ||
|
|
339868838d | ||
|
|
c5579fa349 | ||
|
|
d4a859547c | ||
|
|
779aa240d2 | ||
|
|
9aaad00383 | ||
|
|
6422f7ef78 | ||
|
|
3e51584b3c | ||
|
|
4ff8a53084 | ||
|
|
ccb73437c4 | ||
|
|
b43114f61b | ||
|
|
9bd87ab511 | ||
|
|
b6ea55f7ef | ||
|
|
5f18cec97d | ||
|
|
3ba921ec0e | ||
|
|
e313da254c | ||
|
|
8660cf0d74 | ||
|
|
e0bfdff152 | ||
|
|
c27aed3603 | ||
|
|
cdc6002f0e | ||
|
|
4cf3d9c1a2 | ||
|
|
0473e08e21 | ||
|
|
346faa3de2 | ||
|
|
5ec6dca64d | ||
|
|
1a6b49cfb8 | ||
|
|
c7b75df390 | ||
|
|
f97c09291b | ||
|
|
8f2a5b403c | ||
|
|
ea41a90eae | ||
|
|
b1dd29e64d | ||
|
|
46e47c47ac | ||
|
|
b7bf431f0d | ||
|
|
7f432122d9 | ||
|
|
e7be8c6097 | ||
|
|
adf56a16e1 | ||
|
|
11204b8a2b | ||
|
|
cade27dceb | ||
|
|
5597d28e59 | ||
|
|
0502fec432 | ||
|
|
a6714fc2de | ||
|
|
1219dadbd5 | ||
|
|
77b995f5ed | ||
|
|
2f53b9ff68 | ||
|
|
d84d045849 | ||
|
|
d8e72dfe48 | ||
|
|
88b9f7a74c | ||
|
|
6a19501214 | ||
|
|
ba30b56c5f | ||
|
|
a375e4b2ce | ||
|
|
44fd71e17f | ||
|
|
b41c378de9 |
101
Makefile.gcj
Normal file
101
Makefile.gcj
Normal file
@@ -0,0 +1,101 @@
|
||||
# Makefile for building native I2P binaries and libraries with GCJ
|
||||
#
|
||||
# WARNING: Do not use this yet, as it may explode (etc).
|
||||
#
|
||||
GCJ=gcj #/usr/local/gcc-4.0.2/bin/gcj
|
||||
EXTRA_LD_PATH= #/usr/local/gcc-4.0.2/lib
|
||||
ANT=ant #/opt/apache-ant-1.6.5/bin/ant
|
||||
ANT_TARGET=buildclean
|
||||
NATIVE_DIR=native
|
||||
|
||||
##
|
||||
# Define what jar files get into libi2p.so. The current setup is
|
||||
# *incredibly* lazy, throwing everything in the .so, rather than
|
||||
# give each .jar file its own .so.
|
||||
# i2p.jar: base SDK
|
||||
# mstreaming.jar: streaming API
|
||||
# streaming.jar: full streaming lib implementation
|
||||
# i2ptunnel.jar: I2PTunnel proxy
|
||||
# sam.jar: SAM bridge and API
|
||||
# i2psnark.jar: bittorrent client
|
||||
# router.jar: full I2P router
|
||||
# jbigi.jar: collection of native optimized GMP routines for crypto
|
||||
JAR_BASE=i2p.jar mstreaming.jar streaming.jar
|
||||
JAR_CLIENTS=i2ptunnel.jar sam.jar
|
||||
JAR_ROUTER=router.jar
|
||||
JAR_JBIGI=jbigi.jar
|
||||
JAR_XML=xml-apis.jar resolver.jar xercesImpl.jar
|
||||
JAR_CONSOLE=\
|
||||
i2psnark.jar \
|
||||
javax.servlet.jar \
|
||||
commons-el.jar \
|
||||
commons-logging.jar \
|
||||
jasper-runtime.jar \
|
||||
ant-apache-bcel.jar \
|
||||
ant.jar \
|
||||
jasper-compiler.jar \
|
||||
org.mortbay.jetty.jar \
|
||||
routerconsole.jar
|
||||
JAR_SUCKER=jdom.jar rome-0.7.jar sucker.jar
|
||||
LIBI2P_JARS=${JAR_BASE} ${JAR_CLIENTS} ${JAR_ROUTER} ${JAR_JBIGI}
|
||||
# unfortunately, its not quite ready for most end users, as the
|
||||
# ${JAR_CONSOLE} fails to compile with:
|
||||
# org/apache/commons/logging/impl/LogKitLogger.java: In class 'org.apache.commons.logging.impl.LogKitLogger':
|
||||
# .../LogKitLogger.java: In constructor '(java.lang.String)':
|
||||
# .../LogKitLogger.java:91: error: cannot find file for class org.apache.log.Hierarchy
|
||||
# .../LogKitLogger.java:91: error: cannot find file for class org.apache.log.Hierarchy
|
||||
# .../LogKitLogger.java:104: error: cannot find file for class org.apache.log.Hierarchy
|
||||
# .../LogKitLogger.java:104: confused by earlier errors, bailing out
|
||||
|
||||
#${JAR_CONSOLE}\
|
||||
#${JAR_XML} \
|
||||
#${JAR_SUCKER}
|
||||
#${JAR_CONSOLE}
|
||||
|
||||
SYSTEM_PROPS=-DloggerFilenameOverride=logs/log-router-@.txt \
|
||||
-Dorg.mortbay.http.Version.paranoid=true \
|
||||
-Dorg.mortbay.util.FileResource.checkAliases=false \
|
||||
-Dorg.mortbay.xml.XmlParser.NotValidating=true
|
||||
#SYSTEM_PROPS=-Di2p.weakPRNG=true
|
||||
OPTIMIZE=-O2
|
||||
#OPTIMIZE=-O3
|
||||
|
||||
LD_LIBRARY_PATH=${EXTRA_LD_PATH}:.
|
||||
|
||||
all: jars native
|
||||
@echo "* Build complete"
|
||||
|
||||
jars:
|
||||
@${ANT} ${ANT_TARGET}
|
||||
|
||||
clean: native_clean
|
||||
|
||||
native: native_clean native_shared
|
||||
@echo "* Native code build in ${NATIVE}"
|
||||
|
||||
native_clean:
|
||||
@rm -rf ${NATIVE_DIR}
|
||||
@mkdir ${NATIVE_DIR}
|
||||
|
||||
native_shared: libi2p.so
|
||||
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2p_dsa --main=net.i2p.crypto.DSAEngine
|
||||
@echo "* i2p_dsa is a simple test app with the DSA engine and Fortuna PRNG to make sure crypto is working"
|
||||
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/prng --main=gnu.crypto.prng.FortunaStandalone
|
||||
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2ptunnel --main=net.i2p.i2ptunnel.I2PTunnel
|
||||
@echo "* i2ptunnel is mihi's I2PTunnel CLI"
|
||||
@echo " run it as ./i2ptunnel -cli to avoid awt complaints"
|
||||
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2ptunnelctl --main=net.i2p.i2ptunnel.TunnelControllerGroup
|
||||
@echo "* i2ptunnelctl is a controller for I2PTunnel, reading i2ptunnel.config"
|
||||
@echo " and launching the appropriate proxies"
|
||||
#@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2psnark --main=org.klomp.snark.Snark
|
||||
#@echo "* i2psnark is an anonymous bittorrent client"
|
||||
@cd build ; ${GCJ} ${OPTIMIZE} -fjni -L../${NATIVE_DIR} -li2p ${SYSTEM_PROPS} -o ../${NATIVE_DIR}/i2prouter --main=net.i2p.router.Router
|
||||
@echo "* i2prouter is the main I2P router"
|
||||
@echo " it can be used, and while the router console won't load,"
|
||||
@echo " i2ptunnel will, so it will start all the proxies defined in i2ptunnel.config"
|
||||
|
||||
libi2p.so:
|
||||
@echo "* Building libi2p.so"
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/libi2p.so ${LIBI2P_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/libi2p.so
|
||||
@echo "* libi2p.so built"
|
||||
69
apps/BOB/Demos/echo/echoclient/build.xml
Normal file
69
apps/BOB/Demos/echo/echoclient/build.xml
Normal 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>
|
||||
5
apps/BOB/Demos/echo/echoclient/client.sh
Executable file
5
apps/BOB/Demos/echo/echoclient/client.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
(
|
||||
cd dist
|
||||
java -jar echoclient.jar main 37338 testclient $1
|
||||
)
|
||||
3
apps/BOB/Demos/echo/echoclient/manifest.mf
Normal file
3
apps/BOB/Demos/echo/echoclient/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
629
apps/BOB/Demos/echo/echoclient/nbproject/build-impl.xml
Normal file
629
apps/BOB/Demos/echo/echoclient/nbproject/build-impl.xml
Normal 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 "${ant.java.version}"/>
|
||||
<condition property="have-jdk-older-than-1.4">
|
||||
<or>
|
||||
<contains string="${version-output}" substring="java version "1.0"/>
|
||||
<contains string="${version-output}" substring="java version "1.1"/>
|
||||
<contains string="${version-output}" substring="java version "1.2"/>
|
||||
<contains string="${version-output}" substring="java version "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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
60
apps/BOB/Demos/echo/echoclient/nbproject/project.properties
Normal file
60
apps/BOB/Demos/echo/echoclient/nbproject/project.properties
Normal 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
|
||||
16
apps/BOB/Demos/echo/echoclient/nbproject/project.xml
Normal file
16
apps/BOB/Demos/echo/echoclient/nbproject/project.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
apps/BOB/Demos/echo/echoserver/build.xml
Normal file
69
apps/BOB/Demos/echo/echoserver/build.xml
Normal 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>
|
||||
3
apps/BOB/Demos/echo/echoserver/manifest.mf
Normal file
3
apps/BOB/Demos/echo/echoserver/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
629
apps/BOB/Demos/echo/echoserver/nbproject/build-impl.xml
Normal file
629
apps/BOB/Demos/echo/echoserver/nbproject/build-impl.xml
Normal 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 "${ant.java.version}"/>
|
||||
<condition property="have-jdk-older-than-1.4">
|
||||
<or>
|
||||
<contains string="${version-output}" substring="java version "1.0"/>
|
||||
<contains string="${version-output}" substring="java version "1.1"/>
|
||||
<contains string="${version-output}" substring="java version "1.2"/>
|
||||
<contains string="${version-output}" substring="java version "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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
60
apps/BOB/Demos/echo/echoserver/nbproject/project.properties
Normal file
60
apps/BOB/Demos/echo/echoserver/nbproject/project.properties
Normal 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
|
||||
16
apps/BOB/Demos/echo/echoserver/nbproject/project.xml
Normal file
16
apps/BOB/Demos/echo/echoserver/nbproject/project.xml
Normal 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>
|
||||
4
apps/BOB/Demos/echo/echoserver/server.sh
Executable file
4
apps/BOB/Demos/echo/echoserver/server.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
(
|
||||
cd dist
|
||||
java -jar echoserver.jar main 37337 testserver
|
||||
)
|
||||
@@ -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
14
apps/BOB/bob.config
Normal 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
74
apps/BOB/build.xml
Normal 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
3
apps/BOB/manifest.mf
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
642
apps/BOB/nbproject/build-impl.xml
Normal file
642
apps/BOB/nbproject/build-impl.xml
Normal 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 "${ant.java.version}"/>
|
||||
<condition property="have-jdk-older-than-1.4">
|
||||
<or>
|
||||
<contains string="${version-output}" substring="java version "1.0"/>
|
||||
<contains string="${version-output}" substring="java version "1.1"/>
|
||||
<contains string="${version-output}" substring="java version "1.2"/>
|
||||
<contains string="${version-output}" substring="java version "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>
|
||||
8
apps/BOB/nbproject/genfiles.properties
Normal file
8
apps/BOB/nbproject/genfiles.properties
Normal 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
|
||||
7
apps/BOB/nbproject/private/private.properties
Normal file
7
apps/BOB/nbproject/private/private.properties
Normal 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
|
||||
4
apps/BOB/nbproject/private/private.xml
Normal file
4
apps/BOB/nbproject/private/private.xml
Normal 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>
|
||||
107
apps/BOB/nbproject/project.properties
Normal file
107
apps/BOB/nbproject/project.properties
Normal 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
|
||||
16
apps/BOB/nbproject/project.xml
Normal file
16
apps/BOB/nbproject/project.xml
Normal 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>
|
||||
238
apps/BOB/src/net/i2p/BOB/BOB.java
Normal file
238
apps/BOB/src/net/i2p/BOB/BOB.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
apps/BOB/src/net/i2p/BOB/COPYING
Normal file
21
apps/BOB/src/net/i2p/BOB/COPYING
Normal 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.
|
||||
1427
apps/BOB/src/net/i2p/BOB/DoCMDS.java
Normal file
1427
apps/BOB/src/net/i2p/BOB/DoCMDS.java
Normal file
File diff suppressed because it is too large
Load Diff
137
apps/BOB/src/net/i2p/BOB/I2Plistener.java
Normal file
137
apps/BOB/src/net/i2p/BOB/I2Plistener.java
Normal 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.");
|
||||
}
|
||||
}
|
||||
144
apps/BOB/src/net/i2p/BOB/I2PtoTCP.java
Normal file
144
apps/BOB/src/net/i2p/BOB/I2PtoTCP.java
Normal 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");
|
||||
|
||||
}
|
||||
}
|
||||
56
apps/BOB/src/net/i2p/BOB/Lifted.java
Normal file
56
apps/BOB/src/net/i2p/BOB/Lifted.java
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
276
apps/BOB/src/net/i2p/BOB/MUXlisten.java
Normal file
276
apps/BOB/src/net/i2p/BOB/MUXlisten.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
apps/BOB/src/net/i2p/BOB/Main.java
Normal file
46
apps/BOB/src/net/i2p/BOB/Main.java
Normal 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();
|
||||
}
|
||||
}
|
||||
195
apps/BOB/src/net/i2p/BOB/NamedDB.java
Normal file
195
apps/BOB/src/net/i2p/BOB/NamedDB.java
Normal 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;
|
||||
}
|
||||
}
|
||||
105
apps/BOB/src/net/i2p/BOB/TCPio.java
Normal file
105
apps/BOB/src/net/i2p/BOB/TCPio.java
Normal 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.");
|
||||
}
|
||||
}
|
||||
147
apps/BOB/src/net/i2p/BOB/TCPlistener.java
Normal file
147
apps/BOB/src/net/i2p/BOB/TCPlistener.java
Normal 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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
186
apps/BOB/src/net/i2p/BOB/TCPtoI2P.java
Normal file
186
apps/BOB/src/net/i2p/BOB/TCPtoI2P.java
Normal 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.");
|
||||
|
||||
}
|
||||
}
|
||||
144
apps/BOB/src/net/i2p/BOB/UDPIOthread.java
Normal file
144
apps/BOB/src/net/i2p/BOB/UDPIOthread.java
Normal 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;
|
||||
}
|
||||
}
|
||||
5
apps/BOB/src/net/i2p/BOB/package.html
Normal file
5
apps/BOB/src/net/i2p/BOB/package.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>BOB, the Basic Open Bridge, allows TCP applications to talk over I2P.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -36,6 +36,7 @@ import java.io.File;
|
||||
*/
|
||||
public class Daemon {
|
||||
public static final String VERSION = "2.0.3";
|
||||
private static final Daemon _instance = new Daemon();
|
||||
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
@@ -56,7 +57,7 @@ public class Daemon {
|
||||
* @param log
|
||||
* The log to write changes and conflicts to.
|
||||
*/
|
||||
public static void update(AddressBook master, AddressBook router,
|
||||
public void update(AddressBook master, AddressBook router,
|
||||
File published, SubscriptionList subscriptions, Log log) {
|
||||
router.merge(master, true, null);
|
||||
Iterator iter = subscriptions.iterator();
|
||||
@@ -77,7 +78,7 @@ public class Daemon {
|
||||
* @param home
|
||||
* The directory containing addressbook's configuration files.
|
||||
*/
|
||||
public static void update(Map settings, String home) {
|
||||
public void update(Map settings, String home) {
|
||||
File masterFile = new File(home, (String) settings
|
||||
.get("master_addressbook"));
|
||||
File routerFile = new File(home, (String) settings
|
||||
@@ -97,14 +98,15 @@ 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
|
||||
.get("proxy_host"), Integer.parseInt((String) settings.get("proxy_port")));
|
||||
Log log = new Log(logFile);
|
||||
|
||||
Daemon.update(master, router, published, subscriptions, log);
|
||||
update(master, router, published, subscriptions, log);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +120,11 @@ public class Daemon {
|
||||
* others are ignored.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
_instance.run(args);
|
||||
}
|
||||
|
||||
public void run(String[] args) {
|
||||
String settingsLocation = "config.txt";
|
||||
Map settings = new HashMap();
|
||||
String home;
|
||||
if (args.length > 0) {
|
||||
home = args[0];
|
||||
@@ -138,7 +143,7 @@ public class Daemon {
|
||||
defaultSettings.put("subscriptions", "subscriptions.txt");
|
||||
defaultSettings.put("etags", "etags");
|
||||
defaultSettings.put("last_modified", "last_modified");
|
||||
defaultSettings.put("update_delay", "1");
|
||||
defaultSettings.put("update_delay", "12");
|
||||
|
||||
File homeFile = new File(home);
|
||||
if (!homeFile.exists()) {
|
||||
@@ -151,19 +156,37 @@ public class Daemon {
|
||||
|
||||
File settingsFile = new File(homeFile, settingsLocation);
|
||||
|
||||
Map settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
// wait
|
||||
try {
|
||||
Thread.sleep(5*60*1000);
|
||||
// Static method, and redundent Thread.currentThread().sleep(5*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
while (true) {
|
||||
settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
|
||||
long delay = Long.parseLong((String) settings.get("update_delay"));
|
||||
if (delay < 1) {
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
Daemon.update(settings, home);
|
||||
update(settings, home);
|
||||
try {
|
||||
Thread.sleep(delay * 60 * 60 * 1000);
|
||||
synchronized (this) {
|
||||
wait(delay * 60 * 60 * 1000);
|
||||
}
|
||||
} catch (InterruptedException exp) {
|
||||
}
|
||||
settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to get the addressbook to reread its config and
|
||||
* refetch its subscriptions.
|
||||
*/
|
||||
public static void wakeup() {
|
||||
synchronized (_instance) {
|
||||
_instance.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,12 @@ public class DaemonThread extends Thread {
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5 * 60 * 1000);
|
||||
} catch (InterruptedException exp) {
|
||||
}
|
||||
//try {
|
||||
// Thread.sleep(5 * 60 * 1000);
|
||||
//} catch (InterruptedException exp) {
|
||||
//}
|
||||
Daemon.main(this.args);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.duck.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.duck.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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/>.
|
||||
*
|
||||
*/
|
||||
@@ -1 +0,0 @@
|
||||
java -cp .;log4j-1.2.8.jar;pircbot.jar Bogobot
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
java -cp .:log4j-1.2.8.jar:pircbot.jar Bogobot
|
||||
@@ -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 'dist'." />
|
||||
</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>
|
||||
@@ -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 'dist'." />
|
||||
</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.
@@ -1,39 +0,0 @@
|
||||
The Heartbeat GUI loads up the stat files generated by the Heartbeat
|
||||
engine and renders them visually, offering a way to drill through different
|
||||
data points and take snapshots as things change (by saving particular stat
|
||||
files for later). The GUI itself doesn't need to be on the same machine
|
||||
as the Heartbeat engine - it pulls the stat files through any URL - even
|
||||
through the EepProxy.
|
||||
|
||||
An example Heartbeat GUI config file follows
|
||||
|
||||
# how often do we want to pull new data to render
|
||||
refreshFrequency=60
|
||||
## for each peer test we may want to include in the GUI:
|
||||
# where to find the current stat file (URL or filename)
|
||||
stat.0.location=http://dev.i2p.net/stats/heartbeatStat_khWY_30s_1kb.txt
|
||||
## optional entries for each peer test describing what we want shown
|
||||
## (and how we want it shown)
|
||||
# do we want to plot the send time (from when the ping was sent until the pong server got it)?
|
||||
stat.0.plot.current.send=true
|
||||
# do we want to plot the receive time (from when the pong was sent until reception)?
|
||||
stat.0.plot.current.receive=true
|
||||
# do we want to plot the lost messages?
|
||||
stat.0.plot.current.lost=true
|
||||
# what color should the current lines be rendered in?
|
||||
stat.0.plot.current.color=BLUE
|
||||
## optional entries for each peer test describing what averages we want
|
||||
## rendered
|
||||
# plot 1 minute send average?
|
||||
stat.0.plot.1m.send=true
|
||||
# plot 1 minute receive average?
|
||||
stat.0.plot.1m.receive=true
|
||||
# plot 1 minute lost message average?
|
||||
stat.0.plot.1m.lost=true
|
||||
# what color should the 1 minute averages be rendered as?
|
||||
stat.0.plot.1m.color=GREEN
|
||||
## repeated for all of the averaged periods, e.g.
|
||||
## stat.0.plot.30m, .60m, 1440m (1 day)
|
||||
|
||||
There may be some other options, such as where to store snapshot files, whether
|
||||
to generate PNG images, etc.
|
||||
@@ -1,122 +0,0 @@
|
||||
Heartbeat
|
||||
|
||||
Application layer tool for monitoring the long term health of the
|
||||
network by periodically testing peers, generating stats, and
|
||||
rendering them visually. The engine (both server and client) should
|
||||
work headless and seperate from the GUI, exposing the data in a simple
|
||||
to parse (and human readable) text file for each peer being tested.
|
||||
The GUI then periodically refreshes itself by loading those files (
|
||||
either locally or from a URL) and renders the current state accordingly,
|
||||
giving users a way to check that the network is alive, devs a tool to
|
||||
both monitor the state of the network and to debug different situations (by
|
||||
accessing the stat file - either live or archived).
|
||||
|
||||
The heartbeat configuration file is organized as a standard properties
|
||||
file (by default located at heartbeat.config, but that can be overridden by
|
||||
passing a filename as the first argument to the Heartbeat command):
|
||||
|
||||
# where the router is located (default is localhost)
|
||||
i2cpHost=localhost
|
||||
# I2CP port for the router (default is 7654)
|
||||
i2cpPort=4001
|
||||
# How many hops we want the router to put in our tunnels (default is 2)
|
||||
numHops=2
|
||||
# where our private destination keys are located - if this doesn't exist,
|
||||
# a new one will be created and saved there (by default, heartbeat.keys)
|
||||
privateDestinationFile=heartbeat_r2.keys
|
||||
|
||||
## peer tests configured below:
|
||||
|
||||
# destination peer for test 0
|
||||
peer.0.peer=[destination in base64]
|
||||
# where will we write out the stat data?
|
||||
peer.0.statFile=heartbeatStat_khWY_30s_1kb.txt
|
||||
# how many minutes will we keep stats for?
|
||||
peer.0.statDuration=30
|
||||
# how often will we write out new stat data (in seconds)?
|
||||
peer.0.statFrequency=60
|
||||
# how often will we send a ping to the peer (in seconds)?
|
||||
peer.0.sendFrequency=30
|
||||
# how many bytes will be included in the ping?
|
||||
peer.0.sendSize=1024
|
||||
# take a guess...
|
||||
peer.0.comment=Test with localhost sending 1KB of data every 30 seconds
|
||||
# we can keep track of a few moving averages - this value includes a whitespace
|
||||
# delimited list of numbers, each specifying a period to calculate the average
|
||||
# over (in minutes)
|
||||
peer.0.averagePeriods=1 5 30
|
||||
## repeat the peer.0.* for as many tests as desired, incrementing as necessary
|
||||
|
||||
If there are no peer.* lines, it will simply run a pong server. If any data is
|
||||
missing, it will use the defaults (though there are no defaults for peer.* lines) -
|
||||
running the Heartbeat app with no heartbeat configuration file whatsoever will create
|
||||
a new pong server (storing its keys at heartbeat.keys) and using the I2P router at
|
||||
localhost:7654.
|
||||
|
||||
The stat file generated for each set of peer.n.* lines contains the current state
|
||||
of the test, its averages, as well as any other interesting data points. An example
|
||||
stat file follows (hopefully it is self explanatory):
|
||||
|
||||
peer khWYqCETu9YtPUvGV92ocsbEW5DezhKlIG7ci8RLX3g=
|
||||
local u-9hlR1ik2hemXf0HvKMfeRgrS86CbNQh25e7XBhaQE=
|
||||
peerDest [base 64 of the full destination]
|
||||
localDest [base 64 of the full destination]
|
||||
numTunnelHops 2
|
||||
comment Test with localhost sending 30KB every 20 seconds
|
||||
sendFrequency 20
|
||||
sendSize 30720
|
||||
sessionStart 20040409.22:51:10.915
|
||||
currentTime 20040409.23:31:39.607
|
||||
numPending 2
|
||||
lifetimeSent 118
|
||||
lifetimeRecv 113
|
||||
#averages minutes sendMs recvMs numLost
|
||||
periodAverage 1 1843 771 0
|
||||
periodAverage 5 786 752 1
|
||||
periodAverage 30 855 735 3
|
||||
#action status date and time sent sendMs replyMs
|
||||
EVENT OK 20040409.23:21:44.742 691 670
|
||||
EVENT OK 20040409.23:22:05.201 671 581
|
||||
EVENT OK 20040409.23:22:26.301 1182 1452
|
||||
EVENT OK 20040409.23:22:47.322 24304 1723
|
||||
EVENT OK 20040409.23:23:08.232 2293 1081
|
||||
EVENT OK 20040409.23:23:29.332 1392 641
|
||||
EVENT OK 20040409.23:23:50.262 641 761
|
||||
EVENT OK 20040409.23:24:11.102 651 701
|
||||
EVENT OK 20040409.23:24:31.401 841 621
|
||||
EVENT OK 20040409.23:24:52.061 651 681
|
||||
EVENT OK 20040409.23:25:12.480 701 1623
|
||||
EVENT OK 20040409.23:25:32.990 1442 1212
|
||||
EVENT OK 20040409.23:25:54.230 591 631
|
||||
EVENT OK 20040409.23:26:14.620 620 691
|
||||
EVENT OK 20040409.23:26:35.199 1793 1432
|
||||
EVENT OK 20040409.23:26:56.570 661 641
|
||||
EVENT OK 20040409.23:27:17.200 641 660
|
||||
EVENT OK 20040409.23:27:38.120 611 921
|
||||
EVENT OK 20040409.23:27:58.699 831 621
|
||||
EVENT OK 20040409.23:28:19.559 801 661
|
||||
EVENT OK 20040409.23:28:40.279 601 611
|
||||
EVENT OK 20040409.23:29:00.648 601 621
|
||||
EVENT OK 20040409.23:29:21.288 701 661
|
||||
EVENT LOST 20040409.23:29:41.828
|
||||
EVENT LOST 20040409.23:30:02.327
|
||||
EVENT LOST 20040409.23:30:22.656
|
||||
EVENT OK 20040409.23:31:24.305 1843 771
|
||||
|
||||
The actual ping and pong messages sent are formatted trivially -
|
||||
ping messages contain
|
||||
$from $series $type $sentOn $size $payload
|
||||
while pong messages contain
|
||||
$from $series $type $sentOn $receivedOn $size $payload
|
||||
|
||||
$series is a number describing the sending client's test (so that you can
|
||||
ping the same peer with different configurations concurrently, varying things
|
||||
like the frequency and size of the message, window, etc).
|
||||
|
||||
They are sent as raw binary messages though, so see I2PAdapter.sendPing(..)
|
||||
and I2PAdapter.sendPong(..) for the details.
|
||||
|
||||
To get valid measurements, of course, you will want to make sure that
|
||||
both the heartbeat client and pong server have synchronized clocks (even
|
||||
more so than I2P requires). It is highly recommended that only NTP
|
||||
synchronized peers be used for heartbeat tests.
|
||||
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="heartbeat">
|
||||
<target name="all" depends="clean, buildGUI" />
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="buildGUI" depends="build, jarGUI" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../../core/java/" target="build" />
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac srcdir="./src" debug="true" deprecation="on" source="1.3" target="1.3" destdir="./build/obj" includes="**/*.java" excludes="net/i2p/heartbeat/gui/**" classpath="../../../core/java/build/i2p.jar" />
|
||||
</target>
|
||||
<target name="compileGUI">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac debug="true" source="1.3" target="1.3" deprecation="on" destdir="./build/obj">
|
||||
<src path="src/" />
|
||||
<classpath path="../../../core/java/build/i2p.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/lib/log4j-1.2.8.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/jfreechart-0.9.17.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="./build/heartbeat.jar" basedir="./build/obj" includes="**/*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.heartbeat.Heartbeat" />
|
||||
<attribute name="Class-Path" value="i2p.jar heartbeat.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="jarGUI" depends="compileGUI">
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/jfreechart-0.9.17.jar" todir="build/" />
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/lib/log4j-1.2.8.jar" todir="build/" />
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" todir="build/" />
|
||||
<jar destfile="./build/heartbeatGUI.jar" basedir="./build/obj" includes="**">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.heartbeat.gui.HeartbeatMonitor" />
|
||||
<attribute name="Class-Path" value="log4j-1.2.8.jar jcommon-0.9.2.jar jfreechart-0.9.17.jar heartbeatGUI.jar i2p.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
<echo message="You will need to copy the log4j, jcommon, and jfreechart jar files into your lib dir" />
|
||||
</target>
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc
|
||||
sourcepath="./src:../../../core/java/src:../../../core/java/test" destdir="./build/javadoc"
|
||||
packagenames="*"
|
||||
use="true"
|
||||
access="package"
|
||||
splitindex="true"
|
||||
windowtitle="I2P heartbeat monitor" />
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<ant dir="../../../core/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,468 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Define the configuration for testing against one particular peer as a client
|
||||
*/
|
||||
public class ClientConfig {
|
||||
private static final Log _log = new Log(ClientConfig.class);
|
||||
private Destination _peer;
|
||||
private Destination _us;
|
||||
private String _statFile;
|
||||
private int _statDuration;
|
||||
private int _statFrequency;
|
||||
private int _sendFrequency;
|
||||
private int _sendSize;
|
||||
private int _numHops;
|
||||
private String _comment;
|
||||
private int _averagePeriods[];
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_PREFIX = "peer.";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_PEER = ".peer";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATFILE = ".statFile";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATDURATION = ".statDuration";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATFREQUENCY = ".statFrequency";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_SENDFREQUENCY = ".sendFrequency";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_SENDSIZE = ".sendSize";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_COMMENT = ".comment";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_AVERAGEPERIODS = ".averagePeriods";
|
||||
|
||||
/**
|
||||
* Default constructor...
|
||||
*/
|
||||
public ClientConfig() {
|
||||
this(null, null, null, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dummy client config to be fetched from the specified location
|
||||
* @param location the location to fetch from
|
||||
*/
|
||||
public ClientConfig(String location) {
|
||||
this(null, null, location, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param peer who we will test against
|
||||
* @param us who we are
|
||||
* @param statLocation where the stat data should be stored/fetched
|
||||
* @param duration how many minutes to keep events for
|
||||
* @param statFreq how often to write out stats
|
||||
* @param sendFreq how often to send pings
|
||||
* @param sendSize how large the pings should be
|
||||
* @param numHops how many hops is the current Heartbeat app using
|
||||
* @param comment describe this test
|
||||
* @param averagePeriods list of minutes to summarize over
|
||||
*/
|
||||
public ClientConfig(Destination peer, Destination us, String statLocation, int duration, int statFreq, int sendFreq,
|
||||
int sendSize, int numHops, String comment, int averagePeriods[]) {
|
||||
_peer = peer;
|
||||
_us = us;
|
||||
_statFile = statLocation;
|
||||
_statDuration = duration;
|
||||
_statFrequency = statFreq;
|
||||
_sendFrequency = sendFreq;
|
||||
_sendSize = sendSize;
|
||||
_numHops = numHops;
|
||||
_comment = comment;
|
||||
_averagePeriods = averagePeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the peer to test against
|
||||
*
|
||||
* @return the Destination (peer)
|
||||
*/
|
||||
public Destination getPeer() {
|
||||
return _peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the peer to test against
|
||||
*
|
||||
* @param peer the Destination (peer)
|
||||
*/
|
||||
public void setPeer(Destination peer) {
|
||||
_peer = peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves who we are when we test
|
||||
*
|
||||
* @return the Destination (us)
|
||||
*/
|
||||
public Destination getUs() {
|
||||
return _us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets who we are when we test
|
||||
*
|
||||
* @param us the Destination (us)
|
||||
*/
|
||||
public void setUs(Destination us) {
|
||||
_us = us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the location to write the current stats to
|
||||
*
|
||||
* @return the name of the file
|
||||
*/
|
||||
public String getStatFile() {
|
||||
return _statFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the location we write the current stats to
|
||||
*
|
||||
* @param statFile the name of the file
|
||||
*/
|
||||
public void setStatFile(String statFile) {
|
||||
_statFile = statFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many minutes of statistics should be maintained within the window for this client
|
||||
*
|
||||
* @return the number of minutes
|
||||
*/
|
||||
public int getStatDuration() {
|
||||
return _statDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many minutes of statistics should be maintained within the window for this client
|
||||
*
|
||||
* @param durationMinutes the number of minutes
|
||||
*/
|
||||
public void setStatDuration(int durationMinutes) {
|
||||
_statDuration = durationMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how frequently the stats are written out (in seconds)
|
||||
*
|
||||
* @return the frequency in seconds
|
||||
*/
|
||||
public int getStatFrequency() {
|
||||
return _statFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how frequently the stats are written out (in seconds)
|
||||
*
|
||||
* @param freqSeconds the frequency in seconds
|
||||
*/
|
||||
public void setStatFrequency(int freqSeconds) {
|
||||
_statFrequency = freqSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how frequenty we send messages to the peer (in seconds)
|
||||
*
|
||||
* @return the frequency in seconds
|
||||
*/
|
||||
public int getSendFrequency() {
|
||||
return _sendFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how frequenty we send messages to the peer (in seconds)
|
||||
*
|
||||
* @param freqSeconds the frequency in seconds
|
||||
*/
|
||||
public void setSendFrequency(int freqSeconds) {
|
||||
_sendFrequency = freqSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many bytes the ping messages should be (min values ~700, max ~32KB)
|
||||
*
|
||||
* @return the size in bytes
|
||||
*/
|
||||
public int getSendSize() {
|
||||
return _sendSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many bytes the ping messages should be (min values ~700, max ~32KB)
|
||||
*
|
||||
* @param numBytes the size in bytes
|
||||
*/
|
||||
public void setSendSize(int numBytes) {
|
||||
_sendSize = numBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the brief, 1 line description of the test. Useful comments are along the lines of "The peer is located on a fast router and connection with 2
|
||||
* hop tunnels".
|
||||
*
|
||||
* @return the brief comment
|
||||
*/
|
||||
public String getComment() {
|
||||
return _comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a brief, 1 line description (comment) of the test.
|
||||
*
|
||||
* @param comment the brief comment
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
_comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the periods that the client's tests should be averaged over.
|
||||
*
|
||||
* @return list of periods (in minutes) that the data should be averaged over, or null
|
||||
*/
|
||||
public int[] getAveragePeriods() {
|
||||
return _averagePeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the periods that the client's tests should be averaged over.
|
||||
*
|
||||
* @param periods the list of periods (in minutes) that the data should be averaged over, or null
|
||||
*/
|
||||
public void setAveragePeriods(int periods[]) {
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we're keeping track of the average over the given time period.
|
||||
*
|
||||
* @param minutes how many minutes to monitor
|
||||
*/
|
||||
public void addAveragePeriod(int minutes) {
|
||||
if (_averagePeriods != null) {
|
||||
for (int i = 0; i < _averagePeriods.length; i++) {
|
||||
if (_averagePeriods[i] == minutes)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int numPeriods = 1;
|
||||
if (_averagePeriods != null)
|
||||
numPeriods += _averagePeriods.length;
|
||||
int periods[] = new int[numPeriods];
|
||||
if (_averagePeriods != null)
|
||||
System.arraycopy(_averagePeriods, 0, periods, 0, _averagePeriods.length);
|
||||
periods[periods.length-1] = minutes;
|
||||
Arrays.sort(periods);
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many hops this test engine is configured to use for its outbound and inbound tunnels
|
||||
*
|
||||
* @return the number of hops
|
||||
*/
|
||||
public int getNumHops() {
|
||||
return _numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many hops this test engine is configured to use for its outbound and inbound tunnels
|
||||
*
|
||||
* @param numHops the number of hops
|
||||
*/
|
||||
public void setNumHops(int numHops) {
|
||||
_numHops = numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the client config from the properties specified, deriving the current config entry from the peer number.
|
||||
*
|
||||
* @param clientConfig the properties to load from
|
||||
* @param peerNum the number associated with the peer
|
||||
* @return true if it was loaded correctly, false if there were errors
|
||||
*/
|
||||
public boolean load(Properties clientConfig, int peerNum) {
|
||||
if ((clientConfig == null) || (peerNum < 0)) return false;
|
||||
String peerVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_PEER);
|
||||
String statFileVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATFILE);
|
||||
String statDurationVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATDURATION);
|
||||
String statFrequencyVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATFREQUENCY);
|
||||
String sendFrequencyVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_SENDFREQUENCY);
|
||||
String sendSizeVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_SENDSIZE);
|
||||
String commentVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_COMMENT);
|
||||
String periodsVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_AVERAGEPERIODS);
|
||||
|
||||
if ((peerVal == null) || (statFileVal == null) || (statDurationVal == null) || (statFrequencyVal == null)
|
||||
|| (sendFrequencyVal == null) || (sendSizeVal == null)) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Peer number " + peerNum + " does not exist");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
int duration = getInt(statDurationVal);
|
||||
int statFreq = getInt(statFrequencyVal);
|
||||
int sendFreq = getInt(sendFrequencyVal);
|
||||
int sendSize = getInt(sendSizeVal);
|
||||
|
||||
if ((duration <= 0) || (statFreq <= 0) || (sendFreq < 0) || (sendSize <= 0)) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid client config: duration [" + statDurationVal + "] stat frequency ["
|
||||
+ statFrequencyVal + "] send frequency [" + sendFrequencyVal + "] send size ["
|
||||
+ sendSizeVal + "]");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
statFileVal = statFileVal.trim();
|
||||
if (statFileVal.length() <= 0) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Stat file is blank for peer " + peerNum);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(peerVal);
|
||||
|
||||
if (commentVal == null) {
|
||||
commentVal = "";
|
||||
}
|
||||
|
||||
commentVal = commentVal.trim();
|
||||
commentVal = commentVal.replace('\n', '_');
|
||||
|
||||
List periods = new ArrayList(4);
|
||||
if (periodsVal != null) {
|
||||
StringTokenizer tok = new StringTokenizer(periodsVal);
|
||||
while (tok.hasMoreTokens()) {
|
||||
String periodVal = tok.nextToken();
|
||||
int minutes = getInt(periodVal);
|
||||
if (minutes > 0) {
|
||||
periods.add(new Integer(minutes));
|
||||
}
|
||||
}
|
||||
}
|
||||
int avgPeriods[] = new int[periods.size()];
|
||||
for (int i = 0; i < periods.size(); i++) {
|
||||
avgPeriods[i] = ((Integer) periods.get(i)).intValue();
|
||||
}
|
||||
|
||||
_comment = commentVal;
|
||||
_statDuration = duration;
|
||||
_statFrequency = statFreq;
|
||||
_sendFrequency = sendFreq;
|
||||
_sendSize = sendSize;
|
||||
_statFile = statFileVal;
|
||||
_peer = d;
|
||||
_averagePeriods = avgPeriods;
|
||||
return true;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Peer destination for " + peerNum + " was invalid: " + peerVal);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the client config to the properties specified, deriving the current config entry from the peer number.
|
||||
*
|
||||
* @param clientConfig the properties to store to
|
||||
* @param peerNum the number associated with the peer
|
||||
* @return true if it was stored correctly, false if there were errors
|
||||
*/
|
||||
public boolean store(Properties clientConfig, int peerNum) {
|
||||
if ((_peer == null) || (_sendFrequency < 0) || (_sendSize <= 0) || (_statDuration <= 0)
|
||||
|| (_statFrequency <= 0) || (_statFile == null)) { return false; }
|
||||
|
||||
String comment = _comment;
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
|
||||
comment = comment.trim();
|
||||
comment = comment.replace('\n', '_');
|
||||
|
||||
StringBuffer buf = new StringBuffer(32);
|
||||
if (_averagePeriods != null) {
|
||||
for (int i = 0; i < _averagePeriods.length; i++) {
|
||||
buf.append(_averagePeriods[i]).append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_PEER, _peer.toBase64());
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATFILE, _statFile);
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATDURATION, _statDuration + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATFREQUENCY, _statFrequency + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_SENDFREQUENCY, _sendFrequency + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_SENDSIZE, _sendSize + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_COMMENT, comment);
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_AVERAGEPERIODS, buf.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final int getInt(String val) {
|
||||
if (val == null) return -1;
|
||||
try {
|
||||
int i = Integer.parseInt(val);
|
||||
return i;
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Value [" + val + "] is not a valid integer");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Responsible for actually conducting the tests, coordinating the storing of the
|
||||
* stats, and the management of the rates. This has its own thread specific for
|
||||
* pumping data around as well.
|
||||
*
|
||||
*/
|
||||
class ClientEngine {
|
||||
private static final Log _log = new Log(ClientEngine.class);
|
||||
/** who can send our pings? */
|
||||
private Heartbeat _heartbeat;
|
||||
/** actual test state */
|
||||
private PeerData _data;
|
||||
/** have we been stopped? */
|
||||
private boolean _active;
|
||||
/** used to generate engine IDs */
|
||||
private static int __id = 0;
|
||||
/** this engine's id, unique to the {test,sendingClient,startTime} */
|
||||
private int _id;
|
||||
private static PeerDataWriter writer = new PeerDataWriter();
|
||||
|
||||
/**
|
||||
* Create a new engine that will send its pings through the given heartbeat
|
||||
* system, and will coordinate the test according to the configuration specified.
|
||||
* @param heartbeat the Heartbeat to send pings through
|
||||
* @param config the Configuration to load configuration from =p
|
||||
*/
|
||||
public ClientEngine(Heartbeat heartbeat, ClientConfig config) {
|
||||
_heartbeat = heartbeat;
|
||||
_data = new PeerData(config);
|
||||
_active = false;
|
||||
_id = ++__id;
|
||||
}
|
||||
|
||||
/** stop sending any more pings or writing any more state */
|
||||
public void stopEngine() {
|
||||
_active = false;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Stopping engine talking to peer " + _data.getConfig().getPeer().calculateHash().toBase64());
|
||||
}
|
||||
|
||||
/** start up the test (this does not block, as it fires up the test thread) */
|
||||
public void startEngine() {
|
||||
_active = true;
|
||||
I2PThread t = new I2PThread(new ClientRunner());
|
||||
t.setName("HeartbeatClient " + _id);
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Who are we testing?
|
||||
* @return the Destination (peer) we're testing
|
||||
*/
|
||||
public Destination getPeer() {
|
||||
return _data.getConfig().getPeer();
|
||||
}
|
||||
|
||||
/**
|
||||
* What is our series identifier (used to locally identify a test)
|
||||
* @return the series identifier
|
||||
*/
|
||||
public int getSeriesNum() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive notification from the heartbeat system that a pong was received in
|
||||
* reply to a ping we have sent.
|
||||
*
|
||||
* @param sentOn when did we send the ping?
|
||||
* @param replyOn when did the peer send the pong?
|
||||
*/
|
||||
public void receivePong(long sentOn, long replyOn) {
|
||||
_data.pongReceived(sentOn, replyOn);
|
||||
}
|
||||
|
||||
/** fire off a new ping */
|
||||
private void doSend() {
|
||||
long now = Clock.getInstance().now();
|
||||
_data.addPing(now);
|
||||
_heartbeat.sendPing(_data.getConfig().getPeer(), _id, now, _data.getConfig().getSendSize());
|
||||
}
|
||||
|
||||
/** our actual heartbeat pumper - this drives the test */
|
||||
private class ClientRunner implements Runnable {
|
||||
|
||||
/**
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting engine talking to peer " + _data.getConfig().getPeer().calculateHash().toBase64());
|
||||
|
||||
// when do we need to send the next PING?
|
||||
long nextSend = Clock.getInstance().now();
|
||||
// when do we need to write out the next state data?
|
||||
long nextWrite = Clock.getInstance().now();
|
||||
|
||||
while (_active) {
|
||||
|
||||
if (Clock.getInstance().now() >= nextSend) {
|
||||
doSend();
|
||||
nextSend = Clock.getInstance().now() + _data.getConfig().getSendFrequency() * 1000;
|
||||
}
|
||||
|
||||
if (Clock.getInstance().now() >= nextWrite) {
|
||||
boolean written = writer.persist(_data);
|
||||
if (!written) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Unable to write the client state data");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Client state data written");
|
||||
}
|
||||
}
|
||||
|
||||
_data.cleanup();
|
||||
|
||||
long timeToWait = nextSend - Clock.getInstance().now();
|
||||
if (timeToWait > 0) {
|
||||
try {
|
||||
Thread.sleep(timeToWait);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Main driver for the heartbeat engine, loading 0 or more tests, firing
|
||||
* up a ClientEngine for each, and serving as a pong server. If there isn't
|
||||
* a configuration file, or if the configuration file doesn't specify any tests,
|
||||
* it simply sits around as a pong server, passively responding to whatever is
|
||||
* sent its way. <p />
|
||||
*
|
||||
* The config file format is examplified below:
|
||||
* <pre>
|
||||
* # where the router is located (default is localhost)
|
||||
* i2cpHost=localhost
|
||||
* # I2CP port for the router (default is 7654)
|
||||
* i2cpPort=4001
|
||||
* # How many hops we want the router to put in our tunnels (default is 2)
|
||||
* numHops=2
|
||||
* # where our private destination keys are located - if this doesn't exist,
|
||||
* # a new one will be created and saved there (by default, heartbeat.keys)
|
||||
* privateDestinationFile=heartbeat_r2.keys
|
||||
* # where do we want to export the plain base64 of our destination?
|
||||
* publicDestinationFile=heartbeat_r2.txt
|
||||
*
|
||||
* ## peer tests configured below:
|
||||
*
|
||||
* # destination peer for test 0
|
||||
* peer.0.peer=[destination in base64]
|
||||
* # where will we write out the stat data?
|
||||
* peer.0.statFile=heartbeatStat_khWY_30s_1kb.txt
|
||||
* # how many minutes will we keep stats for?
|
||||
* peer.0.statDuration=30
|
||||
* # how often will we write out new stat data (in seconds)?
|
||||
* peer.0.statFrequency=60
|
||||
* # how often will we send a ping to the peer (in seconds)?
|
||||
* peer.0.sendFrequency=30
|
||||
* # how many bytes will be included in the ping?
|
||||
* peer.0.sendSize=1024
|
||||
* # take a guess...
|
||||
* peer.0.comment=Test with localhost sending 1KB of data every 30 seconds
|
||||
* # we can keep track of a few moving averages - this value includes a whitespace
|
||||
* # delimited list of numbers, each specifying a period to calculate the average
|
||||
* # over (in minutes)
|
||||
* peer.0.averagePeriods=1 5 30
|
||||
* ## repeat the peer.0.* for as many tests as desired, incrementing as necessary
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class Heartbeat {
|
||||
private static final Log _log = new Log(Heartbeat.class);
|
||||
/** location containing this heartbeat's config */
|
||||
private String _configFile;
|
||||
/** clientNum (Integer) to ClientConfig mapping */
|
||||
private Map _clientConfigs;
|
||||
/** series num (Integer) to ClientEngine mapping */
|
||||
private Map _clientEngines;
|
||||
/** helper class for managing our I2P send/receive and message formatting */
|
||||
private I2PAdapter _adapter;
|
||||
/** our own callback that the I2PAdapter notifies on ping or pong messages */
|
||||
private PingPongAdapter _eventAdapter;
|
||||
|
||||
/** if there are no command line arguments, load the config from "heartbeat.config" */
|
||||
public static final String CONFIG_FILE_DEFAULT = "heartbeat.config";
|
||||
|
||||
/**
|
||||
* build up a new heartbeat manager, but don't actually do anything
|
||||
* @param configFile the name of the configuration file
|
||||
*/
|
||||
public Heartbeat(String configFile) {
|
||||
_configFile = configFile;
|
||||
_clientConfigs = new HashMap();
|
||||
_clientEngines = new HashMap();
|
||||
_eventAdapter = new PingPongAdapter();
|
||||
_adapter = new I2PAdapter();
|
||||
_adapter.setListener(_eventAdapter);
|
||||
}
|
||||
|
||||
private Heartbeat() {
|
||||
}
|
||||
|
||||
/** load up the config data (but don't build any engines or start them up) */
|
||||
public void loadConfig() {
|
||||
Properties props = new Properties();
|
||||
FileInputStream fin = null;
|
||||
File configFile = new File(_configFile);
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
fin = new FileInputStream(_configFile);
|
||||
props.load(fin);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error reading the config data", ioe);
|
||||
}
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadBaseConfig(props);
|
||||
loadClientConfigs(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* send a ping message to the peer
|
||||
*
|
||||
* @param peer peer to ping
|
||||
* @param seriesNum id used to keep track of multiple pings (of different size/frequency) to a peer
|
||||
* @param now current time to be sent in the ping (so we can watch for it in the pong)
|
||||
* @param size total message size to send
|
||||
*/
|
||||
void sendPing(Destination peer, int seriesNum, long now, int size) {
|
||||
if (_adapter.getIsConnected()) _adapter.sendPing(peer, seriesNum, now, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* load up the base data (I2CP config, etc)
|
||||
* @param props the properties to load from
|
||||
*/
|
||||
private void loadBaseConfig(Properties props) {
|
||||
_adapter.loadConfig(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* load up all of the test config data
|
||||
* @param props the properties to load from
|
||||
* */
|
||||
private void loadClientConfigs(Properties props) {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ClientConfig config = new ClientConfig();
|
||||
if (!config.load(props, i)) {
|
||||
break;
|
||||
}
|
||||
_clientConfigs.put(new Integer(i), config);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/** connect to the network */
|
||||
private void connect() {
|
||||
boolean connected = _adapter.connect();
|
||||
if (!connected) _log.error("Unable to connect to the router");
|
||||
}
|
||||
|
||||
/** disconnect from the network */
|
||||
private void disconnect() { /* UNUSED */
|
||||
_adapter.disconnect();
|
||||
}
|
||||
|
||||
/** start up all of the tests */
|
||||
public void startEngines() {
|
||||
for (Iterator iter = _clientConfigs.values().iterator(); iter.hasNext();) {
|
||||
ClientConfig config = (ClientConfig) iter.next();
|
||||
ClientEngine engine = new ClientEngine(this, config);
|
||||
config.setUs(_adapter.getLocalDestination());
|
||||
config.setNumHops(_adapter.getNumHops());
|
||||
_clientEngines.put(new Integer(engine.getSeriesNum()), engine);
|
||||
engine.startEngine();
|
||||
}
|
||||
}
|
||||
|
||||
/** stop all of the tests */
|
||||
public void stopEngines() {
|
||||
for (Iterator iter = _clientEngines.values().iterator(); iter.hasNext();) {
|
||||
ClientEngine engine = (ClientEngine) iter.next();
|
||||
engine.stopEngine();
|
||||
}
|
||||
_clientEngines.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire up a new heartbeat system, waiting until, well, forever. Builds
|
||||
* a new heartbeat system, loads the config, connects to the network, starts
|
||||
* the engines, and then sits back and relaxes, responding to any pings and
|
||||
* running any tests. <p />
|
||||
*
|
||||
* <code> <b>Usage: </b> Heartbeat [<i>configFileName</i>]</code> <p />
|
||||
* @param args the list of args passed to the program from the command-line
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
String configFile = CONFIG_FILE_DEFAULT;
|
||||
if (args.length == 1) {
|
||||
configFile = args[0];
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Starting up with config file " + configFile);
|
||||
}
|
||||
Heartbeat heartbeat = new Heartbeat(configFile);
|
||||
heartbeat.loadConfig();
|
||||
heartbeat.connect();
|
||||
heartbeat.startEngines();
|
||||
Object o = new Object();
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (o) {
|
||||
o.wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive event notification from the I2PAdapter
|
||||
*
|
||||
*/
|
||||
private class PingPongAdapter implements I2PAdapter.PingPongEventListener {
|
||||
/**
|
||||
* We were pinged, so always just send a pong back.
|
||||
*
|
||||
* @param from who sent us the ping?
|
||||
* @param seriesNum what series did the sender specify?
|
||||
* @param sentOn when did the sender say they sent their ping?
|
||||
* @param data arbitrary payload data
|
||||
*/
|
||||
public void receivePing(Destination from, int seriesNum, Date sentOn, byte[] data) {
|
||||
if (_adapter.getIsConnected()) {
|
||||
_adapter.sendPong(from, seriesNum, sentOn, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We received a pong, so find the right client engine and tell it about the pong.
|
||||
*
|
||||
* @param from who sent us the pong
|
||||
* @param seriesNum our client ID
|
||||
* @param sentOn when did we send the ping?
|
||||
* @param replyOn when did they send their pong?
|
||||
* @param data the arbitrary data we sent in the ping (that they sent back in the pong)
|
||||
*/
|
||||
public void receivePong(Destination from, int seriesNum, Date sentOn, Date replyOn, byte[] data) {
|
||||
ClientEngine engine = (ClientEngine) _clientEngines.get(new Integer(seriesNum));
|
||||
if (engine.getPeer().equals(from)) {
|
||||
engine.receivePong(sentOn.getTime(), replyOn.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,604 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Tie-in to the I2P SDK for the Heartbeat system, talking to the I2PSession and
|
||||
* dealing with the raw ping and pong messages.
|
||||
*
|
||||
*/
|
||||
class I2PAdapter {
|
||||
private final static Log _log = new Log(I2PAdapter.class);
|
||||
/** I2CP host */
|
||||
private String _i2cpHost;
|
||||
/** I2CP port */
|
||||
private int _i2cpPort;
|
||||
/** how long do we want our tunnels to be? */
|
||||
private int _numHops;
|
||||
/** filename containing the heartbeat engine's private destination info */
|
||||
private String _privateDestFile;
|
||||
/** filename to store the heartbeat engine's public destination in base64*/
|
||||
private String _publicDestFile;
|
||||
/** our destination */
|
||||
private Destination _localDest;
|
||||
/** who do we tell? */
|
||||
private PingPongEventListener _listener;
|
||||
/** how do we talk to the router */
|
||||
private I2PSession _session;
|
||||
/** object that receives our i2cp notifications from the session and tells us */
|
||||
private I2PListener _i2pListener; /* UNUSED */
|
||||
|
||||
/**
|
||||
* This config property tells us where the private destination data for our
|
||||
* connection (or if it doesn't exist, where will we save it)
|
||||
*/
|
||||
private static final String DEST_FILE_PROP = "privateDestinationFile";
|
||||
/** by default, the private destination data is in "heartbeat.keys" */
|
||||
private static final String DEST_FILE_DEFAULT = "heartbeat.keys";
|
||||
/** where will we export the public destination in base 64? */
|
||||
private static final String PUBLIC_DEST_FILE_PROP = "publicDestinationFile";
|
||||
/** where will we export the public destination in base 64? */
|
||||
private static final String PUBLIC_DEST_FILE_DEFAULT = "heartbeat.txt";
|
||||
/** This config property defines where the I2P router is */
|
||||
private static final String I2CP_HOST_PROP = "i2cpHost";
|
||||
/** by default, the I2P host is "localhost" */
|
||||
private static final String I2CP_HOST_DEFAULT = "localhost";
|
||||
/** This config property defines the I2CP port on the router */
|
||||
private static final String I2CP_PORT_PROP = "i2cpPort";
|
||||
/** by default, the I2CP port is 7654 */
|
||||
private static final int I2CP_PORT_DEFAULT = 7654;
|
||||
|
||||
/** This property defines how many hops we want in our tunnels. */
|
||||
public static final String NUMHOPS_PROP = "numHops";
|
||||
/** by default, use 2 hop tunnels */
|
||||
public static final int NUMHOPS_DEFAULT = 2;
|
||||
|
||||
/**
|
||||
* Constructs an I2PAdapter . . .
|
||||
*/
|
||||
public I2PAdapter() {
|
||||
_privateDestFile = null;
|
||||
_publicDestFile = null;
|
||||
_i2cpHost = null;
|
||||
_i2cpPort = -1;
|
||||
_localDest = null;
|
||||
_listener = null;
|
||||
_session = null;
|
||||
_numHops = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* who are we?
|
||||
* @return the destination (us)
|
||||
*/
|
||||
public Destination getLocalDestination() {
|
||||
return _localDest;
|
||||
}
|
||||
|
||||
/**
|
||||
* who gets notified when we receive a ping or a pong?
|
||||
* @return the event listener who gets notified
|
||||
*/
|
||||
public PingPongEventListener getListener() {
|
||||
return _listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets who gets notified when we receive a ping or a pong
|
||||
* @param listener the event listener to get notified
|
||||
*/
|
||||
public void setListener(PingPongEventListener listener) {
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many hops do we want in our tunnels?
|
||||
* @return the number of hops
|
||||
*/
|
||||
public int getNumHops() {
|
||||
return _numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* are we connected?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getIsConnected() {
|
||||
return _session != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in all of the config data
|
||||
* @param props the properties to load from
|
||||
*/
|
||||
void loadConfig(Properties props) {
|
||||
String privDestFile = props.getProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||
String pubDestFile = props.getProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||
String host = props.getProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
||||
String port = props.getProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
||||
String numHops = props.getProperty(NUMHOPS_PROP, "" + NUMHOPS_DEFAULT);
|
||||
|
||||
int portNum = -1;
|
||||
try {
|
||||
portNum = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid I2CP port specified [" + port + "]");
|
||||
}
|
||||
portNum = I2CP_PORT_DEFAULT;
|
||||
}
|
||||
int hops = -1;
|
||||
try {
|
||||
hops = Integer.parseInt(numHops);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid # hops specified [" + numHops + "]");
|
||||
}
|
||||
hops = NUMHOPS_DEFAULT;
|
||||
}
|
||||
|
||||
_numHops = hops;
|
||||
_privateDestFile = privDestFile;
|
||||
_publicDestFile = pubDestFile;
|
||||
_i2cpHost = host;
|
||||
_i2cpPort = portNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* write out the config to the props
|
||||
* @param props the properties to write to
|
||||
*/
|
||||
void storeConfig(Properties props) {
|
||||
if (_privateDestFile != null) {
|
||||
props.setProperty(DEST_FILE_PROP, _privateDestFile);
|
||||
} else {
|
||||
props.setProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||
}
|
||||
|
||||
if (_publicDestFile != null) {
|
||||
props.setProperty(PUBLIC_DEST_FILE_PROP, _publicDestFile);
|
||||
} else {
|
||||
props.setProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||
}
|
||||
|
||||
if (_i2cpHost != null) {
|
||||
props.setProperty(I2CP_HOST_PROP, _i2cpHost);
|
||||
} else {
|
||||
props.setProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
||||
}
|
||||
|
||||
if (_i2cpPort > 0) {
|
||||
props.setProperty(I2CP_PORT_PROP, "" + _i2cpPort);
|
||||
} else {
|
||||
props.setProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
||||
}
|
||||
|
||||
props.setProperty(NUMHOPS_PROP, "" + _numHops);
|
||||
}
|
||||
|
||||
private static final int TYPE_PING = 0;
|
||||
private static final int TYPE_PONG = 1;
|
||||
|
||||
/**
|
||||
* send a ping message to the peer
|
||||
*
|
||||
* @param peer peer to ping
|
||||
* @param seriesNum id used to keep track of multiple pings (of different size/frequency) to a peer
|
||||
* @param now current time to be sent in the ping (so we can watch for it in the pong)
|
||||
* @param size total message size to send
|
||||
*
|
||||
* @throws IllegalStateException if we are not connected to the router
|
||||
*/
|
||||
public void sendPing(Destination peer, int seriesNum, long now, int size) {
|
||||
if (_session == null) throw new IllegalStateException("Not connected to the router");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
|
||||
try {
|
||||
_localDest.writeBytes(baos);
|
||||
DataHelper.writeLong(baos, 2, seriesNum);
|
||||
DataHelper.writeLong(baos, 1, TYPE_PING);
|
||||
DataHelper.writeDate(baos, new Date(now));
|
||||
int padding = size - baos.size();
|
||||
byte paddingData[] = new byte[padding];
|
||||
I2PAppContext.getGlobalContext().random().nextBytes(paddingData);
|
||||
//Arrays.fill(paddingData, (byte) 0x2A);
|
||||
DataHelper.writeLong(baos, 2, padding);
|
||||
baos.write(paddingData);
|
||||
boolean sent = _session.sendMessage(peer, baos.toByteArray());
|
||||
if (!sent) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping to " + peer.calculateHash().toBase64() + " for series "
|
||||
+ seriesNum);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Ping sent to " + peer.calculateHash().toBase64() + " for series " + seriesNum);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the ping message", dfe);
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the ping message", ise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send a pong message to the peer
|
||||
*
|
||||
* @param peer peer to pong
|
||||
* @param seriesNum id given to us in the ping
|
||||
* @param sentOn date the peer said they sent us the message
|
||||
* @param data payload the peer sent us in the ping
|
||||
*
|
||||
* @throws IllegalStateException if we are not connected to the router
|
||||
*/
|
||||
public void sendPong(Destination peer, int seriesNum, Date sentOn, byte data[]) {
|
||||
if (_session == null) throw new IllegalStateException("Not connected to the router");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length + 768);
|
||||
try {
|
||||
_localDest.writeBytes(baos);
|
||||
DataHelper.writeLong(baos, 2, seriesNum);
|
||||
DataHelper.writeLong(baos, 1, TYPE_PONG);
|
||||
DataHelper.writeDate(baos, sentOn);
|
||||
DataHelper.writeDate(baos, new Date(Clock.getInstance().now()));
|
||||
DataHelper.writeLong(baos, 2, data.length);
|
||||
baos.write(data);
|
||||
boolean sent = _session.sendMessage(peer, baos.toByteArray());
|
||||
if (!sent) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the pong to " + peer.calculateHash().toBase64() + " for series "
|
||||
+ seriesNum + " which was sent on " + sentOn);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Pong sent to " + peer.calculateHash().toBase64() + " for series " + seriesNum
|
||||
+ " which was sent on " + sentOn);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the pong message", dfe);
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the pong message", ise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received this data from I2P - parse it into a ping or a pong
|
||||
* and notify accordingly
|
||||
* @param data the data to handle
|
||||
*/
|
||||
private void handleMessage(byte data[]) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
try {
|
||||
Destination from = new Destination();
|
||||
from.readBytes(bais);
|
||||
int series = (int) DataHelper.readLong(bais, 2);
|
||||
long type = DataHelper.readLong(bais, 1);
|
||||
Date sentOn = DataHelper.readDate(bais);
|
||||
Date receivedOn = null;
|
||||
if (type == TYPE_PONG) {
|
||||
receivedOn = DataHelper.readDate(bais);
|
||||
}
|
||||
int size = (int) DataHelper.readLong(bais, 2);
|
||||
byte payload[] = new byte[size];
|
||||
int read = DataHelper.read(bais, payload);
|
||||
if (read != size) { throw new IOException("Malformed payload - read " + read + " instead of " + size); }
|
||||
|
||||
if (_listener == null) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Listener isn't set, but we received a valid message of type " + type + " sent from "
|
||||
+ from.calculateHash().toBase64());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == TYPE_PING) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Ping received from " + from.calculateHash().toBase64() + " on series " + series
|
||||
+ " sent on " + sentOn + " containing " + size + " bytes");
|
||||
}
|
||||
_listener.receivePing(from, series, sentOn, payload);
|
||||
} else if (type == TYPE_PONG) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Pong received from " + from.calculateHash().toBase64() + " on series " + series
|
||||
+ " sent on " + sentOn + " with pong sent on " + receivedOn + " containing " + size
|
||||
+ " bytes");
|
||||
}
|
||||
_listener.receivePong(from, series, sentOn, receivedOn, payload);
|
||||
} else {
|
||||
throw new IOException("Invalid message type " + type);
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error handling the message", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error parsing the message", dfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to the I2P router and either authenticate ourselves with the
|
||||
* destination we're given, or create a new one and write that to the
|
||||
* destination file.
|
||||
*
|
||||
* @return true if we connect successfully, false otherwise
|
||||
*/
|
||||
boolean connect() {
|
||||
I2PClient client = I2PClientFactory.createClient();
|
||||
Destination us = null;
|
||||
File destFile = new File(_privateDestFile);
|
||||
us = verifyDestination(client, destFile);
|
||||
if (us == null) return false;
|
||||
|
||||
// if we're here, we got a destination. lets connect
|
||||
FileInputStream fin = null;
|
||||
try {
|
||||
fin = new FileInputStream(destFile);
|
||||
Properties options = getOptions();
|
||||
I2PSession session = client.createSession(fin, options);
|
||||
I2PListener lsnr = new I2PListener();
|
||||
session.setSessionListener(lsnr);
|
||||
session.connect();
|
||||
_localDest = session.getMyDestination();
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("I2CP Session created and connected as " + _localDest.calculateHash().toBase64());
|
||||
}
|
||||
_session = session;
|
||||
_i2pListener = lsnr;
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error connecting", ise);
|
||||
}
|
||||
return false;
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error loading the destionation", ioe);
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* load, verify, or create a destination
|
||||
*
|
||||
* @param client the client
|
||||
* @param destFile the file holding the destination
|
||||
* @return the destination loaded, or null if there was an error
|
||||
*/
|
||||
private Destination verifyDestination(I2PClient client, File destFile) {
|
||||
Destination us = null;
|
||||
FileInputStream fin = null;
|
||||
if (destFile.exists()) {
|
||||
try {
|
||||
fin = new FileInputStream(destFile);
|
||||
us = new Destination();
|
||||
us.readBytes(fin);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Existing destination loaded: [" + us.toBase64() + "]");
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(_publicDestFile);
|
||||
fos.write(us.toBase64().getBytes());
|
||||
fos.flush();
|
||||
} catch (IOException fioe) {
|
||||
_log.error("Error writing out the plain destination to [" + _publicDestFile + "]", fioe);
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException fioe) {}
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
destFile.delete();
|
||||
us = null;
|
||||
} catch (DataFormatException dfe) {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
destFile.delete();
|
||||
us = null;
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (us == null) {
|
||||
// need to create a new one
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(destFile);
|
||||
us = client.createDestination(fos);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("New destination created: [" + us.toBase64() + "]");
|
||||
}
|
||||
fos.close();
|
||||
|
||||
try {
|
||||
fos = new FileOutputStream(_publicDestFile);
|
||||
fos.write(us.toBase64().getBytes());
|
||||
fos.flush();
|
||||
} catch (IOException fioe) {
|
||||
_log.error("Error writing out the plain destination to [" + _publicDestFile + "]", fioe);
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException fioe) {}
|
||||
fos = null;
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the destination keys being created", ioe);
|
||||
}
|
||||
return null;
|
||||
} catch (I2PException ie) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error creating the destination", ie);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (fos != null) try {
|
||||
fos.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return us;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2PSession connect options
|
||||
* @return the options as Properties
|
||||
*/
|
||||
private Properties getOptions() {
|
||||
Properties props = new Properties();
|
||||
// this should be BEST_EFFORT, but i'm too lazy to update the code to handle tracking
|
||||
// sessionTags and sessionKeys, marking them as delivered on pong.
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
||||
props.setProperty(I2PClient.PROP_TCP_HOST, _i2cpHost);
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, _i2cpPort + "");
|
||||
props.setProperty("tunnels.depthInbound", "" + _numHops);
|
||||
props.setProperty("tunnels.depthOutbound", "" + _numHops);
|
||||
return props;
|
||||
}
|
||||
|
||||
/** disconnect from the I2P router */
|
||||
void disconnect() {
|
||||
if (_session != null) {
|
||||
try {
|
||||
_session.destroySession();
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error destroying the session", ise);
|
||||
}
|
||||
}
|
||||
_session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an event notification system for receiving pings and pongs
|
||||
*
|
||||
*/
|
||||
public interface PingPongEventListener {
|
||||
/**
|
||||
* receive a ping message from the peer
|
||||
*
|
||||
* @param from peer that sent us the ping
|
||||
* @param seriesNum id the peer sent us in the ping
|
||||
* @param sentOn date the peer said they sent us the message
|
||||
* @param data payload from the ping
|
||||
*/
|
||||
void receivePing(Destination from, int seriesNum, Date sentOn, byte data[]);
|
||||
|
||||
/**
|
||||
* receive a pong message from the peer
|
||||
*
|
||||
* @param from peer that sent us the pong
|
||||
* @param seriesNum id the peer sent us in the pong (that we sent them in the ping)
|
||||
* @param sentOn when we sent out the ping
|
||||
* @param replyOn when they sent out the pong
|
||||
* @param data payload from the ping/pong
|
||||
*/
|
||||
void receivePong(Destination from, int seriesNum, Date sentOn, Date replyOn, byte data[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data from the session and pass it along to handleMessage for parsing/dispersal
|
||||
*
|
||||
*/
|
||||
private class I2PListener implements I2PSessionListener {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#disconnected(net.i2p.client.I2PSession)
|
||||
*/
|
||||
public void disconnected(I2PSession session) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Session disconnected");
|
||||
}
|
||||
disconnect();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#errorOccurred(net.i2p.client.I2PSession, java.lang.String, java.lang.Throwable)
|
||||
*/
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Error occurred: " + message, error);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#reportAbuse(net.i2p.client.I2PSession, int)
|
||||
*/
|
||||
public void reportAbuse(I2PSession session, int severity) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Abuse reported with severity " + String.valueOf(severity));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#messageAvailable(net.i2p.client.I2PSession, int, long)
|
||||
*/
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
try {
|
||||
byte data[] = session.receiveMessage(msgId);
|
||||
handleMessage(data);
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Error receiving the message", ise);
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,412 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Contain the current window of data for a particular series of ping/pong stats
|
||||
* sent to a peer. This should be periodically kept clean by calling cleanup()
|
||||
* to timeout expired pings and to drop data outside the window.
|
||||
*
|
||||
*/
|
||||
public class PeerData {
|
||||
private final static Log _log = new Log(PeerData.class);
|
||||
/** peer / sequence / config in this data series */
|
||||
private ClientConfig _peer;
|
||||
/** date sent (Long) to EventDataPoint containing the datapoints sent in the current period */
|
||||
private Map _dataPoints;
|
||||
/** date sent (Long) to EventDataPoint containing pings that haven't yet timed out or been ponged */
|
||||
private TreeMap _pendingPings;
|
||||
private long _sessionStart;
|
||||
private long _lifetimeSent;
|
||||
private long _lifetimeReceived;
|
||||
/** rate averaging the time to send over a variety of periods */
|
||||
private RateStat _sendRate;
|
||||
/** rate averaging the time to receive over a variety of periods */
|
||||
private RateStat _receiveRate;
|
||||
/** rate averaging the frequency of lost messages over a variety of periods */
|
||||
private RateStat _lostRate;
|
||||
|
||||
/** how long we wait before timing out pending pings (30 seconds) */
|
||||
private static final long TIMEOUT_PERIOD = 60 * 1000;
|
||||
|
||||
/** synchronize on this when updating _dataPoints or _pendingPings */
|
||||
private Object _updateLock = new Object();
|
||||
|
||||
/**
|
||||
* Creates a PeerData . . .
|
||||
* @param config configuration to load from
|
||||
*/
|
||||
public PeerData(ClientConfig config) {
|
||||
_peer = config;
|
||||
_dataPoints = new TreeMap();
|
||||
_pendingPings = new TreeMap();
|
||||
_sessionStart = Clock.getInstance().now();
|
||||
_lifetimeSent = 0;
|
||||
_lifetimeReceived = 0;
|
||||
_sendRate = new RateStat("sendRate", "How long it takes to send", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
_receiveRate = new RateStat("receiveRate", "How long it takes to receive", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
_lostRate = new RateStat("lostRate", "How frequently we lose messages", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
}
|
||||
|
||||
/**
|
||||
* turn the periods (# minutes) into rate periods (# milliseconds)
|
||||
* @param periods (in minutes)
|
||||
* @return an array of periods (in milliseconds)
|
||||
*/
|
||||
private static long[] getPeriods(int periods[]) {
|
||||
long rv[] = null;
|
||||
if (periods == null) periods = new int[0];
|
||||
rv = new long[periods.length];
|
||||
for (int i = 0; i < periods.length; i++)
|
||||
rv[i] = (long) periods[i] * 60 * 1000; // they're in minutes
|
||||
Arrays.sort(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many pings are still outstanding?
|
||||
* @return the number of pings outstanding
|
||||
*/
|
||||
public int getPendingCount() {
|
||||
synchronized (_updateLock) {
|
||||
return _pendingPings.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* how many data points are available in the current window?
|
||||
* @return the number of datapoints available
|
||||
*/
|
||||
public int getDataPointCount() {
|
||||
synchronized (_updateLock) {
|
||||
return _dataPoints.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* when did this test begin?
|
||||
* @return when the test began
|
||||
*/
|
||||
public long getSessionStart() { return _sessionStart; }
|
||||
|
||||
/**
|
||||
* sets when the test began
|
||||
* @param when when it began
|
||||
*/
|
||||
public void setSessionStart(long when) { _sessionStart = when; }
|
||||
|
||||
/**
|
||||
* how many pings have we sent for this test?
|
||||
* @return the number of pings sent
|
||||
*/
|
||||
public long getLifetimeSent() { return _lifetimeSent; }
|
||||
|
||||
/**
|
||||
* how many pongs have we received for this test?
|
||||
* @return the number of pings received
|
||||
*/
|
||||
public long getLifetimeReceived() { return _lifetimeReceived; }
|
||||
|
||||
/**
|
||||
* @return the client configuration
|
||||
*/
|
||||
public ClientConfig getConfig() {
|
||||
return _peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* What periods are we averaging the data over (in minutes)?
|
||||
* @return the periods as an array of ints (in minutes)
|
||||
*/
|
||||
public int[] getAveragePeriods() {
|
||||
return (_peer.getAveragePeriods() != null ? _peer.getAveragePeriods() : new int[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* average time to send over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageSendTime(int period) {
|
||||
return getAverage(_sendRate, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* average time to receive over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageReceiveTime(int period) {
|
||||
return getAverage(_receiveRate, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* number of lost messages over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||
*/
|
||||
public double getLostMessages(int period) {
|
||||
Rate rate = _lostRate.getRate(period * 60 * 1000);
|
||||
if (rate == null) return -1;
|
||||
return rate.getCurrentTotalValue();
|
||||
}
|
||||
|
||||
private double getAverage(RateStat stat, int period) {
|
||||
Rate rate = stat.getRate(period * 60 * 1000);
|
||||
if (rate == null) return -1;
|
||||
return rate.getAverageValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ordered list of data points in the current window (after doing a cleanup)
|
||||
*
|
||||
* @return list of EventDataPoint objects
|
||||
*/
|
||||
public List getDataPoints() {
|
||||
cleanup();
|
||||
synchronized (_updateLock) {
|
||||
return new ArrayList(_dataPoints.values());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We have sent the peer a ping on this series (using the send time as given)
|
||||
* @param dateSent when the ping was sent
|
||||
*/
|
||||
public void addPing(long dateSent) {
|
||||
EventDataPoint sent = new EventDataPoint(dateSent);
|
||||
synchronized (_updateLock) {
|
||||
_pendingPings.put(new Long(dateSent), sent);
|
||||
}
|
||||
_lifetimeSent++;
|
||||
}
|
||||
|
||||
/**
|
||||
* we have received a pong from the peer on this series
|
||||
*
|
||||
* @param dateSent when we sent the ping
|
||||
* @param pongSent when the peer received the ping and sent the pong
|
||||
*/
|
||||
public void pongReceived(long dateSent, long pongSent) {
|
||||
long now = Clock.getInstance().now();
|
||||
synchronized (_updateLock) {
|
||||
if (_pendingPings.size() <= 0) {
|
||||
_log.warn("Pong received (sent at " + dateSent + ", " + (now-dateSent)
|
||||
+ "ms ago, pong delay " + (pongSent-dateSent) + "ms, pong receive delay "
|
||||
+ (now-pongSent) + "ms)");
|
||||
return;
|
||||
}
|
||||
Long first = (Long)_pendingPings.firstKey();
|
||||
EventDataPoint data = (EventDataPoint)_pendingPings.remove(new Long(dateSent));
|
||||
|
||||
if (data != null) {
|
||||
data.setPongReceived(now);
|
||||
data.setPongSent(pongSent);
|
||||
data.setWasPonged(true);
|
||||
locked_addDataPoint(data);
|
||||
|
||||
if (dateSent != first.longValue()) {
|
||||
_log.error("Out of order delivery: received " + dateSent
|
||||
+ " but the first pending is " + first.longValue()
|
||||
+ " (delta " + (dateSent - first.longValue()) + ")");
|
||||
} else {
|
||||
_log.info("In order delivery for " + dateSent + " in ping "
|
||||
+ _peer.getComment());
|
||||
}
|
||||
} else {
|
||||
_log.warn("Pong received, but no matching ping? ping sent at = " + dateSent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_sendRate.addData(pongSent - dateSent, 0);
|
||||
_receiveRate.addData(now - pongSent, 0);
|
||||
_lifetimeReceived++;
|
||||
}
|
||||
|
||||
protected void addDataPoint(EventDataPoint data) {
|
||||
synchronized (_updateLock) {
|
||||
locked_addDataPoint(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void locked_addDataPoint(EventDataPoint data) {
|
||||
Object val = _dataPoints.put(new Long(data.getPingSent()), data);
|
||||
if (val != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Duplicate data point received: " + data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drop all datapoints outside the window we're watching, and timeout all
|
||||
* pending pings not ponged in the TIMEOUT_PERIOD, both updating the lost message
|
||||
* rate and coallescing all of the rates.
|
||||
*
|
||||
*/
|
||||
public void cleanup() {
|
||||
long dropBefore = Clock.getInstance().now() - _peer.getStatDuration() * 60 * 1000;
|
||||
long timeoutBefore = Clock.getInstance().now() - TIMEOUT_PERIOD;
|
||||
long numDropped = 0;
|
||||
long numTimedOut = 0;
|
||||
|
||||
synchronized (_updateLock) {
|
||||
numDropped = locked_dropExpired(dropBefore);
|
||||
numTimedOut = locked_timeoutPending(timeoutBefore);
|
||||
}
|
||||
|
||||
_lostRate.addData(numTimedOut, 0);
|
||||
|
||||
_receiveRate.coalesceStats();
|
||||
_sendRate.coalesceStats();
|
||||
_lostRate.coalesceStats();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peer data cleaned up " + numTimedOut + " timed out pings and removed " + numDropped
|
||||
+ " old entries");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all data points that are already too old for us to be interested in
|
||||
*
|
||||
* @param when the earliest ping send time we care about
|
||||
* @return number of data points dropped
|
||||
*/
|
||||
private int locked_dropExpired(long when) {
|
||||
Set toDrop = new HashSet(4);
|
||||
// drop the failed and really old
|
||||
for (Iterator iter = _dataPoints.keySet().iterator(); iter.hasNext(); ) {
|
||||
Long pingTime = (Long)iter.next();
|
||||
if (pingTime.longValue() < when)
|
||||
toDrop.add(pingTime);
|
||||
}
|
||||
for (Iterator iter = toDrop.iterator(); iter.hasNext(); ) {
|
||||
_dataPoints.remove(iter.next());
|
||||
}
|
||||
return toDrop.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* timeout and remove all pings that were sent before the given time,
|
||||
* moving them from the set of pending pings to the set of data points
|
||||
*
|
||||
* @param when the earliest ping send time we care about
|
||||
* @return number of pings timed out
|
||||
*/
|
||||
private int locked_timeoutPending(long when) {
|
||||
Set toDrop = new HashSet(4);
|
||||
for (Iterator iter = _pendingPings.keySet().iterator(); iter.hasNext(); ) {
|
||||
Long pingTime = (Long)iter.next();
|
||||
if (pingTime.longValue() < when) {
|
||||
toDrop.add(pingTime);
|
||||
EventDataPoint point = (EventDataPoint)_pendingPings.get(pingTime);
|
||||
point.setWasPonged(false);
|
||||
locked_addDataPoint(point);
|
||||
}
|
||||
}
|
||||
for (Iterator iter = toDrop.iterator(); iter.hasNext(); ) {
|
||||
_pendingPings.remove(iter.next());
|
||||
}
|
||||
return toDrop.size();
|
||||
}
|
||||
|
||||
/** actual data point for the peer */
|
||||
public class EventDataPoint {
|
||||
private boolean _wasPonged;
|
||||
private long _pingSent;
|
||||
private long _pongSent;
|
||||
private long _pongReceived;
|
||||
|
||||
/**
|
||||
* Creates an EventDataPoint
|
||||
*/
|
||||
public EventDataPoint() { this(-1); }
|
||||
|
||||
/**
|
||||
* Creates an EventDataPoint with pingtime associated with it =)
|
||||
* @param pingSentOn the time a ping was sent
|
||||
*/
|
||||
public EventDataPoint(long pingSentOn) {
|
||||
_wasPonged = false;
|
||||
_pingSent = pingSentOn;
|
||||
_pongSent = -1;
|
||||
_pongReceived = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we send this ping?
|
||||
* @return the time the ping was sent
|
||||
*/
|
||||
public long getPingSent() { return _pingSent; }
|
||||
|
||||
/**
|
||||
* sets when we sent this ping
|
||||
* @param when when we sent the ping
|
||||
*/
|
||||
public void setPingSent(long when) { _pingSent = when; }
|
||||
|
||||
/**
|
||||
* when did the peer receive the ping?
|
||||
* @return the time the ping was receieved
|
||||
*/
|
||||
public long getPongSent() {
|
||||
return _pongSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time the peer received the ping
|
||||
* @param when the time to set
|
||||
*/
|
||||
public void setPongSent(long when) {
|
||||
_pongSent = when;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we receive the peer's pong?
|
||||
* @return the time we receieved the pong
|
||||
*/
|
||||
public long getPongReceived() {
|
||||
return _pongReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time the peer's pong was receieved
|
||||
* @param when the time to set
|
||||
*/
|
||||
public void setPongReceived(long when) {
|
||||
_pongReceived = when;
|
||||
}
|
||||
|
||||
/**
|
||||
* did the peer reply in time?
|
||||
* @return true or false, whether we got a reply in time */
|
||||
public boolean getWasPonged() {
|
||||
return _wasPonged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we receieved the peer's reply in time
|
||||
* @param pong true or false
|
||||
*/
|
||||
public void setWasPonged(boolean pong) {
|
||||
_wasPonged = pong;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Actually write out the stats for peer test
|
||||
*
|
||||
*/
|
||||
public class PeerDataWriter {
|
||||
private final static Log _log = new Log(PeerDataWriter.class);
|
||||
|
||||
/**
|
||||
* persist the peer state to the location specified in the peer config
|
||||
*
|
||||
* @param data the peer data to persist
|
||||
* @return true if it was persisted correctly, false on error
|
||||
*/
|
||||
public boolean persist(PeerData data) {
|
||||
String filename = data.getConfig().getStatFile();
|
||||
File statFile = new File(filename);
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(statFile);
|
||||
persist(data, fos);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error persisting the peer data for "
|
||||
+ data.getConfig().getPeer().calculateHash().toBase64(), ioe);
|
||||
return false;
|
||||
} finally {
|
||||
if (fos != null) try {
|
||||
fos.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* persists the peer state to the output stream
|
||||
* @param data the peer data to persist
|
||||
* @param out where to persist the data
|
||||
* @return true if it was persisted correctly [always (as implemented)], false on error
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean persist(PeerData data, OutputStream out) throws IOException {
|
||||
String header = getHeader(data);
|
||||
|
||||
out.write(header.getBytes());
|
||||
out.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\troundTrip\n".getBytes());
|
||||
for (Iterator iter = data.getDataPoints().iterator(); iter.hasNext();) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint) iter.next();
|
||||
String line = getEvent(point);
|
||||
out.write(line.getBytes());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getHeader(PeerData data) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
buf.append("peer \t").append(data.getConfig().getPeer().calculateHash().toBase64()).append('\n');
|
||||
buf.append("local \t").append(data.getConfig().getUs().calculateHash().toBase64()).append('\n');
|
||||
buf.append("peerDest \t").append(data.getConfig().getPeer().toBase64()).append('\n');
|
||||
buf.append("localDest \t").append(data.getConfig().getUs().toBase64()).append('\n');
|
||||
buf.append("numTunnelHops\t").append(data.getConfig().getNumHops()).append('\n');
|
||||
buf.append("comment \t").append(data.getConfig().getComment()).append('\n');
|
||||
buf.append("sendFrequency\t").append(data.getConfig().getSendFrequency()).append('\n');
|
||||
buf.append("sendSize \t").append(data.getConfig().getSendSize()).append('\n');
|
||||
buf.append("sessionStart \t").append(getTime(data.getSessionStart())).append('\n');
|
||||
buf.append("currentTime \t").append(getTime(Clock.getInstance().now())).append('\n');
|
||||
buf.append("numPending \t").append(data.getPendingCount()).append('\n');
|
||||
buf.append("lifetimeSent \t").append(data.getLifetimeSent()).append('\n');
|
||||
buf.append("lifetimeRecv \t").append(data.getLifetimeReceived()).append('\n');
|
||||
int periods[] = data.getAveragePeriods();
|
||||
buf.append("#averages\tminutes\tsendMs\trecvMs\tnumLost\troundTrip\n");
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
buf.append("periodAverage\t").append(periods[i]).append('\t');
|
||||
buf.append(getNum(data.getAverageSendTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getAverageReceiveTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getLostMessages(periods[i]))).append('\t');
|
||||
double rtt = data.getAverageSendTime(periods[i])
|
||||
+ data.getAverageReceiveTime(periods[i]);
|
||||
buf.append(getNum(rtt)).append('\n');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getEvent(PeerData.EventDataPoint point) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("EVENT\t");
|
||||
if (point.getWasPonged())
|
||||
buf.append("OK\t");
|
||||
else
|
||||
buf.append("LOST\t");
|
||||
buf.append(getTime(point.getPingSent())).append('\t');
|
||||
if (point.getWasPonged()) {
|
||||
buf.append(point.getPongSent() - point.getPingSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPongSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPingSent()).append('\t');
|
||||
}
|
||||
buf.append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private final SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd.HH:mm:ss.SSS", Locale.UK);
|
||||
|
||||
/**
|
||||
* Converts a time (long) to text
|
||||
* @param when the time to convert
|
||||
* @return the textual representation
|
||||
*/
|
||||
public String getTime(long when) {
|
||||
synchronized (_fmt) {
|
||||
return _fmt.format(new Date(when));
|
||||
}
|
||||
}
|
||||
|
||||
private final DecimalFormat _numFmt = new DecimalFormat("#0", new DecimalFormatSymbols(Locale.UK));
|
||||
|
||||
/**
|
||||
* Converts a number (double) to text
|
||||
* @param val the number to convert
|
||||
* @return the textual representation
|
||||
*/
|
||||
public String getNum(double val) {
|
||||
synchronized (_numFmt) {
|
||||
return _numFmt.format(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the control widgets (refresh/load/snapshot and the
|
||||
* tabbed panel with the plot config data)
|
||||
*
|
||||
*/
|
||||
class HeartbeatControlPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatControlPane.class);
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JTabbedPane _configPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private final static Color LIGHT_BLUE = new Color(180, 180, 255); /* UNUSED */
|
||||
private final static Color BLACK = new Color(0, 0, 0);
|
||||
private Color _background = WHITE;
|
||||
private Color _foreground = BLACK;
|
||||
|
||||
/**
|
||||
* Constructs a control panel onto the gui
|
||||
* @param gui the gui the panel is associated with
|
||||
*/
|
||||
public HeartbeatControlPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a test to the panel
|
||||
* @param config the configuration for the test
|
||||
*/
|
||||
public void addTest(PeerPlotConfig config) {
|
||||
_configPane.addTab(config.getTitle(), null, new JScrollPane(new PeerPlotConfigPane(config, this)), config.getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
_gui.pack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a test from the panel
|
||||
* @param config the configuration for the test
|
||||
*/
|
||||
public void removeTest(PeerPlotConfig config) {
|
||||
_gui.getMonitor().getState().removeTest(config);
|
||||
int index = _configPane.indexOfTab(config.getTitle());
|
||||
if (index >= 0)
|
||||
_configPane.removeTabAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when tests have changed
|
||||
*/
|
||||
public void testsUpdated() {
|
||||
List knownNames = new ArrayList(8);
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
PeerPlotState state = _gui.getMonitor().getState().getTest(i);
|
||||
String title = state.getPlotConfig().getTitle();
|
||||
knownNames.add(state.getPlotConfig().getTitle());
|
||||
if (_configPane.indexOfTab(title) >= 0) {
|
||||
_log.debug("We already know about [" + title + "]");
|
||||
} else {
|
||||
_log.info("The test [" + title + "] is new to us");
|
||||
PeerPlotConfigPane pane = new PeerPlotConfigPane(state.getPlotConfig(), this);
|
||||
_configPane.addTab(state.getPlotConfig().getTitle(), null, new JScrollPane(pane), state.getPlotConfig().getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
}
|
||||
}
|
||||
List toRemove = new ArrayList(4);
|
||||
for (int i = 0; i < _configPane.getTabCount(); i++) {
|
||||
if (knownNames.contains(_configPane.getTitleAt(i))) {
|
||||
// noop
|
||||
} else {
|
||||
toRemove.add(_configPane.getTitleAt(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < toRemove.size(); i++) {
|
||||
String title = (String)toRemove.get(i);
|
||||
_log.info("Removing test [" + title + "]");
|
||||
_configPane.removeTabAt(_configPane.indexOfTab(title));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
if (_gui != null)
|
||||
setBackground(_gui.getBackground());
|
||||
else
|
||||
setBackground(_background);
|
||||
setLayout(new BorderLayout());
|
||||
HeartbeatMonitorCommandBar bar = new HeartbeatMonitorCommandBar(_gui);
|
||||
bar.setBackground(getBackground());
|
||||
add(bar, BorderLayout.NORTH);
|
||||
_configPane = new JTabbedPane(JTabbedPane.LEFT);
|
||||
_configPane.setBackground(_background);
|
||||
//add(_configPane, BorderLayout.CENTER);
|
||||
add(_configPane, BorderLayout.SOUTH);
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* The HeartbeatMonitor, complete with main()! Act now, and it's only 5 easy
|
||||
* payments of $19.95 (plus shipping and handling)! You heard me, only _5_
|
||||
* easy payments of $19.95 (plus shipping and handling)! <p />
|
||||
*
|
||||
* (fine print: something about some states in the US requiring the addition
|
||||
* of sales tax... or something) <p />
|
||||
*
|
||||
* (finer print: Satan owns you. Deal with it.) <p />
|
||||
*
|
||||
* (even finer print: usage: <code>HeartbeatMonitor [configFilename]</code>)
|
||||
*/
|
||||
public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor, PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(HeartbeatMonitor.class);
|
||||
private HeartbeatMonitorState _state;
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
|
||||
/**
|
||||
* Delegating constructor.
|
||||
* @see HeartbeatMonitor#HeartbeatMonitor(String)
|
||||
*/
|
||||
public HeartbeatMonitor() { this(null); }
|
||||
|
||||
/**
|
||||
* Creates a HeartbeatMonitor . . .
|
||||
* @param configFilename the configuration file to read from
|
||||
*/
|
||||
public HeartbeatMonitor(String configFilename) {
|
||||
_state = new HeartbeatMonitorState(configFilename);
|
||||
_gui = new HeartbeatMonitorGUI(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the game rollin'
|
||||
*/
|
||||
public void runMonitor() {
|
||||
loadConfig();
|
||||
I2PThread t = new I2PThread(new HeartbeatMonitorRunner(this));
|
||||
t.setName("HeartbeatMonitor");
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
_log.debug("Monitor started");
|
||||
}
|
||||
|
||||
/**
|
||||
* give us all the data/config available
|
||||
* @return the current state (data/config)
|
||||
*/
|
||||
HeartbeatMonitorState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/** for all of the peer tests being monitored, refetch the data and rerender */
|
||||
void refetchData() {
|
||||
_log.debug("Refetching data");
|
||||
for (int i = 0; i < _state.getTestCount(); i++)
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, _state.getTest(i));
|
||||
}
|
||||
|
||||
/** (re)load the config defining what peer tests we are monitoring (and how to render) */
|
||||
void loadConfig() {
|
||||
//for (int i = 0; i < 10; i++) {
|
||||
// load("fake" + i);
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads config data
|
||||
* @param location the name of the location to load data from
|
||||
*/
|
||||
public void load(String location) {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig(location);
|
||||
cfg.addListener(this);
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see PeerPlotStateFetcher.FetchStateReceptor#peerPlotStateFetched
|
||||
*/
|
||||
public synchronized void peerPlotStateFetched(PeerPlotState state) {
|
||||
_state.addTest(state);
|
||||
_gui.stateUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* store the config defining what peer tests we are monitoring (and how to render)
|
||||
*/
|
||||
void storeConfig() {}
|
||||
|
||||
/**
|
||||
* And now, the main function, the one you've all been waiting for! . . .
|
||||
* @param args da args. Should take 1, which is the location to load config data from
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
Thread.currentThread().setName("HeartbeatMonitor.main");
|
||||
if (args.length == 1)
|
||||
new HeartbeatMonitor(args[0]).runMonitor();
|
||||
else
|
||||
new HeartbeatMonitor().runMonitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the config is updated
|
||||
* @param config the updated config
|
||||
*/
|
||||
public void configUpdated(PeerPlotConfig config) {
|
||||
_log.debug("Config updated, revamping the gui");
|
||||
_gui.stateUpdated();
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
class HeartbeatMonitorCommandBar extends JPanel {
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JComboBox _refreshRate;
|
||||
private JTextField _location;
|
||||
|
||||
/**
|
||||
* Constructs a command bar onto the gui
|
||||
* @param gui the gui the command bar is associated with
|
||||
*/
|
||||
public HeartbeatMonitorCommandBar(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
private void refreshChanged(ItemEvent evt) {}
|
||||
private void loadCalled() {
|
||||
_gui.getMonitor().load(_location.getText());
|
||||
}
|
||||
|
||||
private void browseCalled() {
|
||||
JFileChooser chooser = new JFileChooser(_location.getText());
|
||||
chooser.setBackground(_gui.getBackground());
|
||||
chooser.setMultiSelectionEnabled(false);
|
||||
int rv = chooser.showDialog(this, "Load");
|
||||
if (rv == JFileChooser.APPROVE_OPTION)
|
||||
_gui.getMonitor().load(chooser.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
_refreshRate = new JComboBox(new DefaultComboBoxModel(new Object[] {"10 second refresh", "30 second refresh", "1 minute refresh", "5 minute refresh"}));
|
||||
_refreshRate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { refreshChanged(evt); } });
|
||||
_refreshRate.setEnabled(false);
|
||||
_refreshRate.setBackground(_gui.getBackground());
|
||||
//add(_refreshRate);
|
||||
JLabel loadLabel = new JLabel("Load from: ");
|
||||
loadLabel.setBackground(_gui.getBackground());
|
||||
add(loadLabel);
|
||||
_location = new JTextField(20);
|
||||
_location.setToolTipText("Either specify a local filename or a fully qualified URL");
|
||||
_location.setBackground(_gui.getBackground());
|
||||
add(_location);
|
||||
JButton browse = new JButton("Browse...");
|
||||
browse.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { browseCalled(); } });
|
||||
browse.setBackground(_gui.getBackground());
|
||||
add(browse);
|
||||
JButton load = new JButton("Load");
|
||||
load.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadCalled(); } });
|
||||
load.setBackground(_gui.getBackground());
|
||||
add(load);
|
||||
setBackground(_gui.getBackground());
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
class HeartbeatMonitorGUI extends JFrame {
|
||||
private HeartbeatMonitor _monitor;
|
||||
private HeartbeatPlotPane _plotPane;
|
||||
private HeartbeatControlPane _controlPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
/**
|
||||
* Creates the GUI for all youz who be too shoopid for text based shitz
|
||||
* @param monitor the monitor the gui operates over
|
||||
*/
|
||||
public HeartbeatMonitorGUI(HeartbeatMonitor monitor) {
|
||||
super("Heartbeat Monitor");
|
||||
_monitor = monitor;
|
||||
initializeComponents();
|
||||
pack();
|
||||
//setResizable(false);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
HeartbeatMonitor getMonitor() { return _monitor; }
|
||||
|
||||
/** build up all our widgets */
|
||||
private void initializeComponents() {
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
setBackground(_background);
|
||||
|
||||
_plotPane = new JFreeChartHeartbeatPlotPane(this); // new HeartbeatPlotPane(this);
|
||||
_plotPane.setBackground(_background);
|
||||
//JScrollPane pane = new JScrollPane(_plotPane);
|
||||
//pane.setBackground(_background);
|
||||
getContentPane().add(new JScrollPane(_plotPane), BorderLayout.CENTER);
|
||||
|
||||
_controlPane = new HeartbeatControlPane(this);
|
||||
_controlPane.setBackground(_background);
|
||||
getContentPane().add(_controlPane, BorderLayout.SOUTH);
|
||||
|
||||
//JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(_plotPane), new JScrollPane(_controlPane));
|
||||
//getContentPane().add(pane, BorderLayout.CENTER);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
initializeMenus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when the state of the world changes . . .
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
_controlPane.testsUpdated();
|
||||
_plotPane.stateUpdated();
|
||||
}
|
||||
|
||||
private void exitCalled() {
|
||||
_monitor.getState().setWasKilled(true);
|
||||
setVisible(false);
|
||||
System.exit(0);
|
||||
}
|
||||
private void loadConfigCalled() {}
|
||||
private void saveConfigCalled() {}
|
||||
private void loadSnapshotCalled() {}
|
||||
private void saveSnapshotCalled() {}
|
||||
|
||||
private void initializeMenus() {
|
||||
JMenuBar bar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
JMenuItem loadConfig = new JMenuItem("Load config");
|
||||
loadConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadConfigCalled(); } });
|
||||
JMenuItem saveConfig = new JMenuItem("Save config");
|
||||
saveConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveConfigCalled(); } });
|
||||
JMenuItem saveSnapshot = new JMenuItem("Save snapshot");
|
||||
saveSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveSnapshotCalled(); } });
|
||||
JMenuItem loadSnapshot = new JMenuItem("Load snapshot");
|
||||
loadSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadSnapshotCalled(); } });
|
||||
JMenuItem exit = new JMenuItem("Exit");
|
||||
exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { exitCalled(); } });
|
||||
|
||||
fileMenu.add(loadConfig);
|
||||
fileMenu.add(saveConfig);
|
||||
fileMenu.add(loadSnapshot);
|
||||
fileMenu.add(saveSnapshot);
|
||||
fileMenu.add(exit);
|
||||
bar.add(fileMenu);
|
||||
setJMenuBar(bar);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Periodically fire off necessary events (instructing the heartbeat monitor when
|
||||
* to refetch the data, etc). This is the only active thread in the heartbeat
|
||||
* monitor (outside the swing/jvm threads)
|
||||
*/
|
||||
class HeartbeatMonitorRunner implements Runnable {
|
||||
private final static Log _log = new Log(HeartbeatMonitorRunner.class);
|
||||
private HeartbeatMonitor _monitor;
|
||||
|
||||
/**
|
||||
* Creates the thread . . .
|
||||
* @param monitor the monitor the thread runs over
|
||||
*/
|
||||
public HeartbeatMonitorRunner(HeartbeatMonitor monitor) {
|
||||
_monitor = monitor;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
while (!_monitor.getState().getWasKilled()) {
|
||||
_monitor.refetchData();
|
||||
try { Thread.sleep(_monitor.getState().getRefreshRateMs()); } catch (InterruptedException ie) {}
|
||||
}
|
||||
_log.info("Stopping the heartbeat monitor runner");
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* manage the current state of the GUI - all data points, as well as any
|
||||
* rendering or configuration options.
|
||||
*/
|
||||
class HeartbeatMonitorState {
|
||||
private String _configFile;
|
||||
private List _peerPlotState;
|
||||
private int _currentPeerPlotConfig;
|
||||
private int _refreshRateMs;
|
||||
private boolean _killed;
|
||||
|
||||
/** by default, refresh every 30 seconds */
|
||||
private final static int DEFAULT_REFRESH_RATE = 30*1000;
|
||||
/** where do we load/store config info from? */
|
||||
private final static String DEFAULT_CONFIG_FILE = "heartbeatMonitor.config";
|
||||
|
||||
/**
|
||||
* A delegating constructor.
|
||||
* @see HeartbeatMonitorState#HeartbeatMonitorState(String)
|
||||
*/
|
||||
public HeartbeatMonitorState() { this(DEFAULT_CONFIG_FILE); }
|
||||
|
||||
/**
|
||||
* Constructs the state, loading from the specified location
|
||||
* @param configFile the name of the file to load info from
|
||||
*/
|
||||
public HeartbeatMonitorState(String configFile) {
|
||||
_peerPlotState = Collections.synchronizedList(new ArrayList());
|
||||
_refreshRateMs = DEFAULT_REFRESH_RATE;
|
||||
_configFile = configFile;
|
||||
_killed = false;
|
||||
_currentPeerPlotConfig = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many tests are we monitoring?
|
||||
* @return the number of tests
|
||||
*/
|
||||
public int getTestCount() { return _peerPlotState.size(); }
|
||||
|
||||
/**
|
||||
* Retrieves the current info of a test for a certain peer . . .
|
||||
* @param peer a number associated with a certain peer
|
||||
* @return the test data
|
||||
*/
|
||||
public PeerPlotState getTest(int peer) { return (PeerPlotState)_peerPlotState.get(peer); }
|
||||
|
||||
/**
|
||||
* Adds a test . . .
|
||||
* @param peerState the test (by state) to add . . .
|
||||
*/
|
||||
public void addTest(PeerPlotState peerState) {
|
||||
if (!_peerPlotState.contains(peerState))
|
||||
_peerPlotState.add(peerState);
|
||||
}
|
||||
/**
|
||||
* Removes a test . . .
|
||||
* @param peerState the test (by state) to remove . . .
|
||||
*/
|
||||
public void removeTest(PeerPlotState peerState) { _peerPlotState.remove(peerState); }
|
||||
|
||||
/**
|
||||
* Removes a test . . .
|
||||
* @param peerConfig the test (by config) to remove . . .
|
||||
*/
|
||||
public void removeTest(PeerPlotConfig peerConfig) {
|
||||
for (int i = 0; i < getTestCount(); i++) {
|
||||
PeerPlotState state = getTest(i);
|
||||
if (state.getPlotConfig() == peerConfig) {
|
||||
removeTest(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* which of the tests are we currently editing/viewing?
|
||||
* @return the number associated with the test
|
||||
*/
|
||||
public int getPeerPlotConfig() { return _currentPeerPlotConfig; }
|
||||
|
||||
/**
|
||||
* Sets the test we are currently editting/viewing
|
||||
* @param whichTest the number associated with the test
|
||||
*/
|
||||
public void setPeerPlotConfig(int whichTest) { _currentPeerPlotConfig = whichTest; }
|
||||
|
||||
/**
|
||||
* how frequently should we update the data?
|
||||
* @return the current frequency (in milliseconds)
|
||||
*/
|
||||
public int getRefreshRateMs() { return _refreshRateMs; }
|
||||
|
||||
/**
|
||||
* Sets how frequently we should update data
|
||||
* @param ms the frequency (in milliseconds)
|
||||
*/
|
||||
public void setRefreshRateMs(int ms) { _refreshRateMs = ms; }
|
||||
|
||||
/**
|
||||
* where is our config stored?
|
||||
* @return the name of the config file
|
||||
*/
|
||||
public String getConfigFile() { return _configFile; }
|
||||
|
||||
/**
|
||||
* Sets where our config is stored
|
||||
* @param filename the name of the config file
|
||||
*/
|
||||
public void setConfigFile(String filename) { _configFile = filename; }
|
||||
|
||||
/**
|
||||
* have we been shut down?
|
||||
* @return true if we have, false otherwise
|
||||
*/
|
||||
public boolean getWasKilled() { return _killed; }
|
||||
|
||||
/**
|
||||
* Sets if we have been shutdown or not
|
||||
* @param killed true if we've been shutdown, false otherwise
|
||||
*/
|
||||
public void setWasKilled(boolean killed) { _killed = killed; }
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
import net.i2p.heartbeat.PeerDataWriter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*/
|
||||
class HeartbeatPlotPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatPlotPane.class);
|
||||
protected HeartbeatMonitorGUI _gui;
|
||||
private JTextArea _text;
|
||||
|
||||
/**
|
||||
* Constructs the plot pane
|
||||
* @param gui the gui the pane is attached to
|
||||
*/
|
||||
public HeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when things change . . .
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
StringBuffer buf = new StringBuffer(32*1024);
|
||||
PeerDataWriter writer = new PeerDataWriter();
|
||||
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
StaticPeerData data = _gui.getMonitor().getState().getTest(i).getCurrentData();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
|
||||
try {
|
||||
writer.persist(data, baos);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("wtf, error writing to a byte array?", ioe);
|
||||
}
|
||||
buf.append(new String(baos.toByteArray())).append("\n\n\n");
|
||||
}
|
||||
|
||||
_text.setText(buf.toString());
|
||||
}
|
||||
|
||||
protected void initializeComponents() {
|
||||
setBackground(_gui.getBackground());
|
||||
//Dimension size = new Dimension(800, 600);
|
||||
_text = new JTextArea("",30,80); // 16, 60);
|
||||
_text.setAutoscrolls(true);
|
||||
_text.setEditable(false);
|
||||
// _text.setLineWrap(true);
|
||||
// add(new JScrollPane(_text));
|
||||
add(_text);
|
||||
// add(new JScrollPane(_text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
|
||||
// setPreferredSize(size);
|
||||
}
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class JFreeChartAdapter {
|
||||
private final static Log _log = new Log(JFreeChartAdapter.class); /* UNUSED */
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
|
||||
ChartPanel createPanel(HeartbeatMonitorState state) {
|
||||
ChartPanel panel = new ChartPanel(createChart(state));
|
||||
panel.setDisplayToolTips(true);
|
||||
panel.setEnforceFileExtensions(true);
|
||||
panel.setHorizontalZoom(true);
|
||||
panel.setVerticalZoom(true);
|
||||
panel.setMouseZoomable(true, true);
|
||||
panel.getChart().setBackgroundPaint(WHITE);
|
||||
return panel;
|
||||
}
|
||||
|
||||
JFreeChart createChart(HeartbeatMonitorState state) {
|
||||
Plot plot = createPlot(state);
|
||||
JFreeChart chart = new JFreeChart("I2P Heartbeat performance", Font.getFont("arial"), plot, true);
|
||||
return chart;
|
||||
}
|
||||
|
||||
void updateChart(ChartPanel panel, HeartbeatMonitorState state) {
|
||||
XYPlot plot = (XYPlot)panel.getChart().getPlot();
|
||||
plot.setDataset(getCollection(state));
|
||||
updateLines(plot, state);
|
||||
}
|
||||
|
||||
private long getFirst(HeartbeatMonitorState state) { /* UNUSED */
|
||||
long first = -1;
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
List dataPoints = state.getTest(i).getCurrentData().getDataPoints();
|
||||
if ( (dataPoints != null) && (dataPoints.size() > 0) ) {
|
||||
PeerData.EventDataPoint data = (PeerData.EventDataPoint)dataPoints.get(0);
|
||||
if ( (first < 0) || (first > data.getPingSent()) )
|
||||
first = data.getPingSent();
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
Plot createPlot(HeartbeatMonitorState state) {
|
||||
XYItemRenderer renderer = new XYLineAndShapeRenderer(); // new XYDotRenderer(); //
|
||||
XYPlot plot = new XYPlot(getCollection(state), new DateAxis(), new NumberAxis("ms"), renderer);
|
||||
updateLines(plot, state);
|
||||
return plot;
|
||||
}
|
||||
|
||||
private void updateLines(XYPlot plot, HeartbeatMonitorState state) {
|
||||
if (true) return;
|
||||
if (state == null) return;
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
PeerPlotConfig config = state.getTest(i).getPlotConfig();
|
||||
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||
XYSeriesCollection col = ((XYSeriesCollection)plot.getDataset());
|
||||
for (int j = 0; j < col.getSeriesCount(); j++) {
|
||||
//XYItemRenderer renderer = plot.getRendererForDataset(col.getSeries(j));
|
||||
XYItemRenderer renderer = plot.getRendererForDataset(col);
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " send")) {
|
||||
if (curConfig.getPlotSendTime()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " receive")) {
|
||||
if (curConfig.getPlotReceiveTime()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " lost")) {
|
||||
if (curConfig.getPlotLostMessages()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XYSeriesCollection getCollection(HeartbeatMonitorState state) {
|
||||
XYSeriesCollection col = new XYSeriesCollection();
|
||||
if (state != null) {
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
addTest(col, state.getTest(i));
|
||||
}
|
||||
} else {
|
||||
XYSeries series = new XYSeries("latency", false, false);
|
||||
series.add(System.currentTimeMillis(), 0);
|
||||
col.addSeries(series);
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
void addTest(XYSeriesCollection col, PeerPlotState state) {
|
||||
PeerPlotConfig config = state.getPlotConfig();
|
||||
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||
addLines(col, curConfig, config.getTitle(), state.getCurrentData().getDataPoints());
|
||||
addAverageLines(col, config, config.getTitle(), state.getCurrentData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param col the collection of xy series to add to
|
||||
* @param config preferences for how to display this test
|
||||
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||
*/
|
||||
void addLines(XYSeriesCollection col, PeerPlotConfig.PlotSeriesConfig config, String lineName, List data) {
|
||||
if (config.getPlotSendTime()) {
|
||||
XYSeries sendSeries = getSendSeries(data);
|
||||
sendSeries.setName(lineName + " send");
|
||||
sendSeries.setDescription("milliseconds for the ping to reach the peer");
|
||||
col.addSeries(sendSeries);
|
||||
}
|
||||
if (config.getPlotReceiveTime()) {
|
||||
XYSeries recvSeries = getReceiveSeries(data);
|
||||
recvSeries.setName(lineName + " receive");
|
||||
recvSeries.setDescription("milliseconds for the peer's pong to reach the sender");
|
||||
col.addSeries(recvSeries);
|
||||
}
|
||||
if (config.getPlotLostMessages()) {
|
||||
XYSeries lostSeries = getLostSeries(data);
|
||||
lostSeries.setName(lineName + " lost");
|
||||
lostSeries.setDescription("number of ping/pong messages lost");
|
||||
col.addSeries(lostSeries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a data series for each average that we're configured to render
|
||||
*
|
||||
* @param col the collection of xy series to add to
|
||||
* @param config preferences for how to display this test
|
||||
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||
*/
|
||||
void addAverageLines(XYSeriesCollection col, PeerPlotConfig config, String lineName, StaticPeerData data) {
|
||||
if (data.getDataPointCount() <= 0) return;
|
||||
PeerData.EventDataPoint start = (PeerData.EventDataPoint)data.getDataPoints().get(0);
|
||||
PeerData.EventDataPoint finish = (PeerData.EventDataPoint)data.getDataPoints().get(data.getDataPointCount()-1);
|
||||
|
||||
List configs = config.getAverageSeriesConfigs();
|
||||
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||
int minutes = (int)cfg.getPeriod()/(60*1000);
|
||||
if (cfg.getPlotSendTime()) {
|
||||
double time = data.getAverageSendTime(minutes);
|
||||
if (time > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " send " + minutes + "m avg [" + time + "]", false, false);
|
||||
series.add(start.getPingSent(), time);
|
||||
series.add(finish.getPingSent(), time);
|
||||
series.setDescription("send time, averaged over the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
if (cfg.getPlotReceiveTime()) {
|
||||
double time = data.getAverageReceiveTime(minutes);
|
||||
if (time > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " receive " + minutes + "m avg[" + time + "]", false, false);
|
||||
series.add(start.getPingSent(), time);
|
||||
series.add(finish.getPingSent(), time);
|
||||
series.setDescription("receive time, averaged over the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
if (cfg.getPlotLostMessages()) {
|
||||
double num = data.getLostMessages(minutes);
|
||||
if (num > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " lost messages (" + num + " in " + minutes + "m)", false, false);
|
||||
series.add(start.getPingSent(), num);
|
||||
series.add(finish.getPingSent(), num);
|
||||
series.setDescription("number of messages lost in the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XYSeries getSendSeries(List data) {
|
||||
XYSeries series = new XYSeries("sent", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
series.add(point.getPingSent(), point.getPongSent()-point.getPingSent());
|
||||
} else {
|
||||
// series.add(data.getPingSent(), 0);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
XYSeries getReceiveSeries(List data) {
|
||||
XYSeries series = new XYSeries("receive", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
series.add(point.getPingSent(), point.getPongReceived()-point.getPongSent());
|
||||
} else {
|
||||
// series.add(data.getPingSent(), 0);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
XYSeries getLostSeries(List data) {
|
||||
XYSeries series = new XYSeries("lost", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
//series.add(point.getPingSent(), 0);
|
||||
} else {
|
||||
series.add(point.getPingSent(), 1);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*
|
||||
*/
|
||||
class JFreeChartHeartbeatPlotPane extends HeartbeatPlotPane {
|
||||
private final static Log _log = new Log(JFreeChartHeartbeatPlotPane.class); /* UNUSED */
|
||||
private ChartPanel _panel;
|
||||
private JFreeChartAdapter _adapter;
|
||||
|
||||
/**
|
||||
* Creates a JFreeChart plot pane for the given gui
|
||||
* @param gui the heartbeat monitor gui
|
||||
*/
|
||||
public JFreeChartHeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||
super(gui);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the state is updated
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
if (_panel == null) {
|
||||
remove(0); // remove the dummy
|
||||
|
||||
_adapter = new JFreeChartAdapter();
|
||||
_panel = _adapter.createPanel(_gui.getMonitor().getState());
|
||||
_panel.setBackground(_gui.getBackground());
|
||||
add(new JScrollPane(_panel), BorderLayout.CENTER);
|
||||
_gui.pack();
|
||||
} else {
|
||||
_adapter.updateChart(_panel, _gui.getMonitor().getState());
|
||||
//_gui.pack();
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeComponents() {
|
||||
// noop
|
||||
setLayout(new BorderLayout());
|
||||
add(new JLabel(), BorderLayout.CENTER);
|
||||
//dummy.setBackground(_gui.getBackground());
|
||||
//dummy.setPreferredSize(new Dimension(800,600));
|
||||
//add(dummy);
|
||||
|
||||
//add(_panel);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Configure how we want to render a particular clientConfig in the GUI
|
||||
*/
|
||||
class PeerPlotConfig {
|
||||
private final static Log _log = new Log(PeerPlotConfig.class); /* UNUSED */
|
||||
/** where can we find the current state/data (either as a filename or a URL)? */
|
||||
private String _location;
|
||||
/** what test are we defining the plot data for? */
|
||||
private ClientConfig _config;
|
||||
/** how should we render the current data set? */
|
||||
private PlotSeriesConfig _currentSeriesConfig;
|
||||
/** how should we render the various averages available? */
|
||||
private List _averageSeriesConfigs;
|
||||
private Set _listeners;
|
||||
private boolean _disabled;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param location the name of the file/URL to get the data from
|
||||
*/
|
||||
public PeerPlotConfig(String location) {
|
||||
this(location, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a config =)
|
||||
* @param location the location of the file/URL to get the data from
|
||||
* @param config the client's configuration
|
||||
* @param currentSeriesConfig the series config
|
||||
* @param averageSeriesConfigs the average
|
||||
*/
|
||||
public PeerPlotConfig(String location, ClientConfig config, PlotSeriesConfig currentSeriesConfig, List averageSeriesConfigs) {
|
||||
_location = location;
|
||||
if (config == null)
|
||||
config = new ClientConfig(location);
|
||||
_config = config;
|
||||
if (currentSeriesConfig != null)
|
||||
_currentSeriesConfig = currentSeriesConfig;
|
||||
else
|
||||
_currentSeriesConfig = new PlotSeriesConfig(0);
|
||||
|
||||
if (averageSeriesConfigs != null) {
|
||||
_averageSeriesConfigs = averageSeriesConfigs;
|
||||
} else {
|
||||
rebuildAverageSeriesConfigs();
|
||||
}
|
||||
_listeners = Collections.synchronizedSet(new HashSet(2));
|
||||
_disabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Rebuilds' the average series stuff from the client configuration
|
||||
*/
|
||||
public void rebuildAverageSeriesConfigs() {
|
||||
int periods[] = _config.getAveragePeriods();
|
||||
if (periods == null) {
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(0));
|
||||
} else {
|
||||
Arrays.sort(periods);
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(periods.length));
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
_averageSeriesConfigs.add(new PlotSeriesConfig(periods[i]*60*1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an average period
|
||||
* @param minutes the number of minutes averaged over
|
||||
*/
|
||||
public void addAverage(int minutes) {
|
||||
_config.addAveragePeriod(minutes);
|
||||
|
||||
TreeMap ordered = new TreeMap();
|
||||
for (int i = 0; i < _averageSeriesConfigs.size(); i++) {
|
||||
PlotSeriesConfig cfg = (PlotSeriesConfig)_averageSeriesConfigs.get(i);
|
||||
ordered.put(new Long(cfg.getPeriod()), cfg);
|
||||
}
|
||||
Long period = new Long(minutes*60*1000);
|
||||
if (!ordered.containsKey(period))
|
||||
ordered.put(period, new PlotSeriesConfig(minutes*60*1000));
|
||||
|
||||
List cfgs = Collections.synchronizedList(new ArrayList(ordered.size()));
|
||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
||||
cfgs.add(iter.next());
|
||||
|
||||
_averageSeriesConfigs = cfgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where is the current state data supposed to be found? This must either be a
|
||||
* local file path or a URL
|
||||
* @return the current location
|
||||
*/
|
||||
public String getLocation() { return _location; }
|
||||
|
||||
/**
|
||||
* The location the current state data is supposed to be found. This must either be
|
||||
* a local file path or a URL
|
||||
* @param location the location
|
||||
*/
|
||||
public void setLocation(String location) {
|
||||
_location = location;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* What are we configuring?
|
||||
* @return the client configuration
|
||||
*/
|
||||
public ClientConfig getClientConfig() { return _config; }
|
||||
|
||||
/**
|
||||
* Sets what we are currently configuring
|
||||
* @param config the new config
|
||||
*/
|
||||
public void setClientConfig(ClientConfig config) {
|
||||
_config = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* How do we want to render the current data set?
|
||||
* @return the way we currently render the data
|
||||
*/
|
||||
public PlotSeriesConfig getCurrentSeriesConfig() { return _currentSeriesConfig; }
|
||||
|
||||
/**
|
||||
* Sets how we want to render the current data set.
|
||||
* @param config the new config
|
||||
*/
|
||||
public void setCurrentSeriesConfig(PlotSeriesConfig config) {
|
||||
_currentSeriesConfig = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* How do we want to render the averages?
|
||||
* @return the way we currently render the averages
|
||||
*/
|
||||
public List getAverageSeriesConfigs() { return _averageSeriesConfigs; }
|
||||
|
||||
/**
|
||||
* Sets how we want to render the averages
|
||||
* @param configs the new configs
|
||||
*/
|
||||
public void setAverageSeriesConfigs(List configs) { _averageSeriesConfigs = configs; }
|
||||
|
||||
/**
|
||||
* four char description of the peer
|
||||
* @return the name
|
||||
*/
|
||||
public String getPeerName() {
|
||||
Destination peer = getClientConfig().getPeer();
|
||||
if (peer == null)
|
||||
return "????";
|
||||
|
||||
return peer.calculateHash().toBase64().substring(0, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* title: name.packetsize.sendfrequency
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return getPeerName() + '.' + getSize() + '.' + getClientConfig().getSendFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* summary. includes:name, size, sendfrequency, and # of hops
|
||||
* @return the summary
|
||||
*/
|
||||
public String getSummary() {
|
||||
return "Send peer " + getPeerName() + ' ' + getSize() + " every " +
|
||||
getClientConfig().getSendFrequency() + " seconds through " +
|
||||
getClientConfig().getNumHops() + "-hop tunnels";
|
||||
}
|
||||
|
||||
private String getSize() {
|
||||
int bytes = getClientConfig().getSendSize();
|
||||
if (bytes < 1024)
|
||||
return bytes + "b";
|
||||
|
||||
return bytes/1024 + "kb";
|
||||
}
|
||||
|
||||
/**
|
||||
* we've got someone who wants to be notified of changes to the plot config
|
||||
* @param lsnr the listener to be added
|
||||
*/
|
||||
public void addListener(UpdateListener lsnr) { _listeners.add(lsnr); }
|
||||
|
||||
/**
|
||||
* remove a listener
|
||||
* @param lsnr the listener to remove
|
||||
*/
|
||||
public void removeListener(UpdateListener lsnr) { _listeners.remove(lsnr); }
|
||||
|
||||
void fireUpdate() {
|
||||
if (_disabled) return;
|
||||
for (Iterator iter = _listeners.iterator(); iter.hasNext(); ) {
|
||||
((UpdateListener)iter.next()).configUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables notification of events listeners
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
public void disableEvents() { _disabled = true; }
|
||||
|
||||
/**
|
||||
* Enables notification of events listeners
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
public void enableEvents() { _disabled = false; }
|
||||
|
||||
/**
|
||||
* How do we want to render a particular dataset (either the current or the averaged values)?
|
||||
*/
|
||||
public class PlotSeriesConfig {
|
||||
private long _period;
|
||||
private boolean _plotSendTime;
|
||||
private boolean _plotReceiveTime;
|
||||
private boolean _plotLostMessages;
|
||||
private Color _plotLineColor;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param period the period for the config
|
||||
* (0 for current, otherwise # of milliseconds being averaged over)
|
||||
*/
|
||||
public PlotSeriesConfig(long period) {
|
||||
this(period, false, false, false, null);
|
||||
if (period <= 0) {
|
||||
_plotSendTime = true;
|
||||
_plotReceiveTime = true;
|
||||
_plotLostMessages = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a config for the rendering of a particular dataset)
|
||||
* @param period the period for the config
|
||||
* (0 for current, otherwise # of milliseconds being averaged over)
|
||||
* @param plotSend do we plot send times?
|
||||
* @param plotReceive do we plot receive times?
|
||||
* @param plotLost do we plot lost packets?
|
||||
* @param plotColor in what color?
|
||||
*/
|
||||
public PlotSeriesConfig(long period, boolean plotSend, boolean plotReceive, boolean plotLost, Color plotColor) {
|
||||
_period = period;
|
||||
_plotSendTime = plotSend;
|
||||
_plotReceiveTime = plotReceive;
|
||||
_plotLostMessages = plotLost;
|
||||
_plotLineColor = plotColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the plot config this plot series config is a part of
|
||||
* @return the plot config
|
||||
*/
|
||||
public PeerPlotConfig getPlotConfig() { return PeerPlotConfig.this; }
|
||||
|
||||
/**
|
||||
* What period is this series config describing?
|
||||
* @return 0 for current, otherwise # milliseconds that are being averaged over
|
||||
*/
|
||||
public long getPeriod() { return _period; }
|
||||
|
||||
/**
|
||||
* Sets the period this series config is describing
|
||||
* @param period the period
|
||||
* (0 for current, otherwise # milliseconds that are being averaged over)
|
||||
*/
|
||||
public void setPeriod(long period) {
|
||||
_period = period;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we render the time to send (ping to peer)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotSendTime() { return _plotSendTime; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the time to send (ping to peer) or not
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotSendTime(boolean shouldPlot) {
|
||||
_plotSendTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we render the time to receive (peer pong to us)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotReceiveTime() { return _plotReceiveTime; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the time to receive (peer pong to us)
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotReceiveTime(boolean shouldPlot) {
|
||||
_plotReceiveTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/**
|
||||
* Should we render the number of messages lost (ping sent, no pong received in time)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotLostMessages() { return _plotLostMessages; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the number of messages lost (ping sent, no pong received in time) or not
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotLostMessages(boolean shouldPlot) {
|
||||
_plotLostMessages = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/**
|
||||
* What color should we plot the data with?
|
||||
* @return the color
|
||||
*/
|
||||
public Color getPlotLineColor() { return _plotLineColor; }
|
||||
|
||||
/**
|
||||
* Sets the color we should plot the data with
|
||||
* @param color the color to use
|
||||
*/
|
||||
public void setPlotLineColor(Color color) {
|
||||
_plotLineColor = color;
|
||||
fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for listening to updates . . .
|
||||
*/
|
||||
public interface UpdateListener {
|
||||
/**
|
||||
* @param config the peer plot config that changes
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
void configUpdated(PeerPlotConfig config);
|
||||
}
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(PeerPlotConfigPane.class);
|
||||
private PeerPlotConfig _config;
|
||||
private HeartbeatControlPane _parent;
|
||||
private JLabel _title;
|
||||
private JButton _delete;
|
||||
private JLabel _fromLabel;
|
||||
private JTextField _from;
|
||||
private JTextArea _comments;
|
||||
private JLabel _peerLabel;
|
||||
private JTextField _peerKey;
|
||||
private JLabel _localLabel;
|
||||
private JTextField _localKey;
|
||||
private OptionLine _options[];
|
||||
private Random _rnd = new Random();
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
/**
|
||||
* Constructs a pane
|
||||
* @param config the plot config it represents
|
||||
* @param pane the pane this one is attached to
|
||||
*/
|
||||
public PeerPlotConfigPane(PeerPlotConfig config, HeartbeatControlPane pane) {
|
||||
_config = config;
|
||||
_parent = pane;
|
||||
if (_parent != null)
|
||||
_background = _parent.getBackground();
|
||||
_config.addListener(this);
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/** called when the user wants to stop monitoring this test */
|
||||
private void delete() {
|
||||
_parent.removeTest(_config);
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
buildComponents();
|
||||
placeComponents(this);
|
||||
refreshView();
|
||||
//setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
setBackground(_background);
|
||||
}
|
||||
|
||||
/**
|
||||
* place all the gui components onto the given panel
|
||||
* @param body the panel to place the components on
|
||||
*/
|
||||
private void placeComponents(JPanel body) {
|
||||
body.setLayout(new GridBagLayout());
|
||||
GridBagConstraints cts = new GridBagConstraints();
|
||||
|
||||
// row 0: title + delete
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 0;
|
||||
cts.gridwidth = 5;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_title, cts);
|
||||
cts.gridx = 5;
|
||||
cts.gridwidth = 1;
|
||||
cts.anchor = GridBagConstraints.NORTHWEST;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_delete, cts);
|
||||
|
||||
// row 1: from + location
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 1;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_fromLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_from, cts);
|
||||
|
||||
// row 2: comment
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 2;
|
||||
cts.gridwidth = 6;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_comments, cts);
|
||||
|
||||
// row 3: peer + peerKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 3;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_peerLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_peerKey, cts);
|
||||
|
||||
// row 4: local + localKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 4;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_localLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_localKey, cts);
|
||||
|
||||
// row 5-N: data row
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 5 + i;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
if (_options[i]._durationMinutes <= 0)
|
||||
body.add(new JLabel("Data: "), cts);
|
||||
else
|
||||
body.add(new JLabel(_options[i]._durationMinutes + "m avg: "), cts);
|
||||
|
||||
cts.gridx = 1;
|
||||
body.add(_options[i]._send, cts);
|
||||
cts.gridx = 2;
|
||||
body.add(_options[i]._recv, cts);
|
||||
cts.gridx = 3;
|
||||
body.add(_options[i]._lost, cts);
|
||||
cts.gridx = 4;
|
||||
body.add(_options[i]._all, cts);
|
||||
cts.gridx = 5;
|
||||
body.add(_options[i]._color, cts);
|
||||
}
|
||||
}
|
||||
|
||||
/** build all of the gui components */
|
||||
private void buildComponents() {
|
||||
_title = new JLabel(_config.getSummary());
|
||||
_title.setBackground(_background);
|
||||
_delete = new JButton("Delete");
|
||||
_delete.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { delete(); } });
|
||||
_delete.setEnabled(false);
|
||||
_delete.setBackground(_background);
|
||||
_fromLabel = new JLabel("Location: ");
|
||||
_fromLabel.setBackground(_background);
|
||||
_from = new JTextField(_config.getLocation());
|
||||
_from.setEditable(false);
|
||||
_from.setBackground(_background);
|
||||
_comments = new JTextArea(_config.getClientConfig().getComment(), 2, 20);
|
||||
// _comments = new JTextArea(_config.getClientConfig().getComment(), 2, 40);
|
||||
_comments.setEditable(false);
|
||||
_comments.setBackground(_background);
|
||||
_peerLabel = new JLabel("Peer: ");
|
||||
_peerLabel.setBackground(_background);
|
||||
_peerKey = new JTextField(_config.getClientConfig().getPeer().toBase64(), 8);
|
||||
_peerKey.setBackground(_background);
|
||||
_localLabel = new JLabel("Local: ");
|
||||
_localLabel.setBackground(_background);
|
||||
_localKey = new JTextField(_config.getClientConfig().getUs().toBase64(), 8);
|
||||
_localKey.setBackground(_background);
|
||||
|
||||
int averagedPeriods[] = _config.getClientConfig().getAveragePeriods();
|
||||
if (averagedPeriods == null)
|
||||
averagedPeriods = new int[0];
|
||||
|
||||
_options = new OptionLine[1 + averagedPeriods.length];
|
||||
_options[0] = new OptionLine(0);
|
||||
for (int i = 0; i < averagedPeriods.length; i++) {
|
||||
_options[1+i] = new OptionLine(averagedPeriods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** the settings have changed - revise */
|
||||
private void refreshView() {
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_options[i]._durationMinutes);
|
||||
if (cfg == null) {
|
||||
_log.warn("Config for minutes " + _options[i]._durationMinutes + " was not found?");
|
||||
continue;
|
||||
}
|
||||
//_log.debug("Refreshing view for minutes ["+ _options[i]._durationMinutes + "]: send [" +
|
||||
// _options[i]._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
// _options[i]._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
// _options[i]._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
||||
_options[i]._send.setSelected(cfg.getPlotSendTime());
|
||||
_options[i]._recv.setSelected(cfg.getPlotReceiveTime());
|
||||
_options[i]._lost.setSelected(cfg.getPlotLostMessages());
|
||||
if (cfg.getPlotLineColor() != null)
|
||||
_options[i]._color.setBackground(cfg.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find the right config for the given period
|
||||
* @param minutes the minutes to locate the config by
|
||||
* @return the config for the given period, or null
|
||||
*/
|
||||
private PeerPlotConfig.PlotSeriesConfig getConfig(int minutes) {
|
||||
if (minutes <= 0)
|
||||
return _config.getCurrentSeriesConfig();
|
||||
|
||||
List configs = _config.getAverageSeriesConfigs();
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||
if (cfg.getPeriod() == minutes * 60*1000)
|
||||
return cfg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* notified that the config has been updated
|
||||
* @param config the config that was been updated
|
||||
*/
|
||||
public void configUpdated(PeerPlotConfig config) { refreshView(); }
|
||||
|
||||
private class ChooseColor implements ActionListener {
|
||||
private int _minutes;
|
||||
private JButton _button;
|
||||
|
||||
/**
|
||||
* @param minutes the minutes (line) to change the color of...
|
||||
* @param button the associated button
|
||||
*/
|
||||
public ChooseColor(int minutes, JButton button) {
|
||||
_minutes = minutes;
|
||||
_button = button;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||
Color origColor = null;
|
||||
if (cfg != null)
|
||||
origColor = cfg.getPlotLineColor();
|
||||
Color color = JColorChooser.showDialog(PeerPlotConfigPane.this, "What color should this line be?", origColor);
|
||||
if (color != null) {
|
||||
if (cfg != null)
|
||||
cfg.setPlotLineColor(color);
|
||||
_button.setBackground(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OptionLine {
|
||||
int _durationMinutes;
|
||||
JCheckBox _send;
|
||||
JCheckBox _recv;
|
||||
JCheckBox _lost;
|
||||
JCheckBox _all;
|
||||
JButton _color;
|
||||
|
||||
/**
|
||||
* Creates an OptionLine.
|
||||
* @param durationMinutes the minutes =)
|
||||
*/
|
||||
public OptionLine(int durationMinutes) {
|
||||
_durationMinutes = durationMinutes;
|
||||
_send = new JCheckBox("send time");
|
||||
_send.setBackground(_background);
|
||||
_recv = new JCheckBox("receive time");
|
||||
_recv.setBackground(_background);
|
||||
_lost = new JCheckBox("lost messages");
|
||||
_lost.setBackground(_background);
|
||||
_all = new JCheckBox("all");
|
||||
_all.setBackground(_background);
|
||||
_color = new JButton("color");
|
||||
int r = _rnd.nextInt(255);
|
||||
if (r < 0) r = -r;
|
||||
int g = _rnd.nextInt(255);
|
||||
if (g < 0) g = -g;
|
||||
int b = _rnd.nextInt(255);
|
||||
if (b < 0) b = -b;
|
||||
//_color.setBackground(new Color(r, g, b));
|
||||
_color.setBackground(_background);
|
||||
|
||||
_send.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_recv.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_lost.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_all.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_color.addActionListener(new ChooseColor(durationMinutes, _color));
|
||||
_color.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateListener implements ActionListener {
|
||||
private OptionLine _line;
|
||||
private int _minutes;
|
||||
|
||||
/**
|
||||
* Update Listener constructor . . .
|
||||
* @param line the line
|
||||
* @param minutes the minutes
|
||||
*/
|
||||
public UpdateListener(OptionLine line, int minutes) {
|
||||
_line = line;
|
||||
_minutes = minutes;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||
|
||||
cfg.getPlotConfig().disableEvents();
|
||||
_log.debug("Updating data for minutes ["+ _line._durationMinutes + "]: send [" +
|
||||
_line._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
_line._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
_line._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]: config = " + cfg);
|
||||
|
||||
boolean force = _line._all.isSelected();
|
||||
cfg.setPlotSendTime(_line._send.isSelected() || force);
|
||||
cfg.setPlotReceiveTime(_line._recv.isSelected() || force);
|
||||
cfg.setPlotLostMessages(_line._lost.isSelected() || force);
|
||||
cfg.getPlotConfig().enableEvents();
|
||||
cfg.getPlotConfig().fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test stuff
|
||||
* @param args da arsg
|
||||
*/
|
||||
public final static void main(String args[]) {
|
||||
Test t = new Test();
|
||||
t.runTest();
|
||||
}
|
||||
|
||||
private final static class Test implements PeerPlotStateFetcher.FetchStateReceptor {
|
||||
/**
|
||||
* Runs da test
|
||||
*/
|
||||
public void runTest() {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig("C:\\testnet\\r2\\heartbeatStat_10s_30kb.txt");
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.gui.PeerPlotStateFetcher.FetchStateReceptor#peerPlotStateFetched(net.i2p.heartbeat.gui.PeerPlotState)
|
||||
*/
|
||||
public void peerPlotStateFetched(PeerPlotState state) {
|
||||
javax.swing.JFrame f = new javax.swing.JFrame("Test");
|
||||
f.getContentPane().add(new JScrollPane(new PeerPlotConfigPane(state.getPlotConfig(), null)));
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
|
||||
/**
|
||||
* Current data + plot config for a particular test
|
||||
*
|
||||
*/
|
||||
class PeerPlotState {
|
||||
private StaticPeerData _currentData;
|
||||
private PeerPlotConfig _plotConfig;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @see PeerPlotState#PeerPlotState(PeerPlotConfig, StaticPeerData)
|
||||
*/
|
||||
public PeerPlotState() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param config plot config
|
||||
* @see PeerPlotState#PeerPlotState(PeerPlotConfig, StaticPeerData)
|
||||
*/
|
||||
public PeerPlotState(PeerPlotConfig config) {
|
||||
this(config, new StaticPeerData(config.getClientConfig()));
|
||||
}
|
||||
/**
|
||||
* Creates a PeerPlotState
|
||||
* @param config plot config
|
||||
* @param data peer data
|
||||
*/
|
||||
public PeerPlotState(PeerPlotConfig config, StaticPeerData data) {
|
||||
_plotConfig = config;
|
||||
_currentData = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an average
|
||||
* @param minutes mins averaged over
|
||||
* @param sendMs how much later did the peer receieve
|
||||
* @param recvMs how much later did we receieve
|
||||
* @param lost how many were lost
|
||||
*/
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
// make sure we've got the config entry for the average
|
||||
_plotConfig.addAverage(minutes);
|
||||
// add the data point...
|
||||
_currentData.addAverage(minutes, sendMs, recvMs, lost);
|
||||
}
|
||||
|
||||
/**
|
||||
* we successfully got a ping/pong through
|
||||
*
|
||||
* @param sendTime when did the ping get sent?
|
||||
* @param sendMs how much later did the peer receive the ping?
|
||||
* @param recvMs how much later than that did we receive the pong?
|
||||
*/
|
||||
public void addSuccess(long sendTime, int sendMs, int recvMs) {
|
||||
_currentData.addData(sendTime, sendMs, recvMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* we lost a ping/pong
|
||||
*
|
||||
* @param sendTime when did we send the ping?
|
||||
*/
|
||||
public void addLost(long sendTime) {
|
||||
_currentData.addData(sendTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* data set to render
|
||||
* @return the data set
|
||||
*/
|
||||
public StaticPeerData getCurrentData() { return _currentData; }
|
||||
|
||||
/**
|
||||
* Sets the data set to render
|
||||
* @param data the data set
|
||||
*/
|
||||
public void setCurrentData(StaticPeerData data) { _currentData = data; }
|
||||
|
||||
/**
|
||||
* configuration options on how to render the data set
|
||||
* @return the config options
|
||||
*/
|
||||
public PeerPlotConfig getPlotConfig() { return _plotConfig; }
|
||||
|
||||
/**
|
||||
* Sets the configuration options on how to render the data
|
||||
* @param config the config options
|
||||
*/
|
||||
public void setPlotConfig(PeerPlotConfig config) { _plotConfig = config; }
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class PeerPlotStateFetcher {
|
||||
private final static Log _log = new Log(PeerPlotStateFetcher.class);
|
||||
|
||||
/**
|
||||
* Fetch and fill the specified state structure
|
||||
* @param receptor the 'receptor' (callbacks)
|
||||
* @param state the state
|
||||
*/
|
||||
public static void fetchPeerPlotState(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
I2PThread t = new I2PThread(new Fetcher(receptor, state));
|
||||
t.setDaemon(true);
|
||||
t.setName("Fetch state from " + state.getPlotConfig().getLocation());
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback stuff . . .
|
||||
*/
|
||||
public interface FetchStateReceptor {
|
||||
/**
|
||||
* Called when a peer plot state is fetched
|
||||
* @param state state that was fetched
|
||||
*/
|
||||
void peerPlotStateFetched(PeerPlotState state);
|
||||
}
|
||||
|
||||
private static class Fetcher implements Runnable {
|
||||
private PeerPlotState _state;
|
||||
private FetchStateReceptor _receptor;
|
||||
|
||||
/**
|
||||
* Creates a Fetcher thread
|
||||
* @param receptor the 'receptor' (callbacks)
|
||||
* @param state the state
|
||||
*/
|
||||
public Fetcher(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
_state = state;
|
||||
_receptor = receptor;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
String loc = _state.getPlotConfig().getLocation();
|
||||
_log.debug("Load called [" + loc + "]");
|
||||
InputStream in = null;
|
||||
try {
|
||||
try {
|
||||
URL location = new URL(loc);
|
||||
in = location.openStream();
|
||||
} catch (MalformedURLException mue) {
|
||||
_log.debug("Not a url [" + loc + "]");
|
||||
in = null;
|
||||
}
|
||||
|
||||
if (in == null)
|
||||
in = new FileInputStream(loc);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
handleLine(line);
|
||||
}
|
||||
|
||||
if (valid())
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error retrieving from the location [" + loc + "]", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check to make sure we've got everything we need
|
||||
* @return true [always]
|
||||
*/
|
||||
boolean valid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a line from the data set - these can be formatted in one of the
|
||||
* following ways. <p />
|
||||
*
|
||||
* <pre>
|
||||
* peer khWYqCETu9YtPUvGV92ocsbEW5DezhKlIG7ci8RLX3g=
|
||||
* local u-9hlR1ik2hemXf0HvKMfeRgrS86CbNQh25e7XBhaQE=
|
||||
* peerDest [base 64 of the full destination]
|
||||
* localDest [base 64 of the full destination]
|
||||
* numTunnelHops 2
|
||||
* comment Test with localhost sending 30KB every 20 seconds
|
||||
* sendFrequency 20
|
||||
* sendSize 30720
|
||||
* sessionStart 20040409.22:51:10.915
|
||||
* currentTime 20040409.23:31:39.607
|
||||
* numPending 2
|
||||
* lifetimeSent 118
|
||||
* lifetimeRecv 113
|
||||
* #averages minutes sendMs recvMs numLost
|
||||
* periodAverage 1 1843 771 0
|
||||
* periodAverage 5 786 752 1
|
||||
* periodAverage 30 855 735 3
|
||||
* #action status date and time sent sendMs replyMs
|
||||
* EVENT OK 20040409.23:21:44.742 691 670
|
||||
* EVENT OK 20040409.23:22:05.201 671 581
|
||||
* EVENT OK 20040409.23:22:26.301 1182 1452
|
||||
* EVENT OK 20040409.23:22:47.322 24304 1723
|
||||
* EVENT OK 20040409.23:23:08.232 2293 1081
|
||||
* EVENT OK 20040409.23:23:29.332 1392 641
|
||||
* EVENT OK 20040409.23:23:50.262 641 761
|
||||
* EVENT OK 20040409.23:24:11.102 651 701
|
||||
* EVENT OK 20040409.23:24:31.401 841 621
|
||||
* EVENT OK 20040409.23:24:52.061 651 681
|
||||
* EVENT OK 20040409.23:25:12.480 701 1623
|
||||
* EVENT OK 20040409.23:25:32.990 1442 1212
|
||||
* EVENT OK 20040409.23:25:54.230 591 631
|
||||
* EVENT OK 20040409.23:26:14.620 620 691
|
||||
* EVENT OK 20040409.23:26:35.199 1793 1432
|
||||
* EVENT OK 20040409.23:26:56.570 661 641
|
||||
* EVENT OK 20040409.23:27:17.200 641 660
|
||||
* EVENT OK 20040409.23:27:38.120 611 921
|
||||
* EVENT OK 20040409.23:27:58.699 831 621
|
||||
* EVENT OK 20040409.23:28:19.559 801 661
|
||||
* EVENT OK 20040409.23:28:40.279 601 611
|
||||
* EVENT OK 20040409.23:29:00.648 601 621
|
||||
* EVENT OK 20040409.23:29:21.288 701 661
|
||||
* EVENT LOST 20040409.23:29:41.828
|
||||
* EVENT LOST 20040409.23:30:02.327
|
||||
* EVENT LOST 20040409.23:30:22.656
|
||||
* EVENT OK 20040409.23:31:24.305 1843 771
|
||||
* </pre>
|
||||
*
|
||||
* @param line (see above)
|
||||
*/
|
||||
private void handleLine(String line) {
|
||||
if (line.startsWith("peerDest"))
|
||||
handlePeerDest(line);
|
||||
else if (line.startsWith("localDest"))
|
||||
handleLocalDest(line);
|
||||
else if (line.startsWith("numTunnelHops"))
|
||||
handleNumTunnelHops(line);
|
||||
else if (line.startsWith("comment"))
|
||||
handleComment(line);
|
||||
else if (line.startsWith("sendFrequency"))
|
||||
handleSendFrequency(line);
|
||||
else if (line.startsWith("sendSize"))
|
||||
handleSendSize(line);
|
||||
else if (line.startsWith("periodAverage"))
|
||||
handlePeriodAverage(line);
|
||||
else if (line.startsWith("EVENT"))
|
||||
handleEvent(line);
|
||||
else if (line.startsWith("numPending"))
|
||||
handleNumPending(line);
|
||||
else if (line.startsWith("sessionStart"))
|
||||
handleSessionStart(line);
|
||||
else
|
||||
_log.debug("Not handled: " + line);
|
||||
}
|
||||
|
||||
private void handlePeerDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setPeer(d);
|
||||
_log.debug("Setting the peer to " + d.calculateHash().toBase64());
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the peerDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLocalDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setUs(d);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the localDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComment(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
StringBuffer buf = new StringBuffer(line.length()-32);
|
||||
while (tok.hasMoreTokens())
|
||||
buf.append(tok.nextToken()).append(' ');
|
||||
_state.getPlotConfig().getClientConfig().setComment(buf.toString());
|
||||
}
|
||||
|
||||
private void handleNumTunnelHops(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numTunnelHops line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNumPending(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getCurrentData().setPendingCount(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numPending line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendFrequency(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendFrequency line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendSize(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSessionStart(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String date = tok.nextToken();
|
||||
try {
|
||||
long when = getDate(date);
|
||||
_state.getCurrentData().setSessionStart(when);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sessionStart line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePeriodAverage(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
try {
|
||||
// periodAverage minutes sendMs recvMs numLost
|
||||
int min = Integer.parseInt(tok.nextToken());
|
||||
int send = Integer.parseInt(tok.nextToken());
|
||||
int recv = Integer.parseInt(tok.nextToken());
|
||||
int lost = Integer.parseInt(tok.nextToken());
|
||||
_state.addAverage(min, send, recv, lost);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEvent(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
|
||||
// * EVENT OK 20040409.23:29:21.288 701 661
|
||||
// * EVENT LOST 20040409.23:29:41.828
|
||||
tok.nextToken(); // ignore first two
|
||||
tok.nextToken();
|
||||
try {
|
||||
long when = getDate(tok.nextToken());
|
||||
if (when < 0) {
|
||||
_log.error("Invalid EVENT line: [" + line + "]");
|
||||
return;
|
||||
}
|
||||
if (tok.hasMoreTokens()) {
|
||||
int sendMs = Integer.parseInt(tok.nextToken());
|
||||
int recvMs = Integer.parseInt(tok.nextToken());
|
||||
_state.addSuccess(when, sendMs, recvMs);
|
||||
} else {
|
||||
_state.addLost(when);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the EVENT line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd.HH:mm:ss.SSS", Locale.UK);
|
||||
private long getDate(String date) {
|
||||
synchronized (_fmt) {
|
||||
try {
|
||||
return _fmt.parse(date).getTime();
|
||||
} catch (ParseException pe) {
|
||||
_log.error("Unable to parse the date [" + date + "]", pe);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fakeRun() { /* UNUSED */
|
||||
try {
|
||||
Destination peer = new Destination();
|
||||
Destination us = new Destination();
|
||||
peer.fromBase64("3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJ" +
|
||||
"cS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7g" +
|
||||
"fqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teM" +
|
||||
"d5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA");
|
||||
us.fromBase64("W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYpp" +
|
||||
"K9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63" +
|
||||
"rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HC" +
|
||||
"VilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA");
|
||||
_state.getPlotConfig().getClientConfig().setPeer(peer);
|
||||
_state.getPlotConfig().getClientConfig().setUs(us);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(2);
|
||||
_state.getPlotConfig().getClientConfig().setComment("we do stuff\nreally nifty stuff. really");
|
||||
_state.getPlotConfig().getClientConfig().setAveragePeriods(new int[] { 1, 5, 30, 60 });
|
||||
int rnd = new java.util.Random().nextInt();
|
||||
if (rnd > 0)
|
||||
rnd = rnd % 10;
|
||||
else
|
||||
rnd = (-rnd) % 10;
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(rnd);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(16*1024);
|
||||
_state.getPlotConfig().getClientConfig().setStatDuration(10);
|
||||
_state.getPlotConfig().rebuildAverageSeriesConfigs();
|
||||
_state.setCurrentData(new StaticPeerData(_state.getPlotConfig().getClientConfig()));
|
||||
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
|
||||
/**
|
||||
* Raw data points for a test
|
||||
*/
|
||||
class StaticPeerData extends PeerData {
|
||||
private int _pending;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for sending a ping */
|
||||
private Map _averageSendTimes;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for receiving a pong */
|
||||
private Map _averageReceiveTimes;
|
||||
/** Integer (period, in minutes) to Integer (num messages) of how many messages were lost on average */
|
||||
private Map _lostMessages;
|
||||
|
||||
/**
|
||||
* Creates a static peer data with a specified client config ... duh
|
||||
* @param config the client config
|
||||
*/
|
||||
public StaticPeerData(ClientConfig config) {
|
||||
super(config);
|
||||
_averageSendTimes = new HashMap(4);
|
||||
_averageReceiveTimes = new HashMap(4);
|
||||
_lostMessages = new HashMap(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds averaged data
|
||||
* @param minutes the minutes (averaged over)
|
||||
* @param sendMs the send time (ping) in milliseconds
|
||||
* @param recvMs the receive time (pong) in milliseconds
|
||||
* @param lost the number lost
|
||||
*/
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
_averageSendTimes.put(new Integer(minutes), new Integer(sendMs));
|
||||
_averageReceiveTimes.put(new Integer(minutes), new Integer(recvMs));
|
||||
_lostMessages.put(new Integer(minutes), new Integer(lost));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number pending
|
||||
* @param numPending the number pending
|
||||
*/
|
||||
public void setPendingCount(int numPending) { _pending = numPending; }
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.PeerData#setSessionStart(long)
|
||||
*/
|
||||
public void setSessionStart(long when) { super.setSessionStart(when); }
|
||||
|
||||
/**
|
||||
* Adds data
|
||||
* @param sendTime the time it was sent
|
||||
* @param sendMs the send time (ping) in milliseconds
|
||||
* @param recvMs the receive time (pong) in milliseconds
|
||||
*/
|
||||
public void addData(long sendTime, int sendMs, int recvMs) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setPongSent(sendTime + sendMs);
|
||||
dataPoint.setPongReceived(sendTime + sendMs + recvMs);
|
||||
dataPoint.setWasPonged(true);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data
|
||||
* @param sendTime the time it was sent
|
||||
*/
|
||||
public void addData(long sendTime) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setWasPonged(false);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* how many pings are still outstanding?
|
||||
* @return the number of pings outstanding
|
||||
*/
|
||||
public int getPendingCount() { return _pending; }
|
||||
|
||||
|
||||
/**
|
||||
* average time to send over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageSendTime(int period) {
|
||||
Integer i = (Integer)_averageSendTimes.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* average time to receive over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageReceiveTime(int period) {
|
||||
Integer i = (Integer)_averageReceiveTimes.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* number of lost messages over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||
*/
|
||||
public double getLostMessages(int period) {
|
||||
Integer i = (Integer)_lostMessages.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.PeerData#cleanup()
|
||||
*/
|
||||
public void cleanup() {}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
$Id$
|
||||
|
||||
the i2p/apps/httptunnel module is the root of the
|
||||
HTTPTunnel application, and everything within it
|
||||
is released according to the terms of the I2P
|
||||
license policy. That means everything contained
|
||||
within the i2p/apps/httptunnel module is released
|
||||
under the GPL plus the java exception unless
|
||||
otherwise marked. Alternate licenses that may be
|
||||
used include BSD, Cryptix, and MIT, as well as
|
||||
code granted into the public domain.
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="httptunnel">
|
||||
<target name="all" depends="clean, build" />
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../ministreaming/java/" target="build" />
|
||||
<!-- ministreaming will build core -->
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
srcdir="./src"
|
||||
debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="./build/obj"
|
||||
classpath="../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar" />
|
||||
</target>
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="./build/httptunnel.jar" basedir="./build/obj" includes="**/*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.httptunnel.HTTPTunnel" />
|
||||
<attribute name="Class-Path" value="i2p.jar mstreaming.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc
|
||||
sourcepath="./src:../../../core/java/src:../../ministreaming/java/src" destdir="./build/javadoc"
|
||||
packagenames="*"
|
||||
use="true"
|
||||
splitindex="true"
|
||||
windowtitle="HTTPTunnel" />
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,87 +0,0 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Listens on a port for HTTP connections.
|
||||
*/
|
||||
public class HTTPListener extends Thread {
|
||||
|
||||
private static final Log _log = new Log(HTTPListener.class);
|
||||
|
||||
private int port;
|
||||
private String listenHost;
|
||||
private SocketManagerProducer smp;
|
||||
|
||||
/**
|
||||
* A public constructor. It contstructs things. In this case,
|
||||
* it constructs a nice HTTPListener, for all your listening on
|
||||
* HTTP needs. Yep. That's right.
|
||||
* @param smp A SocketManagerProducer, producing Sockets, no doubt
|
||||
* @param port A port, to connect to.
|
||||
* @param listenHost A host, to connect to.
|
||||
*/
|
||||
|
||||
public HTTPListener(SocketManagerProducer smp, int port, String listenHost) {
|
||||
this.smp = smp;
|
||||
this.port = port;
|
||||
start();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
InetAddress lh = listenHost == null ? null : InetAddress.getByName(listenHost);
|
||||
ServerSocket ss = new ServerSocket(port, 0, lh);
|
||||
while (true) {
|
||||
Socket s = ss.accept();
|
||||
new HTTPSocketHandler(this, s);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while accepting connections", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean proxyUsed = false;
|
||||
|
||||
/**
|
||||
* Query whether this is the first use of the proxy or not
|
||||
* @return Whether this is the first proxy use, no doubt.
|
||||
*/
|
||||
public boolean firstProxyUse() {
|
||||
if (true) return false; // FIXME: check a config option here
|
||||
|
||||
if (proxyUsed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
proxyUsed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The SocketManagerProducer being used.
|
||||
*/
|
||||
public SocketManagerProducer getSMP() {
|
||||
return smp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs with HTTP 1.1 flair that a feature isn't implemented.
|
||||
* @param out The stream the text goes to.
|
||||
* @deprecated
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handleNotImplemented(OutputStream out) throws IOException {
|
||||
out.write(("HTTP/1.1 200 Document following\n\n" + "<h1>Feature not implemented</h1>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.httptunnel.handler.RootHandler;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handles a single HTTP socket connection.
|
||||
*/
|
||||
public class HTTPSocketHandler extends Thread {
|
||||
|
||||
private static final Log _log = new Log(HTTPSocketHandler.class);
|
||||
|
||||
private Socket s;
|
||||
private HTTPListener httpl;
|
||||
private RootHandler h;
|
||||
|
||||
/**
|
||||
* A public constructor.
|
||||
* @param httpl An HTTPListener, to listen for HTTP, no doubt
|
||||
* @param s A socket.
|
||||
*/
|
||||
public HTTPSocketHandler(HTTPListener httpl, Socket s) {
|
||||
this.httpl = httpl;
|
||||
this.s = s;
|
||||
h = RootHandler.getInstance();
|
||||
start();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run() {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new BufferedInputStream(s.getInputStream());
|
||||
out = new BufferedOutputStream(s.getOutputStream());
|
||||
Request req = new Request(in);
|
||||
h.handle(req, httpl, out);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling data", ex);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("IOException in finalizer", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* HTTPTunnel
|
||||
* (c) 2003 - 2004 mihi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* In addition, as a special exception, mihi gives permission to link
|
||||
* the code of this program with the proprietary Java implementation
|
||||
* provided by Sun (or other vendors as well), and distribute linked
|
||||
* combinations including the two. You must obey the GNU General
|
||||
* Public License in all respects for all of the code used other than
|
||||
* the proprietary Java implementation. If you modify this file, you
|
||||
* may extend this exception to your version of the file, but you are
|
||||
* not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
|
||||
/**
|
||||
* HTTPTunnel main class.
|
||||
*/
|
||||
public class HTTPTunnel {
|
||||
|
||||
/**
|
||||
* Create a HTTPTunnel instance.
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
int listenPort) {
|
||||
this(initialManagers, maxManagers, shouldThrowAwayManagers, listenPort, "127.0.0.1", 7654);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTTPTunnel instance.
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
* @param i2cpAddress the I2CP address
|
||||
* @param i2cpPort the I2CP port
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
int listenPort, String i2cpAddress, int i2cpPort) {
|
||||
SocketManagerProducer smp = new SocketManagerProducer(initialManagers, maxManagers, shouldThrowAwayManagers,
|
||||
i2cpAddress, i2cpPort);
|
||||
new HTTPListener(smp, listenPort, "127.0.0.1");
|
||||
}
|
||||
|
||||
/**
|
||||
* The all important main function, allowing HTTPTunnel to be
|
||||
* stand-alone, a program in it's own right, and all that jazz.
|
||||
* @param args A list of String passed to the program
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
String host = "127.0.0.1";
|
||||
int port = 7654, max = 1;
|
||||
boolean throwAwayManagers = false;
|
||||
if (args.length > 1) {
|
||||
if (args.length == 4) {
|
||||
host = args[2];
|
||||
port = Integer.parseInt(args[3]);
|
||||
} else if (args.length != 2) {
|
||||
showInfo();
|
||||
return;
|
||||
}
|
||||
max = Integer.parseInt(args[1]);
|
||||
} else if (args.length != 1) {
|
||||
showInfo();
|
||||
return;
|
||||
}
|
||||
if (max == 0) {
|
||||
max = 1;
|
||||
} else if (max < 0) {
|
||||
max = -max;
|
||||
throwAwayManagers = true;
|
||||
}
|
||||
new HTTPTunnel(null, max, throwAwayManagers, Integer.parseInt(args[0]), host, port);
|
||||
}
|
||||
|
||||
private static void showInfo() {
|
||||
System.out.println("Usage: java HTTPTunnel <listenPort> [<max> " + "[<i2cphost> <i2cpport>]]\n"
|
||||
+ " <listenPort> port to listen for browsers\n"
|
||||
+ " <max> max number of SocketMangers in pool, " + "use neg. number\n"
|
||||
+ " to use each SocketManager only once " + "(default: 1)\n"
|
||||
+ " <i2cphost> host to connect to the router " + "(default: 127.0.0.1)\n"
|
||||
+ " <i2cpport> port to connect to the router " + "(default: 7654)");
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* A HTTP request (GET or POST). This will be passed to a hander for
|
||||
* handling it.
|
||||
*/
|
||||
public class Request {
|
||||
|
||||
private static final Log _log = new Log(Request.class);
|
||||
|
||||
// all strings are forced to be ISO-8859-1 encoding
|
||||
private String method;
|
||||
private String url;
|
||||
private String proto;
|
||||
private String params;
|
||||
private String postData;
|
||||
|
||||
/**
|
||||
* A constructor, creating a request from an InputStream
|
||||
* @param in InputStream from which we "read-in" a Request
|
||||
* @throws IOException
|
||||
*/
|
||||
public Request(InputStream in) throws IOException {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in, "ISO-8859-1"));
|
||||
String line = br.readLine();
|
||||
if (line == null) { // no data at all
|
||||
method = null;
|
||||
_log.error("Connection but no data");
|
||||
return;
|
||||
}
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) {
|
||||
method = line;
|
||||
url = "";
|
||||
_log.error("Malformed HTTP request: " + line);
|
||||
} else {
|
||||
method = line.substring(0, pos);
|
||||
url = line.substring(pos + 1);
|
||||
}
|
||||
proto = "";
|
||||
pos = url.indexOf(" ");
|
||||
if (pos != -1) {
|
||||
proto = url.substring(pos); // leading space intended
|
||||
url = url.substring(0, pos);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.length() == 0) break;
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
params = sb.toString(); // no leading empty line!
|
||||
sb = new StringBuffer();
|
||||
// hack for POST requests, ripped from HttpClient
|
||||
// this won't work for large POSTDATA
|
||||
// FIXME: do this better, please.
|
||||
if (!method.equals("GET")) {
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i = br.read();
|
||||
if (i != -1) {
|
||||
sb.append((char) i);
|
||||
}
|
||||
}
|
||||
postData = sb.toString();
|
||||
} else {
|
||||
postData = "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A Request as an array of bytes of a String in ISO-8859-1 format
|
||||
* @throws IOException
|
||||
*/
|
||||
public byte[] toByteArray() throws IOException {
|
||||
if (method == null) return null;
|
||||
return toISO8859_1String().getBytes("ISO-8859-1");
|
||||
|
||||
}
|
||||
|
||||
private String toISO8859_1String() throws IOException {
|
||||
if (method == null) return null;
|
||||
return method + " " + url + proto + "\r\n" + params + "\r\n" + postData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the URL of the request
|
||||
*/
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL of the Request
|
||||
* @param newURL the new URL
|
||||
*/
|
||||
public void setURL(String newURL) {
|
||||
url = newURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a param.
|
||||
* @param name The name of the param
|
||||
* @return The value of the param, or null
|
||||
*/
|
||||
public String getParam(String name) {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) { return line.substring(name.length()); }
|
||||
}
|
||||
return null;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a param.
|
||||
* @param name the name of the param
|
||||
* @param value the value to be set
|
||||
*/
|
||||
public void setParam(String name, String value) {
|
||||
try {
|
||||
StringBuffer sb = new StringBuffer(params.length() + value.length());
|
||||
BufferedReader br = new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
boolean replaced = false;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
replaced = true;
|
||||
if (value == null) continue; // kill param
|
||||
line = name + value;
|
||||
}
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
if (!replaced && value != null) {
|
||||
sb.append(name).append(value).append("\r\n");
|
||||
}
|
||||
params = sb.toString();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
|
||||
/**
|
||||
* Produces SocketManagers in a thread and gives them to those who
|
||||
* need them.
|
||||
*/
|
||||
public class SocketManagerProducer extends Thread {
|
||||
|
||||
private ArrayList myManagers = new ArrayList();
|
||||
private HashMap usedManagers = new HashMap();
|
||||
private int port;
|
||||
private String host;
|
||||
private int maxManagers;
|
||||
private boolean shouldThrowAwayManagers;
|
||||
|
||||
/**
|
||||
* Public constructor creating a SocketManagerProducer
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param host which host to listen on
|
||||
* @param port which port to listen on
|
||||
*/
|
||||
public SocketManagerProducer(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
String host, int port) {
|
||||
if (maxManagers < 1) { throw new IllegalArgumentException("maxManagers < 1"); }
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.shouldThrowAwayManagers = shouldThrowAwayManagers;
|
||||
if (initialManagers != null) {
|
||||
myManagers.addAll(Arrays.asList(initialManagers));
|
||||
}
|
||||
this.maxManagers = maxManagers;
|
||||
this.shouldThrowAwayManagers = shouldThrowAwayManagers;
|
||||
setDaemon(true);
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread producing new SocketManagers.
|
||||
*/
|
||||
public void run() {
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
// without mcDonalds mode, we most probably need no
|
||||
// new managers.
|
||||
while (!shouldThrowAwayManagers && myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
}
|
||||
// produce a new manager, regardless whether it is needed
|
||||
// or not. Do not synchronized this part, since it can be
|
||||
// quite time-consuming.
|
||||
I2PSocketManager newManager = I2PSocketManagerFactory.createManager(host, port, new Properties());
|
||||
// when done, check if it is needed.
|
||||
synchronized (this) {
|
||||
while (myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
myManagers.add(newManager);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a manager for connecting to a given destination. Each
|
||||
* destination will always get the same manager.
|
||||
*
|
||||
* @param dest the destination to connect to
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager(String dest) {
|
||||
I2PSocketManager result = (I2PSocketManager) usedManagers.get(dest);
|
||||
if (result == null) {
|
||||
result = getManager();
|
||||
usedManagers.put(dest, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a "new" SocketManager. Depending on the anonymity settings,
|
||||
* this can be a completely new one or one randomly selected from
|
||||
* a pool.
|
||||
*
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager() {
|
||||
while (myManagers.size() == 0) {
|
||||
myWait(); // no manager here, so wait until one is produced
|
||||
}
|
||||
int which = (int) (Math.random() * myManagers.size());
|
||||
I2PSocketManager result = (I2PSocketManager) myManagers.get(which);
|
||||
if (shouldThrowAwayManagers) {
|
||||
myManagers.remove(which);
|
||||
notifyAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until InterruptedException
|
||||
*/
|
||||
public void myWait() {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Chain multiple filters. Decorator pattern...
|
||||
*/
|
||||
public class ChainFilter implements Filter {
|
||||
|
||||
private static final Log _log = new Log(ChainFilter.class);
|
||||
|
||||
private Collection filters; // perhaps protected?
|
||||
|
||||
/**
|
||||
* @param filters A collection (list) of filters to chain to
|
||||
*/
|
||||
public ChainFilter(Collection filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#filter(byte[])
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
byte[] buf = toFilter;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
buf = f.filter(buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#finish()
|
||||
*/
|
||||
public byte[] finish() {
|
||||
// this is a bit complicated. Think about it...
|
||||
try {
|
||||
byte[] buf = EMPTY;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (buf.length != 0) {
|
||||
baos.write(f.filter(buf));
|
||||
}
|
||||
baos.write(f.finish());
|
||||
buf = baos.toByteArray();
|
||||
}
|
||||
return buf;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error chaining filters", ex);
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
/**
|
||||
* A generic filtering interface.
|
||||
*/
|
||||
public interface Filter {
|
||||
|
||||
/**
|
||||
* An empty byte array.
|
||||
*/
|
||||
public static final byte[] EMPTY = new byte[0];
|
||||
|
||||
/**
|
||||
* Filter some data. Not all filtered data need to be returned.
|
||||
* @param toFilter the bytes that are to be filtered.
|
||||
* @return the filtered data
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter);
|
||||
|
||||
/**
|
||||
* Data stream has finished. Return all of the rest data.
|
||||
* @return the rest of the data
|
||||
*/
|
||||
public byte[] finish();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
/**
|
||||
* A filter letting everything pass as is.
|
||||
*/
|
||||
public class NullFilter implements Filter {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#filter(byte[])
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
return toFilter;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#finish()
|
||||
*/
|
||||
public byte[] finish() {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.httptunnel.SocketManagerProducer;
|
||||
import net.i2p.httptunnel.filter.Filter;
|
||||
import net.i2p.httptunnel.filter.NullFilter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler for browsing Eepsites.
|
||||
*/
|
||||
public class EepHandler {
|
||||
|
||||
private static final Log _log = new Log(EepHandler.class);
|
||||
private static I2PAppContext _context = new I2PAppContext();
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
/* package private */EepHandler(ErrorHandler eh) {
|
||||
errorHandler = eh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @param destination destination as a string, (subject to naming
|
||||
* service lookup)
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
/* boolean fromProxy, */String destination) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = _context.namingService().lookup(destination);
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination);
|
||||
return;
|
||||
}
|
||||
I2PSocketManager sm = smp.getManager(destination);
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
req.setParam("Host: ", dest.toBase64());
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param req the Request to send out
|
||||
* @param f a Filter to apply to the bytes retrieved from the Destination
|
||||
* @param out where to write the results
|
||||
* @param dest the Destination of the Request
|
||||
* @param sm an I2PSocketManager, to get a socket for the Destination
|
||||
* @return boolean, true if something was written, false otherwise.
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean handle(Request req, Filter f, OutputStream out, Destination dest,
|
||||
I2PSocketManager sm) throws IOException {
|
||||
I2PSocket s = null;
|
||||
boolean written = false;
|
||||
try {
|
||||
synchronized (sm) {
|
||||
s = sm.connect(dest, new I2PSocketOptions());
|
||||
}
|
||||
InputStream in = new BufferedInputStream(s.getInputStream());
|
||||
OutputStream sout = new BufferedOutputStream(s.getOutputStream());
|
||||
sout.write(req.toByteArray());
|
||||
sout.flush();
|
||||
byte[] buffer = new byte[16384], filtered;
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
if (len != buffer.length) {
|
||||
byte[] b2 = new byte[len];
|
||||
System.arraycopy(buffer, 0, b2, 0, len);
|
||||
filtered = f.filter(b2);
|
||||
} else {
|
||||
filtered = f.filter(buffer);
|
||||
}
|
||||
written = true;
|
||||
out.write(filtered);
|
||||
}
|
||||
filtered = f.finish();
|
||||
written = true;
|
||||
out.write(filtered);
|
||||
out.flush();
|
||||
} catch (SocketException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} finally {
|
||||
if (s != null) s.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user