forked from I2P_Developers/i2p.i2p
Compare commits
1253 Commits
i2p-0.9.6
...
i2p-0.9.14
Author | SHA1 | Date | |
---|---|---|---|
c7de4e46c1 | |||
fbdc535287 | |||
![]() |
64ec9f6a00 | ||
![]() |
2d6f71dc12 | ||
d4722e0d2c | |||
7187f6f714 | |||
![]() |
e10e05166f | ||
![]() |
b0f8d84a7f | ||
0e9ceba057 | |||
fe3059f0ab | |||
![]() |
bd566f52cf | ||
b7e0dabe61 | |||
2d2348f671 | |||
b28eb708a4 | |||
![]() |
bf9c4b2346 | ||
d33aa097fe | |||
8673c232b6 | |||
d3ea5d2122 | |||
370d2555c7 | |||
5332cee3e8 | |||
1246e1c498 | |||
d6b0b1b93c | |||
1e0c970c95 | |||
db9f49c7d4 | |||
1603353ae8 | |||
6753d23309 | |||
ca5755b0fd | |||
2c8223274d | |||
f0dd09cf9c | |||
4746d9eb80 | |||
99401c5639 | |||
58578d9020 | |||
af575d6c95 | |||
![]() |
e9c8748c0b | ||
![]() |
08409d016b | ||
![]() |
42bfbfc60b | ||
![]() |
c7c087d964 | ||
![]() |
bd45d5483f | ||
ce4874d825 | |||
![]() |
9b408b67ef | ||
c3bf100082 | |||
b282ccd890 | |||
![]() |
f38b741813 | ||
![]() |
3a899d52d1 | ||
a2567b0ee2 | |||
4b0019c732 | |||
5d21738410 | |||
df81006b42 | |||
2c7006e9bd | |||
![]() |
b1caa8d5a3 | ||
8b2ffada10 | |||
![]() |
0998738e94 | ||
![]() |
c04062bbdf | ||
![]() |
0c7a3a3a39 | ||
f364a83f4f | |||
9dabc75866 | |||
2c185ea76c | |||
39e859c368 | |||
dfbe3c4eb1 | |||
b8170a544b | |||
![]() |
4e7f92ec89 | ||
![]() |
292683268b | ||
dc14abd4d3 | |||
dd782f08f7 | |||
d57dc9a8a2 | |||
4e463d57ce | |||
e0c0cc8b63 | |||
cc50d47376 | |||
4da7548caa | |||
91a676cb36 | |||
48a32fb3b8 | |||
845b45a57d | |||
7b7a620999 | |||
82217d5ebc | |||
b95ec70d7d | |||
aa3d3670a4 | |||
8198c83982 | |||
![]() |
75ff7987b8 | ||
![]() |
9c87685c02 | ||
![]() |
ce2bb85440 | ||
![]() |
43fdff2292 | ||
06525adf3d | |||
cff4210dfd | |||
d855c5de50 | |||
![]() |
f1a738340f | ||
![]() |
9827c48527 | ||
![]() |
367d68e552 | ||
![]() |
1498ed361e | ||
91bc16ce05 | |||
![]() |
861a1e26d7 | ||
![]() |
a5b2f9a5e9 | ||
![]() |
9550484037 | ||
![]() |
b33284bb8e | ||
ce2694e8fb | |||
![]() |
44073732e2 | ||
fef591412e | |||
![]() |
f191e50b14 | ||
3379432e5f | |||
bb9129b61b | |||
0fc3029aaa | |||
d8c8586ccf | |||
38a4728283 | |||
7888705b01 | |||
31938f49d6 | |||
c95ed2ea96 | |||
b5ed247a53 | |||
22aff49747 | |||
e4430f05e4 | |||
1047691c64 | |||
f3180b3f6f | |||
616866cc9e | |||
![]() |
58512b8230 | ||
ca4555c496 | |||
bc99bc7206 | |||
1420c773a6 | |||
690b40ed77 | |||
986de4c1d6 | |||
01da32364f | |||
8b1abc08db | |||
![]() |
69e56f8f6b | ||
![]() |
b611d0238a | ||
2dcc9b7a1e | |||
3e54b5d544 | |||
8845ce6e1c | |||
![]() |
ff189e796c | ||
![]() |
89c07ac969 | ||
![]() |
a8e878f894 | ||
![]() |
1f8f3eb4d9 | ||
8fd2a05bf9 | |||
002d057c92 | |||
![]() |
ab44488e4c | ||
![]() |
653ffbc82e | ||
95fd0291e3 | |||
2a269ff1a9 | |||
83ccfb4596 | |||
![]() |
e968828916 | ||
![]() |
ed85a2b82b | ||
![]() |
e692e21dc9 | ||
662fe3ebc2 | |||
1bf8fd92e4 | |||
4dd8a6421a | |||
884b285bf5 | |||
cb340152df | |||
299a44e7eb | |||
40e5bcbdbb | |||
d328e78727 | |||
1bcb9b24b6 | |||
3c1c130bf0 | |||
df3442563c | |||
331b1fa742 | |||
b97a53177e | |||
633b71ba19 | |||
f3dd42143d | |||
7c79f5d5e5 | |||
af5c0bd8a7 | |||
![]() |
c07bfe34ab | ||
![]() |
49681415e2 | ||
![]() |
190e8c01b7 | ||
6ae86f7d81 | |||
![]() |
0aeb3ca75e | ||
![]() |
1d3e12abb7 | ||
![]() |
5e8428ef6c | ||
![]() |
19e3064529 | ||
![]() |
f9dbd74ad8 | ||
ff837cf66e | |||
e0914c358e | |||
0e9bb23c7b | |||
7ff5d36f07 | |||
5a3eab0c7c | |||
c28f707f55 | |||
ef96c88719 | |||
![]() |
faa2435e33 | ||
![]() |
0537a221d3 | ||
![]() |
99c5a1978f | ||
d106f483a1 | |||
![]() |
dee84e70ae | ||
![]() |
09995b77b4 | ||
![]() |
06894f9f0b | ||
73943b1a08 | |||
b573dab05f | |||
a766eca283 | |||
a65edbef92 | |||
7479aa235e | |||
4167cd955b | |||
d1bd893a7b | |||
2467856011 | |||
d32b4e9f24 | |||
1acd5caaa8 | |||
f69b757305 | |||
![]() |
d2db41bc89 | ||
![]() |
f3b4377ee1 | ||
![]() |
551a8091a9 | ||
![]() |
f994590ad7 | ||
8371b8f806 | |||
![]() |
5d04f8db89 | ||
![]() |
06de347373 | ||
![]() |
2bf2eb482e | ||
a93666cd36 | |||
dbb7eb3d88 | |||
39169f0450 | |||
df71308664 | |||
e393f82eb7 | |||
8480a204ea | |||
197be5f60f | |||
5621e9b390 | |||
![]() |
485d785e0b | ||
![]() |
8d71d496be | ||
738bae46d2 | |||
d519228efb | |||
72c404c4d4 | |||
d2e3547a2e | |||
8d9790fd77 | |||
cd91a6b2a4 | |||
e165c1805d | |||
![]() |
292b0a81c0 | ||
![]() |
b9e9c07d95 | ||
![]() |
837bf9eafe | ||
cfdbef05c5 | |||
![]() |
47b10e9771 | ||
![]() |
1b5a2ddef3 | ||
![]() |
c161649ed5 | ||
![]() |
c9b5c03e1b | ||
![]() |
c4c04d7ec5 | ||
![]() |
b4e03fa969 | ||
1cdcf1cb0a | |||
56b6992ca8 | |||
2beaea4a86 | |||
2dc97b160a | |||
a014918c0d | |||
fb9a4eb87a | |||
cd83c48526 | |||
5b2766ddfb | |||
f912b01137 | |||
b0db4e4fff | |||
649f76fb06 | |||
67ea2f3717 | |||
e9e535cb94 | |||
7822b5c3ac | |||
767bd05ce1 | |||
36ebe19cd7 | |||
943ea957a2 | |||
04a3673366 | |||
1dfbe73b73 | |||
87889bb322 | |||
aa0616d7c5 | |||
611ff6357e | |||
91d7a0ab98 | |||
f5661da595 | |||
3f56ce206d | |||
8a2308b411 | |||
04cabf40b5 | |||
4e0c4f6f98 | |||
75bd235eb2 | |||
05236b093a | |||
260ebe512c | |||
c2dab16c8c | |||
945d455f33 | |||
c8f8f6ff34 | |||
0d4f597a59 | |||
775047fbc2 | |||
1e4b43314c | |||
b365817c99 | |||
bbb04774d1 | |||
1823e5e641 | |||
4d2dc1c8e8 | |||
6986f90bf8 | |||
b43ebd2486 | |||
7bf3ea5200 | |||
![]() |
490727b401 | ||
49f4f3398d | |||
![]() |
b84682fdc9 | ||
b9491b269b | |||
b70cbb28b2 | |||
673c14287a | |||
b4a0ffdbbd | |||
3b2e5bded2 | |||
![]() |
67eb3cc140 | ||
5a683149ab | |||
b75ad1ca5a | |||
552ab31559 | |||
4abfde4047 | |||
6ecfedba37 | |||
43883a90d2 | |||
3930113f00 | |||
029198c213 | |||
493788f4f8 | |||
028776de88 | |||
![]() |
705de68aa3 | ||
eb96a74e32 | |||
614f34c6b4 | |||
f77a3c7f56 | |||
6de81d41d2 | |||
7ac9dc5542 | |||
2195c2fe98 | |||
3f35e927dd | |||
5ec659513b | |||
1039a4b7a0 | |||
88899c1233 | |||
![]() |
d429514a3a | ||
b2c6fcbb73 | |||
3b1e030b39 | |||
e097a1caeb | |||
![]() |
d6b09f8bab | ||
6d46344171 | |||
24e807b238 | |||
fdf6f5d51f | |||
4b938a02e7 | |||
44a5740a04 | |||
8d73b2e838 | |||
e1fc6893b4 | |||
![]() |
7487ab8848 | ||
![]() |
e675416b8c | ||
![]() |
24a133fe67 | ||
0570feda6f | |||
b206665c72 | |||
8a6fb132f5 | |||
6992ca8b98 | |||
fd916a7646 | |||
90cd68900e | |||
3f865edb4f | |||
![]() |
2e8681de2c | ||
2d85b98c20 | |||
![]() |
d28d6efb79 | ||
![]() |
43d84a5f07 | ||
![]() |
e4d57f62bb | ||
![]() |
a974268e7b | ||
1695af7011 | |||
![]() |
682c4cd0b8 | ||
![]() |
0f6d039391 | ||
![]() |
d6233a8798 | ||
![]() |
4f12e81dbb | ||
![]() |
ab612d0088 | ||
![]() |
3fa7bb9dc5 | ||
![]() |
22b3d4d70b | ||
bd6c588c74 | |||
6c202e8f1d | |||
24e6750529 | |||
![]() |
af7ce8e18e | ||
c73f0eeeb5 | |||
c68769cf7f | |||
3e639a319d | |||
1bbb79f5b1 | |||
![]() |
84e6991374 | ||
![]() |
5d1796bb6f | ||
![]() |
bfba732f76 | ||
738c5ed14e | |||
beed080390 | |||
3624d66c12 | |||
2cca2781fd | |||
31d485299c | |||
a39f667c2f | |||
5283fc923e | |||
c57552f4e9 | |||
96b4c6b219 | |||
51911bd9a8 | |||
1f5926e4e9 | |||
d6a02a13ad | |||
![]() |
e282491798 | ||
![]() |
2b0dfed012 | ||
9d80aff977 | |||
a0724dc009 | |||
8c820bb237 | |||
3fdc964eac | |||
597662d0dc | |||
![]() |
17c80c29e6 | ||
![]() |
5d0bfc63fa | ||
![]() |
0c449f8b8e | ||
![]() |
36b6baa33e | ||
![]() |
2c049878c6 | ||
81c58c1796 | |||
36a3edf612 | |||
4b6fd3d387 | |||
f777696e14 | |||
c9c181c14a | |||
a62b7a4374 | |||
9d7a9c9895 | |||
5d6a1c5e35 | |||
c48266fdc4 | |||
895d54d36d | |||
![]() |
ba0e1a3aa9 | ||
![]() |
6ec665db50 | ||
![]() |
7f4c52cf42 | ||
![]() |
37728e38c9 | ||
18b4a2427b | |||
3102970540 | |||
c679091afd | |||
91cdf85772 | |||
aab8b10adf | |||
![]() |
5bcfe1ec72 | ||
4209c291ba | |||
7c5dc7fa55 | |||
c6dfb8744a | |||
6e0ca92041 | |||
2f7eb56790 | |||
8c98ef7328 | |||
45997fd1d5 | |||
6a3e5ec620 | |||
18cbf3d253 | |||
4df6a6f47b | |||
![]() |
5542406f3d | ||
a9fceae181 | |||
c79ff0dc09 | |||
e2fc5c6957 | |||
5667a6647f | |||
b70d616083 | |||
![]() |
75fa2b1809 | ||
66d9017d58 | |||
![]() |
53efb7119a | ||
![]() |
8b946bb56b | ||
8ed34e3edf | |||
![]() |
d8fef53aef | ||
6af82f2a9a | |||
36b2547ca4 | |||
72e96cdd23 | |||
a2ba9bbdb1 | |||
![]() |
f6d9a6917f | ||
2e91890401 | |||
1956068698 | |||
855cae0a45 | |||
ef3a12f01a | |||
37bf750ab9 | |||
090a790a9d | |||
![]() |
8ef3bb3d82 | ||
![]() |
388019249d | ||
![]() |
91d1364832 | ||
![]() |
2ec1d8484f | ||
9a01fdf57c | |||
deec84713f | |||
0d028122a6 | |||
4998f86efe | |||
839bd51bc8 | |||
936f2bb317 | |||
0cd774273c | |||
fe391ff29f | |||
001b127258 | |||
7c00a5165f | |||
e1c3e2c1c7 | |||
e9b3577eec | |||
3622501471 | |||
b7207fd29f | |||
4dc1241d2f | |||
c59603d31b | |||
3ab149a399 | |||
99f28519fb | |||
05aa88b4e8 | |||
887f953efb | |||
5e16c42e4e | |||
![]() |
2cea7cdb30 | ||
![]() |
e60da8e8ff | ||
be12995753 | |||
c30419107f | |||
2cacded182 | |||
ec22a1dafc | |||
![]() |
434bf13be9 | ||
![]() |
236df32f30 | ||
28575dbdae | |||
5b9d669d79 | |||
b2f4fde7e5 | |||
9eefe1e935 | |||
b91f041ad7 | |||
ba96f72899 | |||
![]() |
5d322245d8 | ||
6b16907e40 | |||
0c326f989e | |||
e0a499dd0f | |||
0f862124fe | |||
d00be4ceee | |||
ec8354860e | |||
f9144f2fbf | |||
5d2ff5e648 | |||
ce475d2cd6 | |||
72bd1fe91b | |||
![]() |
747d833392 | ||
![]() |
3427464de6 | ||
9ca625a64e | |||
![]() |
9e87fd9b13 | ||
5b6ed48ec0 | |||
96f6865835 | |||
![]() |
fa50f9f246 | ||
![]() |
538b4b10d7 | ||
![]() |
bdb3e26d07 | ||
![]() |
ec87600e80 | ||
0624f46e67 | |||
![]() |
ece1198dd4 | ||
8bbab31872 | |||
8c6922ac5f | |||
6b67f399f6 | |||
![]() |
a9598633b3 | ||
![]() |
1fb2672b67 | ||
![]() |
4308ce6347 | ||
![]() |
32b095efbd | ||
eb4bdfcefb | |||
![]() |
fc6554cabc | ||
![]() |
058590f69b | ||
576984badc | |||
![]() |
9825fcf97b | ||
![]() |
1ed96d72b2 | ||
![]() |
a29935abb3 | ||
![]() |
e92a5da5a5 | ||
![]() |
f08e0299ef | ||
9757435b09 | |||
80fadb4580 | |||
![]() |
8658c23974 | ||
![]() |
0264cc9030 | ||
![]() |
bd5b6b32b5 | ||
![]() |
dc0a1281bf | ||
c20c697126 | |||
44e7110c9a | |||
c860c49c6b | |||
b16e66d39a | |||
![]() |
3b06f0b83c | ||
0bc6c23ac9 | |||
17e63b054c | |||
0fae0640d6 | |||
d054e12952 | |||
![]() |
dc60c2b478 | ||
b59aa1fb69 | |||
![]() |
54a21bfa7b | ||
![]() |
50f55877f8 | ||
![]() |
f9ff262318 | ||
![]() |
91ba76f2a6 | ||
![]() |
ec97bc2f81 | ||
fba209ca7d | |||
b91b242a1a | |||
38186c8f75 | |||
1b3aefbbce | |||
c03511b971 | |||
78e7599a8a | |||
dc871cf1eb | |||
![]() |
e98b9d0af5 | ||
![]() |
2a09d5baa6 | ||
41e071efe5 | |||
e8e239616f | |||
![]() |
1feb317f8b | ||
![]() |
09668453d0 | ||
5842e25205 | |||
5219791673 | |||
bf485d8bce | |||
cc97a19d3c | |||
38c02b44b9 | |||
04a596899a | |||
ee1ed1bb82 | |||
2b39d28e99 | |||
8cb503d8bb | |||
efff25a87c | |||
6e2583ad92 | |||
af84bcf945 | |||
3dc429415b | |||
ec9dd25631 | |||
2bda87d5a7 | |||
![]() |
a7a816e0a7 | ||
3d9d722cee | |||
289a8e7b40 | |||
![]() |
7d3aa33c25 | ||
0db1314595 | |||
68641626aa | |||
5b9fb403c9 | |||
![]() |
a4114b96fd | ||
![]() |
de184ed139 | ||
04c342ec6a | |||
27ce28027d | |||
f8a54bde19 | |||
3acfdbe8f7 | |||
d9fed57c89 | |||
46e7e9be82 | |||
d87d4eb232 | |||
88ea451f81 | |||
![]() |
822ec4aa53 | ||
7b0b07933f | |||
7fe8573df4 | |||
![]() |
c180292358 | ||
![]() |
a3fa48dcbe | ||
445e4301d5 | |||
![]() |
736da22bba | ||
![]() |
f29c64cd70 | ||
![]() |
aa4b4b9d2b | ||
![]() |
1112fc8544 | ||
![]() |
9b361ac445 | ||
![]() |
0ff423fc57 | ||
![]() |
efe3bd2c05 | ||
![]() |
f112baac48 | ||
![]() |
707f616498 | ||
![]() |
ed2feb3ff7 | ||
![]() |
a17b1b99c0 | ||
![]() |
27bc32f2f3 | ||
![]() |
b535054e13 | ||
![]() |
97a9a6090a | ||
![]() |
8b8e2c88c1 | ||
![]() |
9d7ee30c15 | ||
![]() |
4ee144533a | ||
![]() |
0f2a983bb7 | ||
![]() |
8fd2f9090e | ||
![]() |
8770d7eae0 | ||
![]() |
c59ef24acf | ||
![]() |
85aa2fb083 | ||
434b9fa0d1 | |||
56116ad8c2 | |||
c0ef19a281 | |||
![]() |
9804e5b7d9 | ||
![]() |
2f33186e58 | ||
![]() |
0347c56c96 | ||
![]() |
e77409e57a | ||
![]() |
615ba94559 | ||
![]() |
ce0596d5b1 | ||
![]() |
35b6926e4f | ||
76925fa3bd | |||
dbdf36d85c | |||
60aa8c57a4 | |||
001070f677 | |||
![]() |
c6f2d4948b | ||
8699c82614 | |||
1d7eedd463 | |||
796a231f54 | |||
![]() |
e1fcad686c | ||
ffa03f2b83 | |||
54fb91ba8e | |||
e498e2113f | |||
f42ac71fe0 | |||
74f2fd06cc | |||
143a0dfc47 | |||
![]() |
fdb0097934 | ||
![]() |
0dde4162e6 | ||
844bae18ba | |||
9e4d5c0e61 | |||
9b8d3eb688 | |||
![]() |
8478bfbddc | ||
![]() |
d6bb5f6a4d | ||
![]() |
e9fec9354b | ||
![]() |
f9f0e6d0a2 | ||
![]() |
3bc0be1cbe | ||
![]() |
8d826cee93 | ||
![]() |
e853d9a40b | ||
![]() |
15bf94b479 | ||
![]() |
6314f33d8f | ||
![]() |
5fa0376f58 | ||
![]() |
552dd189a5 | ||
![]() |
57144f3e6a | ||
0454639db8 | |||
![]() |
c32b451733 | ||
![]() |
2f4765665d | ||
![]() |
bff79cdae8 | ||
![]() |
4bddf8ae0b | ||
![]() |
ae79deff39 | ||
![]() |
e3aeb267f8 | ||
![]() |
c5c26c440d | ||
![]() |
77971624b4 | ||
![]() |
f5621c5082 | ||
![]() |
3fa7fe9733 | ||
![]() |
c97d07e10a | ||
![]() |
567c328331 | ||
![]() |
3aa982529e | ||
![]() |
0c07f9ff96 | ||
![]() |
f0055ccbfe | ||
![]() |
693cc828c2 | ||
![]() |
688dd23111 | ||
![]() |
e38db5eb44 | ||
![]() |
817f531619 | ||
![]() |
53623da2eb | ||
![]() |
4910266d9b | ||
![]() |
24ae66df6d | ||
![]() |
228bd980db | ||
![]() |
f161a2dfc9 | ||
![]() |
abe1dc676e | ||
9de57a5d5a | |||
![]() |
2cc742c3ed | ||
![]() |
5bcfe025d5 | ||
![]() |
6dc6ca7713 | ||
![]() |
eabcc96a99 | ||
![]() |
28b6675979 | ||
![]() |
413ad6b0e6 | ||
![]() |
a7a7e96188 | ||
![]() |
796dbc5d2e | ||
![]() |
c86845078c | ||
![]() |
89dcceefee | ||
![]() |
bacce17990 | ||
![]() |
e61e950713 | ||
![]() |
244209d3b7 | ||
dbe0a8240e | |||
7e3e08532f | |||
1d4190734d | |||
96cf1d60c2 | |||
![]() |
3aa33378c1 | ||
![]() |
747bd0c5a3 | ||
ea7b42810f | |||
19022baa27 | |||
![]() |
e8248f5005 | ||
![]() |
f8178b7165 | ||
![]() |
79b5d9748d | ||
b53ed94e8f | |||
df84a2fcd0 | |||
![]() |
25e7dea370 | ||
![]() |
90919ebf6b | ||
76078deb3f | |||
![]() |
1b95a03d2e | ||
![]() |
108039de08 | ||
![]() |
addd2e6d6a | ||
![]() |
5c38d5a6c9 | ||
69489dd19e | |||
3fce0e8e45 | |||
![]() |
35fb332c2c | ||
1b5309be05 | |||
d2a1025b3f | |||
![]() |
0a8f79f0e3 | ||
18e4c2ac63 | |||
90c2e08489 | |||
598ef67c4e | |||
1b9d870b91 | |||
68f67b7c8e | |||
![]() |
d2f0c251c0 | ||
2b2f34b3f1 | |||
4e680479da | |||
d1b93e0705 | |||
4382def62f | |||
952a56c537 | |||
67aead214b | |||
50f45a50a7 | |||
![]() |
6b326c3705 | ||
![]() |
919ec3af01 | ||
![]() |
ca5a301a4f | ||
ae76a6ee1a | |||
5cbecb3599 | |||
5a34e1de4f | |||
c810694e07 | |||
ca866d48e6 | |||
![]() |
f1e77499e2 | ||
9007db1485 | |||
85c998e500 | |||
8296f8229e | |||
059ae3a80e | |||
![]() |
67e242c441 | ||
e23f3b4875 | |||
06ea9af733 | |||
884818f518 | |||
3f39bd0f7b | |||
![]() |
48cce6435b | ||
777e08c8b6 | |||
8c4b0b7c00 | |||
dae8b25374 | |||
![]() |
2ae293444e | ||
0f11d3566a | |||
fa70d439c3 | |||
0010581405 | |||
1d659e4f8a | |||
![]() |
509f00c5e2 | ||
![]() |
aeb3241abb | ||
8909df3c88 | |||
1cffcae36b | |||
d2ee5b96ad | |||
0506a5915b | |||
91ef3fd0bc | |||
![]() |
79f5484f87 | ||
![]() |
6afd2c4b97 | ||
06b09f89de | |||
bd0eee6aa9 | |||
![]() |
5bc13c16dc | ||
![]() |
626daeb86e | ||
a92913da4c | |||
f0f363e8c3 | |||
7839c0fec3 | |||
4d24d65c1f | |||
ddf761b1f8 | |||
2814fe75b1 | |||
7316c82ef3 | |||
e04646bd37 | |||
8f8022347d | |||
![]() |
acc0ab66a3 | ||
5a6acf1d85 | |||
ca45194c30 | |||
102506ebe8 | |||
d06f1c4a30 | |||
c732c1c038 | |||
4aa1bba575 | |||
9d3925eb20 | |||
80fdf4e917 | |||
35a86e603b | |||
8f7b31aed3 | |||
0f5a0b6b1b | |||
4cf3906ed2 | |||
57875586cf | |||
ad8ec011d0 | |||
0d93b86a56 | |||
63712002e2 | |||
67af1a17c1 | |||
9cac546547 | |||
3ffb321f46 | |||
14ea6d8d0a | |||
8e0dbf31ba | |||
5187bf1eae | |||
99471d8e1b | |||
012e999354 | |||
bdd9900d0d | |||
c71b485083 | |||
a78d34ab4b | |||
255ebe7efb | |||
5f7a761e42 | |||
09548358fa | |||
df381c37ff | |||
![]() |
31e96b416d | ||
![]() |
53b0f7b579 | ||
45deaa3a87 | |||
0c8eabcdf6 | |||
f9571740ae | |||
eb2af2b5fd | |||
ded00300b4 | |||
811819af69 | |||
![]() |
1804c852bb | ||
3ec602865d | |||
0c0a25b038 | |||
208192f445 | |||
![]() |
d0f635e30c | ||
20b2f7dcb1 | |||
cf66951818 | |||
c6f41cc8fa | |||
45a579403a | |||
74a57abfb4 | |||
380783c1ba | |||
![]() |
c8843a736d | ||
![]() |
e69fefda62 | ||
![]() |
513da3b743 | ||
7513d42e9e | |||
8872437caf | |||
![]() |
712c77a4b6 | ||
38cef14cf4 | |||
05c3b0d391 | |||
854090e9d8 | |||
f035815f7a | |||
df4302dda0 | |||
31f117e74c | |||
890f40b2ac | |||
3ac8083faf | |||
249319f76f | |||
efe87060b4 | |||
afe3ff57cf | |||
6bb1505d3b | |||
a1c8e3eae3 | |||
aa171bbaa6 | |||
845b70fe0c | |||
82b1eb7c18 | |||
4bd27ea1d3 | |||
d0f6be3161 | |||
7764257e41 | |||
af0e72ac4d | |||
0534440695 | |||
c2fa2d0c5b | |||
887017b54c | |||
3a4f5a2f1b | |||
3fb4643742 | |||
a5e3bc9b85 | |||
8a0c3f10f4 | |||
e1d808a284 | |||
e755051ebe | |||
d7c3ffa4de | |||
cba3b249dd | |||
32f250003e | |||
e004b0e6e9 | |||
a5c5917a5f | |||
![]() |
cbd24946b6 | ||
9b4842931a | |||
e04cf132cc | |||
7d237b4cf6 | |||
3cbfd09722 | |||
0ae774dd68 | |||
2884df873e | |||
![]() |
d4d1424c4f | ||
![]() |
33827f9aaf | ||
30a666c833 | |||
9a00621fa4 | |||
![]() |
46bc479884 | ||
![]() |
6ab6abf4dd | ||
0c6a9ff2a0 | |||
aefc5b5317 | |||
25682fdea7 | |||
9318099845 | |||
fdf38a952d | |||
fb40ab1f00 | |||
3499ed7bb0 | |||
b05906a3c2 | |||
61d5f46295 | |||
9ebfccd8f6 | |||
4fb3e86e4d | |||
837517e94e | |||
f47ec65b8f | |||
6fede7f524 | |||
bd0c18b2e3 | |||
fba596c78c | |||
![]() |
61f2b49022 | ||
![]() |
e71a1a5c4d | ||
![]() |
683ce3254f | ||
![]() |
df555731c4 | ||
![]() |
641fc0cae9 | ||
![]() |
5ab1d6896a | ||
0ae2d92fcd | |||
26c8201e03 | |||
![]() |
37521c69a2 | ||
![]() |
43383a5b3c | ||
![]() |
bfea3e4dd6 | ||
![]() |
35b02a52e1 | ||
![]() |
8e3e566915 | ||
![]() |
968b9a0304 | ||
![]() |
c97f0f3d22 | ||
![]() |
65b1124d81 | ||
89034e1f9d | |||
9f2fa6a8be | |||
19cf8787d8 | |||
a80c34c1df | |||
ab8900f910 | |||
ce2d0b0e12 | |||
87d98781a9 | |||
79dc95dd66 | |||
c6533202f7 | |||
b5dc9bc0ba | |||
79891c6677 | |||
68aa1aea8e | |||
4ffaf4128e | |||
801ca47a0c | |||
43f5062169 | |||
7ab4dd7f4b | |||
71c0104236 | |||
a608d21571 | |||
935ddaa0b2 | |||
945e7b75fd | |||
![]() |
5e90780590 | ||
a8a21ea7ce | |||
23444e4b81 | |||
a3ea1f9429 | |||
78d4b6d8a7 | |||
3e3399adc6 | |||
1e554dd0fe | |||
![]() |
388e7088e1 | ||
![]() |
e65289cd0d | ||
![]() |
c4d68a8352 | ||
![]() |
7be0a93251 | ||
![]() |
175f47293a | ||
27936fce04 | |||
![]() |
592680302f | ||
55318cf14b | |||
83ead0c304 | |||
38ec55bc72 | |||
c4f97ed65e | |||
78a426e9ac | |||
928b4bbbe5 | |||
d27c465371 | |||
4d62f63c71 | |||
f4039b085a | |||
![]() |
53ed10cfc8 | ||
0859dbe57f | |||
42bc4bb1f4 | |||
caead8a3a4 | |||
7394c7997b | |||
0298e4ab4c | |||
e3a5cdbbc2 | |||
![]() |
6ae46abac0 | ||
![]() |
615a5f3c39 | ||
![]() |
6812dc1db8 | ||
41595cafce | |||
d6c4e411be | |||
6ca797ec1f | |||
8655988c66 | |||
de5f2940ce | |||
1933e6239b | |||
8aec1e2eb6 | |||
![]() |
def30c5903 | ||
![]() |
193f0bbc42 | ||
![]() |
b7a3b7bf05 | ||
![]() |
a2bd45fa9b | ||
![]() |
fd297118f9 | ||
7171edad24 | |||
d8466333f3 | |||
a5e4d586eb | |||
![]() |
28a1c22438 | ||
![]() |
74e238322d | ||
![]() |
1f3227409b | ||
![]() |
afda1da9c3 | ||
f2857e8f97 | |||
4802b1e2cd | |||
0328304f04 | |||
06d2db0046 | |||
![]() |
0539610219 | ||
170be8f033 | |||
ca0bb1ab76 | |||
cdccb51456 | |||
![]() |
870ecb847f | ||
![]() |
8ba493c60e | ||
![]() |
f3affff5be | ||
5941a52a0d | |||
04e6beb43c | |||
1284c7ace0 | |||
![]() |
63414f0348 | ||
![]() |
c8f22fdfd0 | ||
7737bf5212 | |||
4340f70d72 | |||
6dbd8a6d1a | |||
076871fe44 | |||
be753d7a1a | |||
e3f02553fd | |||
767ef8c489 | |||
482787fbc3 | |||
![]() |
b2d72f90ce | ||
![]() |
dd181a90e1 | ||
19faa352e3 | |||
ffda7f6326 | |||
8ebacf4c10 | |||
a02cc25844 | |||
8aeca5b433 | |||
7b4855d7cf | |||
803d7ff282 | |||
![]() |
a1c724f866 | ||
![]() |
96609e9173 | ||
f5518739e2 | |||
e7c8d28b99 | |||
dff357a658 | |||
cc271de7df | |||
a7485ab5a3 | |||
![]() |
7133736702 | ||
![]() |
2313d82369 | ||
1b42d99e66 | |||
![]() |
d709f46183 | ||
![]() |
97c1676bcb | ||
02b92ac3fe | |||
29eb1d5dc5 | |||
a87fc68cfd | |||
bc1cf64df4 | |||
b607d7b223 | |||
4e00eaf9a3 | |||
90cc71d14d | |||
554a3a6b0e | |||
8505e8a1ca | |||
![]() |
54ec878698 | ||
![]() |
ea4606fe79 | ||
![]() |
96de87fdde | ||
![]() |
55d571ffec | ||
![]() |
ae347c4fa1 | ||
![]() |
e93beb7c63 | ||
![]() |
018098b8ef | ||
![]() |
1e2fb4bea5 | ||
![]() |
171f0d2671 | ||
![]() |
175cb0817e | ||
3b46acc285 | |||
d31ce49e77 | |||
![]() |
8937c4bf2a | ||
![]() |
2902a708f9 | ||
20e152e79a | |||
c1210b1c04 | |||
71038c311f | |||
1cf9ae381d | |||
![]() |
4cb5a27a05 | ||
![]() |
b0b0124138 | ||
![]() |
9e12801503 | ||
70a8ab1d1a | |||
f3c4a26483 | |||
9a1e1a92ca | |||
732eddd1b9 | |||
2caa6ad975 | |||
d3e0161a6b | |||
![]() |
67859f67b0 | ||
![]() |
b486ae5c26 | ||
![]() |
aab4a3ab44 | ||
![]() |
e9e550fb55 | ||
![]() |
f80ea386a0 | ||
![]() |
7429762d2e | ||
aabbdc1c1b | |||
3af766bd6e | |||
![]() |
614b8b4cdd | ||
![]() |
bec62c1be7 | ||
![]() |
7f8efca0ba | ||
![]() |
76de4faf62 | ||
![]() |
dfc4948a6f | ||
![]() |
ba0e58e66a | ||
![]() |
18531f0c09 | ||
![]() |
93df048bd6 | ||
![]() |
2927382a2b | ||
![]() |
b4780d16eb | ||
6f5f4d179b | |||
b9a5dd48f6 | |||
0db7e2873c | |||
b84bfd575f | |||
![]() |
70bb81bcc3 | ||
![]() |
7ebb26b734 | ||
![]() |
fb93609d8b | ||
![]() |
eb051d64c7 | ||
![]() |
58bb94a960 | ||
![]() |
98d932a0f5 | ||
de4b0198b7 | |||
570f8526b0 | |||
d173b79949 | |||
![]() |
67f73d7198 | ||
![]() |
6e36d374ea | ||
![]() |
740b37b70c | ||
![]() |
782e38bdcf | ||
![]() |
937404b39c | ||
![]() |
a0bf223031 | ||
6b15caab4b | |||
3aafea0d98 | |||
![]() |
1c68852f45 | ||
![]() |
4f6065b4fa | ||
![]() |
14944982fb | ||
![]() |
10bf74e045 | ||
![]() |
a9d9e6b572 | ||
79f8e88e5f | |||
![]() |
bddfe3ed86 | ||
![]() |
a308179d81 | ||
![]() |
f8648ff4c4 | ||
552f91b6b8 | |||
726eb58724 | |||
eb5a23fc5b | |||
d4c8e03f86 | |||
46d13d2b08 | |||
003dc37817 | |||
847a441d59 | |||
![]() |
a5f3220df0 | ||
![]() |
a5df6d419d | ||
![]() |
78a25f0b17 | ||
![]() |
dc7ea9c126 | ||
![]() |
70adc4df32 | ||
![]() |
c47f491e2f | ||
![]() |
1d9b89db23 | ||
![]() |
ec70f2420c | ||
![]() |
f525685765 | ||
4970fd22dc | |||
ac9392b9e6 | |||
5ba86ca254 | |||
87826daae9 | |||
![]() |
7df52a155e | ||
d2184f418f | |||
![]() |
f91f81158f | ||
bb100de702 | |||
322e76d2a9 | |||
1444f1239f | |||
5bd028bff5 | |||
![]() |
25feb745bc | ||
7e0654ae0a | |||
00d1b7519f | |||
faadbf700d | |||
180d42541a | |||
bdc4eff1c4 | |||
fa0b52fc3a | |||
f9f1391057 | |||
34b7081303 | |||
e0cd71069f | |||
36e898d668 | |||
a90827c9b2 | |||
![]() |
dd451d3ccd | ||
![]() |
937f4f2f40 | ||
![]() |
e7718b1fba | ||
![]() |
29b599bc8d | ||
![]() |
6bbd34eed9 | ||
![]() |
f939f689fc | ||
a48fba0102 | |||
02923138d0 | |||
87d142bace | |||
933ad52398 | |||
![]() |
9d52ef5fbe | ||
![]() |
34748d23be | ||
![]() |
15dae0fd92 | ||
![]() |
ccf6cf5e20 | ||
36d4b20bdc | |||
a70810ffae | |||
526df43233 | |||
660be7d579 | |||
876109d3a5 | |||
39493e0f24 | |||
62413331da | |||
68d25afcba | |||
182fe900b8 | |||
0fb4f6ab6a | |||
ebc5e72908 | |||
![]() |
081b692736 | ||
e1c68d22a3 | |||
b7dc8f425e | |||
4a65676738 | |||
000ca7c7b7 | |||
9386270b57 | |||
f0886c5f6e | |||
239cd2b744 | |||
db9827779e | |||
905eed6643 | |||
![]() |
5711d96744 | ||
fc2734c484 | |||
75261a0ce4 | |||
7fc2cd9cde | |||
e72a763019 | |||
ff20174572 | |||
7d08183334 | |||
66f7505baa | |||
e54465b226 | |||
78c17ba353 | |||
bfac9e398d | |||
eef5661008 | |||
4b9a7323ad | |||
![]() |
429ccf21b6 | ||
![]() |
4805a77d40 | ||
![]() |
3a707a143d | ||
![]() |
b4264063f4 | ||
![]() |
535c782b7c | ||
3833ad534f | |||
3d42946ff5 | |||
a1afa1c1b0 | |||
![]() |
8fb65292cf | ||
![]() |
29ce84ff33 | ||
378c5a0d4e | |||
![]() |
ca569038e8 | ||
![]() |
4092eba606 | ||
![]() |
63e71d8a3d | ||
![]() |
278caf72e0 | ||
![]() |
4d6b7556c3 | ||
e5e7dbbb58 | |||
e394d3d4c5 | |||
6c62c1f362 | |||
3daf287de8 | |||
![]() |
5c4c02161c | ||
![]() |
ba859fc9ad | ||
9a4cd11748 | |||
![]() |
8acf5f3079 | ||
c0350702fd | |||
55880844a5 | |||
729282c0c4 | |||
d603c3b5cd | |||
5cda1ec703 | |||
ec3756a69f | |||
0b49fa98f9 | |||
226c7eb8e3 | |||
![]() |
addffcffcb | ||
be262c6a70 | |||
a374f00613 | |||
fcdf837f33 | |||
febc0a5237 | |||
a19140e186 | |||
e0b25cdcf9 | |||
e332c8bc27 | |||
7318632db9 | |||
1b38a6478b | |||
6ceea60c92 | |||
fcaebb4416 | |||
0be3beb30e | |||
![]() |
3210dd8d3e | ||
5e51c6abef | |||
5e953b0857 | |||
c76c80043f | |||
3a49d6d28f | |||
94e34ff366 | |||
af27c76b2c | |||
60336c9555 | |||
a85b7aa9f8 | |||
228e6d7d03 | |||
31531ee882 | |||
368c2073b2 | |||
757df8c726 | |||
c6121cb31e | |||
eecab472eb | |||
b71631d2ec | |||
3ec78e27b4 | |||
![]() |
5375e425ac | ||
![]() |
ebb2f1396b |
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# Just to try and prevent some noob disasters.
|
||||
# Use git add -f foo.jar to ignore this ignore list
|
||||
|
||||
# generated release files
|
||||
*.exe
|
||||
*.[gx]z
|
||||
*.bz2
|
||||
*.[rwjt]ar
|
||||
*.sig
|
||||
*.su[d23]
|
||||
*.deb
|
||||
*.zip
|
||||
*.torrent
|
||||
|
||||
*~
|
||||
web-fragment.xml
|
||||
web-out.xml
|
||||
*.out
|
||||
|
||||
# Temporary/build dirs
|
||||
build/
|
||||
pkg-temp/
|
||||
classes/
|
||||
dist/
|
||||
/installer/resources/locale/mo
|
||||
/tmp
|
||||
/apps/jetty/jettylib
|
||||
*_jsp.java
|
||||
*.class
|
||||
|
||||
# Debian-related
|
||||
/debian/copyright
|
||||
/debian/changelog
|
||||
.pc/
|
||||
|
||||
# Build property overrides
|
||||
/override.properties
|
||||
|
||||
# Reporting
|
||||
*.fba
|
||||
sloccount.sc
|
||||
/reports/
|
||||
|
||||
# Don't allow patches
|
||||
*.(diff|patch)
|
||||
|
||||
# but allow debian/patches
|
||||
!/debian/patches/*.(patch|diff)
|
25
.mtn-ignore
25
.mtn-ignore
@@ -1,5 +1,7 @@
|
||||
# Just to try and prevent some noob disasters.
|
||||
# Use mtn add --no-respect-ignore foo.jar to ignore this ignore list
|
||||
|
||||
# Temporary/build files
|
||||
_jsp\.java$
|
||||
\.bz2$
|
||||
\.tar$
|
||||
@@ -14,18 +16,35 @@ _jsp\.java$
|
||||
\.sig$
|
||||
\.sud$
|
||||
\.su2$
|
||||
.\su3$
|
||||
\.tar$
|
||||
\.war$
|
||||
.\deb$
|
||||
\.zip$
|
||||
\.torrent$
|
||||
^\.
|
||||
^build
|
||||
^pkg-temp/
|
||||
~$
|
||||
web-fragment.xml
|
||||
web-out.xml
|
||||
|
||||
# Temporary/build dirs
|
||||
^build
|
||||
^pkg-temp
|
||||
/build
|
||||
/classes/
|
||||
/classes
|
||||
/dist
|
||||
^installer/resources/locale/mo
|
||||
/tmp
|
||||
^apps/jetty/jettylib
|
||||
|
||||
# Debian-related
|
||||
^debian/copyright
|
||||
^debian/changelog
|
||||
^.pc/
|
||||
|
||||
# Build property overrides
|
||||
override.properties
|
||||
|
||||
# Reporting
|
||||
sloccount.sc
|
||||
^reports/
|
||||
|
146
.tx/config
146
.tx/config
@@ -9,16 +9,41 @@ trans.es = apps/i2ptunnel/locale/messages_es.po
|
||||
trans.fr = apps/i2ptunnel/locale/messages_fr.po
|
||||
trans.hu = apps/i2ptunnel/locale/messages_hu.po
|
||||
trans.it = apps/i2ptunnel/locale/messages_it.po
|
||||
trans.ja = apps/i2ptunnel/locale/messages_ja.po
|
||||
trans.nb = apps/i2ptunnel/locale/messages_nb.po
|
||||
trans.nl = apps/i2ptunnel/locale/messages_nl.po
|
||||
trans.pl = apps/i2ptunnel/locale/messages_pl.po
|
||||
trans.pt = apps/i2ptunnel/locale/messages_pt.po
|
||||
trans.ru = apps/i2ptunnel/locale/messages_ru.po
|
||||
trans.pt_BR = apps/i2ptunnel/locale/messages_pt_BR.po
|
||||
trans.ru_RU = apps/i2ptunnel/locale/messages_ru.po
|
||||
trans.sk = apps/i2ptunnel/locale/messages_sk.po
|
||||
trans.sv_SE = apps/i2ptunnel/locale/messages_sv.po
|
||||
trans.uk_UA = apps/i2ptunnel/locale/messages_uk.po
|
||||
trans.vi = apps/i2ptunnel/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale/messages_zh.po
|
||||
|
||||
[I2P.proxy]
|
||||
source_file = apps/i2ptunnel/locale-proxy/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale-proxy/messages_ar.po
|
||||
trans.cs = apps/i2ptunnel/locale-proxy/messages_cs.po
|
||||
trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
|
||||
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
|
||||
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
|
||||
trans.hu = apps/i2ptunnel/locale-proxy/messages_hu.po
|
||||
trans.it = apps/i2ptunnel/locale-proxy/messages_it.po
|
||||
trans.nb = apps/i2ptunnel/locale-proxy/messages_nb.po
|
||||
trans.nl = apps/i2ptunnel/locale-proxy/messages_nl.po
|
||||
trans.pl = apps/i2ptunnel/locale-proxy/messages_pl.po
|
||||
trans.pt = apps/i2ptunnel/locale-proxy/messages_pt.po
|
||||
trans.pt_BR = apps/i2ptunnel/locale-proxy/messages_pt_BR.po
|
||||
trans.ro = apps/i2ptunnel/locale-proxy/messages_ro.po
|
||||
trans.ru_RU = apps/i2ptunnel/locale-proxy/messages_ru.po
|
||||
trans.sv_SE = apps/i2ptunnel/locale-proxy/messages_sv.po
|
||||
trans.uk_UA = apps/i2ptunnel/locale-proxy/messages_uk.po
|
||||
trans.vi = apps/i2ptunnel/locale-proxy/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale-proxy/messages_zh.po
|
||||
|
||||
[I2P.routerconsole]
|
||||
source_file = apps/routerconsole/locale/messages_en.po
|
||||
source_lang = en
|
||||
@@ -33,16 +58,68 @@ trans.fi = apps/routerconsole/locale/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale/messages_fr.po
|
||||
trans.hu = apps/routerconsole/locale/messages_hu.po
|
||||
trans.it = apps/routerconsole/locale/messages_it.po
|
||||
trans.ja = apps/routerconsole/locale/messages_ja.po
|
||||
trans.nb = apps/routerconsole/locale/messages_nb.po
|
||||
trans.nl = apps/routerconsole/locale/messages_nl.po
|
||||
trans.pl = apps/routerconsole/locale/messages_pl.po
|
||||
trans.pt = apps/routerconsole/locale/messages_pt.po
|
||||
trans.ru = apps/routerconsole/locale/messages_ru.po
|
||||
trans.pt_BR = apps/routerconsole/locale/messages_pt_BR.po
|
||||
trans.ro = apps/routerconsole/locale/messages_ro.po
|
||||
trans.ru_RU = apps/routerconsole/locale/messages_ru.po
|
||||
trans.sv_SE = apps/routerconsole/locale/messages_sv.po
|
||||
trans.tr_TR = apps/routerconsole/locale/messages_tr.po
|
||||
trans.uk_UA = apps/routerconsole/locale/messages_uk.po
|
||||
trans.vi = apps/routerconsole/locale/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale/messages_zh.po
|
||||
|
||||
[I2P.welcome]
|
||||
source_file = apps/routerconsole/locale-news/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale-news/messages_ar.po
|
||||
trans.de = apps/routerconsole/locale-news/messages_de.po
|
||||
trans.es = apps/routerconsole/locale-news/messages_es.po
|
||||
trans.fr = apps/routerconsole/locale-news/messages_fr.po
|
||||
trans.he = apps/routerconsole/locale-news/messages_he.po
|
||||
trans.ja = apps/routerconsole/locale-news/messages_ja.po
|
||||
trans.it = apps/routerconsole/locale-news/messages_it.po
|
||||
trans.nl = apps/routerconsole/locale-news/messages_nl.po
|
||||
trans.pl = apps/routerconsole/locale-news/messages_pl.po
|
||||
trans.pt = apps/routerconsole/locale-news/messages_pt.po
|
||||
trans.pt_BR = apps/routerconsole/locale-news/messages_pt_BR.po
|
||||
trans.ro = apps/routerconsole/locale-news/messages_ro.po
|
||||
trans.ru_RU = apps/routerconsole/locale-news/messages_ru.po
|
||||
trans.sk = apps/routerconsole/locale-news/messages_sk.po
|
||||
trans.sv_SE = apps/routerconsole/locale-news/messages_sv.po
|
||||
trans.tr_TR = apps/routerconsole/locale-news/messages_tr.po
|
||||
trans.zh_CN = apps/routerconsole/locale-news/messages_zh.po
|
||||
|
||||
[I2P.countries]
|
||||
type = PO
|
||||
source_file = apps/routerconsole/locale-countries/messages_en.po
|
||||
source_lang = en
|
||||
trans.da = apps/routerconsole/locale-countries/messages_da.po
|
||||
trans.de = apps/routerconsole/locale-countries/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-countries/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-countries/messages_es.po
|
||||
trans.et_EE = apps/routerconsole/locale-countries/messages_et.po
|
||||
trans.fi = apps/routerconsole/locale-countries/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale-countries/messages_fr.po
|
||||
trans.hu = apps/routerconsole/locale-countries/messages_hu.po
|
||||
trans.it = apps/routerconsole/locale-countries/messages_it.po
|
||||
trans.ja = apps/routerconsole/locale-countries/messages_ja.po
|
||||
trans.nb = apps/routerconsole/locale-countries/messages_nb.po
|
||||
trans.nl = apps/routerconsole/locale-countries/messages_nl.po
|
||||
trans.pl = apps/routerconsole/locale-countries/messages_pl.po
|
||||
trans.pt = apps/routerconsole/locale-countries/messages_pt.po
|
||||
trans.pt_BR = apps/routerconsole/locale-countries/messages_pt_BR.po
|
||||
trans.ro = apps/routerconsole/locale-countries/messages_ro.po
|
||||
trans.ru_RU = apps/routerconsole/locale-countries/messages_ru.po
|
||||
trans.sk = apps/routerconsole/locale-countries/messages_sk.po
|
||||
trans.sv_SE = apps/routerconsole/locale-countries/messages_sv.po
|
||||
trans.tr_TR = apps/routerconsole/locale-countries/messages_tr.po
|
||||
trans.vi = apps/routerconsole/locale-countries/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale-countries/messages_zh.po
|
||||
|
||||
[I2P.i2psnark]
|
||||
source_file = apps/i2psnark/locale/messages_en.po
|
||||
source_lang = en
|
||||
@@ -57,7 +134,9 @@ trans.nb = apps/i2psnark/locale/messages_nb.po
|
||||
trans.nl = apps/i2psnark/locale/messages_nl.po
|
||||
trans.pl = apps/i2psnark/locale/messages_pl.po
|
||||
trans.pt = apps/i2psnark/locale/messages_pt.po
|
||||
trans.ro = apps/i2psnark/locale/messages_ro.po
|
||||
trans.ru_RU = apps/i2psnark/locale/messages_ru.po
|
||||
trans.sk = apps/i2psnark/locale/messages_sk.po
|
||||
trans.sv_SE = apps/i2psnark/locale/messages_sv.po
|
||||
trans.vi = apps/i2psnark/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
|
||||
@@ -74,10 +153,13 @@ trans.es = apps/susidns/locale/messages_es.po
|
||||
trans.fr = apps/susidns/locale/messages_fr.po
|
||||
trans.hu = apps/susidns/locale/messages_hu.po
|
||||
trans.it = apps/susidns/locale/messages_it.po
|
||||
trans.ja = apps/susidns/locale/messages_ja.po
|
||||
trans.nl = apps/susidns/locale/messages_nl.po
|
||||
trans.pl = apps/susidns/locale/messages_pl.po
|
||||
trans.pt = apps/susidns/locale/messages_pt.po
|
||||
trans.ru = apps/susidns/locale/messages_ru.po
|
||||
trans.pt_BR = apps/susidns/locale/messages_pt_BR.po
|
||||
trans.ro = apps/susidns/locale/messages_ro.po
|
||||
trans.ru_RU = apps/susidns/locale/messages_ru.po
|
||||
trans.sv_SE = apps/susidns/locale/messages_sv.po
|
||||
trans.uk_UA = apps/susidns/locale/messages_uk.po
|
||||
trans.vi = apps/susidns/locale/messages_vi.po
|
||||
@@ -95,11 +177,16 @@ trans.es = apps/desktopgui/locale/messages_es.po
|
||||
trans.fr = apps/desktopgui/locale/messages_fr.po
|
||||
trans.hu = apps/desktopgui/locale/messages_hu.po
|
||||
trans.it = apps/desktopgui/locale/messages_it.po
|
||||
trans.ja = apps/desktopgui/locale/messages_ja.po
|
||||
trans.nl = apps/desktopgui/locale/messages_nl.po
|
||||
trans.pl = apps/desktopgui/locale/messages_pl.po
|
||||
trans.ru = apps/desktopgui/locale/messages_ru.po
|
||||
trans.pt_BR = apps/desktopgui/locale/messages_pt_BR.po
|
||||
trans.ro = apps/desktopgui/locale/messages_ro.po
|
||||
trans.ru_RU = apps/desktopgui/locale/messages_ru.po
|
||||
trans.sk = apps/desktopgui/locale/messages_sk.po
|
||||
trans.sv_SE = apps/desktopgui/locale/messages_sv.po
|
||||
trans.uk_UA = apps/desktopgui/locale/messages_uk.po
|
||||
trans.tr_TR = apps/desktopgui/locale/messages_tr.po
|
||||
trans.vi = apps/desktopgui/locale/messages_vi.po
|
||||
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
|
||||
|
||||
@@ -112,11 +199,14 @@ trans.es = apps/susimail/locale/messages_es.po
|
||||
trans.fr = apps/susimail/locale/messages_fr.po
|
||||
trans.hu = apps/susimail/locale/messages_hu.po
|
||||
trans.it = apps/susimail/locale/messages_it.po
|
||||
trans.ja = apps/susimail/locale/messages_ja.po
|
||||
trans.nl = apps/susimail/locale/messages_nl.po
|
||||
trans.ru = apps/susimail/locale/messages_ru.po
|
||||
trans.ru_RU = apps/susimail/locale/messages_ru.po
|
||||
trans.sv_SE = apps/susimail/locale/messages_sv.po
|
||||
trans.pl = apps/susimail/locale/messages_pl.po
|
||||
trans.pt = apps/susimail/locale/messages_pt.po
|
||||
trans.pt_BR = apps/susimail/locale/messages_pt_BR.po
|
||||
trans.ro = apps/susimail/locale/messages_ro.po
|
||||
trans.uk_UA = apps/susimail/locale/messages_uk.po
|
||||
trans.vi = apps/susimail/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susimail/locale/messages_zh.po
|
||||
@@ -131,20 +221,60 @@ trans.es = debian/po/es.po
|
||||
trans.fr = debian/po/fr.po
|
||||
trans.it = debian/po/it.po
|
||||
trans.hu = debian/po/hu.po
|
||||
trans.ja = debian/po/ja.po
|
||||
trans.ko = debian/po/ko.po
|
||||
trans.pl = debian/po/pl.po
|
||||
trans.ru = debian/po/ru.po
|
||||
trans.pt = debian/po/pt.po
|
||||
trans.ro = debian/po/ro.po
|
||||
trans.ru_RU = debian/po/ru.po
|
||||
trans.sk = debian/po/sk.po
|
||||
trans.sv_SE = debian/po/sv.po
|
||||
trans.uk_UA = debian/po/uk.po
|
||||
trans.tr_TR = debian/po/tr.po
|
||||
trans.zh_CN = debian/po/zh.po
|
||||
|
||||
[I2P.i2prouter-script]
|
||||
source_file = installer/resources/locale/po/messages_en.po
|
||||
source_lang = en
|
||||
trans.de = installer/resources/locale/po/messages_de.po
|
||||
trans.es = installer/resources/locale/po/messages_es.po
|
||||
trans.fr = installer/resources/locale/po/messages_fr.po
|
||||
trans.it = installer/resources/locale/po/messages_it.po
|
||||
trans.sv_SE = installer/resources/locale/po/messages_sv.po
|
||||
trans.pl = installer/resources/locale/po/messages_pl.po
|
||||
trans.ja = installer/resources/locale/po/messages_ja.po
|
||||
trans.pt = installer/resources/locale/po/messages_pt.po
|
||||
trans.pt_BR = installer/resources/locale/po/messages_pt_BR.po
|
||||
trans.ro = installer/resources/locale/po/messages_ro.po
|
||||
trans.ru_RU = installer/resources/locale/po/messages_ru.po
|
||||
trans.sk = installer/resources/locale/po/messages_sk.po
|
||||
trans.sv_SE = installer/resources/locale/po/messages_sv.po
|
||||
trans.tr_TR = installer/resources/locale/po/messages_tr.po
|
||||
trans.zh_CN = installer/resources/locale/po/messages_zh.po
|
||||
|
||||
[I2P.getopt]
|
||||
source_file = core/java/src/gnu/getopt/MessagesBundle.properties
|
||||
source_lang = en
|
||||
type = PROPERTIES
|
||||
trans.cs = core/java/src/gnu/getopt/MessagesBundle_cs.properties
|
||||
trans.de = core/java/src/gnu/getopt/MessagesBundle_de.properties
|
||||
trans.es = core/java/src/gnu/getopt/MessagesBundle_es.properties
|
||||
trans.fr = core/java/src/gnu/getopt/MessagesBundle_fr.properties
|
||||
trans.hu = core/java/src/gnu/getopt/MessagesBundle_hu.properties
|
||||
trans.it = core/java/src/gnu/getopt/MessagesBundle_it.properties
|
||||
trans.ja = core/java/src/gnu/getopt/MessagesBundle_ja.properties
|
||||
trans.nl = core/java/src/gnu/getopt/MessagesBundle_nl.properties
|
||||
trans.nb = core/java/src/gnu/getopt/MessagesBundle_nb.properties
|
||||
trans.pl = core/java/src/gnu/getopt/MessagesBundle_pl.properties
|
||||
trans.pt_BR = core/java/src/gnu/getopt/MessagesBundle_pt_BR.properties
|
||||
trans.ro = core/java/src/gnu/getopt/MessagesBundle_ro.properties
|
||||
trans.ru_RU = core/java/src/gnu/getopt/MessagesBundle_ru.properties
|
||||
trans.sk = core/java/src/gnu/getopt/MessagesBundle_sk.properties
|
||||
trans.zh_CN = core/java/src/gnu/getopt/MessagesBundle_zh.properties
|
||||
|
||||
[I2P.streaming]
|
||||
source_file = apps/ministreaming/locale/messages_en.po
|
||||
source_lang = en
|
||||
|
||||
[main]
|
||||
host = http://www.transifex.net
|
||||
host = https://www.transifex.com
|
||||
|
||||
|
@@ -12,7 +12,7 @@ you may use:
|
||||
to configure the router.
|
||||
|
||||
If you're having trouble, swing by http://forum.i2p/, check the
|
||||
website at http://www.i2p2.de/, or get on irc://irc.freenode.net/#i2p
|
||||
website at https://geti2p.net/, or get on irc://irc.freenode.net/#i2p
|
||||
|
||||
I2P will create and store files and configuration data in the user directory
|
||||
~/.i2p/ on Linux and %APPDATA%\I2P\ on Windows. This directory is created
|
||||
@@ -39,7 +39,10 @@ To uninstall I2P:
|
||||
rm -rf $I2PInstallDir ~/.i2p
|
||||
|
||||
Supported JVMs:
|
||||
Windows: Latest available from http://java.com/download (1.5+ supported)
|
||||
Linux: Latest available from http://java.com/download (1.5+ supported)
|
||||
FreeBSD: 1.5-compatible (NIO required)
|
||||
Other operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
All platforms: Java 1.6 or higher required; 1.7 or higher recommended
|
||||
Windows: OpenJDK or Oracle from http://java.com/download
|
||||
Linux: OpenJDK or Oracle from http://java.com/download
|
||||
FreeBSD: OpenJDK or Oracle from http://java.com/download
|
||||
Raspberry Pi: Oracle 8 Early Access https://jdk8.java.net/download.html
|
||||
PowerPC: IBM SDK 7 http://www.ibm.com/developerworks/java/jdk/linux/download.html
|
||||
Other operating systems and JVMs: See https://trac.i2p2.de/wiki/java or https://geti2p.net/download
|
||||
|
@@ -2,7 +2,7 @@ I2P source installation instructions
|
||||
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher
|
||||
Non-linux operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java
|
||||
Apache Ant 1.7.0 or higher
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
|
17
LICENSE.txt
17
LICENSE.txt
@@ -36,7 +36,7 @@ Public domain except as listed below:
|
||||
Copyright (c) 2003, TheCrypto
|
||||
See licenses/LICENSE-ElGamalDSA.txt
|
||||
|
||||
SHA256 and HMAC-SHA256:
|
||||
SHA256 and HMAC:
|
||||
Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
|
||||
See licenses/LICENSE-SHA256.txt
|
||||
|
||||
@@ -76,6 +76,11 @@ Public domain except as listed below:
|
||||
Copyright 2012 Hiroshi Nakamura <nahi@ruby-lang.org>
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
Getopt:
|
||||
Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
|
||||
Router (router.jar):
|
||||
Public domain except as listed below:
|
||||
UPnP.java:
|
||||
@@ -132,7 +137,7 @@ Installer:
|
||||
|
||||
|
||||
|
||||
Java Service Wrapper Community Edition 32-bit 3.5.13:
|
||||
Java Service Wrapper Community Edition 32-bit 3.5.19:
|
||||
Copyright (C) 1999-2011 Tanuki Software, Ltd. All Rights Reserved.
|
||||
See licenses/LICENSE-Wrapper.txt
|
||||
|
||||
@@ -177,7 +182,7 @@ Applications:
|
||||
By welterde.
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
Jetty 7.6.10.v20130312:
|
||||
Jetty 8.1.15.v20140411:
|
||||
See licenses/ABOUT-Jetty.html
|
||||
See licenses/NOTICE-Jetty.html
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
@@ -207,7 +212,7 @@ Applications:
|
||||
FatCow icons: See licenses/LICENSE-FatCowIcons.txt
|
||||
|
||||
GeoIP Data:
|
||||
Copyright (c) 2008 MaxMind, Inc. All Rights Reserved.
|
||||
This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
|
||||
See licenses/LICENSE-GeoIP.txt
|
||||
|
||||
Router Console and I2PSnark themes:
|
||||
@@ -243,8 +248,8 @@ Applications:
|
||||
Bundles systray4j-2.4.1:
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
Tomcat 6.0.36:
|
||||
Copyright 1999-2012 The Apache Software Foundation
|
||||
Tomcat 6.0.41:
|
||||
Copyright 1999-2014 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
||||
|
12
README.txt
12
README.txt
@@ -1,6 +1,6 @@
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher
|
||||
Non-linux operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java
|
||||
Apache Ant 1.7.0 or higher
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
@@ -15,20 +15,20 @@ To build:
|
||||
ant installer-osx
|
||||
|
||||
Run 'ant' with no arguments to see other build options.
|
||||
See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions.
|
||||
See INSTALL.txt or https://geti2p.net/download for installation instructions.
|
||||
|
||||
Documentation:
|
||||
http://www.i2p2.de/how
|
||||
https://geti2p.net/how
|
||||
API: run 'ant javadoc' then start at build/javadoc/index.html
|
||||
|
||||
Latest release:
|
||||
http://www.i2p2.de/download.html
|
||||
https://geti2p.net/download
|
||||
|
||||
To get development branch from source control:
|
||||
http://www.i2p2.de/newdevelopers.html
|
||||
https://geti2p.net/newdevelopers
|
||||
|
||||
FAQ:
|
||||
http://www.i2p2.de/faq.html
|
||||
https://geti2p.net/faq
|
||||
|
||||
Need help?
|
||||
IRC irc.freenode.net #i2p
|
||||
|
@@ -1,30 +1,70 @@
|
||||
ou will need atleast monotone > = 0.41 to get the most recent build source
|
||||
and connect it to an already running i2p router.
|
||||
Getting the sources
|
||||
===================
|
||||
|
||||
OR:
|
||||
Monotone
|
||||
--------
|
||||
|
||||
You may download the actual "stable" source from
|
||||
http://code.google.com/p/i2p/downloads/list
|
||||
The bleeding-edge source code is available both within and outside of I2P. The
|
||||
I2P project uses Monotone to maintain the codebase.
|
||||
|
||||
You will need to follwing tools to build the i2p and i2p-base packages:
|
||||
Information on retrieving the source with monotone is available within I2P at
|
||||
http://i2p-projekt.i2p/monotone and from the internet at https://geti2p.net/monotone.
|
||||
|
||||
bash >= 3.1.017
|
||||
requiredbuilder >= 0.16.3 ( http://www.stabellini.net/requiredbuilder.html )
|
||||
jre >= 6u11
|
||||
jdk >= 6u11
|
||||
apache-ant >= 1.7.1
|
||||
perl >= 5.10.0
|
||||
python >= 2.5.2
|
||||
Monotone 1.0 Slackbuilds are available at http://slackbuilds.org/.
|
||||
|
||||
Reccomended:
|
||||
monotone >= 0.41 ( http://pkgs.dr.ea.ms )
|
||||
Git
|
||||
---
|
||||
|
||||
See also:
|
||||
Git is also an option to retrieve the I2P source code. That said, the I2P
|
||||
Monotone servers are *the* authoritative source.
|
||||
|
||||
i2p/readme.txt
|
||||
Public Git repositories hosting the I2P source and managed by I2P project team members include
|
||||
|
||||
AND
|
||||
- https://github.com/i2p/i2p.i2p
|
||||
- http://git.repo.i2p/w/i2p.i2p.git (mirrored from Github)
|
||||
- http://sourceforge.net/p/i2p/code/
|
||||
|
||||
i2p-base/readme.txt
|
||||
|
||||
for information and handy tips.
|
||||
Tarball
|
||||
-------
|
||||
|
||||
The latest stable release is always available from the I2P homepage at
|
||||
https://geti2p.net/get/.
|
||||
|
||||
|
||||
This SlackBuild
|
||||
===============
|
||||
|
||||
Requirements
|
||||
-------------
|
||||
|
||||
The following are needed to build the i2p package:
|
||||
|
||||
* jre >= 6
|
||||
* jdk >= 6
|
||||
* gettext
|
||||
* apache-ant >= 1.7.1
|
||||
|
||||
If you don't care about bundling the translations, the gettext requirement can
|
||||
be avoided by adding -Drequire.gettext=false to the ant lines in
|
||||
i2p/i2p.SlackBuild
|
||||
|
||||
A JRE >= v6 is the only requirement to run I2P.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
As the root user, run either $I2PSRC/Slackware/i2p/i2p.SlackBuild or `ant slackpkg` to create a package
|
||||
in $I2PSRC/Slackware/i2p which can be installed using the Slackware packaging tools.
|
||||
|
||||
See also
|
||||
========
|
||||
|
||||
Please also take a look at
|
||||
|
||||
* i2p/README
|
||||
* eepget(1)
|
||||
* i2prouter(1)
|
||||
* http://i2p-projekt.i2p / https://geti2p.net
|
||||
|
||||
for additional information and tips.
|
||||
|
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project basedir="." default="slackpkg">
|
||||
<target name="slackpkg">
|
||||
<echo message="Building Slackware package." />
|
||||
<exec executable="./i2p-base.SlackBuild">
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
@@ -1,157 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# Now in the future we only need to look for '#I2P' and '#/I2P'
|
||||
# for modifications to rc.local and rc.local_shutdown.
|
||||
# I was a moron for not doing it this way in the first place :-) -- Sponge
|
||||
#
|
||||
#
|
||||
|
||||
touch /etc/rc.d/rc.local
|
||||
touch /etc/rc.d/rc.local_shutdown
|
||||
|
||||
echo
|
||||
echo -n "Check 1: /etc/rc.d/rc.local "
|
||||
I2PRCA=`grep -c /etc/rc.d/rc.local -e '/etc/rc.d/rc.i2p'`
|
||||
|
||||
if [ $I2PRCA -eq 0 ] ; then
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "modified."
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
# Fix old installs, or where people have modified.
|
||||
|
||||
echo -n " Check 1A: "
|
||||
I2PRCC=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
|
||||
|
||||
if [ $I2PRCC -eq 0 ] ; then
|
||||
DATA=$(cat /etc/rc.d/rc.local | sed -re 's/if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/#I2P\n\( cd \/tmp ; rm -Rf i2p-*.tmp \)\nif \[ -x \/etc\/rc.d\/rc.i2p \] ; then/')
|
||||
echo "${DATA}" > /etc/rc.d/rc.local
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
|
||||
echo -n " Check 1B: "
|
||||
I2PRCE=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
|
||||
if [ $I2PRCE -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/i2p-\*\.tmp/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/i2p-\*\.tmp/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local
|
||||
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks ok so far,"
|
||||
fi
|
||||
echo -n " Check 1C: "
|
||||
I2PRCF=`grep -c /etc/rc.d/rc.local -e '#/I2P'`
|
||||
if [ $I2PRCF -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/^#I2P/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local
|
||||
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks ok so far,"
|
||||
fi
|
||||
echo " Done."
|
||||
fi
|
||||
|
||||
echo -n "Check 2: /etc/rc.d/rc.local_shutdown "
|
||||
I2PRCB=`grep -c /etc/rc.d/rc.local_shutdown -e '/etc/rc.d/rc.i2p'`
|
||||
if [ $I2PRCB -eq 0 ] ; then
|
||||
echo "#I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "modified."
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
# Fix old installs
|
||||
|
||||
echo -n " Check 1A: "
|
||||
I2PRCG=`grep -c /etc/rc.d/rc.local_shutdown -e '#I2P'`
|
||||
if [ $I2PRCG -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
|
||||
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
echo -n " Check 1B: "
|
||||
I2PRCH=`grep -c /etc/rc.d/rc.local_shutdown -e '#/I2P'`
|
||||
if [ $I2PRCH -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^#I2P/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
|
||||
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
echo " Done."
|
||||
fi
|
||||
|
||||
if [ -f /etc/rc.d/rc.i2p ] ; then
|
||||
if [ -x /etc/rc.d/rc.i2p ] ; then
|
||||
chmod +x /etc/rc.d/rc.i2p.new
|
||||
fi
|
||||
# Hopefully get admin's attention.
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -e "\007" ; sleep 0.3
|
||||
echo "It apears that you already have /etc/rc.d/rc.i2p"
|
||||
echo "You should replace it with /etc/rc.d/rc.i2p.new as soon as possible"
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -e "\007" ; sleep 0.3
|
||||
else
|
||||
mv /etc/rc.d/rc.i2p.new /etc/rc.d/rc.i2p
|
||||
echo
|
||||
echo "Installation finished. The i2p start/stop script has been"
|
||||
echo "installed in /etc/rc.d . You should chmod +x"
|
||||
echo '/etc/rc.d/rc.i2p to start it on boot.'
|
||||
echo
|
||||
fi
|
||||
|
||||
exit
|
@@ -1,57 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Heavily based on the Slackware 12.2 SlackBuild
|
||||
# Slackware build script for I2P
|
||||
#
|
||||
# PLEASE READ THIS:
|
||||
# How to start I2P:
|
||||
# After installpkg command, doinst.sh will execute a post-installation script
|
||||
# needed by I2P. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# I2P service with /etc/rc.d/rc.i2p start.
|
||||
#
|
||||
# Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
# this page: http://localhost:7657/index.jsp
|
||||
#
|
||||
# Here you can configure I2P, watch network status and navigate anonimously.
|
||||
# It's suggested to subscribe to various dns host, like i2host.i2p
|
||||
# For any additional information, visit i2host.i2p and forum.i2p
|
||||
#
|
||||
|
||||
CWD=$(pwd)
|
||||
TMP=/tmp
|
||||
PKG=/$TMP/package-base-i2p
|
||||
NAME=i2p-base
|
||||
VERSION=0.0.4
|
||||
BUILD=1sponge
|
||||
ARCH=noarch
|
||||
INSTALL_DIR=opt
|
||||
|
||||
# Less than slackware 13?
|
||||
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
|
||||
if [ $SLKPLT -lt 13 ] ; then
|
||||
EXT=tgz
|
||||
else
|
||||
EXT=txz
|
||||
fi
|
||||
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
cd $PKG
|
||||
chown -R root:root .
|
||||
|
||||
mkdir -p $PKG/etc/rc.d
|
||||
mkdir -p $PKG/install
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/i2prouter|g" "$CWD/rc.i2p_def" > $PKG/etc/rc.d/rc.i2p.new
|
||||
chmod 644 $PKG/etc/rc.d/rc.i2p.new
|
||||
cat "$CWD/doinst.sh" > $PKG/install/doinst.sh
|
||||
cat "$CWD/slack-desc" > $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
#
|
||||
# Not really that important to exec this
|
||||
# as there aren't any deps we don't know.
|
||||
#
|
||||
# requiredbuilder -v -y -s $CWD $PKG
|
||||
#
|
||||
cat "$CWD/slack-required" > $PKG/install/slack-required
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT
|
@@ -1,68 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Start/stop i2p service.
|
||||
|
||||
i2p_start() {
|
||||
# Check if router is up first!
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'" > /dev/null
|
||||
if [ $? -eq 0 ] ; then {
|
||||
# I2p is already running, so tell the user.
|
||||
echo "I2P is already running..."
|
||||
i2p_status
|
||||
}
|
||||
else
|
||||
{
|
||||
# Just in-case there are leftover junk in /tmp...
|
||||
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
|
||||
# Now that all junk is cleaned up, start.
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory start )'"
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
i2p_stop() {
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory stop )'"
|
||||
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
|
||||
}
|
||||
|
||||
i2p_restart() {
|
||||
# We want a FULL cycle here, not the wrappers idea of this!
|
||||
i2p_stop
|
||||
i2p_start
|
||||
}
|
||||
|
||||
i2p_status() {
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'"
|
||||
}
|
||||
|
||||
i2p_console() {
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory console )'"
|
||||
}
|
||||
|
||||
i2p_dump() {
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory dump )'"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
i2p_start
|
||||
;;
|
||||
'stop')
|
||||
i2p_stop
|
||||
;;
|
||||
'restart')
|
||||
i2p_restart
|
||||
;;
|
||||
'status')
|
||||
i2p_status
|
||||
;;
|
||||
'console')
|
||||
i2p_console
|
||||
;;
|
||||
'dump')
|
||||
i2p_dump
|
||||
;;
|
||||
*)
|
||||
echo "usage $0 start|stop|restart|status|console|dump"
|
||||
;;
|
||||
esac
|
||||
|
@@ -1,10 +0,0 @@
|
||||
An rc file called rc.i2p has been placed into the /etc/rc.d directory.
|
||||
If you want to change installation dir, change the variable INSTALL_DIR
|
||||
on base-i2p.SlackBuild and rebuild the package. You also will need to do the
|
||||
same for the i2p package.
|
||||
|
||||
The install script will insert everything needed into /etc/rc.d/rc.local and
|
||||
into /etc/rc.d/rc.local_shutdown automatically.
|
||||
|
||||
If you want to start I2P at boot you have to chmod +x /etc/rc.d/rc.i2p
|
||||
|
@@ -1,19 +0,0 @@
|
||||
# HOW TO EDIT THIS FILE:
|
||||
# The "handy ruler" below makes it easier to edit a package description. Line
|
||||
# up the first '|' above the ':' following the base package name, and the '|' on
|
||||
# the right side marks the last column you can put a character in. You must make
|
||||
# exactly 11 lines for the formatting to be correct. It's also customary to
|
||||
# leave one space after the ':'.
|
||||
|
||||
|-----handy-ruler------------------------------------------------------|
|
||||
base-i2p: base-i2p (I2P anonymizing network base config files)
|
||||
base-i2p:
|
||||
base-i2p: I2P is an anonymizing network, offering a simple layer that
|
||||
base-i2p: identity-sensitive applications can use to securely communicate. All
|
||||
base-i2p: data is wrapped with several layers of encryption, and the network is
|
||||
base-i2p: both distributed and dynamic, with no trusted parties.
|
||||
base-i2p: Many applications are available that interface with I2P, including
|
||||
base-i2p: mail, peer-peer file sharing, IRC chat, and others.
|
||||
base-i2p:
|
||||
base-i2p: This package provides the startup files.
|
||||
base-i2p:
|
@@ -1 +0,0 @@
|
||||
bash >= 3.1.017
|
89
Slackware/i2p/README
Normal file
89
Slackware/i2p/README
Normal file
@@ -0,0 +1,89 @@
|
||||
The I2P package will be installed to /opt/i2p.
|
||||
|
||||
To install to another location, set the variable INSTALL_DIR in i2p.SlackBuild
|
||||
and rebuild the package.
|
||||
|
||||
|
||||
Installing and Upgrading:
|
||||
=========================
|
||||
|
||||
I2P has an auto-update function but generally speaking packages are managed by
|
||||
packaging systems. Changing a package's files outside of the package system can
|
||||
cause problems. To upgrade when there's a new I2P release, retrieve the new
|
||||
source, re-run the SlackBuild, then use upgradepkg to update.
|
||||
|
||||
To ignore all this and upgrade "in-network", simply change the permissions of the installation
|
||||
directory (/opt/i2p by default). Something like the following would suffice:
|
||||
|
||||
chown -R USERNAME /opt/i2p
|
||||
|
||||
|
||||
Starting and using I2P
|
||||
======================
|
||||
|
||||
Using the initscript
|
||||
--------------------
|
||||
|
||||
To start I2P at boot, set the executable bit on /etc/rc.d/rc.i2p, add this
|
||||
script to rc.local*, and set the variable "RUN_AS_USER" in /etc/rc.d/rc.i2p.
|
||||
|
||||
Optionally, create a new user/group with limited rights to run I2P.
|
||||
|
||||
Something like the following would work to start I2P at system boot, running under the
|
||||
"i2p" account:
|
||||
|
||||
echo '[ -x /etc/rc.d/rc.i2p ] && /etc/rc.d/rc.i2p start' >> /etc/rc.d/rc.local
|
||||
echo '[ -x /etc/rc.d/rc.i2p ] && /etc/rc.d/rc.i2p stop' >> /etc/.rc.d/rc.local_shutdown
|
||||
sed -i .bak 's/^.*\(RUN_AS_USER\)=.*/\1=i2p/' /etc/rc.d/rc.i2p
|
||||
chmod 755 /etc/rc.d/rc.i2p
|
||||
|
||||
Unless running as a user named "i2psvc", I2P's config directory defaults to
|
||||
$HOME/.i2p. In the case of the "i2psvc" user, the default config directory is
|
||||
/var/lib/i2p/i2p-config.
|
||||
|
||||
It should not need to be said that using the "root" account is not recommended.
|
||||
|
||||
When running using the initscript, I2P will write its logs to /var/log/i2p.
|
||||
|
||||
Starting I2P "on-demand"
|
||||
------------------------
|
||||
|
||||
As with a normal installation, I2P can be started with "i2prouter start". The
|
||||
i2prouter and eepget scripts hve been installed to /usr/bin so they'll be
|
||||
accessible in the default system PATH.
|
||||
|
||||
When running using the i2prouter script, I2P will write its logs to $HOME/.i2p.
|
||||
|
||||
|
||||
Configuring your browser
|
||||
------------------------
|
||||
|
||||
In order to access eepSites (I2P-internal web sites) your web browser needs to
|
||||
be configured. Set the HTTP Proxy to 127.0.0.1 and port 4444. For more information, see
|
||||
https://geti2p.net/en/about/browser-config
|
||||
|
||||
The I2P router console is reachable at http://127.0.0.1:7657.
|
||||
|
||||
|
||||
Addressbook subscriptions
|
||||
-------------------------
|
||||
|
||||
Please see the FAQs at http://i2p-projekt.i2p/faq or https://geti2p.net/faq for information about
|
||||
the various addressbook services.
|
||||
|
||||
|
||||
Chatting on IRC
|
||||
---------------
|
||||
|
||||
I2P comes preconfigured with a tunnel pointing to the I2P-only IRC network,
|
||||
Irc2P. Signing on is easy, just connect to 127.0.0.1 on port 6668. Do not
|
||||
configure a proxy in your IRC client.
|
||||
|
||||
|
||||
Additional information
|
||||
======================
|
||||
|
||||
Within I2P: http://i2p-projekt.i2p/, http://forum.i2p/, http://zzz.i2p/, http://trac.i2p2.i2p/
|
||||
On the Internet: https://geti2p.net/, https://trac.i2p2.de
|
||||
Manpages: i2prouter(1), eepget(1)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<project basedir="." default="slackpkg">
|
||||
<target name="slackpkg">
|
||||
<echo message="Building Slackware package." />
|
||||
<exec executable="./i2p.SlackBuild">
|
||||
</exec>
|
||||
<chmod file="./i2p.Slackbuild" perm="755" />
|
||||
<exec executable="./i2p.SlackBuild" failifexecutionfails="true" />
|
||||
</target>
|
||||
</project>
|
||||
|
@@ -1,72 +1,60 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Abort on error or unset variables
|
||||
set -e
|
||||
set -u
|
||||
|
||||
# This is changed by i2p.SlackBuild
|
||||
INST_DIR=directory
|
||||
PKGNAME="%pkg"
|
||||
|
||||
( cd install
|
||||
config() {
|
||||
NEW="$1"
|
||||
OLD="$(dirname $NEW)/$(basename $NEW .new)"
|
||||
if [ ! -r $NEW ]; then
|
||||
# If we get here there's a flaw in the packaging. We'll just return so that
|
||||
# we don't emit a spurious error for the user. (It's not the user's problem).
|
||||
return
|
||||
fi
|
||||
|
||||
echo
|
||||
for i in *.config ; {
|
||||
if [ -f $INST_DIR/$i ] ; then
|
||||
echo "Please check ${INST_DIR}${i}, as there is a new version."
|
||||
cp $i $INST_DIR/$i.new
|
||||
else
|
||||
cp $i $INST_DIR/$i
|
||||
fi
|
||||
# If this file doesn't exist yet, drop the .new extension.
|
||||
if [ ! -r $OLD ]; then
|
||||
mv $NEW $OLD
|
||||
return
|
||||
elif [ "$(md5sum $OLD | cut -d' ' -f1)" = "$(md5sum $NEW | cut -d' ' -f1)" ]; then
|
||||
# If there are no differences in the files, remove the file with the .new extension.
|
||||
rm $NEW
|
||||
return
|
||||
fi
|
||||
# Alert the admin if they differ, but let's not be terribly obnoxious about it.
|
||||
echo "WARNING: The files $OLD and $NEW differ." >&2
|
||||
}
|
||||
|
||||
)
|
||||
# Unlike previous versions of the package, we install i2prouter and eepget to /usr/bin
|
||||
# to make them available within the system PATH.
|
||||
|
||||
( cd $INST_DIR
|
||||
if [ -f blocklist.txt ] ; then
|
||||
echo "Please check ${INST_DIR}blocklist.txt, as there is a new version."
|
||||
else
|
||||
mv blocklist.txt.new blocklist.txt
|
||||
fi
|
||||
)
|
||||
# Users might still want to /opt/i2p/i2prouter or /opt/i2p/eepget so we'll create symlinks
|
||||
# in the installation directory.
|
||||
ln -sf /usr/bin/eepget $INST_DIR
|
||||
ln -sf /usr/bin/i2prouter $INST_DIR
|
||||
(cd /usr/doc/$PKGNAME; ln -sf $INST_DIR/history.txt changelog)
|
||||
|
||||
( cd $INST_DIR/eepsite
|
||||
if [ -f jetty.xml ] ; then
|
||||
echo "Please check ${INST_DIR}/eepsite, as there are new files."
|
||||
else
|
||||
find $PKG/$INSTALL_DIR/i2p -name "*.xml.new" -exec sh -c 'mv "$0" "${0/.new}"' {} \;
|
||||
fi
|
||||
)
|
||||
|
||||
( cd $INST_DIR/eepsite/docroot
|
||||
if [ -f index.html ] ; then
|
||||
rm index.html.new
|
||||
else
|
||||
mv index.html.new index.html
|
||||
fi
|
||||
if [ -f favicon.ico ] ; then
|
||||
rm favicon.ico.new
|
||||
else
|
||||
mv favicon.ico.new favicon.ico
|
||||
fi
|
||||
)
|
||||
|
||||
echo
|
||||
echo "FINISHING I2P INSTALLATION. PLEASE WAIT."
|
||||
|
||||
cd $INST_DIR
|
||||
|
||||
|
||||
|
||||
OS_ARCH=`uname -m`
|
||||
X86_64=`echo "$OS_ARCH" | grep x86_64`
|
||||
if [ "X$X86_64" = "X" ]; then
|
||||
wrapperpath="./lib/wrapper/linux"
|
||||
if $(uname -m | grep -q '64'); then
|
||||
(cd $INST_DIR; ln -sf i2psvc-linux-x86-64 i2psvc)
|
||||
else
|
||||
wrapperpath="./lib/wrapper/linux64"
|
||||
(cd $INST_DIR; ln -sf i2psvc-linux-x86-32 i2psvc)
|
||||
fi
|
||||
cp $wrapperpath/libwrapper.so ./lib/
|
||||
cp $wrapperpath/wrapper.jar ./lib/
|
||||
cp $wrapperpath/i2psvc .
|
||||
rm -rf ./lib/wrapper
|
||||
chmod 744 ./i2psvc
|
||||
|
||||
echo
|
||||
echo "Installation finished."
|
||||
echo
|
||||
config /etc/rc.d/rc.i2p.new
|
||||
config $INST_DIR/wrapper.config.new
|
||||
|
||||
exit
|
||||
if [ -e /var/log/packages/i2p-base* ]; then
|
||||
echo "Warning: This package supercedes the 'i2p-base' package." >&2
|
||||
echo
|
||||
echo "You may want to 'removepkg i2p-base'" >&2
|
||||
echo "and check the contents of /etc/rc.d/rc.local*" >&2
|
||||
echo "for correctness" >&2
|
||||
fi
|
||||
|
||||
# Remove extraneous 'sh' from sponge's set-up
|
||||
sed -i 's|sh /etc/rc\.d/rc\.i2p|/etc/rc.d/rc.i2p|g' /etc/rc.d/rc.local*
|
||||
|
@@ -3,135 +3,124 @@
|
||||
# Heavily based on the Slackware 12.2 SlackBuild
|
||||
# Slackware build script for I2P
|
||||
#
|
||||
# PLEASE READ THIS:
|
||||
# Probably you will never have to update I2P packages with upgradepkg,
|
||||
# just because I2P has an auto-update function.
|
||||
# Really you should not ever use any "upgrade" method.
|
||||
#
|
||||
# The correct way to upgrade is to:
|
||||
# 1: install the upgrade
|
||||
# 2: remove the old package
|
||||
#
|
||||
# It is a terrible shame that upgradepkg doesn't do this, infact,
|
||||
# it would actually be the correct way for *any* package!
|
||||
# Packages are generally prohibited from being updated outside
|
||||
# of the package manager; this I2P SlackBuild is no different.
|
||||
#
|
||||
# If you'd like to use the I2P "in-network" updates anyway, you'll need to
|
||||
# grant the user that I2P will run as write permission to the installation directory
|
||||
# (/opt/i2p by default).
|
||||
#
|
||||
# For safety's sake, a user's I2P config files will *never* be overwritten by any upgrade method.
|
||||
# In the future this SlackBuild may alert when a default config file is updated.
|
||||
##
|
||||
|
||||
BUILD=1sponge
|
||||
# Make sure makepkg and friends can be found
|
||||
PATH=$PATH:/sbin
|
||||
|
||||
# abort on error and unset variables (same as set -e and set -u, respectively)
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
|
||||
if [ $(id -ur) -ne 0 ]; then
|
||||
echo "ERROR: SlackBuilds require root access." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD=1kytv
|
||||
# INSTALL_DIR is referenced from /, don't prefix it with a '/'
|
||||
INSTALL_DIR=opt
|
||||
NAME=i2p
|
||||
ARCH=noarch
|
||||
|
||||
# Less than slackware 13?
|
||||
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
|
||||
if [ $SLKPLT -lt 13 ] ; then
|
||||
EXT=tgz
|
||||
else
|
||||
EXT=txz
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# This mess is here due to the totally moronic way i2p does versioning.
|
||||
# We correct it here.
|
||||
#
|
||||
ROUTER=$(echo -ne "_")$(cat ../../router/java/src/net/i2p/router/RouterVersion.java | grep -e "public final static long BUILD" | cut -f2 -d"=" | cut -f1 -d";" | sed -re "s/ //g")
|
||||
if [ "$ROUTER" == "_" ] ; then
|
||||
ROUTER="_0"
|
||||
fi
|
||||
|
||||
#
|
||||
# That was the easy one, now for the tough one.
|
||||
#
|
||||
|
||||
CORE=$(cat ../../core/java/src/net/i2p/CoreVersion.java | grep -e "public final static String VERSION" | cut -f2 -d'"' | sed -re "s/ //g")
|
||||
CORE1=$(echo -n $CORE.x.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
|
||||
CORE2=$(echo -n $CORE.x | sed -re "s/(.*)\.(.*)\.(.*)\.(.*)/\1/")
|
||||
|
||||
if [ "$CORE.x.x" == "$CORE1" ] ; then
|
||||
CORE=$(echo -ne $CORE".0.0")
|
||||
fi
|
||||
if [ "$CORE.x" == "$CORE2" ] ; then
|
||||
CORE=$(echo -ne $CORE".0")
|
||||
fi
|
||||
|
||||
VERSION=$(echo $CORE$ROUTER)
|
||||
#
|
||||
# Whew!
|
||||
# OK, let's build i2p
|
||||
#
|
||||
|
||||
CWD=$(pwd)
|
||||
CWD=$(readlink -m $(dirname $0))
|
||||
I2PSRC=$(readlink -m $CWD/../../)
|
||||
TMP=/tmp
|
||||
|
||||
PKG=$TMP/package-i2p
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
|
||||
cd $CWD/../../
|
||||
if [ -e "/etc/slackware-version" ]; then
|
||||
# Older than Slackware 13?
|
||||
SLACKVER=$(sed -e "s/Slackware\s\+\([0-9]\+\)\.\?\([0-9]\+\)\?/\1/" /etc/slackware-version)
|
||||
if [ $SLACKVER -lt 13 ] ; then
|
||||
EXT=tgz
|
||||
else
|
||||
EXT=txz
|
||||
fi
|
||||
else
|
||||
echo "ERROR: This script is only intended for use on Slackware systems.">&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract version strings
|
||||
I2PBUILD=$(sed -e '/^.\+long\s\+BUILD/!d' -e 's/^.\+long\s\+BUILD\s\+=\s\+\([0-9]\+\);/\1/' $I2PSRC/router/java/src/net/i2p/router/RouterVersion.java)
|
||||
# Thanks to user "ihavei2p" for the second awk statement
|
||||
# If the version is x.y, it'll be set to x.y.0. Otherwise the version string will be unchanged
|
||||
CORE=$(awk -F'"' '/static\s+String\s+VERSION/{print $2}' $I2PSRC/core/java/src/net/i2p/CoreVersion.java | \
|
||||
awk -F. '{ if (NF > 3) { print; exit } else if ($3 == "") { $3=0; print $1"."$2"."$3 } else print }')
|
||||
VERSION="${CORE}_${I2PBUILD}"
|
||||
|
||||
[ -d $PKG ] && rm -rf $PKG
|
||||
mkdir -p $PKG/$INSTALL_DIR $PKG/install
|
||||
|
||||
cd "$I2PSRC"
|
||||
ant distclean
|
||||
#ant dist
|
||||
ant tarball
|
||||
ant jbigi-linux-x86-only preppkg-unix
|
||||
|
||||
tar xjvf i2p.tar.bz2 -C $TMP
|
||||
chown -R root:root $I2PSRC/pkg-temp
|
||||
cp -a $I2PSRC/pkg-temp $PKG/$INSTALL_DIR/i2p
|
||||
|
||||
cd $TMP/i2p
|
||||
chown -R root:root .
|
||||
|
||||
mkdir -p $PKG/$INSTALL_DIR/
|
||||
cp -a ../i2p $PKG/$INSTALL_DIR/
|
||||
|
||||
mkdir -p $PKG/install
|
||||
|
||||
#############################################################################
|
||||
# Preconfigureation to make package smaller, and...
|
||||
# we keep as much as reasonable in the installation directory.
|
||||
# This makes the install map fairly well to the standard installation.
|
||||
# It also makes it easier to find the log and pid files!
|
||||
#############################################################################
|
||||
# $INSTALL_DIR is used by this SlackBuild.
|
||||
# [%$]INSTALL_PATH , [%$]SYSTEM_java_io_tmpdir, and [%$]USER_HOME have the correct paths set
|
||||
# by the IzPack installer.
|
||||
cd $PKG/$INSTALL_DIR/i2p
|
||||
for file in wrapper.config eepget i2prouter runplain.sh; do
|
||||
sed -i "s|[%$]INSTALL_PATH|/$INSTALL_DIR/i2p|g;s|[$%]SYSTEM_java_io_tmpdir|$TMP|g;s/[%$]USER_HOME/\$HOME/g" $file
|
||||
done
|
||||
mv wrapper.config wrapper.config.new
|
||||
|
||||
# wrapper.config $INSTALL_PATH and $SYSTEM_java_io_tmpdir
|
||||
sed "s|\$INSTALL_PATH|/$INSTALL_DIR/i2p|g" wrapper.config > a
|
||||
sed "s|\$SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > wrapper.config
|
||||
# eepget %INSTALL_PATH
|
||||
sed "s|\$INSTALL_PATH|/$INSTALL_DIR/i2p|g" eepget > a
|
||||
rm eepget
|
||||
mv a eepget
|
||||
# runplain.sh %INSTALL_PATH and %SYSTEM_java_io_tmpdir
|
||||
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" runplain.sh > a
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > runplain.sh
|
||||
# i2prouter %INSTALL_PATH and %SYSTEM_java_io_tmpdir
|
||||
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" i2prouter > a
|
||||
rm i2prouter
|
||||
mv a i2prouter
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" i2prouter > a
|
||||
sed "s|#ALLOW_ROOT=true|ALLOW_ROOT=true|g" a > i2prouter
|
||||
install -d $PKG/usr/bin
|
||||
install -d $PKG/usr/doc/$NAME-$VERSION
|
||||
install -d $PKG/etc/rc.d
|
||||
mv licenses LICENSE.txt -t $PKG/usr/doc/$NAME-$VERSION
|
||||
|
||||
chmod 744 ./i2prouter
|
||||
chmod 744 ./osid
|
||||
chmod 744 ./runplain.sh
|
||||
chmod 744 ./eepget
|
||||
chmod 744 ./scripts/i2pbench.sh
|
||||
chmod 744 ./scripts/i2ptest.sh
|
||||
rm -Rf ./lib/*.dll ./*.bat ./*.exe ./installer ./icons ./a postinstall.sh
|
||||
# runplain.sh will live in the installation directory. eepget and i2prouter will go to /usr/bin
|
||||
# with symlinks in INST_DIR (created in doinst.sh)
|
||||
install -m755 i2prouter $PKG/usr/bin
|
||||
install -m755 eepget $PKG/usr/bin
|
||||
chmod 755 ./runplain.sh
|
||||
|
||||
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
|
||||
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
|
||||
find $PKG/$INSTALL_DIR/i2p -name "*.xml" -exec mv {} {}.new \;
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
if [ $INSTALL_DIR != 'opt' ]; then
|
||||
sed "s|\(The I2P package\)\s\+will be\s\+\(installed to\).+|\1 has been \2 $INSTALL_DIR/i2p|g" $CWD/README > $PKG/usr/doc/$NAME-$VERSION/README
|
||||
else
|
||||
sed "s|will be installed|has been installed|" $CWD/README > $PKG/usr/doc/$NAME-$VERSION/README
|
||||
fi
|
||||
|
||||
install -d $PKG/usr/man/man1
|
||||
gzip -9 man/*.1
|
||||
install -m644 man/*.1.gz $PKG/usr/man/man1
|
||||
rm -rf ./man
|
||||
|
||||
# We install all x86 wrapper binaries.
|
||||
# The i2prouter script will try to determine the OS (linux), the bits (32 VS 64) and should be able
|
||||
# to figure out the correct wrapper binary to use.
|
||||
|
||||
# However: In case the i2prouter script's detection fails, "$INST_DIR/i2psvc" will point to
|
||||
# what 'we' think the correct binary is.
|
||||
#
|
||||
# A good reason for installing all binaries: in case the user, for whatever reason, switches from an
|
||||
# x64 JRE to an x86 JRE, I2P should continue to work without needing to be reinstalled.
|
||||
install -m755 $I2PSRC/installer/lib/wrapper/linux/i2psvc ./i2psvc-linux-x86-32
|
||||
install -m644 $I2PSRC/installer/lib/wrapper/linux/libwrapper.so ./lib/libwrapper-linux-x86-32.so
|
||||
install -m755 $I2PSRC/installer/lib/wrapper/linux64/i2psvc ./i2psvc-linux-x86-64
|
||||
install -m644 $I2PSRC/installer/lib/wrapper/linux64/libwrapper.so ./lib/libwrapper-linux-x86-64.so
|
||||
install -m644 $I2PSRC/installer/lib/wrapper/all/wrapper.jar ./lib/wrapper.jar
|
||||
install -m644 $I2PSRC/build/jbigi.jar $PKG/$INSTALL_DIR/i2p/lib/jbigi.jar
|
||||
|
||||
rm -f ./postinstall.sh ./osid ./INSTALL-*.txt
|
||||
sed "s|directory|/$INSTALL_DIR/i2p|" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
sed -i "s|%pkg|$NAME-$VERSION|" $PKG/install/doinst.sh
|
||||
sed "s|%INST_DIR|/$INSTALL_DIR/i2p|" $CWD/rc.i2p> $PKG/etc/rc.d/rc.i2p.new
|
||||
cp $CWD/slack-desc $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
#
|
||||
# requiredbuilder messes up REALLY bad, and thinks java is perl?!
|
||||
# It also did not catch the shell requirements! BOOOOOOOOOOO! HISSSSSSSS!
|
||||
#
|
||||
# requiredbuilder -v -y -s $CWD $PKG
|
||||
#
|
||||
cat $CWD/slack-required > $PKG/install/slack-required
|
||||
cp $CWD/slack-required $PKG/install/slack-required
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT
|
||||
|
185
Slackware/i2p/rc.i2p
Normal file
185
Slackware/i2p/rc.i2p
Normal file
@@ -0,0 +1,185 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Abort on errors
|
||||
set -e
|
||||
|
||||
##
|
||||
# This *must* be configured. Set this to the user that will run I2P.
|
||||
# Note: If you don't want I2P to start automatically at boot,
|
||||
# use "i2prouter start" as a non-root user to start I2P.
|
||||
#RUN_AS_USER=
|
||||
##
|
||||
|
||||
##
|
||||
# Set the locale as desired.
|
||||
# Note: this is not the same as the language shown in the I2P router console.
|
||||
# This affects the locale used in wrapper.log. For best results, use a
|
||||
# unicode enabled locale. This is especially important for foreign language torrents.
|
||||
#
|
||||
# If not set the user's configured locale will be used.
|
||||
#RCLOCALE=
|
||||
##
|
||||
|
||||
#####################################################
|
||||
# Nothing below this point should need to be edited #
|
||||
#####################################################
|
||||
# %INST_DIR is set by i2p.SlackBuild
|
||||
INSTALL_DIR="%INST_DIR"
|
||||
# Make sure the package is installed and that the wrapper can be found
|
||||
[ -d $INSTALL_DIR ] && [ -x $INSTALL_DIR/i2psvc ] || (echo "The I2P package is not installed" >&2 ; exit 1)
|
||||
|
||||
if [ -z $RUN_AS_USER ]; then
|
||||
echo "ERROR: RUN_AS_USER not configured in $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $(id -ur) -ne 0 ]; then
|
||||
echo 'ERROR: You must be root to start this service.' >&2
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $RCLOCALE ]; then
|
||||
if [ ! $(locale -a |grep -q "en_US\.utf8") ]; then
|
||||
RCLOCALE="en_US.utf8"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Abort this script if any referenced variables haven't been set
|
||||
set -u
|
||||
|
||||
if $(uname -m |grep -q '64'); then
|
||||
BITS='64'
|
||||
else
|
||||
BITS=''
|
||||
fi
|
||||
|
||||
PATH="$PATH:/usr/lib$BITS/java/bin:/usr/lib$BITS/java/jre/bin"
|
||||
RUN=/var/run/i2p
|
||||
PIDFILE="$RUN/i2p.pid"
|
||||
WRAPPER_CONF="$INSTALL_DIR/wrapper.config"
|
||||
WRAPPERLOG=/var/log/i2p/wrapper.log
|
||||
I2PTEMP="/tmp/i2p-daemon"
|
||||
DESC="The I2P daemon"
|
||||
JAVABINARY=$(awk -F'=' '/^ *wrapper\.java\.command/{print $2}' "$WRAPPER_CONF")
|
||||
|
||||
if [ ! $(which $JAVABINARY 2>/dev/null) ]; then
|
||||
for rc in /etc/profile.d/*jdk*.sh /etc/profile.d/*java*.sh; do
|
||||
[ -r $rc ] && . $rc
|
||||
done
|
||||
if [ ! $(which $JAVABINARY 2>/dev/null) ]; then
|
||||
echo "ERROR: Cannot find java. Please set the path to java in $WRAPPER_CONF" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
JAVA=$(which $JAVABINARY 2>/dev/null)
|
||||
|
||||
I2P_ARGS="$WRAPPER_CONF \
|
||||
wrapper.java.additional.1=-DloggerFilenameOverride=/var/log/i2p/log-router-@.txt \
|
||||
wrapper.java.additional.10=-Dwrapper.logfile=$WRAPPERLOG \
|
||||
wrapper.java.additional.11=-Di2p.dir.pid=$RUN \
|
||||
wrapper.java.additional.12=-Di2p.dir.temp=$I2PTEMP \
|
||||
wrapper.java.command=$JAVA \
|
||||
wrapper.logfile=$WRAPPERLOG \
|
||||
wrapper.pidfile=$PIDFILE \
|
||||
wrapper.daemonize=TRUE"
|
||||
|
||||
LC_ALL=$RCLOCALE
|
||||
LANG=$RCLOCALE
|
||||
export LC_ALL LANG
|
||||
|
||||
is_running() {
|
||||
if [ -r $PIDFILE ]; then
|
||||
PID="$(cat ${PIDFILE})" 2>/dev/null 2>&1
|
||||
if ! kill -0 $PID >/dev/null 2>&1; then
|
||||
rm "$PIDFILE"
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
if is_running; then
|
||||
echo "ERROR: $DESC is already running." >&2
|
||||
fi
|
||||
|
||||
for DIR in $RUN $I2PTEMP; do
|
||||
test -d $DIR && rm -rf $DIR
|
||||
mkdir -p $DIR
|
||||
chown -R $RUN_AS_USER $DIR
|
||||
done
|
||||
[ -d /var/log/i2p ] || mkdir /var/log/i2p
|
||||
chown -R $RUN_AS_USER /var/log/i2p
|
||||
|
||||
echo -n "Starting $DESC..."
|
||||
TZ=UTC su $RUN_AS_USER -c "$INSTALL_DIR/i2psvc $I2P_ARGS"
|
||||
is_running
|
||||
echo "[pid: $PID]"
|
||||
}
|
||||
|
||||
stop(){
|
||||
if is_running; then
|
||||
echo -n "Stopping $DESC [pid: $PID] (this could take a while)."
|
||||
kill "$PID" >/dev/null 2>&1
|
||||
while kill -0 "$PID" > /dev/null 2>&1; do
|
||||
echo -n .
|
||||
sleep 1
|
||||
done
|
||||
rm -rf "$RUN" "$I2PTEMP"
|
||||
echo done.
|
||||
return 0
|
||||
else
|
||||
echo "$DESC is not running." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Unset +u to allow the 'usage' text to be displayed
|
||||
set +u
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
status)
|
||||
if is_running; then
|
||||
echo "$DESC is running [pid: $PID]" >&2
|
||||
else
|
||||
echo "$DESC is not running." >&2
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
graceful)
|
||||
if is_running; then
|
||||
kill -HUP $PID
|
||||
echo "Graceful shutdown of $DESC initiated." >&2
|
||||
echo "This may take up to 11 minutes." >&2
|
||||
fi
|
||||
;;
|
||||
dump)
|
||||
if is_running; then
|
||||
kill -3 $PID
|
||||
echo "Threads dumped to $WRAPPERLOG" >&2
|
||||
else
|
||||
echo "$DESC is not running." >&2
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
if is_running; then
|
||||
stop
|
||||
start
|
||||
else
|
||||
echo "$DESC is not running." >&2
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 start|stop|status|restart|graceful|dump"
|
||||
;;
|
||||
esac
|
@@ -1,47 +0,0 @@
|
||||
Building:
|
||||
The i2p package will be installed in /opt/i2p
|
||||
|
||||
If you want to change installation dir, change the variable INSTALL_DIR
|
||||
on i2p.SlackBuild and rebuild the package. You will also need to do the same
|
||||
in the base-i2p package.
|
||||
|
||||
Installation and Upgrade:
|
||||
Probably you will never have to update i2p packages. However if you do,
|
||||
be sure to installpkg first, then removepkg or custom config files can
|
||||
be lost with upgradepkg. I2P has an auto-update function. However using
|
||||
installpkg then removepkg lowers the demand on the I2P network as a
|
||||
whole, and is by far faster.
|
||||
|
||||
After installpkg command, doinst.sh will execute a postinstallation script
|
||||
needed by I2P. Be sure to also install the base-i2p package.
|
||||
|
||||
Optional:
|
||||
|
||||
chmod +x /etc/rc.d/rc.i2p only if you want it to start on boot and stop on
|
||||
shutdown.
|
||||
|
||||
How to start I2P:
|
||||
|
||||
Start I2P service with-
|
||||
sh /etc/rc.d/rc.i2p start
|
||||
|
||||
Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
this page: http://localhost:7657/index.jsp
|
||||
Here you can configure I2P, watch network status and navigate anonimously.
|
||||
It's suggested to subscribe to various addressbook hosts so that you can
|
||||
get to the many available eepsites and other service on I2P. These are not
|
||||
set up by default for security reasons.
|
||||
|
||||
Please see the faqs on http://www.i2p2.i2p/ or http://www.i2p2.de/ on how
|
||||
to subscribe to the various addressbook services.
|
||||
|
||||
To stop I2P:
|
||||
/etc/rc.d/rc.i2p stop
|
||||
|
||||
|
||||
For any additional information:
|
||||
|
||||
Within I2P- http://www.i2p2.i2p/, http://forum.i2p/, http://zzz.i2p
|
||||
|
||||
Internet (not reccomended!) - http://www.i2p2.de/, http://forum.i2p2.de/
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# leave one space after the ':'.
|
||||
|
||||
|-----handy-ruler----------------------------------------------------------|
|
||||
i2p: i2p (an anonymizing network)
|
||||
i2p: I2P (an anonymizing network)
|
||||
i2p:
|
||||
i2p: I2P is an anonymizing network, offering a simple layer that
|
||||
i2p: identity-sensitive applications can use to securely communicate. All
|
||||
@@ -14,6 +14,6 @@ i2p: data is wrapped with several layers of encryption, and the network is
|
||||
i2p: both distributed and dynamic, with no trusted parties.
|
||||
i2p: Many applications are available that interface with I2P, including
|
||||
i2p: mail, peer-peer file sharing, IRC chat, and others.
|
||||
i2p: WARNING: To upgrade installpkg FIRST _THEN_ removepkg.
|
||||
i2p: For more information, see: http://www.i2p2.de/
|
||||
i2p:
|
||||
i2p: For more information, see: https://geti2p.net/
|
||||
i2p:
|
||||
|
@@ -1,4 +1 @@
|
||||
jre >= 5
|
||||
i2p-base >= 0.0.1
|
||||
bash >= 3.1.017
|
||||
|
||||
jre >= 6
|
||||
|
8
apps/BOB/.classpath
Normal file
8
apps/BOB/.classpath
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
|
||||
<classpathentry kind="output" path="build"/>
|
||||
</classpath>
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>lib</name>
|
||||
<name>BOB</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -25,12 +27,17 @@ import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.*;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
@@ -105,57 +112,76 @@ import net.i2p.util.SimpleTimer2;
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class BOB {
|
||||
public class BOB implements Runnable, ClientApp {
|
||||
|
||||
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";
|
||||
public final static String PROP_CFG_VER = "BOB.CFG.VER";
|
||||
private static NamedDB database;
|
||||
private static Properties props = new Properties();
|
||||
private static AtomicBoolean spin = new AtomicBoolean(true);
|
||||
|
||||
private static BOB _bob;
|
||||
|
||||
private NamedDB database;
|
||||
private Properties props = new Properties();
|
||||
private AtomicBoolean spin = new AtomicBoolean(true);
|
||||
private static final String P_RUNNING = "RUNNING";
|
||||
private static final String P_STARTING = "STARTING";
|
||||
private static final String P_STOPPING = "STOPPING";
|
||||
private static AtomicBoolean lock = new AtomicBoolean(false);
|
||||
private AtomicBoolean lock = new AtomicBoolean(false);
|
||||
// no longer used.
|
||||
// private static int maxConnections = 0;
|
||||
|
||||
/**
|
||||
* Log a warning
|
||||
*
|
||||
* @param arg
|
||||
*/
|
||||
public static void info(String arg) {
|
||||
System.out.println("INFO:" + arg);
|
||||
(new Log(BOB.class)).info(arg);
|
||||
}
|
||||
private final Logger _log;
|
||||
private final ClientAppManager _mgr;
|
||||
private final String[] _args;
|
||||
private volatile ClientAppState _state = UNINITIALIZED;
|
||||
|
||||
/**
|
||||
* Log a warning
|
||||
*
|
||||
* @param arg
|
||||
*/
|
||||
public static void warn(String arg) {
|
||||
System.out.println("WARNING:" + arg);
|
||||
(new Log(BOB.class)).warn(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error
|
||||
*
|
||||
* @param arg
|
||||
*/
|
||||
public static void error(String arg) {
|
||||
System.out.println("ERROR: " + arg);
|
||||
(new Log(BOB.class)).error(arg);
|
||||
}
|
||||
private volatile ServerSocket listener;
|
||||
private volatile Thread _runner;
|
||||
|
||||
/**
|
||||
* Stop BOB gracefully
|
||||
* @deprecated unused
|
||||
*/
|
||||
public static void stop() {
|
||||
spin.set(false);
|
||||
_bob.shutdown(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* For ClientApp interface.
|
||||
* Does NOT open the listener socket or start threads; caller must call startup()
|
||||
*
|
||||
* @param mgr may be null
|
||||
* @param args non-null
|
||||
* @throws Exception on bad args
|
||||
* @since 0.9.10
|
||||
*/
|
||||
public BOB(I2PAppContext context, ClientAppManager mgr, String[] args) {
|
||||
// If we were run from command line, log to stdout
|
||||
boolean logToStdout = false;
|
||||
URL classResource = BOB.class.getResource("BOB.class");
|
||||
if (classResource != null) {
|
||||
String classPath = classResource.toString();
|
||||
if (classPath.startsWith("jar")) {
|
||||
String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
|
||||
"/META-INF/MANIFEST.MF";
|
||||
try {
|
||||
Manifest manifest = new Manifest(new URL(manifestPath).openStream());
|
||||
Attributes attrs = manifest.getMainAttributes();
|
||||
String mainClass = attrs.getValue("Main-Class");
|
||||
if ("net.i2p.BOB.Main".equals(mainClass))
|
||||
logToStdout = true;
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
_log = new Logger(context.logManager().getLog(BOB.class), logToStdout);
|
||||
|
||||
_mgr = mgr;
|
||||
_args = args;
|
||||
_state = INITIALIZED;
|
||||
database = new NamedDB();
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,8 +190,22 @@ public class BOB {
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
database = new NamedDB();
|
||||
ServerSocket listener = null;
|
||||
try {
|
||||
_bob = new BOB(I2PAppContext.getGlobalContext(), null, args);
|
||||
_bob.startup();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void loadConfig() {
|
||||
int i = 0;
|
||||
boolean save = false;
|
||||
// Set up all defaults to be passed forward to other threads.
|
||||
@@ -176,116 +216,144 @@ public class BOB {
|
||||
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
|
||||
i = Y1.hashCode();
|
||||
i = Y2.hashCode();
|
||||
Log _log = new Log(BOB.class);
|
||||
try {
|
||||
{
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
try {
|
||||
FileInputStream fi = new FileInputStream(cfg);
|
||||
props.load(fi);
|
||||
fi.close();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
warn("Unable to load up the BOB config file " + cfg.getAbsolutePath() + ", Using defaults.");
|
||||
warn(fnfe.toString());
|
||||
save = true;
|
||||
} catch (IOException ioe) {
|
||||
warn("IOException on BOB config file " + cfg.getAbsolutePath() + ", using defaults.");
|
||||
warn(ioe.toString());
|
||||
}
|
||||
{
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
// 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");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_PORT)) {
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_PORT)) {
|
||||
props.setProperty(PROP_BOB_PORT, "2827"); // 0xB0B
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.length")) {
|
||||
props.setProperty("inbound.length", "1");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.length")) {
|
||||
props.setProperty("outbound.length", "1");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.lengthVariance")) {
|
||||
props.setProperty("inbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.lengthVariance")) {
|
||||
props.setProperty("outbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_HOST)) {
|
||||
props.setProperty(PROP_BOB_HOST, "localhost");
|
||||
save = true;
|
||||
}
|
||||
// PROP_RELIABILITY_NONE, PROP_RELIABILITY_BEST_EFFORT, PROP_RELIABILITY_GUARANTEED
|
||||
if (!props.containsKey(PROP_CFG_VER)) {
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE);
|
||||
props.setProperty(PROP_CFG_VER,"1");
|
||||
save = true;
|
||||
}
|
||||
if (save) {
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
try {
|
||||
warn("Writing new defaults file " + cfg.getAbsolutePath());
|
||||
FileOutputStream fo = new FileOutputStream(cfg);
|
||||
props.store(fo, cfg.getAbsolutePath());
|
||||
fo.close();
|
||||
} catch (IOException ioe) {
|
||||
error("IOException on BOB config file " + cfg.getAbsolutePath() + ", " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
boolean g = false;
|
||||
spin.set(true);
|
||||
FileInputStream fi = null;
|
||||
try {
|
||||
info("BOB is now running.");
|
||||
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
Socket server = null;
|
||||
listener.setSoTimeout(500); // .5 sec
|
||||
|
||||
while (spin.get()) {
|
||||
//DoCMDS connection;
|
||||
|
||||
try {
|
||||
server = listener.accept();
|
||||
server.setKeepAlive(true);
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
|
||||
if (g) {
|
||||
DoCMDS conn_c = new DoCMDS(spin, lock, server, props, database, _log);
|
||||
Thread t = new Thread(conn_c);
|
||||
t.setName("BOB.DoCMDS " + i);
|
||||
t.start();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
fi = new FileInputStream(cfg);
|
||||
props.load(fi);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Unable to load up the BOB config file " + cfg.getAbsolutePath() + ", Using defaults.", fnfe);
|
||||
save = true;
|
||||
} catch (IOException ioe) {
|
||||
error("IOException on socket listen: " + ioe);
|
||||
ioe.printStackTrace();
|
||||
_log.warn("IOException on BOB config file " + cfg.getAbsolutePath() + ", using defaults.", ioe);
|
||||
} finally {
|
||||
if (fi != null) try { fi.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
// 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");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_PORT)) {
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_PORT)) {
|
||||
props.setProperty(PROP_BOB_PORT, "2827"); // 0xB0B
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.length")) {
|
||||
props.setProperty("inbound.length", "1");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.length")) {
|
||||
props.setProperty("outbound.length", "1");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.lengthVariance")) {
|
||||
props.setProperty("inbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.lengthVariance")) {
|
||||
props.setProperty("outbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_HOST)) {
|
||||
props.setProperty(PROP_BOB_HOST, "localhost");
|
||||
save = true;
|
||||
}
|
||||
// PROP_RELIABILITY_NONE, PROP_RELIABILITY_BEST_EFFORT, PROP_RELIABILITY_GUARANTEED
|
||||
if (!props.containsKey(PROP_CFG_VER)) {
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE);
|
||||
props.setProperty(PROP_CFG_VER,"1");
|
||||
save = true;
|
||||
}
|
||||
if (save) {
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
FileOutputStream fo = null;
|
||||
try {
|
||||
_log.warn("Writing new defaults file " + cfg.getAbsolutePath());
|
||||
fo = new FileOutputStream(cfg);
|
||||
props.store(fo, cfg.getAbsolutePath());
|
||||
} catch (IOException ioe) {
|
||||
_log.error("IOException on BOB config file " + cfg.getAbsolutePath(), ioe);
|
||||
} finally {
|
||||
if (fo != null) try { fo.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void startListener() throws IOException {
|
||||
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
listener.setSoTimeout(500); // .5 sec
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void startThread() {
|
||||
I2PAppThread t = new I2PAppThread(this, "BOBListener");
|
||||
t.start();
|
||||
_runner = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
public void run() {
|
||||
if (listener == null) return;
|
||||
changeState(RUNNING);
|
||||
_log.info("BOB is now running.");
|
||||
if (_mgr != null)
|
||||
_mgr.register(this);
|
||||
|
||||
int i = 0;
|
||||
boolean g = false;
|
||||
spin.set(true);
|
||||
try {
|
||||
Socket server = null;
|
||||
|
||||
while (spin.get()) {
|
||||
//DoCMDS connection;
|
||||
|
||||
try {
|
||||
server = listener.accept();
|
||||
server.setKeepAlive(true);
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
|
||||
if (g) {
|
||||
DoCMDS conn_c = new DoCMDS(spin, lock, server, props, database, _log);
|
||||
Thread t = new Thread(conn_c);
|
||||
t.setName("BOB.DoCMDS " + i);
|
||||
t.start();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
changeState(STOPPING);
|
||||
} catch (Exception e) {
|
||||
if (spin.get())
|
||||
_log.error("Unexpected error while listening for connections", e);
|
||||
else
|
||||
e = null;
|
||||
changeState(STOPPING, e);
|
||||
} finally {
|
||||
info("BOB is now shutting down...");
|
||||
_log.info("BOB is now shutting down...");
|
||||
// Clean up everything.
|
||||
try {
|
||||
listener.close();
|
||||
@@ -308,7 +376,7 @@ public class BOB {
|
||||
database.releaseReadLock();
|
||||
database.getWriteLock();
|
||||
nickinfo.getWriteLock();
|
||||
nickinfo.add(P_STOPPING, new Boolean(true));
|
||||
nickinfo.add(P_STOPPING, Boolean.valueOf(true));
|
||||
nickinfo.releaseWriteLock();
|
||||
database.releaseWriteLock();
|
||||
} else {
|
||||
@@ -316,8 +384,8 @@ public class BOB {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
}
|
||||
info("BOB is now stopped.");
|
||||
|
||||
changeState(STOPPED);
|
||||
_log.info("BOB is now stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,4 +437,86 @@ public class BOB {
|
||||
waitjoin(groups[i], level + 1, groups[i].getName());
|
||||
}
|
||||
}
|
||||
|
||||
////// begin ClientApp interface
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public void startup() throws IOException {
|
||||
if (_state != INITIALIZED)
|
||||
return;
|
||||
changeState(STARTING);
|
||||
try {
|
||||
startListener();
|
||||
} catch (IOException e) {
|
||||
_log.error("Error starting BOB on"
|
||||
+ props.getProperty(PROP_BOB_HOST)
|
||||
+ ":" + props.getProperty(PROP_BOB_PORT), e);
|
||||
changeState(START_FAILED, e);
|
||||
throw e;
|
||||
}
|
||||
startThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public void shutdown(String[] args) {
|
||||
if (_state != RUNNING)
|
||||
return;
|
||||
changeState(STOPPING);
|
||||
spin.set(false);
|
||||
if (_runner != null)
|
||||
_runner.interrupt();
|
||||
else
|
||||
changeState(STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public ClientAppState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BOB";
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "BOB " + Arrays.toString(_args);
|
||||
}
|
||||
|
||||
////// end ClientApp interface
|
||||
////// begin ClientApp helpers
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void changeState(ClientAppState state) {
|
||||
changeState(state, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private synchronized void changeState(ClientAppState state, Exception e) {
|
||||
_state = state;
|
||||
if (_mgr != null)
|
||||
_mgr.notify(this, state, null, e);
|
||||
}
|
||||
|
||||
////// end ClientApp helpers
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@ import net.i2p.client.I2PClientFactory;
|
||||
//import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
//import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.util.Log;
|
||||
// needed only for debugging.
|
||||
// import java.util.logging.Level;
|
||||
// import java.util.logging.Logger;
|
||||
@@ -56,7 +55,7 @@ public class DoCMDS implements Runnable {
|
||||
private ByteArrayOutputStream prikey;
|
||||
private boolean dk, ns, ip, op;
|
||||
private NamedDB nickinfo;
|
||||
private Log _log;
|
||||
private Logger _log;
|
||||
private AtomicBoolean LIVE;
|
||||
private AtomicBoolean lock;
|
||||
/* database strings */
|
||||
@@ -164,7 +163,7 @@ public class DoCMDS implements Runnable {
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
DoCMDS(AtomicBoolean LIVE, AtomicBoolean lock, Socket server, Properties props, NamedDB database, Log _log) {
|
||||
DoCMDS(AtomicBoolean LIVE, AtomicBoolean lock, Socket server, Properties props, NamedDB database, Logger _log) {
|
||||
this.lock = lock;
|
||||
this.LIVE = LIVE;
|
||||
this.server = server;
|
||||
@@ -388,7 +387,7 @@ public class DoCMDS implements Runnable {
|
||||
* Does the base64 information look OK
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
* @return OK
|
||||
*/
|
||||
private boolean is64ok(String data) {
|
||||
try {
|
||||
@@ -606,7 +605,7 @@ public class DoCMDS implements Runnable {
|
||||
break die;
|
||||
}
|
||||
} catch (I2PException ipe) {
|
||||
BOB.error("Error generating keys" + ipe);
|
||||
_log.error("Error generating keys", ipe);
|
||||
out.println("ERROR generating keys");
|
||||
}
|
||||
|
||||
@@ -665,7 +664,7 @@ public class DoCMDS implements Runnable {
|
||||
break die;
|
||||
}
|
||||
try {
|
||||
nickinfo.add(P_QUIET, new Boolean(Boolean.parseBoolean(Arg) == true));
|
||||
nickinfo.add(P_QUIET, Boolean.valueOf(Arg));
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
wunlock();
|
||||
@@ -817,10 +816,10 @@ public class DoCMDS implements Runnable {
|
||||
try {
|
||||
database.add(Arg, nickinfo);
|
||||
nickinfo.add(P_NICKNAME, Arg);
|
||||
nickinfo.add(P_STARTING, new Boolean(false));
|
||||
nickinfo.add(P_RUNNING, new Boolean(false));
|
||||
nickinfo.add(P_STOPPING, new Boolean(false));
|
||||
nickinfo.add(P_QUIET, new Boolean(false));
|
||||
nickinfo.add(P_STARTING, Boolean.valueOf(false));
|
||||
nickinfo.add(P_RUNNING, Boolean.valueOf(false));
|
||||
nickinfo.add(P_STOPPING, Boolean.valueOf(false));
|
||||
nickinfo.add(P_QUIET, Boolean.valueOf(false));
|
||||
nickinfo.add(P_INHOST, "localhost");
|
||||
nickinfo.add(P_OUTHOST, "localhost");
|
||||
Properties Q = new Properties();
|
||||
@@ -989,7 +988,7 @@ public class DoCMDS implements Runnable {
|
||||
prt = Integer.parseInt(Arg);
|
||||
if (prt > 1 && prt < 65536) {
|
||||
try {
|
||||
nickinfo.add(P_INPORT, new Integer(prt));
|
||||
nickinfo.add(P_INPORT, Integer.valueOf(prt));
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
wunlock();
|
||||
@@ -1076,7 +1075,7 @@ public class DoCMDS implements Runnable {
|
||||
prt = Integer.parseInt(Arg);
|
||||
if (prt > 1 && prt < 65536) {
|
||||
try {
|
||||
nickinfo.add(P_OUTPORT, new Integer(prt));
|
||||
nickinfo.add(P_OUTPORT, Integer.valueOf(prt));
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
wunlock();
|
||||
@@ -1355,7 +1354,7 @@ public class DoCMDS implements Runnable {
|
||||
break die;
|
||||
}
|
||||
|
||||
nickinfo.add(P_STOPPING, new Boolean(true));
|
||||
nickinfo.add(P_STOPPING, Boolean.valueOf(true));
|
||||
try {
|
||||
wunlock();
|
||||
|
||||
|
@@ -22,7 +22,6 @@ import net.i2p.I2PException;
|
||||
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
|
||||
@@ -32,7 +31,7 @@ import net.i2p.util.Log;
|
||||
public class I2Plistener implements Runnable {
|
||||
|
||||
private NamedDB info, database;
|
||||
private Log _log;
|
||||
private Logger _log;
|
||||
public I2PSocketManager socketManager;
|
||||
public I2PServerSocket serverSocket;
|
||||
private AtomicBoolean lives;
|
||||
@@ -45,7 +44,7 @@ public class I2Plistener implements Runnable {
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
|
||||
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Logger _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
|
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -39,10 +39,8 @@ public class Lifted {
|
||||
*
|
||||
**/
|
||||
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));
|
||||
for (Map.Entry<Object, Object> e : src_prop.entrySet()) {
|
||||
dest_prop.put((String)e.getKey(), (String)e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
apps/BOB/src/net/i2p/BOB/Logger.java
Normal file
44
apps/BOB/src/net/i2p/BOB/Logger.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package net.i2p.BOB;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class Logger {
|
||||
public Log log;
|
||||
private boolean logToStdout;
|
||||
|
||||
public Logger(Log log, boolean logToStdout) {
|
||||
this.log = log;
|
||||
this.logToStdout = logToStdout;
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
if (logToStdout)
|
||||
System.out.println("INFO: " + msg);
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info(msg);
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
warn(msg, null);
|
||||
}
|
||||
|
||||
public void warn(String msg, Throwable e) {
|
||||
if (logToStdout) {
|
||||
System.out.println("WARNING: " + msg);
|
||||
if (e != null)
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn(msg, e);
|
||||
}
|
||||
|
||||
public void error(String msg, Throwable e) {
|
||||
if (logToStdout) {
|
||||
System.out.println("ERROR: " + msg);
|
||||
if (e != null)
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (log.shouldLog(Log.ERROR))
|
||||
log.error(msg, e);
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ import java.net.ServerSocket;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
@@ -36,7 +37,7 @@ import net.i2p.util.Log;
|
||||
public class MUXlisten implements Runnable {
|
||||
|
||||
private NamedDB database, info;
|
||||
private Log _log;
|
||||
private Logger _log;
|
||||
private I2PSocketManager socketManager;
|
||||
private ByteArrayInputStream prikey;
|
||||
private ThreadGroup tg;
|
||||
@@ -57,7 +58,7 @@ public class MUXlisten implements Runnable {
|
||||
* @throws net.i2p.I2PException
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
MUXlisten(AtomicBoolean lock, NamedDB database, NamedDB info, Log _log) throws I2PException, IOException, RuntimeException {
|
||||
MUXlisten(AtomicBoolean lock, NamedDB database, NamedDB info, Logger _log) throws I2PException, IOException, RuntimeException {
|
||||
try {
|
||||
int port = 0;
|
||||
InetAddress host = null;
|
||||
@@ -70,7 +71,7 @@ public class MUXlisten implements Runnable {
|
||||
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(true));
|
||||
this.info.add("STARTING", Boolean.valueOf(true));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
this.database.getReadLock();
|
||||
@@ -96,15 +97,25 @@ public class MUXlisten implements Runnable {
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
|
||||
String i2cpHost = Q.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
int i2cpPort = 7654;
|
||||
String i2cpPortStr = Q.getProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
try {
|
||||
i2cpPort = Integer.parseInt(i2cpPortStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IllegalArgumentException("Invalid I2CP port specified [" + i2cpPortStr + "]");
|
||||
}
|
||||
|
||||
if (this.come_in) {
|
||||
this.listener = new ServerSocket(port, backlog, host);
|
||||
}
|
||||
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
|
||||
socketManager = I2PSocketManagerFactory.createManager(
|
||||
prikey, i2cpHost, i2cpPort, Q);
|
||||
} catch (IOException e) {
|
||||
// Something went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.add("STARTING", Boolean.valueOf(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
throw new IOException(e.toString());
|
||||
@@ -112,7 +123,7 @@ public class MUXlisten implements Runnable {
|
||||
// Something went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.add("STARTING", Boolean.valueOf(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
throw new RuntimeException(e);
|
||||
@@ -120,7 +131,7 @@ public class MUXlisten implements Runnable {
|
||||
// Something else went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.add("STARTING", Boolean.valueOf(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
e.printStackTrace();
|
||||
@@ -160,7 +171,7 @@ public class MUXlisten implements Runnable {
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("RUNNING", new Boolean(true));
|
||||
info.add("RUNNING", Boolean.valueOf(true));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
@@ -204,7 +215,7 @@ public class MUXlisten implements Runnable {
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", new Boolean(false));
|
||||
info.add("STARTING", Boolean.valueOf(false));
|
||||
} catch (Exception e) {
|
||||
wunlock();
|
||||
break quit;
|
||||
@@ -258,9 +269,9 @@ public class MUXlisten implements Runnable {
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", new Boolean(false));
|
||||
info.add("STOPPING", new Boolean(true));
|
||||
info.add("RUNNING", new Boolean(false));
|
||||
info.add("STARTING", Boolean.valueOf(false));
|
||||
info.add("STOPPING", Boolean.valueOf(true));
|
||||
info.add("RUNNING", Boolean.valueOf(false));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
@@ -309,9 +320,9 @@ public class MUXlisten implements Runnable {
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", new Boolean(false));
|
||||
info.add("STOPPING", new Boolean(false));
|
||||
info.add("RUNNING", new Boolean(false));
|
||||
info.add("STARTING", Boolean.valueOf(false));
|
||||
info.add("STOPPING", Boolean.valueOf(false));
|
||||
info.add("RUNNING", Boolean.valueOf(false));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
|
@@ -23,7 +23,7 @@ package net.i2p.BOB;
|
||||
public class NamedDB {
|
||||
|
||||
private volatile Object[][] data;
|
||||
private volatile int index, writersWaiting, readers;
|
||||
private int index, writersWaiting, readers;
|
||||
|
||||
/**
|
||||
* make initial NULL object
|
||||
@@ -31,7 +31,6 @@ public class NamedDB {
|
||||
*/
|
||||
public NamedDB() {
|
||||
this.data = new Object[1][2];
|
||||
this.index = this.writersWaiting = this.readers = 0;
|
||||
}
|
||||
|
||||
synchronized public void getReadLock() {
|
||||
|
@@ -116,7 +116,6 @@ public class TCPio implements Runnable {
|
||||
Aout.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,6 @@ import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
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
|
||||
@@ -32,7 +31,7 @@ import net.i2p.util.Log;
|
||||
public class TCPlistener implements Runnable {
|
||||
|
||||
private NamedDB info, database;
|
||||
private Log _log;
|
||||
private Logger _log;
|
||||
public I2PSocketManager socketManager;
|
||||
public I2PServerSocket serverSocket;
|
||||
private ServerSocket listener;
|
||||
@@ -45,7 +44,7 @@ public class TCPlistener implements Runnable {
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
|
||||
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Logger _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
|
@@ -70,12 +70,10 @@ public class TCPtoI2P implements Runnable {
|
||||
* @throws IOException
|
||||
*/
|
||||
private static String lnRead(InputStream in) throws IOException {
|
||||
String S;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int b;
|
||||
char c;
|
||||
|
||||
S = new String();
|
||||
|
||||
while (true) {
|
||||
b = in.read();
|
||||
if (b == 13) {
|
||||
@@ -87,9 +85,9 @@ public class TCPtoI2P implements Runnable {
|
||||
break;
|
||||
}
|
||||
c = (char) (b & 0x7f); // We only care about ASCII
|
||||
S = new String(S + c);
|
||||
builder.append(c);
|
||||
}
|
||||
return S;
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +99,7 @@ public class TCPtoI2P implements Runnable {
|
||||
*/
|
||||
private void Emsg(String e, OutputStream out) throws IOException {
|
||||
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
|
||||
out.write("ERROR ".concat(e).getBytes());
|
||||
out.write("ERROR ".concat(e).getBytes("UTF-8"));
|
||||
out.write(13);
|
||||
out.write(10);
|
||||
out.flush();
|
||||
|
@@ -106,8 +106,10 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||
// _log.debug("Message available: id = " + msgId + " size = " + size);
|
||||
try {
|
||||
byte msg[] = session.receiveMessage(msgId);
|
||||
out.write(msg);
|
||||
out.flush();
|
||||
if (msg != null) {
|
||||
out.write(msg);
|
||||
out.flush();
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
up = false;
|
||||
} catch (IOException ioe) {
|
||||
|
8
apps/addressbook/.classpath
Normal file
8
apps/addressbook/.classpath
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="java/src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/javax.servlet.jar"/>
|
||||
<classpathentry kind="output" path="build"/>
|
||||
</classpath>
|
17
apps/addressbook/.project
Normal file
17
apps/addressbook/.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>addressbook</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@@ -7,6 +7,7 @@
|
||||
<property name="jar" value="addressbook.jar"/>
|
||||
<property name="war" value="addressbook.war"/>
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.6" />
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="${build}"/>
|
||||
@@ -24,6 +25,18 @@
|
||||
<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" />
|
||||
</classpath>
|
||||
</depend>
|
||||
</target>
|
||||
|
||||
<target name="dependServlet" if="depend.available">
|
||||
<depend
|
||||
cache="../../build"
|
||||
srcdir="${src}"
|
||||
@@ -37,9 +50,22 @@
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init, depend">
|
||||
<javac debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
includeAntRuntime="false"
|
||||
srcdir="${src}" destdir="${build}">
|
||||
srcdir="${src}" destdir="${build}"
|
||||
excludes="net/i2p/addressbook/Servlet.java">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
<pathelement location="../../core/java/build/i2p.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="compileServlet" depends="init, dependServlet, compile">
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
includeAntRuntime="false"
|
||||
srcdir="${src}" destdir="${build}"
|
||||
includes="net/i2p/addressbook/Servlet.java">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
<pathelement location="../../core/java/build/i2p.jar" />
|
||||
@@ -48,11 +74,11 @@
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- unused for now, as we oddly ship addressbook as a .war -->
|
||||
<!-- unused for now (except for Android), as we oddly ship addressbook as a .war -->
|
||||
<target name="jar" depends="compile, changes">
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes" value="" />
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="addressbook.Daemon"/>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
@@ -64,7 +90,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="war" depends="compile, changes, warUpToDate" unless="war.uptodate">
|
||||
<target name="war" depends="compileServlet, changes, warUpToDate" unless="war.uptodate">
|
||||
<mkdir dir="${dist}/tmp"/>
|
||||
<mkdir dir="${dist}/tmp/WEB-INF"/>
|
||||
<mkdir dir="${dist}/tmp/WEB-INF/classes"/>
|
||||
|
@@ -120,11 +120,11 @@ class AddressBook {
|
||||
subscription.setLastFetched(I2PAppContext.getGlobalContext().clock().now());
|
||||
subf = tmp;
|
||||
} else {
|
||||
a = Collections.EMPTY_MAP;
|
||||
a = Collections.emptyMap();
|
||||
tmp.delete();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
a = Collections.EMPTY_MAP;
|
||||
a = Collections.emptyMap();
|
||||
}
|
||||
this.addresses = a;
|
||||
this.subFile = subf;
|
||||
@@ -148,7 +148,7 @@ class AddressBook {
|
||||
try {
|
||||
a = ConfigParser.parse(file);
|
||||
} catch (IOException exp) {
|
||||
a = new HashMap();
|
||||
a = new HashMap<String, String>();
|
||||
}
|
||||
this.addresses = a;
|
||||
this.subFile = null;
|
||||
@@ -260,7 +260,7 @@ class AddressBook {
|
||||
* An AddressBook to merge with.
|
||||
* @param overwrite True to overwrite
|
||||
* @param log
|
||||
* The log to write messages about new addresses or conflicts to.
|
||||
* The log to write messages about new addresses or conflicts to. May be null.
|
||||
*
|
||||
* @throws IllegalStateException if this was created with the Subscription constructor.
|
||||
*/
|
||||
|
@@ -138,7 +138,8 @@ class ConfigIterator implements Iterator<Map.Entry<String, String>> {
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Map.Entry))
|
||||
return false;
|
||||
Map.Entry e = (Map.Entry) o;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<Object, Object> e = (Map.Entry<Object, Object>) o;
|
||||
return key.equals(e.getKey()) && value.equals(e.getValue());
|
||||
}
|
||||
}
|
||||
|
@@ -87,11 +87,11 @@ class ConfigParser {
|
||||
*
|
||||
*/
|
||||
public static Map<String, String> parse(BufferedReader input) throws IOException {
|
||||
Map<String, String> result = new HashMap();
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
String inputLine;
|
||||
inputLine = input.readLine();
|
||||
while (inputLine != null) {
|
||||
inputLine = ConfigParser.stripComments(inputLine);
|
||||
inputLine = stripComments(inputLine);
|
||||
String[] splitLine = inputLine.split("=");
|
||||
if (splitLine.length == 2) {
|
||||
result.put(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim());
|
||||
@@ -116,7 +116,7 @@ class ConfigParser {
|
||||
FileInputStream fileStream = new FileInputStream(file);
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(
|
||||
fileStream));
|
||||
Map<String, String> rv = ConfigParser.parse(input);
|
||||
Map<String, String> rv = parse(input);
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException ioe) {}
|
||||
@@ -136,7 +136,7 @@ class ConfigParser {
|
||||
public static Map<String, String> parse(String string) throws IOException {
|
||||
StringReader stringReader = new StringReader(string);
|
||||
BufferedReader input = new BufferedReader(stringReader);
|
||||
return ConfigParser.parse(input);
|
||||
return parse(input);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +153,7 @@ class ConfigParser {
|
||||
public static Map<String, String> parse(File file, Map<String, String> map) {
|
||||
Map<String, String> result;
|
||||
try {
|
||||
result = ConfigParser.parse(file);
|
||||
result = parse(file);
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (!result.containsKey(entry.getKey()))
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
@@ -161,7 +161,7 @@ class ConfigParser {
|
||||
} catch (IOException exp) {
|
||||
result = map;
|
||||
try {
|
||||
ConfigParser.write(result, file);
|
||||
write(result, file);
|
||||
} catch (IOException exp2) {
|
||||
}
|
||||
}
|
||||
@@ -179,10 +179,10 @@ class ConfigParser {
|
||||
*/
|
||||
public static List<String> parseSubscriptions(BufferedReader input)
|
||||
throws IOException {
|
||||
List<String> result = new LinkedList();
|
||||
List<String> result = new LinkedList<String>();
|
||||
String inputLine = input.readLine();
|
||||
while (inputLine != null) {
|
||||
inputLine = ConfigParser.stripComments(inputLine).trim();
|
||||
inputLine = stripComments(inputLine).trim();
|
||||
if (inputLine.length() > 0) {
|
||||
result.add(inputLine);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ class ConfigParser {
|
||||
FileInputStream fileStream = new FileInputStream(file);
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(
|
||||
fileStream));
|
||||
List<String> rv = ConfigParser.parseSubscriptions(input);
|
||||
List<String> rv = parseSubscriptions(input);
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException ioe) {}
|
||||
@@ -224,7 +224,7 @@ class ConfigParser {
|
||||
public static List<String> parseSubscriptions(String string) throws IOException {
|
||||
StringReader stringReader = new StringReader(string);
|
||||
BufferedReader input = new BufferedReader(stringReader);
|
||||
return ConfigParser.parseSubscriptions(input);
|
||||
return parseSubscriptions(input);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,18 +234,30 @@ class ConfigParser {
|
||||
*
|
||||
* @param file
|
||||
* A File to attempt to parse.
|
||||
* @param list list of files to parse
|
||||
* @param list The default subscriptions to be saved and returned if the file cannot be read
|
||||
* @return A List consisting of one element for each line in file, or if
|
||||
* file cannot be read, list.
|
||||
*/
|
||||
public static List<String> parseSubscriptions(File file, List<String> list) {
|
||||
List<String> result;
|
||||
try {
|
||||
result = ConfigParser.parseSubscriptions(file);
|
||||
result = parseSubscriptions(file);
|
||||
// Fix up files that contain the old default
|
||||
// which was changed in 0.9.11
|
||||
if (result.remove(Daemon.OLD_DEFAULT_SUB)) {
|
||||
for (String sub : list) {
|
||||
if (!result.contains(sub))
|
||||
result.add(sub);
|
||||
}
|
||||
try {
|
||||
writeSubscriptions(result, file);
|
||||
// TODO log
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
} catch (IOException exp) {
|
||||
result = list;
|
||||
try {
|
||||
ConfigParser.writeSubscriptions(result, file);
|
||||
writeSubscriptions(result, file);
|
||||
} catch (IOException exp2) {
|
||||
}
|
||||
}
|
||||
@@ -289,8 +301,7 @@ class ConfigParser {
|
||||
boolean success = false;
|
||||
if (!isWindows) {
|
||||
File tmp = SecureFile.createTempFile("temp-", ".tmp", file.getAbsoluteFile().getParentFile());
|
||||
ConfigParser
|
||||
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8")));
|
||||
write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8")));
|
||||
success = tmp.renameTo(file);
|
||||
if (!success) {
|
||||
tmp.delete();
|
||||
@@ -299,8 +310,7 @@ class ConfigParser {
|
||||
}
|
||||
if (!success) {
|
||||
// hmm, that didn't work, try it the old way
|
||||
ConfigParser
|
||||
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
||||
write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +347,7 @@ class ConfigParser {
|
||||
*/
|
||||
public static void writeSubscriptions(List<String> list, File file)
|
||||
throws IOException {
|
||||
ConfigParser.writeSubscriptions(list, new BufferedWriter(
|
||||
writeSubscriptions(list, new BufferedWriter(
|
||||
new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@ import net.i2p.client.naming.SingleFileNamingService;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Main class of addressbook. Performs updates, and runs the main loop.
|
||||
@@ -47,8 +48,11 @@ import net.i2p.util.SecureDirectory;
|
||||
public class Daemon {
|
||||
public static final String VERSION = "2.0.4";
|
||||
private static final Daemon _instance = new Daemon();
|
||||
private boolean _running;
|
||||
private volatile boolean _running;
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String DEFAULT_SUB = "http://i2p-projekt.i2p/hosts.txt";
|
||||
/** @since 0.9.12 */
|
||||
static final String OLD_DEFAULT_SUB = "http://www.i2p2.i2p/hosts.txt";
|
||||
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
@@ -168,7 +172,7 @@ public class Daemon {
|
||||
if (publishedNS == null)
|
||||
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
|
||||
success = publishedNS.putIfAbsent(key, dest);
|
||||
if (!success) {
|
||||
if (log != null && !success) {
|
||||
try {
|
||||
log.append("Save to published address book " + published.getCanonicalPath() + " failed for new key " + key);
|
||||
} catch (IOException ioe) {}
|
||||
@@ -250,14 +254,14 @@ public class Daemon {
|
||||
}
|
||||
delay *= 60 * 60 * 1000;
|
||||
|
||||
List<String> defaultSubs = new LinkedList();
|
||||
List<String> defaultSubs = new LinkedList<String>();
|
||||
// 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");
|
||||
defaultSubs.add(DEFAULT_SUB);
|
||||
|
||||
SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
|
||||
etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, settings
|
||||
.get("proxy_host"), Integer.parseInt(settings.get("proxy_port")));
|
||||
Log log = new Log(logFile);
|
||||
Log log = SystemVersion.isAndroid() ? null : new Log(logFile);
|
||||
|
||||
// If false, add hosts via naming service; if true, write hosts.txt file directly
|
||||
// Default false
|
||||
@@ -330,7 +334,7 @@ public class Daemon {
|
||||
homeFile = new SecureDirectory(System.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
Map<String, String> defaultSettings = new HashMap();
|
||||
Map<String, String> defaultSettings = new HashMap<String, String>();
|
||||
defaultSettings.put("proxy_host", "127.0.0.1");
|
||||
defaultSettings.put("proxy_port", "4444");
|
||||
defaultSettings.put("master_addressbook", "../userhosts.txt");
|
||||
|
@@ -41,7 +41,9 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*
|
||||
*/
|
||||
public class Servlet extends HttpServlet {
|
||||
private DaemonThread thread;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private transient DaemonThread thread;
|
||||
//private String nonce;
|
||||
//private static final String PROP_NONCE = "addressbook.nonce";
|
||||
|
||||
|
@@ -81,7 +81,7 @@ class SubscriptionIterator implements Iterator<AddressBook> {
|
||||
// DataHelper.formatDuration(I2PAppContext.getGlobalContext().clock().now() - sub.getLastFetched()) +
|
||||
// " ago but the minimum delay is " +
|
||||
// DataHelper.formatDuration(this.delay));
|
||||
return new AddressBook(Collections.EMPTY_MAP);
|
||||
return new AddressBook(Collections.<String, String> emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -69,7 +69,7 @@ class SubscriptionList {
|
||||
public SubscriptionList(File locationsFile, File etagsFile,
|
||||
File lastModifiedFile, File lastFetchedFile, long delay, List<String> defaultSubs, String proxyHost,
|
||||
int proxyPort) {
|
||||
this.subscriptions = new LinkedList();
|
||||
this.subscriptions = new LinkedList<Subscription>();
|
||||
this.etagsFile = etagsFile;
|
||||
this.lastModifiedFile = lastModifiedFile;
|
||||
this.lastFetchedFile = lastFetchedFile;
|
||||
@@ -84,17 +84,17 @@ class SubscriptionList {
|
||||
try {
|
||||
etags = ConfigParser.parse(etagsFile);
|
||||
} catch (IOException exp) {
|
||||
etags = new HashMap();
|
||||
etags = new HashMap<String, String>();
|
||||
}
|
||||
try {
|
||||
lastModified = ConfigParser.parse(lastModifiedFile);
|
||||
} catch (IOException exp) {
|
||||
lastModified = new HashMap();
|
||||
lastModified = new HashMap<String, String>();
|
||||
}
|
||||
try {
|
||||
lastFetched = ConfigParser.parse(lastFetchedFile);
|
||||
} catch (IOException exp) {
|
||||
lastFetched = new HashMap();
|
||||
lastFetched = new HashMap<String, String>();
|
||||
}
|
||||
for (String location : locations) {
|
||||
this.subscriptions.add(new Subscription(location, etags.get(location),
|
||||
@@ -121,9 +121,9 @@ class SubscriptionList {
|
||||
* won't be read back correctly; the '=' should be escaped.
|
||||
*/
|
||||
public void write() {
|
||||
Map<String, String> etags = new HashMap();
|
||||
Map<String, String> lastModified = new HashMap();
|
||||
Map<String, String> lastFetched = new HashMap();
|
||||
Map<String, String> etags = new HashMap<String, String>();
|
||||
Map<String, String> lastModified = new HashMap<String, String>();
|
||||
Map<String, String> lastFetched = new HashMap<String, String>();
|
||||
for (Subscription sub : this.subscriptions) {
|
||||
if (sub.getEtag() != null) {
|
||||
etags.put(sub.getLocation(), sub.getEtag());
|
||||
|
@@ -4,6 +4,15 @@
|
||||
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
|
||||
|
||||
<web-app>
|
||||
<filter>
|
||||
<filter-name>XSSFilter</filter-name>
|
||||
<filter-class>net.i2p.servlet.filters.XSSFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>XSSFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>addressbook</servlet-name>
|
||||
<servlet-class>net.i2p.addressbook.Servlet</servlet-class>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_router"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry kind="lib" path="/lib/wrapper/all/wrapper.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/installer"/>
|
||||
<classpathentry kind="output" path="build"/>
|
||||
</classpath>
|
||||
|
@@ -7,12 +7,13 @@
|
||||
<property name="jar" value="desktopgui.jar"/>
|
||||
<property name="resources" value="resources"/>
|
||||
<property name="javadoc" value="javadoc"/>
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="javac.version" value="1.6" />
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<condition property="no.bundle">
|
||||
<isfalse value="${require.gettext}" />
|
||||
</condition>
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="${build}"/>
|
||||
@@ -27,7 +28,7 @@
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init">
|
||||
<javac debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
includeAntRuntime="false"
|
||||
srcdir="${src}" destdir="${build}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
@@ -44,6 +45,7 @@
|
||||
|
||||
<target name="bundle" unless="no.bundle">
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<env key="JAVA_HOME" value="${java.home}" />
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
|
@@ -16,6 +16,10 @@ TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
RC=0
|
||||
|
||||
if ! $(which javac > /dev/null 2>&1); then
|
||||
export JAVAC=${JAVA_HOME}/../bin/javac
|
||||
fi
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
POUPDATE=1
|
||||
|
@@ -11,6 +11,7 @@ msgstr ""
|
||||
"POT-Creation-Date: 2011-02-20 11:53+0000\n"
|
||||
"PO-Revision-Date: 2011-02-26 19:46-0000\n"
|
||||
"Last-Translator: hamada <hamada@mail.i2p>\n"
|
||||
"Language: ar\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -3,19 +3,19 @@
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-01-09 18:07+0000\n"
|
||||
"PO-Revision-Date: 2011-03-22 15:49+0000\n"
|
||||
"Last-Translator: blabla <blabla@trash-mail.com>\n"
|
||||
"Language-Team: German <>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
@@ -46,10 +46,10 @@ msgstr "I2P neustarten"
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Systemleistensymbol konfigurieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Systemleistensymbol aktivieren?"
|
||||
|
@@ -8,11 +8,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 14:09+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"Language: \n"
|
||||
"Language: en\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -46,10 +46,10 @@ msgstr ""
|
||||
msgid "Stop I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr ""
|
||||
|
@@ -2,21 +2,26 @@
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
# Translators:
|
||||
# blabla <blabla@trash-mail.com>, 2011
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# foo <foo@bar>, 2009
|
||||
# Boxoa590, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-03-30 21:58+0100\n"
|
||||
"Last-Translator: magma <magma@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"Language: \n"
|
||||
"POT-Creation-Date: 2014-01-09 19:14+0000\n"
|
||||
"PO-Revision-Date: 2013-06-08 04:50+0000\n"
|
||||
"Last-Translator: Boxoa590\n"
|
||||
"Language-Team: French (http://www.transifex.com/projects/p/I2P/language/"
|
||||
"fr/)\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
@@ -24,7 +29,7 @@ msgstr "Démarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P démarre!"
|
||||
msgstr "I2P démarre !"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
@@ -32,7 +37,7 @@ msgstr "Démarrage"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancer le navigateur"
|
||||
msgstr "Lancer le navigateur I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
@@ -46,11 +51,10 @@ msgstr "Redémarrer I2P"
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arrêter I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configuration de l'icône de notification"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Activer l'icône de notification"
|
||||
|
||||
msgstr "Activer l'icône de notification ?"
|
||||
|
56
apps/desktopgui/locale/messages_ja.po
Normal file
56
apps/desktopgui/locale/messages_ja.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# plazmism <gomidori@live.jp>, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2013-11-26 10:38+0000\n"
|
||||
"Last-Translator: plazmism <gomidori@live.jp>\n"
|
||||
"Language-Team: Japanese (http://www.transifex.com/projects/p/I2P/language/ja/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ja\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P を開始"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P 起動中!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "起動中"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P ブラウザを起動"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "desktopgui を設定"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P を再起動"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P を停止"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "トレイアイコン設定"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "トレイアイコンを有効にしますか?"
|
57
apps/desktopgui/locale/messages_pt_BR.po
Normal file
57
apps/desktopgui/locale/messages_pt_BR.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# testsubject67 <deborinha97@hotmail.com>, 2014
|
||||
# blueboy, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
|
||||
"PO-Revision-Date: 2014-07-05 17:40+0000\n"
|
||||
"Last-Translator: testsubject67 <deborinha97@hotmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/I2P/language/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Conectar-se à I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Conectando-se a I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Conectando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lançar o navegador I2P "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Configurar desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reinicializar o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Interromper o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configuração de ícone de bandeja"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Ativar ícone de bandeja?"
|
57
apps/desktopgui/locale/messages_ro.po
Normal file
57
apps/desktopgui/locale/messages_ro.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-01-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2013-11-11 11:31+0000\n"
|
||||
"Last-Translator: polearnik <polearnik@mail.ru>\n"
|
||||
"Language-Team: Romanian (http://www.transifex.com/projects/p/I2P/language/"
|
||||
"ro/)\n"
|
||||
"Language: ro\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?"
|
||||
"2:1));\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Start I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P se pornește!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Începere"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lansare I2P Browser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Configurarea desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Restart I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Stop I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configurare pictogramei din bara de sistem"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Ar trebui să fie activata pictograma din bara de sistem?"
|
@@ -2,21 +2,24 @@
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# foo <foo@bar>, 2009
|
||||
# Роман Азаренко <transifex@basicxp.ru>, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-19 17:26+0000\n"
|
||||
"PO-Revision-Date: 2011-02-23 10:23+0500\n"
|
||||
"Last-Translator: Hidden Z <hiddenz@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"Language: \n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2013-12-04 11:46+0000\n"
|
||||
"Last-Translator: Bergitte <alvina_alexandrova@mail.ru>\n"
|
||||
"Language-Team: Russian (Russia) (http://www.transifex.com/projects/p/I2P/language/ru_RU/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"Language: ru_RU\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
@@ -32,7 +35,7 @@ msgstr "Запускается"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Запустить I2P браузер"
|
||||
msgstr "Запустить браузер I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
@@ -48,9 +51,8 @@ msgstr "Остановить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Настройка иконки в трее"
|
||||
msgstr "Конфигурация значка в области уведомлений"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Отображать ли иконку в трее?"
|
||||
|
||||
msgstr "Отображать ли значок в области уведомлений?"
|
||||
|
57
apps/desktopgui/locale/messages_sk.po
Normal file
57
apps/desktopgui/locale/messages_sk.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Krantišek <jaksrn@gmail.com>, 2014
|
||||
# Svistwarrior273 <romanbeno273@gmail.com>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
|
||||
"PO-Revision-Date: 2014-04-20 09:56+0000\n"
|
||||
"Last-Translator: Svistwarrior273 <romanbeno273@gmail.com>\n"
|
||||
"Language-Team: Slovak (http://www.transifex.com/projects/p/I2P/language/sk/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: sk\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Spustiť I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P sa spúšťa!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Spúšťa sa"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Spustiť I2P prehliadač"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Nakonfigurovať desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reštartovať I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zastaviť I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Konfigurácia ikony v lište"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Mala by byť ikona v lište povolená?"
|
56
apps/desktopgui/locale/messages_tr.po
Normal file
56
apps/desktopgui/locale/messages_tr.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Kaya Zeren <kayazeren@gmail.com>, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2013-04-26 06:07+0000\n"
|
||||
"Last-Translator: Kaya Zeren <kayazeren@gmail.com>\n"
|
||||
"Language-Team: Turkish (Turkey) (http://www.transifex.com/projects/p/I2P/language/tr_TR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: tr_TR\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P başlasın"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P başlatılıyor!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Başlatılıyor"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P Tarayıcısını Açın"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Masaüstü Arayüzünü Ayarlayın"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P Yeniden Başlasın"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P Durdurulsun"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Sistem tepsisi simgesi ayarı"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Sistem tepsisi simgesi kullanılsın"
|
@@ -3,20 +3,22 @@
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# <gribua@gmail.com>, 2011.
|
||||
# Translators:
|
||||
# Denis Blank <gribua@gmail.com>, 2011
|
||||
# LinuxChata, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-06-19 14:01+0000\n"
|
||||
"Last-Translator: Pharmasolin <gribua@gmail.com>\n"
|
||||
"Language-Team: Ukrainian (Ukraine) (http://www.transifex.net/projects/p/I2P/team/uk_UA/)\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
|
||||
"PO-Revision-Date: 2014-06-22 10:20+0000\n"
|
||||
"Last-Translator: LinuxChata\n"
|
||||
"Language-Team: Ukrainian (Ukraine) (http://www.transifex.com/projects/p/I2P/language/uk_UA/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: uk_UA\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
@@ -46,12 +48,10 @@ msgstr "Перезапустити I2P"
|
||||
msgid "Stop I2P"
|
||||
msgstr "Зупинити I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Настройка трей-іконки"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Чм повинна трей-іконка бути включена?"
|
||||
|
||||
|
||||
msgstr "Чи повинна трей-іконка бути включена?"
|
||||
|
@@ -7,9 +7,6 @@ package net.i2p.desktopgui;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.desktopgui.router.RouterManager;
|
||||
import net.i2p.desktopgui.util.*;
|
||||
import net.i2p.util.Log;
|
||||
|
@@ -1,28 +1,15 @@
|
||||
package net.i2p.desktopgui;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Image;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.awt.Desktop.Action;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
||||
import net.i2p.desktopgui.router.RouterManager;
|
||||
import net.i2p.desktopgui.util.BrowseException;
|
||||
import net.i2p.desktopgui.util.ConfigurationManager;
|
||||
import net.i2p.desktopgui.util.I2PDesktop;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
|
@@ -32,7 +32,6 @@ public class DesktopguiConfigurationFrame extends javax.swing.JFrame {
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
@@ -115,7 +114,7 @@ public class DesktopguiConfigurationFrame extends javax.swing.JFrame {
|
||||
System.out.println("Enabling desktopgui");
|
||||
}
|
||||
try {
|
||||
RouterManager.getRouterContext().setProperty(property, value);
|
||||
RouterManager.getRouterContext().router().saveConfig(property, value);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DesktopguiConfigurationFrame.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
@@ -5,8 +5,6 @@ import java.io.IOException;
|
||||
import org.tanukisoftware.wrapper.WrapperManager;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
||||
import net.i2p.desktopgui.util.ConfigurationManager;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
|
@@ -78,7 +78,7 @@ public class ConfigurationManager {
|
||||
* @return The value of a configuration: true if found, defaultValue if not found.
|
||||
*/
|
||||
public boolean getBooleanConfiguration(String arg, boolean defaultValue) {
|
||||
Boolean value = ((Boolean) booleanConfigurations.get("startWithI2P"));
|
||||
Boolean value = booleanConfigurations.get("startWithI2P");
|
||||
System.out.println(value);
|
||||
if(value != null) {
|
||||
return value;
|
||||
|
@@ -1,13 +1,8 @@
|
||||
package net.i2p.desktopgui.util;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.TrayIcon;
|
||||
import java.awt.Desktop.Action;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import net.i2p.desktopgui.router.RouterManager;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PDesktop {
|
||||
|
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="java/src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/javax.servlet.jar"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/jetty-util.jar"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/org.mortbay.jetty.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/jetty"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
|
||||
<classpathentry kind="output" path="java/build/obj"/>
|
||||
</classpath>
|
||||
|
@@ -17,29 +17,28 @@
|
||||
<classpath>
|
||||
<pathelement location="../../../core/java/build/obj" />
|
||||
<pathelement location="../../ministreaming/java/build/obj" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
</classpath>
|
||||
</depend>
|
||||
</target>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.6" />
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<condition property="no.bundle">
|
||||
<isfalse value="${require.gettext}" />
|
||||
</condition>
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<target name="compile" depends="depend">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
srcdir="./src"
|
||||
debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
destdir="./build/obj"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
@@ -130,6 +129,7 @@
|
||||
<!-- Update the messages_*.po files.
|
||||
We need to supply the bat file for windows, and then change the fail property to true -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<env key="JAVA_HOME" value="${java.home}" />
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
@@ -175,7 +175,6 @@
|
||||
<copy file="../../jetty/jettylib/commons-logging.jar" tofile="./dist/lib/commons-logging.jar" />
|
||||
<copy file="../../jetty/jettylib/javax.servlet.jar" tofile="./dist/lib/javax.servlet.jar" />
|
||||
<copy file="../../jetty/jettylib/org.mortbay.jetty.jar" tofile="./dist/lib/org.mortbay.jetty.jar" />
|
||||
<copy file="../../jetty/jettylib/jasper-compiler.jar" tofile="./dist/lib/jasper-compiler.jar" />
|
||||
<copy file="../../jetty/jettylib/jasper-runtime.jar" tofile="./dist/lib/jasper-runtime.jar" />
|
||||
<copy file="../../ministreaming/java/build/mstreaming.jar" tofile="./dist/lib/mstreaming.jar" />
|
||||
<copy file="../../streaming/java/build/streaming.jar" tofile="./dist/lib/streaming.jar" />
|
||||
|
@@ -15,6 +15,10 @@ TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
RC=0
|
||||
|
||||
if ! $(which javac > /dev/null 2>&1); then
|
||||
export JAVAC=${JAVA_HOME}/../bin/javac
|
||||
fi
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
POUPDATE=1
|
||||
|
@@ -1,28 +0,0 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Help sort Hashes in relation to a base key using the XOR metric
|
||||
*
|
||||
* @since 0.9.2
|
||||
*/
|
||||
class XORComparator<T extends SimpleDataStructure> implements Comparator<T> {
|
||||
private final byte[] _base;
|
||||
|
||||
/**
|
||||
* @param target key to compare distances with
|
||||
*/
|
||||
public XORComparator(T target) {
|
||||
_base = target.getData();
|
||||
}
|
||||
|
||||
public int compare(T lhs, T rhs) {
|
||||
byte lhsDelta[] = DataHelper.xor(lhs.getData(), _base);
|
||||
byte rhsDelta[] = DataHelper.xor(rhs.getData(), _base);
|
||||
return DataHelper.compareTo(lhsDelta, rhsDelta);
|
||||
}
|
||||
}
|
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.I2PSessionException;
|
||||
@@ -37,7 +36,9 @@ class BWLimits {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/****
|
||||
public static void main(String args[]) {
|
||||
System.out.println(Arrays.toString(getBWLimits("127.0.0.1", 7654)));
|
||||
}
|
||||
****/
|
||||
}
|
||||
|
@@ -33,79 +33,106 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.ObjectCounter;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* Accepts connections on a TCP port and routes them to sub-acceptors.
|
||||
* Accepts connections on a I2PServerSocket and routes them to PeerAcceptors.
|
||||
*/
|
||||
class ConnectionAcceptor implements Runnable
|
||||
{
|
||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ConnectionAcceptor.class);
|
||||
private I2PServerSocket serverSocket;
|
||||
private PeerAcceptor peeracceptor;
|
||||
private final PeerAcceptor peeracceptor;
|
||||
private Thread thread;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final ObjectCounter<Hash> _badCounter = new ObjectCounter();
|
||||
private final ObjectCounter<Hash> _badCounter = new ObjectCounter<Hash>();
|
||||
private final SimpleTimer2.TimedEvent _cleaner;
|
||||
|
||||
private boolean stop;
|
||||
private boolean socketChanged;
|
||||
private volatile boolean stop;
|
||||
|
||||
private static final int MAX_BAD = 2;
|
||||
// protocol errors before blacklisting.
|
||||
private static final int MAX_BAD = 1;
|
||||
private static final long BAD_CLEAN_INTERVAL = 30*60*1000;
|
||||
|
||||
public ConnectionAcceptor(I2PSnarkUtil util) { _util = util; }
|
||||
/**
|
||||
* Multitorrent. Caller MUST call startAccepting()
|
||||
*/
|
||||
public ConnectionAcceptor(I2PSnarkUtil util, PeerCoordinatorSet set) {
|
||||
_util = util;
|
||||
_cleaner = new Cleaner();
|
||||
peeracceptor = new PeerAcceptor(set);
|
||||
}
|
||||
|
||||
public synchronized void startAccepting(PeerCoordinatorSet set, I2PServerSocket socket) {
|
||||
if (serverSocket != socket) {
|
||||
if ( (peeracceptor == null) || (peeracceptor.coordinators != set) )
|
||||
peeracceptor = new PeerAcceptor(set);
|
||||
serverSocket = socket;
|
||||
/**
|
||||
* May be called even when already running. May be called to start up again after halt().
|
||||
*/
|
||||
public synchronized void startAccepting() {
|
||||
stop = false;
|
||||
socketChanged = true;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("ConnectionAcceptor startAccepting new thread? " + (thread == null));
|
||||
if (thread == null) {
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
_cleaner.reschedule(BAD_CLEAN_INTERVAL, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionAcceptor(I2PSnarkUtil util, I2PServerSocket serverSocket,
|
||||
/**
|
||||
* Unused (single torrent).
|
||||
* Do NOT call startAccepting().
|
||||
*/
|
||||
public ConnectionAcceptor(I2PSnarkUtil util,
|
||||
PeerAcceptor peeracceptor)
|
||||
{
|
||||
this.serverSocket = serverSocket;
|
||||
this.peeracceptor = peeracceptor;
|
||||
_util = util;
|
||||
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
_cleaner = new Cleaner();
|
||||
}
|
||||
|
||||
public void halt()
|
||||
/**
|
||||
* May be restarted later with startAccepting().
|
||||
*/
|
||||
public synchronized void halt()
|
||||
{
|
||||
if (stop) return;
|
||||
stop = true;
|
||||
locked_halt();
|
||||
Thread t = thread;
|
||||
if (t != null) {
|
||||
t.interrupt();
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
|
||||
I2PServerSocket ss = serverSocket;
|
||||
if (ss != null)
|
||||
|
||||
/**
|
||||
* Caller must synch
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private void locked_halt()
|
||||
{
|
||||
I2PServerSocket ss = _util.getServerSocket();
|
||||
if (ss != null) {
|
||||
try
|
||||
{
|
||||
ss.close();
|
||||
}
|
||||
catch(I2PException ioe) { }
|
||||
|
||||
Thread t = thread;
|
||||
if (t != null)
|
||||
t.interrupt();
|
||||
}
|
||||
_badCounter.clear();
|
||||
_cleaner.cancel();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
serverSocket = _util.getServerSocket();
|
||||
socketChanged = true;
|
||||
/**
|
||||
* Effectively unused, would only be called if we changed
|
||||
* I2CP host/port, which is hidden in the gui if in router context
|
||||
* FIXME this only works if already running
|
||||
*/
|
||||
public synchronized void restart() {
|
||||
Thread t = thread;
|
||||
if (t != null)
|
||||
t.interrupt();
|
||||
@@ -113,21 +140,32 @@ class ConnectionAcceptor implements Runnable
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return 6881; // serverSocket.getLocalPort();
|
||||
return TrackerClient.PORT; // serverSocket.getLocalPort();
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
run2();
|
||||
} finally {
|
||||
synchronized(this) {
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void run2()
|
||||
{
|
||||
while(!stop)
|
||||
{
|
||||
if (socketChanged) {
|
||||
// ok, already updated
|
||||
socketChanged = false;
|
||||
}
|
||||
I2PServerSocket serverSocket = _util.getServerSocket();
|
||||
while ( (serverSocket == null) && (!stop)) {
|
||||
if (!(_util.isConnecting() || _util.connected())) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
serverSocket = _util.getServerSocket();
|
||||
if (serverSocket == null)
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
if(stop)
|
||||
break;
|
||||
@@ -135,24 +173,26 @@ class ConnectionAcceptor implements Runnable
|
||||
{
|
||||
I2PSocket socket = serverSocket.accept();
|
||||
if (socket == null) {
|
||||
if (socketChanged) {
|
||||
continue;
|
||||
} else {
|
||||
I2PServerSocket ss = _util.getServerSocket();
|
||||
if (ss != serverSocket) {
|
||||
serverSocket = ss;
|
||||
socketChanged = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (socket.getPeerDestination().equals(_util.getMyDestination())) {
|
||||
_log.error("Incoming connection from myself");
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
if (_badCounter.count(socket.getPeerDestination().calculateHash()) >= MAX_BAD) {
|
||||
Hash h = socket.getPeerDestination().calculateHash();
|
||||
if (socket.getLocalPort() == 80) {
|
||||
_badCounter.increment(h);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Rejecting connection from " + socket.getPeerDestination().calculateHash() + " after " + MAX_BAD + " failures");
|
||||
_log.error("Dropping incoming HTTP from " + h);
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
int bad = _badCounter.count(h);
|
||||
if (bad >= MAX_BAD) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Rejecting connection from " + h +
|
||||
" after " + bad + " failures, max is " + MAX_BAD);
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
@@ -162,26 +202,34 @@ class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
catch (I2PException ioe)
|
||||
{
|
||||
if (!socketChanged) {
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
int level = stop ? Log.WARN : Log.ERROR;
|
||||
if (_log.shouldLog(level))
|
||||
_log.log(level, "Error while accepting", ioe);
|
||||
synchronized(this) {
|
||||
if (!stop) {
|
||||
locked_halt();
|
||||
thread = null;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
int level = stop ? Log.WARN : Log.ERROR;
|
||||
if (_log.shouldLog(level))
|
||||
_log.log(level, "Error while accepting", ioe);
|
||||
synchronized(this) {
|
||||
if (!stop) {
|
||||
locked_halt();
|
||||
thread = null;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// catch oom?
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (serverSocket != null)
|
||||
serverSocket.close();
|
||||
}
|
||||
catch (I2PException ignored) { }
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("ConnectionAcceptor closed");
|
||||
}
|
||||
|
||||
private class Handler implements Runnable {
|
||||
@@ -214,7 +262,17 @@ class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
|
||||
/** @since 0.9.1 */
|
||||
private class Cleaner implements SimpleTimer.TimedEvent {
|
||||
public void timeReached() { _badCounter.clear(); }
|
||||
private class Cleaner extends SimpleTimer2.TimedEvent {
|
||||
|
||||
public Cleaner() {
|
||||
super(_util.getContext().simpleTimer2());
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
if (stop)
|
||||
return;
|
||||
_badCounter.clear();
|
||||
schedule(BAD_CLEAN_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -37,8 +37,20 @@ interface CoordinatorListener
|
||||
*/
|
||||
void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo);
|
||||
|
||||
/**
|
||||
* Is this number of uploaders over the per-torrent limit?
|
||||
*/
|
||||
public boolean overUploadLimit(int uploaders);
|
||||
|
||||
/**
|
||||
* Are we currently over the upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Is the total (in Bps) over the upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total);
|
||||
|
||||
public void addMessage(String message);
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ abstract class ExtensionHandler {
|
||||
public static final int ID_DHT = 3;
|
||||
/** not using the option bit since the compact format is different */
|
||||
public static final String TYPE_DHT = "i2p_dht";
|
||||
/** Pieces * SHA1 Hash length, + 25% extra for file names, benconding overhead, etc */
|
||||
/** Pieces * SHA1 Hash length, + 25% extra for file names, bencoding overhead, etc */
|
||||
private static final int MAX_METADATA_SIZE = Storage.MAX_PIECES * 20 * 5 / 4;
|
||||
private static final int PARALLEL_REQUESTS = 3;
|
||||
|
||||
@@ -43,8 +43,8 @@ abstract class ExtensionHandler {
|
||||
* @return bencoded outgoing handshake message
|
||||
*/
|
||||
public static byte[] getHandshake(int metasize, boolean pexAndMetadata, boolean dht) {
|
||||
Map<String, Object> handshake = new HashMap();
|
||||
Map<String, Integer> m = new HashMap();
|
||||
Map<String, Object> handshake = new HashMap<String, Object>();
|
||||
Map<String, Integer> m = new HashMap<String, Integer>();
|
||||
if (pexAndMetadata) {
|
||||
m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA));
|
||||
m.put(TYPE_PEX, Integer.valueOf(ID_PEX));
|
||||
@@ -56,7 +56,7 @@ abstract class ExtensionHandler {
|
||||
}
|
||||
// include the map even if empty so the far-end doesn't NPE
|
||||
handshake.put("m", m);
|
||||
handshake.put("p", Integer.valueOf(6881));
|
||||
handshake.put("p", Integer.valueOf(TrackerClient.PORT));
|
||||
handshake.put("v", "I2PSnark");
|
||||
handshake.put("reqq", Integer.valueOf(5));
|
||||
return BEncoder.bencode(handshake);
|
||||
@@ -110,7 +110,8 @@ abstract class ExtensionHandler {
|
||||
// drop if we need metainfo and we haven't found anybody yet
|
||||
synchronized(state) {
|
||||
if (!state.isInitialized()) {
|
||||
log.debug("Dropping peer, we need metadata! " + peer);
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("Dropping peer, we need metadata! " + peer);
|
||||
peer.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -124,7 +125,8 @@ abstract class ExtensionHandler {
|
||||
// drop if we need metainfo and we haven't found anybody yet
|
||||
synchronized(state) {
|
||||
if (!state.isInitialized()) {
|
||||
log.debug("Dropping peer, we need metadata! " + peer);
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("Dropping peer, we need metadata! " + peer);
|
||||
peer.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -274,7 +276,7 @@ abstract class ExtensionHandler {
|
||||
|
||||
/** REQUEST and REJECT are the same except for message type */
|
||||
private static void sendMessage(Peer peer, int type, int piece) {
|
||||
Map<String, Object> map = new HashMap();
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("msg_type", Integer.valueOf(type));
|
||||
map.put("piece", Integer.valueOf(piece));
|
||||
byte[] payload = BEncoder.bencode(map);
|
||||
@@ -289,7 +291,7 @@ abstract class ExtensionHandler {
|
||||
}
|
||||
|
||||
private static void sendPiece(Peer peer, int piece, byte[] data) {
|
||||
Map<String, Object> map = new HashMap();
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("msg_type", Integer.valueOf(TYPE_DATA));
|
||||
map.put("piece", Integer.valueOf(piece));
|
||||
map.put("total_size", Integer.valueOf(data.length));
|
||||
@@ -332,7 +334,7 @@ abstract class ExtensionHandler {
|
||||
if (ids.length < HASH_LENGTH)
|
||||
return;
|
||||
int len = Math.min(ids.length, (I2PSnarkUtil.MAX_CONNECTIONS - 1) * HASH_LENGTH);
|
||||
List<PeerID> peers = new ArrayList(len / HASH_LENGTH);
|
||||
List<PeerID> peers = new ArrayList<PeerID>(len / HASH_LENGTH);
|
||||
for (int off = 0; off < len; off += HASH_LENGTH) {
|
||||
byte[] hash = new byte[HASH_LENGTH];
|
||||
System.arraycopy(ids, off, hash, 0, HASH_LENGTH);
|
||||
@@ -380,7 +382,7 @@ abstract class ExtensionHandler {
|
||||
public static void sendPEX(Peer peer, List<Peer> pList) {
|
||||
if (pList.isEmpty())
|
||||
return;
|
||||
Map<String, Object> map = new HashMap();
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
byte[] peers = new byte[HASH_LENGTH * pList.size()];
|
||||
int off = 0;
|
||||
for (Peer p : pList) {
|
||||
@@ -404,7 +406,7 @@ abstract class ExtensionHandler {
|
||||
* @since DHT
|
||||
*/
|
||||
public static void sendDHT(Peer peer, int qport, int rport) {
|
||||
Map<String, Object> map = new HashMap();
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("port", Integer.valueOf(qport));
|
||||
map.put("rport", Integer.valueOf(rport));
|
||||
byte[] payload = BEncoder.bencode(map);
|
||||
|
@@ -3,16 +3,12 @@ package org.klomp.snark;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
@@ -33,7 +29,6 @@ import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
@@ -81,6 +76,7 @@ public class I2PSnarkUtil {
|
||||
public static final int MAX_CONNECTIONS = 16; // per torrent
|
||||
public static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
|
||||
public static final boolean DEFAULT_USE_DHT = true;
|
||||
public static final String EEPGET_USER_AGENT = "I2PSnark";
|
||||
|
||||
public I2PSnarkUtil(I2PAppContext ctx) {
|
||||
this(ctx, "i2psnark");
|
||||
@@ -94,10 +90,10 @@ public class I2PSnarkUtil {
|
||||
_context = ctx;
|
||||
_log = _context.logManager().getLog(Snark.class);
|
||||
_baseName = baseName;
|
||||
_opts = new HashMap();
|
||||
_opts = new HashMap<String, String>();
|
||||
//setProxy("127.0.0.1", 4444);
|
||||
setI2CPConfig("127.0.0.1", 7654, null);
|
||||
_banlist = new ConcurrentHashSet();
|
||||
_banlist = new ConcurrentHashSet<Hash>();
|
||||
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
|
||||
_maxUpBW = DEFAULT_MAX_UP_BW;
|
||||
_maxConnections = MAX_CONNECTIONS;
|
||||
@@ -158,7 +154,7 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the session options and tells the router
|
||||
* This updates ALL the session options (not just the bw) and tells the router
|
||||
* @param limit KBps
|
||||
*/
|
||||
public void setMaxUpBW(int limit) {
|
||||
@@ -220,10 +216,8 @@ public class I2PSnarkUtil {
|
||||
_log.debug("Connecting to I2P", new Exception("I did it"));
|
||||
Properties opts = _context.getProperties();
|
||||
if (_opts != null) {
|
||||
for (Iterator iter = _opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
opts.setProperty(key, _opts.get(key).toString());
|
||||
}
|
||||
for (Map.Entry<String, String> entry : _opts.entrySet() )
|
||||
opts.setProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (opts.getProperty("inbound.nickname") == null)
|
||||
opts.setProperty("inbound.nickname", _baseName.replace("i2psnark", "I2PSnark"));
|
||||
@@ -259,6 +253,8 @@ public class I2PSnarkUtil {
|
||||
opts.setProperty("i2p.streaming.enforceProtocol", "true");
|
||||
if (opts.getProperty("i2p.streaming.disableRejectLogging") == null)
|
||||
opts.setProperty("i2p.streaming.disableRejectLogging", "true");
|
||||
if (opts.getProperty("i2p.streaming.answerPings") == null)
|
||||
opts.setProperty("i2p.streaming.answerPings", "false");
|
||||
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
||||
_connecting = false;
|
||||
}
|
||||
@@ -324,6 +320,8 @@ public class I2PSnarkUtil {
|
||||
if (_banlist.contains(dest))
|
||||
throw new IOException("Not trying to contact " + dest.toBase64() + ", as they are banlisted");
|
||||
try {
|
||||
// TODO opts.setPort(xxx); connect(addr, opts)
|
||||
// DHT moved above 6881 in 0.9.9
|
||||
I2PSocket rv = _manager.connect(addr);
|
||||
if (rv != null)
|
||||
_banlist.remove(dest);
|
||||
@@ -331,7 +329,9 @@ public class I2PSnarkUtil {
|
||||
} catch (I2PException ie) {
|
||||
_banlist.add(dest);
|
||||
_context.simpleScheduler().addEvent(new Unbanlist(dest), 10*60*1000);
|
||||
throw new IOException("Unable to reach the peer " + peer + ": " + ie.getMessage());
|
||||
IOException ioe = new IOException("Unable to reach the peer " + peer);
|
||||
ioe.initCause(ie);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,6 +394,7 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
}
|
||||
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
||||
get.addHeader("User-Agent", EEPGET_USER_AGENT);
|
||||
if (get.fetch(timeout)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||
@@ -435,6 +436,7 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(initialSize);
|
||||
EepGet get = new I2PSocketEepGet(_context, _manager, retries, -1, maxSize, null, out, fetchURL);
|
||||
get.addHeader("User-Agent", EEPGET_USER_AGENT);
|
||||
if (get.fetch(timeout)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.size());
|
||||
@@ -513,7 +515,7 @@ public class I2PSnarkUtil {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Using existing session for lookup of " + ip);
|
||||
try {
|
||||
return sess.lookupDest(h);
|
||||
return sess.lookupDest(h, 15*1000);
|
||||
} catch (I2PSessionException ise) {
|
||||
}
|
||||
}
|
||||
@@ -573,7 +575,7 @@ public class I2PSnarkUtil {
|
||||
*/
|
||||
public List<String> getOpenTrackers() {
|
||||
if (!shouldUseOpenTrackers())
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
return _openTrackers;
|
||||
}
|
||||
|
||||
|
143
apps/i2psnark/java/src/org/klomp/snark/IdleChecker.java
Normal file
143
apps/i2psnark/java/src/org/klomp/snark/IdleChecker.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
*/
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* Periodically check for idle condition based on connected peers,
|
||||
* and reduce/restore tunnel count as necessary.
|
||||
* We can't use the I2CP idle detector because it's based on traffic,
|
||||
* so DHT and announces would keep it non-idle.
|
||||
*
|
||||
* @since 0.9.7
|
||||
*/
|
||||
class IdleChecker extends SimpleTimer2.TimedEvent {
|
||||
|
||||
private final SnarkManager _mgr;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final PeerCoordinatorSet _pcs;
|
||||
private final Log _log;
|
||||
private int _consec;
|
||||
private int _consecNotRunning;
|
||||
private boolean _isIdle;
|
||||
|
||||
private static final long CHECK_TIME = 63*1000;
|
||||
private static final int MAX_CONSEC_IDLE = 4;
|
||||
private static final int MAX_CONSEC_NOT_RUNNING = 20;
|
||||
|
||||
/**
|
||||
* Caller must schedule
|
||||
*/
|
||||
public IdleChecker(SnarkManager mgr, PeerCoordinatorSet pcs) {
|
||||
super(mgr.util().getContext().simpleTimer2());
|
||||
_util = mgr.util();
|
||||
_log = _util.getContext().logManager().getLog(IdleChecker.class);
|
||||
_mgr = mgr;
|
||||
_pcs = pcs;
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
if (_util.connected()) {
|
||||
boolean torrentRunning = false;
|
||||
boolean hasPeers = false;
|
||||
for (PeerCoordinator pc : _pcs) {
|
||||
if (!pc.halted()) {
|
||||
torrentRunning = true;
|
||||
if (pc.getPeers() > 0) {
|
||||
hasPeers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (torrentRunning) {
|
||||
_consecNotRunning = 0;
|
||||
} else {
|
||||
if (_consecNotRunning++ >= MAX_CONSEC_NOT_RUNNING) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Closing tunnels on idle");
|
||||
_util.disconnect();
|
||||
_mgr.addMessage(_util.getString("I2P tunnel closed."));
|
||||
schedule(3 * CHECK_TIME);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPeers) {
|
||||
if (_isIdle)
|
||||
restoreTunnels();
|
||||
} else {
|
||||
if (!_isIdle) {
|
||||
if (_consec++ >= MAX_CONSEC_IDLE)
|
||||
reduceTunnels();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_isIdle = false;
|
||||
_consec = 0;
|
||||
_consecNotRunning = 0;
|
||||
}
|
||||
schedule(CHECK_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce to 1 in / 1 out tunnel
|
||||
*/
|
||||
private void reduceTunnels() {
|
||||
_isIdle = true;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Reducing tunnels on idle");
|
||||
setTunnels("1", "1", "0", "0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore tunnel count
|
||||
*/
|
||||
private void restoreTunnels() {
|
||||
_isIdle = false;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Restoring tunnels on activity");
|
||||
Map<String, String> opts = _util.getI2CPOptions();
|
||||
String i = opts.get("inbound.quantity");
|
||||
if (i == null)
|
||||
i = "3";
|
||||
String o = opts.get("outbound.quantity");
|
||||
if (o == null)
|
||||
o = "3";
|
||||
String ib = opts.get("inbound.backupQuantity");
|
||||
if (ib == null)
|
||||
ib = "0";
|
||||
String ob= opts.get("outbound.backupQuantity");
|
||||
if (ob == null)
|
||||
ob = "0";
|
||||
setTunnels(i, o, ib, ob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set in / out / in backup / out backup tunnel counts
|
||||
*/
|
||||
private void setTunnels(String i, String o, String ib, String ob) {
|
||||
_consec = 0;
|
||||
I2PSocketManager mgr = _util.getSocketManager();
|
||||
if (mgr != null) {
|
||||
I2PSession sess = mgr.getSession();
|
||||
if (sess != null) {
|
||||
Properties newProps = new Properties();
|
||||
newProps.setProperty("inbound.quantity", i);
|
||||
newProps.setProperty("outbound.quantity", o);
|
||||
newProps.setProperty("inbound.backupQuantity", ib);
|
||||
newProps.setProperty("outbound.backupQuantity", ob);
|
||||
sess.updateOptions(newProps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,7 +6,6 @@ import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
@@ -188,9 +187,9 @@ class MagnetState {
|
||||
* @return true if this was the last piece
|
||||
* @throws NPE, IllegalArgumentException, IOException, ...
|
||||
*/
|
||||
public MetaInfo buildMetaInfo() throws Exception {
|
||||
private MetaInfo buildMetaInfo() throws Exception {
|
||||
// top map has nothing in it but the info map (no announce)
|
||||
Map<String, BEValue> map = new HashMap();
|
||||
Map<String, BEValue> map = new HashMap<String, BEValue>();
|
||||
InputStream is = new ByteArrayInputStream(metainfoBytes);
|
||||
BDecoder dec = new BDecoder(is);
|
||||
BEValue bev = dec.bdecodeMap();
|
||||
|
@@ -133,7 +133,7 @@ public class MagnetURI {
|
||||
}
|
||||
if (idx < 0 || idx > uri.length())
|
||||
return null;
|
||||
List<String> rv = new ArrayList();
|
||||
List<String> rv = new ArrayList<String>();
|
||||
while (true) {
|
||||
String p = uri.substring(idx);
|
||||
uri = p;
|
||||
|
@@ -62,6 +62,9 @@ public class MetaInfo
|
||||
private final long length;
|
||||
private final boolean privateTorrent;
|
||||
private final List<List<String>> announce_list;
|
||||
private final String comment;
|
||||
private final String created_by;
|
||||
private final long creation_date;
|
||||
private Map<String, BEValue> infoMap;
|
||||
|
||||
/**
|
||||
@@ -87,6 +90,9 @@ public class MetaInfo
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = null;
|
||||
this.created_by = null;
|
||||
this.creation_date = 0;
|
||||
|
||||
// TODO if we add a parameter for other keys
|
||||
//if (other != null) {
|
||||
@@ -150,11 +156,11 @@ public class MetaInfo
|
||||
if (val == null) {
|
||||
this.announce_list = null;
|
||||
} else {
|
||||
this.announce_list = new ArrayList();
|
||||
this.announce_list = new ArrayList<List<String>>();
|
||||
List<BEValue> bl1 = val.getList();
|
||||
for (BEValue bev : bl1) {
|
||||
List<BEValue> bl2 = bev.getList();
|
||||
List<String> sl2 = new ArrayList();
|
||||
List<String> sl2 = new ArrayList<String>();
|
||||
for (BEValue bev2 : bl2) {
|
||||
sl2.add(bev2.getString());
|
||||
}
|
||||
@@ -162,6 +168,32 @@ public class MetaInfo
|
||||
}
|
||||
}
|
||||
|
||||
// misc. optional top-level stuff
|
||||
val = m.get("comment");
|
||||
String st = null;
|
||||
if (val != null) {
|
||||
try {
|
||||
st = val.getString();
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
this.comment = st;
|
||||
val = m.get("created by");
|
||||
st = null;
|
||||
if (val != null) {
|
||||
try {
|
||||
st = val.getString();
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
this.created_by = st;
|
||||
val = m.get("creation date");
|
||||
long time = 0;
|
||||
if (val != null) {
|
||||
try {
|
||||
time = val.getLong() * 1000;
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
this.creation_date = time;
|
||||
|
||||
val = m.get("info");
|
||||
if (val == null)
|
||||
throw new InvalidBEncodingException("Missing info map");
|
||||
@@ -184,7 +216,18 @@ public class MetaInfo
|
||||
|
||||
// BEP 27
|
||||
val = info.get("private");
|
||||
privateTorrent = val != null && val.getString().equals("1");
|
||||
if (val != null) {
|
||||
Object o = val.getValue();
|
||||
// Is it supposed to be a number or a string?
|
||||
// i2psnark does it as a string. BEP 27 doesn't say.
|
||||
// Transmission does numbers. So does libtorrent.
|
||||
// We handle both as of 0.9.9.
|
||||
// We switch to storing as number as of 0.9.14.
|
||||
privateTorrent = "1".equals(o) ||
|
||||
((o instanceof Number) && ((Number) o).intValue() == 1);
|
||||
} else {
|
||||
privateTorrent = false;
|
||||
}
|
||||
|
||||
val = info.get("piece length");
|
||||
if (val == null)
|
||||
@@ -218,9 +261,9 @@ public class MetaInfo
|
||||
if (size == 0)
|
||||
throw new InvalidBEncodingException("zero size files list");
|
||||
|
||||
List<List<String>> m_files = new ArrayList(size);
|
||||
List<List<String>> m_files_utf8 = new ArrayList(size);
|
||||
List<Long> m_lengths = new ArrayList(size);
|
||||
List<List<String>> m_files = new ArrayList<List<String>>(size);
|
||||
List<List<String>> m_files_utf8 = new ArrayList<List<String>>(size);
|
||||
List<Long> m_lengths = new ArrayList<Long>(size);
|
||||
long l = 0;
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
@@ -246,7 +289,7 @@ public class MetaInfo
|
||||
if (path_length == 0)
|
||||
throw new InvalidBEncodingException("zero size file path list");
|
||||
|
||||
List<String> file = new ArrayList(path_length);
|
||||
List<String> file = new ArrayList<String>(path_length);
|
||||
Iterator<BEValue> it = path_list.iterator();
|
||||
while (it.hasNext()) {
|
||||
String s = it.next().getString();
|
||||
@@ -269,7 +312,7 @@ public class MetaInfo
|
||||
path_list = val.getList();
|
||||
path_length = path_list.size();
|
||||
if (path_length > 0) {
|
||||
file = new ArrayList(path_length);
|
||||
file = new ArrayList<String>(path_length);
|
||||
it = path_list.iterator();
|
||||
while (it.hasNext())
|
||||
file.add(it.next().getString());
|
||||
@@ -381,6 +424,33 @@ public class MetaInfo
|
||||
return lengths;
|
||||
}
|
||||
|
||||
/**
|
||||
* The comment string or null.
|
||||
* Not available for locally-created torrents.
|
||||
* @since 0.9.7
|
||||
*/
|
||||
public String getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* The created-by string or null.
|
||||
* Not available for locally-created torrents.
|
||||
* @since 0.9.7
|
||||
*/
|
||||
public String getCreatedBy() {
|
||||
return this.created_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* The creation date (ms) or zero.
|
||||
* Not available for locally-created torrents.
|
||||
* @since 0.9.7
|
||||
*/
|
||||
public long getCreationDate() {
|
||||
return this.creation_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pieces.
|
||||
*/
|
||||
@@ -447,9 +517,10 @@ public class MetaInfo
|
||||
|
||||
sha1.update(bs, off, length);
|
||||
byte[] hash = sha1.digest();
|
||||
for (int i = 0; i < 20; i++)
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (hash[i] != piece_hashes[20 * piece + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -458,7 +529,6 @@ public class MetaInfo
|
||||
* @since 0.9.1
|
||||
*/
|
||||
boolean checkPiece(PartialPiece pp) {
|
||||
MessageDigest sha1 = SHA1.getInstance();
|
||||
int piece = pp.getPiece();
|
||||
byte[] hash;
|
||||
try {
|
||||
@@ -470,9 +540,10 @@ public class MetaInfo
|
||||
_log.warn("Error checking", ioe);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < 20; i++)
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (hash[i] != piece_hashes[20 * piece + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -501,12 +572,17 @@ public class MetaInfo
|
||||
* Creates a copy of this MetaInfo that shares everything except the
|
||||
* announce URL.
|
||||
* Drops any announce-list.
|
||||
* Preserves infohash and info map, including any non-standard fields.
|
||||
* @param announce may be null
|
||||
*/
|
||||
public MetaInfo reannounce(String announce)
|
||||
public MetaInfo reannounce(String announce) throws InvalidBEncodingException
|
||||
{
|
||||
return new MetaInfo(announce, name, name_utf8, files,
|
||||
lengths, piece_length,
|
||||
piece_hashes, length, privateTorrent, null);
|
||||
Map<String, BEValue> m = new HashMap<String, BEValue>();
|
||||
if (announce != null)
|
||||
m.put("announce", new BEValue(DataHelper.getUTF8(announce)));
|
||||
Map<String, BEValue> info = createInfoMap();
|
||||
m.put("info", new BEValue(info));
|
||||
return new MetaInfo(m);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,12 +590,12 @@ public class MetaInfo
|
||||
*/
|
||||
public synchronized byte[] getTorrentData()
|
||||
{
|
||||
Map m = new HashMap();
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
if (announce != null)
|
||||
m.put("announce", announce);
|
||||
if (announce_list != null)
|
||||
m.put("announce-list", announce_list);
|
||||
Map info = createInfoMap();
|
||||
Map<String, BEValue> info = createInfoMap();
|
||||
m.put("info", info);
|
||||
// don't save this locally, we should only do this once
|
||||
return BEncoder.bencode(m);
|
||||
@@ -539,32 +615,48 @@ public class MetaInfo
|
||||
// or else we will lose any non-standard keys and corrupt the infohash.
|
||||
if (infoMap != null)
|
||||
return Collections.unmodifiableMap(infoMap);
|
||||
// we should only get here if serving a magnet on a torrent we created
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Creating new infomap", new Exception());
|
||||
// otherwise we must create it
|
||||
Map info = new HashMap();
|
||||
info.put("name", name);
|
||||
Map<String, BEValue> info = new HashMap<String, BEValue>();
|
||||
info.put("name", new BEValue(DataHelper.getUTF8(name)));
|
||||
if (name_utf8 != null)
|
||||
info.put("name.utf-8", name_utf8);
|
||||
info.put("name.utf-8", new BEValue(DataHelper.getUTF8(name_utf8)));
|
||||
// BEP 27
|
||||
if (privateTorrent)
|
||||
info.put("private", "1");
|
||||
// switched to number in 0.9.14
|
||||
//info.put("private", new BEValue(DataHelper.getUTF8("1")));
|
||||
info.put("private", new BEValue(Integer.valueOf(1)));
|
||||
|
||||
info.put("piece length", Integer.valueOf(piece_length));
|
||||
info.put("pieces", piece_hashes);
|
||||
info.put("piece length", new BEValue(Integer.valueOf(piece_length)));
|
||||
info.put("pieces", new BEValue(piece_hashes));
|
||||
if (files == null)
|
||||
info.put("length", Long.valueOf(length));
|
||||
info.put("length", new BEValue(Long.valueOf(length)));
|
||||
else
|
||||
{
|
||||
List l = new ArrayList();
|
||||
List<BEValue> l = new ArrayList<BEValue>();
|
||||
for (int i = 0; i < files.size(); i++)
|
||||
{
|
||||
Map file = new HashMap();
|
||||
file.put("path", files.get(i));
|
||||
if ( (files_utf8 != null) && (files_utf8.size() > i) )
|
||||
file.put("path.utf-8", files_utf8.get(i));
|
||||
file.put("length", lengths.get(i));
|
||||
l.add(file);
|
||||
Map<String, BEValue> file = new HashMap<String, BEValue>();
|
||||
List<String> fi = files.get(i);
|
||||
List<BEValue> befiles = new ArrayList<BEValue>(fi.size());
|
||||
for (int j = 0; j < fi.size(); j++) {
|
||||
befiles.add(new BEValue(DataHelper.getUTF8(fi.get(j))));
|
||||
}
|
||||
file.put("path", new BEValue(befiles));
|
||||
if ( (files_utf8 != null) && (files_utf8.size() > i) ) {
|
||||
List<String> fiu = files_utf8.get(i);
|
||||
List<BEValue> beufiles = new ArrayList<BEValue>(fiu.size());
|
||||
for (int j = 0; j < fiu.size(); j++) {
|
||||
beufiles.add(new BEValue(DataHelper.getUTF8(fiu.get(j))));
|
||||
}
|
||||
file.put("path.utf-8", new BEValue(beufiles));
|
||||
}
|
||||
file.put("length", new BEValue(lengths.get(i)));
|
||||
l.add(new BEValue(file));
|
||||
}
|
||||
info.put("files", l);
|
||||
info.put("files", new BEValue(l));
|
||||
}
|
||||
|
||||
// TODO if we add the ability for other keys in the first constructor
|
||||
|
@@ -31,7 +31,7 @@ import net.i2p.util.SecureFile;
|
||||
*
|
||||
* @since 0.8.2
|
||||
*/
|
||||
class PartialPiece implements Comparable {
|
||||
class PartialPiece implements Comparable<PartialPiece> {
|
||||
|
||||
// we store the piece so we can use it in compareTo()
|
||||
private final Piece piece;
|
||||
@@ -295,8 +295,7 @@ class PartialPiece implements Comparable {
|
||||
* then rarest first,
|
||||
* then highest downloaded first
|
||||
*/
|
||||
public int compareTo(Object o) throws ClassCastException {
|
||||
PartialPiece opp = (PartialPiece)o;
|
||||
public int compareTo(PartialPiece opp) {
|
||||
int d = this.piece.compareTo(opp.piece);
|
||||
if (d != 0)
|
||||
return d;
|
||||
|
@@ -28,6 +28,8 @@ import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
@@ -37,7 +39,7 @@ import net.i2p.util.Log;
|
||||
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
|
||||
public class Peer implements Comparable
|
||||
public class Peer implements Comparable<Peer>
|
||||
{
|
||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(Peer.class);
|
||||
// Identifying property, the peer id of the other side.
|
||||
@@ -68,8 +70,10 @@ public class Peer implements Comparable
|
||||
private I2PSocket sock;
|
||||
|
||||
private boolean deregister = true;
|
||||
private static long __id;
|
||||
private long _id;
|
||||
private static final AtomicLong __id = new AtomicLong();
|
||||
private final long _id;
|
||||
private final AtomicBoolean _disconnected = new AtomicBoolean();
|
||||
|
||||
final static long CHECK_PERIOD = PeerCoordinator.CHECK_PERIOD; // 40 seconds
|
||||
final static int RATE_DEPTH = PeerCoordinator.RATE_DEPTH; // make following arrays RATE_DEPTH long
|
||||
private long uploaded_old[] = {-1,-1,-1};
|
||||
@@ -98,7 +102,7 @@ public class Peer implements Comparable
|
||||
this.my_id = my_id;
|
||||
this.infohash = infohash;
|
||||
this.metainfo = metainfo;
|
||||
_id = ++__id;
|
||||
_id = __id.incrementAndGet();
|
||||
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
|
||||
}
|
||||
|
||||
@@ -123,7 +127,7 @@ public class Peer implements Comparable
|
||||
|
||||
byte[] id = handshake(in, out);
|
||||
this.peerID = new PeerID(id, sock.getPeerDestination());
|
||||
_id = ++__id;
|
||||
_id = __id.incrementAndGet();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
|
||||
}
|
||||
@@ -190,9 +194,8 @@ public class Peer implements Comparable
|
||||
* Compares the PeerIDs.
|
||||
* @deprecated unused?
|
||||
*/
|
||||
public int compareTo(Object o)
|
||||
public int compareTo(Peer p)
|
||||
{
|
||||
Peer p = (Peer)o;
|
||||
int rv = peerID.compareTo(p.peerID);
|
||||
if (rv == 0) {
|
||||
if (_id > p._id) return 1;
|
||||
@@ -457,6 +460,8 @@ public class Peer implements Comparable
|
||||
|
||||
void disconnect()
|
||||
{
|
||||
if (!_disconnected.compareAndSet(false, true))
|
||||
return;
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
{
|
||||
@@ -476,9 +481,11 @@ public class Peer implements Comparable
|
||||
PeerConnectionIn in = s.in;
|
||||
if (in != null)
|
||||
in.disconnect();
|
||||
PeerConnectionOut out = s.out;
|
||||
if (out != null)
|
||||
out.disconnect();
|
||||
// this is blocking in streaming, so do this after closing the socket
|
||||
// so it won't really block
|
||||
//PeerConnectionOut out = s.out;
|
||||
//if (out != null)
|
||||
// out.disconnect();
|
||||
PeerListener pl = s.listener;
|
||||
if (pl != null)
|
||||
pl.disconnected(this);
|
||||
@@ -492,6 +499,13 @@ public class Peer implements Comparable
|
||||
_log.warn("Error disconnecting " + toString(), ioe);
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
// this is blocking in streaming, so do this after closing the socket
|
||||
// so it won't really block
|
||||
PeerConnectionOut out = s.out;
|
||||
if (out != null)
|
||||
out.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,8 +26,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.Base64;
|
||||
@@ -170,8 +168,7 @@ class PeerAcceptor
|
||||
if (b != PROTO[i])
|
||||
throw new IOException("Bad protocol 0x" + Integer.toHexString(b) + " at byte " + i);
|
||||
}
|
||||
if (in.skip(8) != 8)
|
||||
throw new IOException("EOF before hash");
|
||||
DataHelper.skip(in, 8);
|
||||
byte buf[] = new byte[20];
|
||||
int read = DataHelper.read(in, buf);
|
||||
if (read != buf.length)
|
||||
|
@@ -24,7 +24,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -73,7 +72,7 @@ class PeerCheckerTask implements Runnable
|
||||
|
||||
// Keep track of peers we remove now,
|
||||
// we will add them back to the end of the list.
|
||||
List<Peer> removed = new ArrayList();
|
||||
List<Peer> removed = new ArrayList<Peer>();
|
||||
int uploadLimit = coordinator.allowedUploaders();
|
||||
boolean overBWLimit = coordinator.overUpBWLimit();
|
||||
DHT dht = _util.getDHT();
|
||||
@@ -222,7 +221,8 @@ class PeerCheckerTask implements Runnable
|
||||
peer.keepAlive();
|
||||
// announce them to local tracker (TrackerClient does this too)
|
||||
if (dht != null && (_runCount % 5) == 0) {
|
||||
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash(),
|
||||
peer.isCompleted());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ class PeerCheckerTask implements Runnable
|
||||
|
||||
// announce ourselves to local tracker (TrackerClient does this too)
|
||||
if (dht != null && (_runCount % 16) == 0) {
|
||||
dht.announce(coordinator.getInfoHash());
|
||||
dht.announce(coordinator.getInfoHash(), coordinator.completed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -65,7 +65,7 @@ class PeerConnectionIn implements Runnable
|
||||
try {
|
||||
din.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error closing the stream from " + peer, ioe);
|
||||
//_log.warn("Error closing the stream from " + peer, ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
@@ -42,10 +43,10 @@ class PeerConnectionOut implements Runnable
|
||||
private boolean quit;
|
||||
|
||||
// Contains Messages.
|
||||
private final List<Message> sendQueue = new ArrayList();
|
||||
private final List<Message> sendQueue = new ArrayList<Message>();
|
||||
|
||||
private static long __id = 0;
|
||||
private long _id;
|
||||
private static final AtomicLong __id = new AtomicLong();
|
||||
private final long _id;
|
||||
|
||||
long lastSent;
|
||||
|
||||
@@ -53,10 +54,9 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
this.peer = peer;
|
||||
this.dout = dout;
|
||||
_id = ++__id;
|
||||
_id = __id.incrementAndGet();
|
||||
|
||||
lastSent = System.currentTimeMillis();
|
||||
quit = false;
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
@@ -66,7 +66,7 @@ class PeerConnectionOut implements Runnable
|
||||
|
||||
/**
|
||||
* Continuesly monitors for more outgoing messages that have to be send.
|
||||
* Stops if quit is true of an IOException occurs.
|
||||
* Stops if quit is true or an IOException occurs.
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
@@ -116,10 +116,10 @@ class PeerConnectionOut implements Runnable
|
||||
// And remove piece messages if we are choking.
|
||||
|
||||
// this should get fixed for starvation
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (m == null && it.hasNext())
|
||||
{
|
||||
Message nm = (Message)it.next();
|
||||
Message nm = it.next();
|
||||
if (nm.type == Message.PIECE)
|
||||
{
|
||||
if (state.choking) {
|
||||
@@ -135,7 +135,7 @@ class PeerConnectionOut implements Runnable
|
||||
nm = null;
|
||||
}
|
||||
|
||||
if (m == null && nm != null)
|
||||
if (nm != null)
|
||||
{
|
||||
m = nm;
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
@@ -215,13 +215,13 @@ class PeerConnectionOut implements Runnable
|
||||
thread.interrupt();
|
||||
|
||||
sendQueue.clear();
|
||||
sendQueue.notify();
|
||||
sendQueue.notifyAll();
|
||||
}
|
||||
if (dout != null) {
|
||||
try {
|
||||
dout.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error closing the stream to " + peer, ioe);
|
||||
//_log.warn("Error closing the stream to " + peer, ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,10 +274,10 @@ class PeerConnectionOut implements Runnable
|
||||
boolean removed = false;
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Message m = (Message)it.next();
|
||||
Message m = it.next();
|
||||
if (m.type == type)
|
||||
{
|
||||
it.remove();
|
||||
@@ -360,13 +360,13 @@ class PeerConnectionOut implements Runnable
|
||||
|
||||
/** reransmit requests not received in 7m */
|
||||
private static final int REQ_TIMEOUT = (2 * SEND_TIMEOUT) + (60 * 1000);
|
||||
void retransmitRequests(List requests)
|
||||
void retransmitRequests(List<Request> requests)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
Iterator it = requests.iterator();
|
||||
Iterator<Request> it = requests.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Request req = (Request)it.next();
|
||||
Request req = it.next();
|
||||
if(now > req.sendTime + REQ_TIMEOUT) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Retransmit request " + req + " to peer " + peer);
|
||||
@@ -375,12 +375,12 @@ class PeerConnectionOut implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
void sendRequests(List requests)
|
||||
void sendRequests(List<Request> requests)
|
||||
{
|
||||
Iterator it = requests.iterator();
|
||||
Iterator<Request> it = requests.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Request req = (Request)it.next();
|
||||
Request req = it.next();
|
||||
sendRequest(req);
|
||||
}
|
||||
}
|
||||
@@ -391,10 +391,10 @@ class PeerConnectionOut implements Runnable
|
||||
// (multiple choke/unchokes received cause duplicate requests in the queue)
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Message m = (Message)it.next();
|
||||
Message m = it.next();
|
||||
if (m.type == Message.REQUEST && m.piece == req.getPiece() &&
|
||||
m.begin == req.off && m.length == req.len)
|
||||
{
|
||||
@@ -419,10 +419,10 @@ class PeerConnectionOut implements Runnable
|
||||
int total = 0;
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Message m = (Message)it.next();
|
||||
Message m = it.next();
|
||||
if (m.type == Message.PIECE)
|
||||
total += m.length;
|
||||
}
|
||||
@@ -489,10 +489,10 @@ class PeerConnectionOut implements Runnable
|
||||
// See if it is still in our send queue
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Message m = (Message)it.next();
|
||||
Message m = it.next();
|
||||
if (m.type == Message.REQUEST
|
||||
&& m.piece == req.getPiece()
|
||||
&& m.begin == req.off
|
||||
@@ -530,10 +530,10 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
synchronized (sendQueue)
|
||||
{
|
||||
Iterator it = sendQueue.iterator();
|
||||
Iterator<Message> it = sendQueue.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Message m = (Message)it.next();
|
||||
Message m = it.next();
|
||||
if (m.type == Message.PIECE
|
||||
&& m.piece == piece
|
||||
&& m.begin == begin
|
||||
|
@@ -151,12 +151,12 @@ class PeerCoordinator implements PeerListener
|
||||
this.listener = listener;
|
||||
this.snark = torrent;
|
||||
|
||||
wantedPieces = new ArrayList();
|
||||
wantedPieces = new ArrayList<Piece>();
|
||||
setWantedPieces();
|
||||
partialPieces = new ArrayList(getMaxConnections() + 1);
|
||||
peers = new LinkedBlockingQueue();
|
||||
partialPieces = new ArrayList<PartialPiece>(getMaxConnections() + 1);
|
||||
peers = new LinkedBlockingQueue<Peer>();
|
||||
magnetState = new MagnetState(infohash, metainfo);
|
||||
pexPeers = new ConcurrentHashSet();
|
||||
pexPeers = new ConcurrentHashSet<PeerID>();
|
||||
|
||||
// Install a timer to check the uploaders.
|
||||
// Randomize the first start time so multiple tasks are spread out,
|
||||
@@ -218,7 +218,7 @@ class PeerCoordinator implements PeerListener
|
||||
/** for web page detailed stats */
|
||||
public List<Peer> peerList()
|
||||
{
|
||||
return new ArrayList(peers);
|
||||
return new ArrayList<Peer>(peers);
|
||||
}
|
||||
|
||||
public byte[] getID()
|
||||
@@ -412,7 +412,7 @@ class PeerCoordinator implements PeerListener
|
||||
public void halt()
|
||||
{
|
||||
halted = true;
|
||||
List<Peer> removed = new ArrayList();
|
||||
List<Peer> removed = new ArrayList<Peer>();
|
||||
synchronized(peers)
|
||||
{
|
||||
// Stop peer checker task.
|
||||
@@ -613,7 +613,7 @@ class PeerCoordinator implements PeerListener
|
||||
// linked list will contain all interested peers that we choke.
|
||||
// At the start are the peers that have us unchoked at the end the
|
||||
// other peer that are interested, but are choking us.
|
||||
List<Peer> interested = new LinkedList();
|
||||
List<Peer> interested = new LinkedList<Peer>();
|
||||
int count = 0;
|
||||
int unchokedCount = 0;
|
||||
int maxUploaders = allowedUploaders();
|
||||
@@ -729,7 +729,7 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
|
||||
Piece piece = null;
|
||||
List<Piece> requested = new ArrayList();
|
||||
List<Piece> requested = new ArrayList<Piece>();
|
||||
int wantedSize = END_GAME_THRESHOLD + 1;
|
||||
synchronized(wantedPieces)
|
||||
{
|
||||
@@ -833,7 +833,7 @@ class PeerCoordinator implements PeerListener
|
||||
_log.debug("Updated piece priorities called but no priorities to set?");
|
||||
return;
|
||||
}
|
||||
List<Piece> toCancel = new ArrayList();
|
||||
List<Piece> toCancel = new ArrayList<Piece>();
|
||||
synchronized(wantedPieces) {
|
||||
// Add incomplete and previously unwanted pieces to the list
|
||||
// Temp to avoid O(n**2)
|
||||
@@ -999,13 +999,13 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
snark.stopTorrent();
|
||||
String msg = "Error writing storage (piece " + piece + ") for " + metainfo.getName() + ": " + ioe;
|
||||
_log.error(msg, ioe);
|
||||
if (listener != null) {
|
||||
listener.addMessage(msg);
|
||||
listener.addMessage("Fatal storage error: Stopping torrent " + metainfo.getName());
|
||||
}
|
||||
snark.stopTorrent();
|
||||
throw new RuntimeException(msg, ioe);
|
||||
}
|
||||
wantedPieces.remove(p);
|
||||
@@ -1019,7 +1019,7 @@ class PeerCoordinator implements PeerListener
|
||||
|
||||
// Announce to the world we have it!
|
||||
// Disconnect from other seeders when we get the last piece
|
||||
List<Peer> toDisconnect = done ? new ArrayList() : null;
|
||||
List<Peer> toDisconnect = done ? new ArrayList<Peer>() : null;
|
||||
for (Peer p : peers) {
|
||||
if (p.isConnected())
|
||||
{
|
||||
@@ -1202,22 +1202,23 @@ class PeerCoordinator implements PeerListener
|
||||
boolean skipped = false;
|
||||
for(Piece piece : wantedPieces) {
|
||||
if (piece.getId() == savedPiece) {
|
||||
if (peer.isCompleted() && piece.getPeerCount() > 1) {
|
||||
if (peer.isCompleted() && piece.getPeerCount() > 1 &&
|
||||
wantedPieces.size() > 2*END_GAME_THRESHOLD) {
|
||||
// Try to preserve rarest-first
|
||||
// by not requesting a partial piece that non-seeders also have
|
||||
// by not requesting a partial piece that at least two non-seeders also have
|
||||
// from a seeder
|
||||
boolean nonSeeds = false;
|
||||
int nonSeeds = 0;
|
||||
for (Peer pr : peers) {
|
||||
PeerState state = pr.state;
|
||||
if (state == null) continue;
|
||||
BitField bf = state.bitfield;
|
||||
if (bf == null) continue;
|
||||
if (bf.get(savedPiece) && !pr.isCompleted()) {
|
||||
nonSeeds = true;
|
||||
break;
|
||||
if (++nonSeeds > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nonSeeds) {
|
||||
if (nonSeeds > 1) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
@@ -1231,16 +1232,16 @@ class PeerCoordinator implements PeerListener
|
||||
return pp;
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
if (skipped)
|
||||
_log.warn("Partial piece " + pp + " with multiple peers skipped for seeder");
|
||||
_log.info("Partial piece " + pp + " with multiple peers skipped for seeder");
|
||||
else
|
||||
_log.warn("Partial piece " + pp + " NOT in wantedPieces??");
|
||||
_log.info("Partial piece " + pp + " NOT in wantedPieces??");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN) && !partialPieces.isEmpty())
|
||||
_log.warn("Peer " + peer + " has none of our partials " + partialPieces);
|
||||
if (_log.shouldLog(Log.INFO) && !partialPieces.isEmpty())
|
||||
_log.info("Peer " + peer + " has none of our partials " + partialPieces);
|
||||
}
|
||||
// ...and this section turns this into the general move-requests-around code!
|
||||
// Temporary? So PeerState never calls wantPiece() directly for now...
|
||||
|
@@ -12,11 +12,11 @@ import net.i2p.crypto.SHA1Hash;
|
||||
* Each PeerCoordinator is added to the set from within the Snark (and removed
|
||||
* from it there too)
|
||||
*/
|
||||
class PeerCoordinatorSet {
|
||||
class PeerCoordinatorSet implements Iterable<PeerCoordinator> {
|
||||
private final Map<SHA1Hash, PeerCoordinator> _coordinators;
|
||||
|
||||
public PeerCoordinatorSet() {
|
||||
_coordinators = new ConcurrentHashMap();
|
||||
_coordinators = new ConcurrentHashMap<SHA1Hash, PeerCoordinator>();
|
||||
}
|
||||
|
||||
public Iterator<PeerCoordinator> iterator() {
|
||||
|
@@ -24,7 +24,6 @@ import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -43,7 +42,7 @@ import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
* and the PeerID is not required.
|
||||
* Equality is now determined solely by the dest hash.
|
||||
*/
|
||||
class PeerID implements Comparable
|
||||
public class PeerID implements Comparable<PeerID>
|
||||
{
|
||||
private byte[] id;
|
||||
private Destination address;
|
||||
@@ -53,12 +52,13 @@ class PeerID implements Comparable
|
||||
private boolean triedDestLookup;
|
||||
private final int hash;
|
||||
private final I2PSnarkUtil util;
|
||||
private String _toStringCache;
|
||||
|
||||
public PeerID(byte[] id, Destination address)
|
||||
{
|
||||
this.id = id;
|
||||
this.address = address;
|
||||
this.port = 6881;
|
||||
this.port = TrackerClient.PORT;
|
||||
this.destHash = address.calculateHash().getData();
|
||||
hash = calculateHash();
|
||||
util = null;
|
||||
@@ -77,22 +77,22 @@ class PeerID implements Comparable
|
||||
* Creates a PeerID from a Map containing BEncoded peer id, ip and
|
||||
* port.
|
||||
*/
|
||||
public PeerID(Map m)
|
||||
public PeerID(Map<String, BEValue> m)
|
||||
throws InvalidBEncodingException, UnknownHostException
|
||||
{
|
||||
BEValue bevalue = (BEValue)m.get("peer id");
|
||||
BEValue bevalue = m.get("peer id");
|
||||
if (bevalue == null)
|
||||
throw new InvalidBEncodingException("peer id missing");
|
||||
id = bevalue.getBytes();
|
||||
|
||||
bevalue = (BEValue)m.get("ip");
|
||||
bevalue = m.get("ip");
|
||||
if (bevalue == null)
|
||||
throw new InvalidBEncodingException("ip missing");
|
||||
address = I2PSnarkUtil.getDestinationFromBase64(bevalue.getString());
|
||||
if (address == null)
|
||||
throw new InvalidBEncodingException("Invalid destination [" + bevalue.getString() + "]");
|
||||
|
||||
port = 6881;
|
||||
port = TrackerClient.PORT;
|
||||
this.destHash = address.calculateHash().getData();
|
||||
hash = calculateHash();
|
||||
util = null;
|
||||
@@ -106,7 +106,7 @@ class PeerID implements Comparable
|
||||
public PeerID(byte[] dest_hash, I2PSnarkUtil util) throws InvalidBEncodingException
|
||||
{
|
||||
// id and address remain null
|
||||
port = 6881;
|
||||
port = TrackerClient.PORT;
|
||||
if (dest_hash.length != 32)
|
||||
throw new InvalidBEncodingException("bad hash length");
|
||||
destHash = dest_hash;
|
||||
@@ -196,10 +196,8 @@ class PeerID implements Comparable
|
||||
* Compares port, address and id.
|
||||
* @deprecated unused? and will NPE now that address can be null?
|
||||
*/
|
||||
public int compareTo(Object o)
|
||||
public int compareTo(PeerID pid)
|
||||
{
|
||||
PeerID pid = (PeerID)o;
|
||||
|
||||
int result = port - pid.port;
|
||||
if (result != 0)
|
||||
return result;
|
||||
@@ -219,13 +217,15 @@ class PeerID implements Comparable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String "id@address" where id is the base64 encoded id
|
||||
* and address is the base64 dest (was the base64 hash of the dest) which
|
||||
* Returns the String "id@address" where id is the first 4 chars of the base64 encoded id
|
||||
* and address is the first 6 chars of the base64 dest (was the base64 hash of the dest) which
|
||||
* should match what the bytemonsoon tracker reports on its web pages.
|
||||
*/
|
||||
@Override
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (_toStringCache != null)
|
||||
return _toStringCache;
|
||||
if (id == null || address == null)
|
||||
return "unkn@" + Base64.encode(destHash).substring(0, 6);
|
||||
int nonZero = 0;
|
||||
@@ -235,7 +235,8 @@ class PeerID implements Comparable
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Base64.encode(id, nonZero, id.length-nonZero).substring(0,4) + "@" + address.toBase64().substring(0,6);
|
||||
_toStringCache = Base64.encode(id, nonZero, id.length-nonZero).substring(0,4) + "@" + address.toBase64().substring(0,6);
|
||||
return _toStringCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -27,6 +27,8 @@ import net.i2p.data.DataHelper;
|
||||
/**
|
||||
* TimerTask that monitors the peers and total up/download speeds.
|
||||
* Works together with the main Snark class to report periodical statistics.
|
||||
*
|
||||
* @deprecated unused, for command line client only, commented out in Snark.java
|
||||
*/
|
||||
class PeerMonitorTask implements Runnable
|
||||
{
|
||||
@@ -35,8 +37,8 @@ class PeerMonitorTask implements Runnable
|
||||
|
||||
private final PeerCoordinator coordinator;
|
||||
|
||||
private long lastDownloaded = 0;
|
||||
private long lastUploaded = 0;
|
||||
//private long lastDownloaded = 0;
|
||||
//private long lastUploaded = 0;
|
||||
|
||||
PeerMonitorTask(PeerCoordinator coordinator)
|
||||
{
|
||||
@@ -45,6 +47,7 @@ class PeerMonitorTask implements Runnable
|
||||
|
||||
public void run()
|
||||
{
|
||||
/*****
|
||||
// Get some statistics
|
||||
int peers = 0;
|
||||
int uploaders = 0;
|
||||
@@ -117,5 +120,6 @@ class PeerMonitorTask implements Runnable
|
||||
|
||||
lastDownloaded = downloaded;
|
||||
lastUploaded = uploaded;
|
||||
****/
|
||||
}
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ class PeerState implements DataLoader
|
||||
final PeerConnectionOut out;
|
||||
|
||||
// Outstanding request
|
||||
private final List<Request> outstandingRequests = new ArrayList();
|
||||
private final List<Request> outstandingRequests = new ArrayList<Request>();
|
||||
/** the tail (NOT the head) of the request queue */
|
||||
private Request lastRequest = null;
|
||||
|
||||
@@ -451,7 +451,7 @@ class PeerState implements DataLoader
|
||||
synchronized List<Request> returnPartialPieces()
|
||||
{
|
||||
Set<Integer> pcs = getRequestedPieces();
|
||||
List<Request> rv = new ArrayList(pcs.size());
|
||||
List<Request> rv = new ArrayList<Request>(pcs.size());
|
||||
for (Integer p : pcs) {
|
||||
Request req = getLowestOutstandingRequest(p.intValue());
|
||||
if (req != null) {
|
||||
@@ -469,7 +469,7 @@ class PeerState implements DataLoader
|
||||
* @return all pieces we are currently requesting, or empty Set
|
||||
*/
|
||||
synchronized private Set<Integer> getRequestedPieces() {
|
||||
Set<Integer> rv = new HashSet(outstandingRequests.size() + 1);
|
||||
Set<Integer> rv = new HashSet<Integer>(outstandingRequests.size() + 1);
|
||||
for (Request req : outstandingRequests) {
|
||||
rv.add(Integer.valueOf(req.getPiece()));
|
||||
if (pendingRequest != null)
|
||||
|
@@ -7,7 +7,7 @@ import java.util.Set;
|
||||
* This class is used solely by PeerCoordinator.
|
||||
* Caller must synchronize on many of these methods.
|
||||
*/
|
||||
class Piece implements Comparable {
|
||||
class Piece implements Comparable<Piece> {
|
||||
|
||||
private final int id;
|
||||
private final Set<PeerID> peers;
|
||||
@@ -18,7 +18,7 @@ class Piece implements Comparable {
|
||||
|
||||
public Piece(int id) {
|
||||
this.id = id;
|
||||
this.peers = new HashSet(I2PSnarkUtil.MAX_CONNECTIONS / 2);
|
||||
this.peers = new HashSet<PeerID>(I2PSnarkUtil.MAX_CONNECTIONS / 2);
|
||||
// defer creating requests to save memory
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ class Piece implements Comparable {
|
||||
* Highest priority first,
|
||||
* then rarest first
|
||||
*/
|
||||
public int compareTo(Object o) throws ClassCastException {
|
||||
int pdiff = ((Piece)o).priority - this.priority; // reverse
|
||||
public int compareTo(Piece op) {
|
||||
int pdiff = op.priority - this.priority; // reverse
|
||||
if (pdiff != 0)
|
||||
return pdiff;
|
||||
return this.peers.size() - ((Piece)o).peers.size();
|
||||
return this.peers.size() - op.peers.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,7 +82,7 @@ class Piece implements Comparable {
|
||||
public void setRequested(Peer peer, boolean requested) {
|
||||
if (requested) {
|
||||
if (this.requests == null)
|
||||
this.requests = new HashSet(2);
|
||||
this.requests = new HashSet<PeerID>(2);
|
||||
this.requests.add(peer.getPeerID());
|
||||
} else {
|
||||
if (this.requests != null)
|
||||
|
@@ -25,7 +25,6 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
@@ -34,7 +33,6 @@ import java.util.StringTokenizer;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -71,8 +69,6 @@ public class Snark
|
||||
"Commands: 'info', 'list', 'quit'.";
|
||||
****/
|
||||
|
||||
// String indicating main activity
|
||||
String activity = "Not started";
|
||||
|
||||
/****
|
||||
private static class OOMListener implements I2PThread.OOMEventListener {
|
||||
@@ -229,14 +225,17 @@ public class Snark
|
||||
private final CompleteListener completeListener;
|
||||
private volatile boolean stopped;
|
||||
private volatile boolean starting;
|
||||
private byte[] id;
|
||||
private final byte[] id;
|
||||
private final byte[] infoHash;
|
||||
private String additionalTrackerURL;
|
||||
private final I2PSnarkUtil _util;
|
||||
protected final I2PSnarkUtil _util;
|
||||
private final Log _log;
|
||||
private final PeerCoordinatorSet _peerCoordinatorSet;
|
||||
private String trackerProblems;
|
||||
private int trackerSeenPeers;
|
||||
private volatile String trackerProblems;
|
||||
private volatile int trackerSeenPeers;
|
||||
private volatile boolean _autoStoppable;
|
||||
// String indicating main activity
|
||||
private volatile String activity = "Not started";
|
||||
|
||||
|
||||
/** from main() via parseArguments() single torrent */
|
||||
@@ -318,7 +317,6 @@ public class Snark
|
||||
*/
|
||||
|
||||
// Figure out what the torrent argument represents.
|
||||
meta = null;
|
||||
File f = null;
|
||||
InputStream in = null;
|
||||
byte[] x_infoHash = null;
|
||||
@@ -526,18 +524,17 @@ public class Snark
|
||||
if (_peerCoordinatorSet != null) {
|
||||
// multitorrent
|
||||
_peerCoordinatorSet.add(coordinator);
|
||||
if (acceptor != null) {
|
||||
acceptor.startAccepting(_peerCoordinatorSet, serversocket);
|
||||
} else {
|
||||
// error
|
||||
}
|
||||
} else {
|
||||
// single torrent
|
||||
acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
|
||||
acceptor = new ConnectionAcceptor(_util, new PeerAcceptor(coordinator));
|
||||
}
|
||||
// TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator?
|
||||
trackerclient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
|
||||
}
|
||||
// ensure acceptor is running when in multitorrent
|
||||
if (_peerCoordinatorSet != null && acceptor != null) {
|
||||
acceptor.startAccepting();
|
||||
}
|
||||
|
||||
stopped = false;
|
||||
if (coordinator.halted()) {
|
||||
@@ -761,7 +758,7 @@ public class Snark
|
||||
PeerCoordinator coord = coordinator;
|
||||
if (coord != null)
|
||||
return coord.peerList();
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -905,6 +902,16 @@ public class Snark
|
||||
return additionalTrackerURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.9
|
||||
*/
|
||||
public boolean isAutoStoppable() { return _autoStoppable; }
|
||||
|
||||
/**
|
||||
* @since 0.9.9
|
||||
*/
|
||||
public void setAutoStoppable(boolean yes) { _autoStoppable = yes; }
|
||||
|
||||
/**
|
||||
* Sets debug, ip and torrent variables then creates a Snark
|
||||
* instance. Calls usage(), which terminates the program, if
|
||||
@@ -1144,8 +1151,8 @@ public class Snark
|
||||
// System.out.println(); // We have all the disk space we need.
|
||||
}
|
||||
|
||||
private boolean allChecked = false;
|
||||
private boolean checking = false;
|
||||
private boolean allChecked;
|
||||
private boolean checking;
|
||||
//private boolean prechecking = true;
|
||||
|
||||
public void storageChecked(Storage storage, int num, boolean checked)
|
||||
@@ -1222,12 +1229,12 @@ public class Snark
|
||||
*/
|
||||
final static int MIN_TOTAL_UPLOADERS = 4;
|
||||
final static int MAX_TOTAL_UPLOADERS = 10;
|
||||
|
||||
public boolean overUploadLimit(int uploaders) {
|
||||
if (_peerCoordinatorSet == null || uploaders <= 0)
|
||||
return false;
|
||||
int totalUploaders = 0;
|
||||
for (Iterator<PeerCoordinator> iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
|
||||
PeerCoordinator c = iter.next();
|
||||
for (PeerCoordinator c : _peerCoordinatorSet) {
|
||||
if (!c.halted())
|
||||
totalUploaders += c.uploaders;
|
||||
}
|
||||
@@ -1240,8 +1247,7 @@ public class Snark
|
||||
if (_peerCoordinatorSet == null)
|
||||
return false;
|
||||
long total = 0;
|
||||
for (Iterator<PeerCoordinator> iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
|
||||
PeerCoordinator c = iter.next();
|
||||
for (PeerCoordinator c : _peerCoordinatorSet) {
|
||||
if (!c.halted())
|
||||
total += c.getCurrentUploadRate();
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -14,7 +15,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.update.*;
|
||||
@@ -35,8 +36,8 @@ import net.i2p.util.Log;
|
||||
import net.i2p.util.OrderedProperties;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
import org.klomp.snark.dht.DHT;
|
||||
|
||||
@@ -70,6 +71,7 @@ public class SnarkManager implements CompleteListener {
|
||||
private final Map<String, Tracker> _trackerMap;
|
||||
private UpdateManager _umgr;
|
||||
private UpdateHandler _uhandler;
|
||||
private SimpleTimer2.TimedEvent _idleChecker;
|
||||
|
||||
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
|
||||
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
|
||||
@@ -112,7 +114,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* "name", "announceURL=websiteURL" pairs
|
||||
* '=' in announceURL must be escaped as ,
|
||||
*/
|
||||
public static final String DEFAULT_TRACKERS[] = {
|
||||
private static final String DEFAULT_TRACKERS[] = {
|
||||
// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
|
||||
// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
|
||||
// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
|
||||
@@ -129,6 +131,17 @@ public class SnarkManager implements CompleteListener {
|
||||
// ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/"
|
||||
};
|
||||
|
||||
public static final Set<String> DEFAULT_TRACKER_ANNOUNCES;
|
||||
|
||||
static {
|
||||
Set<String> ann = new HashSet();
|
||||
for (int i = 1; i < DEFAULT_TRACKERS.length; i += 2) {
|
||||
String urls[] = DEFAULT_TRACKERS[i].split("=", 2);
|
||||
ann.add(urls[0]);
|
||||
}
|
||||
DEFAULT_TRACKER_ANNOUNCES = Collections.unmodifiableSet(ann);
|
||||
}
|
||||
|
||||
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
|
||||
public static final String PROP_TRACKERS = "i2psnark.trackers";
|
||||
|
||||
@@ -146,20 +159,20 @@ public class SnarkManager implements CompleteListener {
|
||||
* @since 0.9.6
|
||||
*/
|
||||
public SnarkManager(I2PAppContext ctx, String ctxPath, String ctxName) {
|
||||
_snarks = new ConcurrentHashMap();
|
||||
_magnets = new ConcurrentHashSet();
|
||||
_snarks = new ConcurrentHashMap<String, Snark>();
|
||||
_magnets = new ConcurrentHashSet<String>();
|
||||
_addSnarkLock = new Object();
|
||||
_context = ctx;
|
||||
_contextPath = ctxPath;
|
||||
_contextName = ctxName;
|
||||
_log = _context.logManager().getLog(SnarkManager.class);
|
||||
_messages = new LinkedBlockingQueue();
|
||||
_messages = new LinkedBlockingQueue<String>();
|
||||
_util = new I2PSnarkUtil(_context, ctxName);
|
||||
String cfile = ctxName + CONFIG_FILE_SUFFIX;
|
||||
_configFile = new File(cfile);
|
||||
if (!_configFile.isAbsolute())
|
||||
_configFile = new File(_context.getConfigDir(), cfile);
|
||||
_trackerMap = new ConcurrentHashMap(4);
|
||||
_trackerMap = new ConcurrentHashMap<String, Tracker>(4);
|
||||
loadConfig(null);
|
||||
}
|
||||
|
||||
@@ -169,7 +182,7 @@ public class SnarkManager implements CompleteListener {
|
||||
public void start() {
|
||||
_running = true;
|
||||
_peerCoordinatorSet = new PeerCoordinatorSet();
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util);
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
||||
_monitor.start();
|
||||
// only if default instance
|
||||
@@ -178,6 +191,8 @@ public class SnarkManager implements CompleteListener {
|
||||
_context.simpleScheduler().addEvent(new Register(), 4*60*1000);
|
||||
// Not required, Jetty has a shutdown hook
|
||||
//_context.addShutdownTask(new SnarkManagerShutdown());
|
||||
_idleChecker = new IdleChecker(this, _peerCoordinatorSet);
|
||||
_idleChecker.schedule(5*60*1000);
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
@@ -185,10 +200,13 @@ public class SnarkManager implements CompleteListener {
|
||||
public void timeReached() {
|
||||
if (!_running)
|
||||
return;
|
||||
_umgr = _context.updateManager();
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
_umgr = (UpdateManager) cmgr.getRegisteredApp(UpdateManager.APP_NAME);
|
||||
if (_umgr != null) {
|
||||
_uhandler = new UpdateHandler(_context, _umgr, SnarkManager.this);
|
||||
_umgr.register(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT, 10);
|
||||
_umgr.register(_uhandler, UpdateType.ROUTER_SIGNED_SU3, UpdateMethod.TORRENT, 10);
|
||||
_log.warn("Registering with update manager");
|
||||
} else {
|
||||
_log.warn("No update manager to register with");
|
||||
@@ -206,10 +224,12 @@ public class SnarkManager implements CompleteListener {
|
||||
if (_umgr != null && _uhandler != null) {
|
||||
//_uhandler.shutdown();
|
||||
_umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
|
||||
_umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED_SU3, UpdateMethod.TORRENT);
|
||||
}
|
||||
_running = false;
|
||||
_monitor.interrupt();
|
||||
_connectionAcceptor.halt();
|
||||
_idleChecker.cancel();
|
||||
stopAllTorrents(true);
|
||||
}
|
||||
|
||||
@@ -221,7 +241,20 @@ public class SnarkManager implements CompleteListener {
|
||||
|
||||
private static final int MAX_MESSAGES = 100;
|
||||
|
||||
/**
|
||||
* Use if it does not include a link.
|
||||
* Escapes '<' and '>' before queueing
|
||||
*/
|
||||
public void addMessage(String message) {
|
||||
addMessageNoEscape(message.replace("<", "<").replace(">", ">"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use if it includes a link.
|
||||
* Does not escape '<' and '>' before queueing
|
||||
* @since 0.9.14.1
|
||||
*/
|
||||
public void addMessageNoEscape(String message) {
|
||||
_messages.offer(message);
|
||||
while (_messages.size() > MAX_MESSAGES) {
|
||||
_messages.poll();
|
||||
@@ -233,8 +266,8 @@ public class SnarkManager implements CompleteListener {
|
||||
/** newest last */
|
||||
public List<String> getMessages() {
|
||||
if (_messages.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
return new ArrayList(_messages);
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<String>(_messages);
|
||||
}
|
||||
|
||||
/** @since 0.9 */
|
||||
@@ -419,7 +452,7 @@ public class SnarkManager implements CompleteListener {
|
||||
String i2cpHost = _config.getProperty(PROP_I2CP_HOST);
|
||||
int i2cpPort = getInt(PROP_I2CP_PORT, 7654);
|
||||
String opts = _config.getProperty(PROP_I2CP_OPTS);
|
||||
Map i2cpOpts = new HashMap();
|
||||
Map<String, String> i2cpOpts = new HashMap<String, String>();
|
||||
if (opts != null) {
|
||||
StringTokenizer tok = new StringTokenizer(opts, " ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
@@ -524,7 +557,7 @@ public class SnarkManager implements CompleteListener {
|
||||
_util.setStartupDelay(minutes);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_STARTUP_DELAY, Integer.toString(minutes));
|
||||
addMessage(_("Startup delay changed to {0}", DataHelper.formatDuration2(minutes * 60 * 1000)));
|
||||
addMessage(_("Startup delay changed to {0}", DataHelper.formatDuration2(minutes * (60L * 1000))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +592,7 @@ public class SnarkManager implements CompleteListener {
|
||||
}
|
||||
|
||||
if (dataDir != null && !dataDir.equals(getDataDir().getAbsolutePath())) {
|
||||
dataDir = dataDir.trim();
|
||||
dataDir = DataHelper.stripHTML(dataDir.trim());
|
||||
File dd = new File(dataDir);
|
||||
if (!dd.isAbsolute()) {
|
||||
addMessage(_("Data directory must be an absolute path") + ": " + dataDir);
|
||||
@@ -588,8 +621,8 @@ public class SnarkManager implements CompleteListener {
|
||||
try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
Map<String, String> opts = new HashMap();
|
||||
if (i2cpOpts == null) i2cpOpts = "";
|
||||
Map<String, String> opts = new HashMap<String, String>();
|
||||
i2cpOpts = DataHelper.stripHTML(i2cpOpts);
|
||||
StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String pair = tok.nextToken();
|
||||
@@ -597,7 +630,7 @@ public class SnarkManager implements CompleteListener {
|
||||
if (split > 0)
|
||||
opts.put(pair.substring(0, split), pair.substring(split+1));
|
||||
}
|
||||
Map<String, String> oldOpts = new HashMap();
|
||||
Map<String, String> oldOpts = new HashMap<String, String>();
|
||||
String oldI2CPOpts = _config.getProperty(PROP_I2CP_OPTS);
|
||||
if (oldI2CPOpts == null) oldI2CPOpts = "";
|
||||
tok = new StringTokenizer(oldI2CPOpts, " \t\n");
|
||||
@@ -635,6 +668,7 @@ public class SnarkManager implements CompleteListener {
|
||||
addMessage(_("I2CP options changed to {0}", i2cpOpts));
|
||||
_util.setI2CPConfig(oldI2CPHost, oldI2CPPort, opts);
|
||||
} else {
|
||||
// Won't happen, I2CP host/port, are hidden in the GUI if in router context
|
||||
if (_util.connected()) {
|
||||
_util.disconnect();
|
||||
addMessage(_("Disconnecting old I2CP destination"));
|
||||
@@ -658,6 +692,8 @@ public class SnarkManager implements CompleteListener {
|
||||
for (Snark snark : _snarks.values()) {
|
||||
if (snark.restartAcceptor()) {
|
||||
addMessage(_("I2CP listener restarted for \"{0}\"", snark.getBaseName()));
|
||||
// this is the common ConnectionAcceptor, so we only need to do it once
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -727,7 +763,7 @@ public class SnarkManager implements CompleteListener {
|
||||
*/
|
||||
private List<String> getOpenTrackers() {
|
||||
if (!_util.shouldUseOpenTrackers())
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
return getListConfig(PROP_OPENTRACKERS, I2PSnarkUtil.DEFAULT_OPENTRACKERS);
|
||||
}
|
||||
|
||||
@@ -744,7 +780,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void saveOpenTrackers(List<String> ot) {
|
||||
String val = setListConfig(PROP_OPENTRACKERS, ot);
|
||||
setListConfig(PROP_OPENTRACKERS, ot);
|
||||
if (ot == null)
|
||||
ot = Collections.singletonList(I2PSnarkUtil.DEFAULT_OPENTRACKERS);
|
||||
_util.setOpenTrackers(ot);
|
||||
@@ -772,7 +808,7 @@ public class SnarkManager implements CompleteListener {
|
||||
if (val == null)
|
||||
val = dflt;
|
||||
if (val == null)
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
return Arrays.asList(val.split(","));
|
||||
}
|
||||
|
||||
@@ -823,7 +859,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* An unsynchronized copy.
|
||||
*/
|
||||
public Set<String> listTorrentFiles() {
|
||||
return new HashSet(_snarks.keySet());
|
||||
return new HashSet<String>(_snarks.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -894,7 +930,7 @@ public class SnarkManager implements CompleteListener {
|
||||
filename = sfile.getCanonicalPath();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to add the torrent " + filename, ioe);
|
||||
addMessage(_("Error: Could not add the torrent {0}", filename) + ": " + ioe.getMessage());
|
||||
addMessage(_("Error: Could not add the torrent {0}", filename) + ": " + ioe);
|
||||
return;
|
||||
}
|
||||
File dataDir = getDataDir();
|
||||
@@ -1008,7 +1044,8 @@ public class SnarkManager implements CompleteListener {
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus) {
|
||||
addMagnet(name, ih, trackerURL, updateStatus, shouldAutoStart(), this);
|
||||
// updateStatus is true from UI, false from config file bulk add
|
||||
addMagnet(name, ih, trackerURL, updateStatus, updateStatus, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1375,7 +1412,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* @return failure message or null on success
|
||||
*/
|
||||
private String validateTorrent(MetaInfo info) {
|
||||
List files = info.getFiles();
|
||||
List<List<String>> files = info.getFiles();
|
||||
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
|
||||
return _("Too many files in \"{0}\" ({1}), deleting it!", info.getName(), files.size());
|
||||
} else if ( (files == null) && (info.getName().endsWith(".torrent")) ) {
|
||||
@@ -1391,7 +1428,7 @@ public class SnarkManager implements CompleteListener {
|
||||
return _("Torrent \"{0}\" has no data, deleting it!", info.getName());
|
||||
} else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) {
|
||||
System.out.println("torrent info: " + info.toString());
|
||||
List lengths = info.getLengths();
|
||||
List<Long> lengths = info.getLengths();
|
||||
if (lengths != null)
|
||||
for (int i = 0; i < lengths.size(); i++)
|
||||
System.out.println("File " + i + " is " + lengths.get(i) + " long.");
|
||||
@@ -1478,7 +1515,7 @@ public class SnarkManager implements CompleteListener {
|
||||
private class DirMonitor implements Runnable {
|
||||
public void run() {
|
||||
// don't bother delaying if auto start is false
|
||||
long delay = 60 * 1000 * getStartupDelayMinutes();
|
||||
long delay = (60L * 1000) * getStartupDelayMinutes();
|
||||
if (delay > 0 && shouldAutoStart()) {
|
||||
addMessage(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
@@ -1533,7 +1570,7 @@ public class SnarkManager implements CompleteListener {
|
||||
if (meta.getFiles() != null)
|
||||
buf.append('/');
|
||||
buf.append("\">").append(storage.getBaseName()).append("</a>");
|
||||
addMessage(_("Download finished: {0}", buf.toString())); // + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')');
|
||||
addMessageNoEscape(_("Download finished: {0}", buf.toString())); // + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')');
|
||||
updateStatus(snark);
|
||||
}
|
||||
|
||||
@@ -1643,7 +1680,7 @@ public class SnarkManager implements CompleteListener {
|
||||
*/
|
||||
private void monitorTorrents(File dir) {
|
||||
String fileNames[] = dir.list(TorrentFilenameFilter.instance());
|
||||
List<String> foundNames = new ArrayList(0);
|
||||
List<String> foundNames = new ArrayList<String>(0);
|
||||
if (fileNames != null) {
|
||||
for (int i = 0; i < fileNames.length; i++) {
|
||||
try {
|
||||
@@ -1658,8 +1695,8 @@ public class SnarkManager implements CompleteListener {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
|
||||
// lets find new ones first...
|
||||
for (int i = 0; i < foundNames.size(); i++) {
|
||||
if (existingNames.contains(foundNames.get(i))) {
|
||||
for (String name : foundNames) {
|
||||
if (existingNames.contains(name)) {
|
||||
// already known. noop
|
||||
} else {
|
||||
if (shouldAutoStart() && !_util.connect())
|
||||
@@ -1667,17 +1704,17 @@ public class SnarkManager implements CompleteListener {
|
||||
try {
|
||||
// Snark.fatal() throws a RuntimeException
|
||||
// don't let one bad torrent kill the whole loop
|
||||
addTorrent(foundNames.get(i), !shouldAutoStart());
|
||||
addTorrent(name, !shouldAutoStart());
|
||||
} catch (Exception e) {
|
||||
addMessage(_("Unable to add {0}", foundNames.get(i)) + ": " + e);
|
||||
addMessage(_("Error: Could not add the torrent {0}", name) + ": " + e);
|
||||
_log.error("Unable to add the torrent " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't remove magnet torrents that don't have a torrent file yet
|
||||
existingNames.removeAll(_magnets);
|
||||
// now lets see which ones have been removed...
|
||||
for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
for (String name : existingNames) {
|
||||
if (foundNames.contains(name)) {
|
||||
// known and still there. noop
|
||||
} else {
|
||||
@@ -1729,7 +1766,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public List<Tracker> getSortedTrackers() {
|
||||
List<Tracker> rv = new ArrayList(_trackerMap.values());
|
||||
List<Tracker> rv = new ArrayList<Tracker>(_trackerMap.values());
|
||||
Collections.sort(rv, new IgnoreCaseComparator());
|
||||
return rv;
|
||||
}
|
||||
@@ -1855,6 +1892,14 @@ public class SnarkManager implements CompleteListener {
|
||||
private final Snark snark;
|
||||
public ThreadedStarter(Snark s) { snark = s; }
|
||||
public void run() {
|
||||
try {
|
||||
run2();
|
||||
} catch (Exception e) {
|
||||
_log.error("Error starting", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void run2() {
|
||||
if (snark != null) {
|
||||
if (snark.isStopped())
|
||||
snark.startTorrent();
|
||||
@@ -1938,7 +1983,7 @@ public class SnarkManager implements CompleteListener {
|
||||
* ignore case, current locale
|
||||
* @since 0.9
|
||||
*/
|
||||
private static class IgnoreCaseComparator implements Comparator<Tracker> {
|
||||
private static class IgnoreCaseComparator implements Comparator<Tracker>, Serializable {
|
||||
public int compare(Tracker l, Tracker r) {
|
||||
return l.name.toLowerCase().compareTo(r.name.toLowerCase());
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -50,17 +51,7 @@ import net.i2p.util.SystemVersion;
|
||||
public class Storage
|
||||
{
|
||||
private final MetaInfo metainfo;
|
||||
private long[] lengths;
|
||||
private RandomAccessFile[] rafs;
|
||||
private String[] names;
|
||||
private Object[] RAFlock; // lock on RAF access
|
||||
private long[] RAFtime; // when was RAF last accessed, or 0 if closed
|
||||
private File[] RAFfile; // File to make it easier to reopen
|
||||
/** priorities by file; default 0; may be null. @since 0.8.1 */
|
||||
private int[] priorities;
|
||||
/** is the file empty and sparse? */
|
||||
private boolean[] isSparse;
|
||||
|
||||
private final List<TorrentFile> _torrentFiles;
|
||||
private final StorageListener listener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final Log _log;
|
||||
@@ -78,13 +69,13 @@ public class Storage
|
||||
|
||||
/** The default piece size. */
|
||||
private static final int DEFAULT_PIECE_SIZE = 256*1024;
|
||||
/** note that we start reducing max number of peer connections above 1MB */
|
||||
public static final int MAX_PIECE_SIZE = 2*1024*1024;
|
||||
/** bigger than this will be rejected */
|
||||
public static final int MAX_PIECE_SIZE = 4*1024*1024;
|
||||
/** The maximum number of pieces in a torrent. */
|
||||
public static final int MAX_PIECES = 10*1024;
|
||||
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
|
||||
|
||||
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap();
|
||||
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap<String, String>();
|
||||
|
||||
private static final boolean _isWindows = SystemVersion.isWindows();
|
||||
|
||||
@@ -108,6 +99,9 @@ public class Storage
|
||||
piece_size = metainfo.getPieceLength(0);
|
||||
pieces = needed;
|
||||
total_length = metainfo.getTotalLength();
|
||||
List<List<String>> files = metainfo.getFiles();
|
||||
int sz = files != null ? files.size() : 1;
|
||||
_torrentFiles = new ArrayList<TorrentFile>(sz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,13 +124,13 @@ public class Storage
|
||||
_log = util.getContext().logManager().getLog(Storage.class);
|
||||
this.listener = listener;
|
||||
// Create names, rafs and lengths arrays.
|
||||
getFiles(baseFile);
|
||||
_torrentFiles = getFiles(baseFile);
|
||||
|
||||
long total = 0;
|
||||
ArrayList<Long> lengthsList = new ArrayList();
|
||||
for (int i = 0; i < lengths.length; i++)
|
||||
ArrayList<Long> lengthsList = new ArrayList<Long>();
|
||||
for (TorrentFile tf : _torrentFiles)
|
||||
{
|
||||
long length = lengths[i];
|
||||
long length = tf.length;
|
||||
total += length;
|
||||
lengthsList.add(Long.valueOf(length));
|
||||
}
|
||||
@@ -166,11 +160,11 @@ public class Storage
|
||||
bitfield = new BitField(pieces);
|
||||
needed = 0;
|
||||
|
||||
List<List<String>> files = new ArrayList();
|
||||
for (int i = 0; i < names.length; i++)
|
||||
List<List<String>> files = new ArrayList<List<String>>();
|
||||
for (TorrentFile tf : _torrentFiles)
|
||||
{
|
||||
List<String> file = new ArrayList();
|
||||
StringTokenizer st = new StringTokenizer(names[i], File.separator);
|
||||
List<String> file = new ArrayList<String>();
|
||||
StringTokenizer st = new StringTokenizer(tf.name, File.separator);
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
String part = st.nextToken();
|
||||
@@ -179,8 +173,7 @@ public class Storage
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
if (files.size() == 1) // FIXME: ...and if base file not a directory or should this be the only check?
|
||||
// this makes a bad metainfo if the directory has only one file in it
|
||||
if (files.size() == 1 && !baseFile.isDirectory())
|
||||
{
|
||||
files = null;
|
||||
lengthsList = null;
|
||||
@@ -221,42 +214,29 @@ public class Storage
|
||||
return piece_hashes;
|
||||
}
|
||||
|
||||
private void getFiles(File base) throws IOException
|
||||
private List<TorrentFile> getFiles(File base) throws IOException
|
||||
{
|
||||
if (base.getAbsolutePath().equals("/"))
|
||||
throw new IOException("Don't seed root");
|
||||
ArrayList files = new ArrayList();
|
||||
List<File> files = new ArrayList<File>();
|
||||
addFiles(files, base);
|
||||
|
||||
int size = files.size();
|
||||
names = new String[size];
|
||||
lengths = new long[size];
|
||||
rafs = new RandomAccessFile[size];
|
||||
RAFlock = new Object[size];
|
||||
RAFtime = new long[size];
|
||||
RAFfile = new File[size];
|
||||
priorities = new int[size];
|
||||
isSparse = new boolean[size];
|
||||
List<TorrentFile> rv = new ArrayList<TorrentFile>(size);
|
||||
|
||||
int i = 0;
|
||||
Iterator it = files.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
File f = (File)it.next();
|
||||
names[i] = f.getPath();
|
||||
if (base.isDirectory() && names[i].startsWith(base.getPath()))
|
||||
names[i] = names[i].substring(base.getPath().length() + 1);
|
||||
lengths[i] = f.length();
|
||||
RAFlock[i] = new Object();
|
||||
RAFfile[i] = f;
|
||||
i++;
|
||||
}
|
||||
for (File f : files) {
|
||||
rv.add(new TorrentFile(base, f));
|
||||
}
|
||||
// Sort to prevent exposing OS type, and to make it more likely
|
||||
// the same torrent created twice will have the same infohash.
|
||||
Collections.sort(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IOException if too many total files
|
||||
*/
|
||||
private void addFiles(List l, File f) throws IOException {
|
||||
private void addFiles(List<File> l, File f) throws IOException {
|
||||
if (!f.isDirectory()) {
|
||||
if (l.size() >= SnarkManager.MAX_FILES_PER_TORRENT)
|
||||
throw new IOException("Too many files, limit is " + SnarkManager.MAX_FILES_PER_TORRENT + ", zip them?");
|
||||
@@ -331,8 +311,8 @@ public class Storage
|
||||
*/
|
||||
public long remaining(String file) {
|
||||
long bytes = 0;
|
||||
for (int i = 0; i < rafs.length; i++) {
|
||||
File f = RAFfile[i];
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
// use canonical in case snark dir or sub dirs are symlinked
|
||||
String canonical = null;
|
||||
if (f != null) {
|
||||
@@ -347,11 +327,11 @@ public class Storage
|
||||
return 0;
|
||||
int psz = piece_size;
|
||||
long start = bytes;
|
||||
long end = start + lengths[i];
|
||||
long end = start + tf.length;
|
||||
int pc = (int) (bytes / psz);
|
||||
long rv = 0;
|
||||
if (!bitfield.get(pc))
|
||||
rv = Math.min(psz - (start % psz), lengths[i]);
|
||||
rv = Math.min(psz - (start % psz), tf.length);
|
||||
for (int j = pc + 1; (((long)j) * psz) < end && j < pieces; j++) {
|
||||
if (!bitfield.get(j)) {
|
||||
if (((long)(j+1))*psz < end)
|
||||
@@ -362,7 +342,7 @@ public class Storage
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
bytes += lengths[i];
|
||||
bytes += tf.length;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -372,16 +352,16 @@ public class Storage
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public int getPriority(String file) {
|
||||
if (complete() || metainfo.getFiles() == null || priorities == null)
|
||||
if (complete() || metainfo.getFiles() == null)
|
||||
return 0;
|
||||
for (int i = 0; i < rafs.length; i++) {
|
||||
File f = RAFfile[i];
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
// use canonical in case snark dir or sub dirs are symlinked
|
||||
if (f != null) {
|
||||
try {
|
||||
String canonical = f.getCanonicalPath();
|
||||
if (canonical.equals(file))
|
||||
return priorities[i];
|
||||
return tf.priority;
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
@@ -396,16 +376,16 @@ public class Storage
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public void setPriority(String file, int pri) {
|
||||
if (complete() || metainfo.getFiles() == null || priorities == null)
|
||||
if (complete() || metainfo.getFiles() == null)
|
||||
return;
|
||||
for (int i = 0; i < rafs.length; i++) {
|
||||
File f = RAFfile[i];
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
// use canonical in case snark dir or sub dirs are symlinked
|
||||
if (f != null) {
|
||||
try {
|
||||
String canonical = f.getCanonicalPath();
|
||||
if (canonical.equals(file)) {
|
||||
priorities[i] = pri;
|
||||
tf.priority = pri;
|
||||
return;
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
@@ -419,6 +399,15 @@ public class Storage
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public int[] getFilePriorities() {
|
||||
if (complete())
|
||||
return null;
|
||||
int sz = _torrentFiles.size();
|
||||
if (sz <= 1)
|
||||
return null;
|
||||
int[] priorities = new int[sz];
|
||||
for (int i = 0; i < sz; i++) {
|
||||
priorities[i] = _torrentFiles.get(i).priority;
|
||||
}
|
||||
return priorities;
|
||||
}
|
||||
|
||||
@@ -429,7 +418,18 @@ public class Storage
|
||||
* @since 0.8.1
|
||||
*/
|
||||
void setFilePriorities(int[] p) {
|
||||
priorities = p;
|
||||
if (p == null) {
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
tf.priority = 0;
|
||||
}
|
||||
} else {
|
||||
int sz = _torrentFiles.size();
|
||||
if (p.length != sz)
|
||||
throw new IllegalArgumentException();
|
||||
for (int i = 0; i < sz; i++) {
|
||||
_torrentFiles.get(i).priority = p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,22 +442,23 @@ public class Storage
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public int[] getPiecePriorities() {
|
||||
if (complete() || metainfo.getFiles() == null || priorities == null)
|
||||
if (complete() || metainfo.getFiles() == null)
|
||||
return null;
|
||||
int[] rv = new int[metainfo.getPieces()];
|
||||
int file = 0;
|
||||
long pcEnd = -1;
|
||||
long fileEnd = lengths[0] - 1;
|
||||
long fileEnd = _torrentFiles.get(0).length - 1;
|
||||
int psz = piece_size;
|
||||
for (int i = 0; i < rv.length; i++) {
|
||||
pcEnd += psz;
|
||||
int pri = priorities[file];
|
||||
while (fileEnd <= pcEnd && file < lengths.length - 1) {
|
||||
int pri = _torrentFiles.get(file).priority;
|
||||
while (fileEnd <= pcEnd && file < _torrentFiles.size() - 1) {
|
||||
file++;
|
||||
TorrentFile tf = _torrentFiles.get(file);
|
||||
long oldFileEnd = fileEnd;
|
||||
fileEnd += lengths[file];
|
||||
if (priorities[file] > pri && oldFileEnd < pcEnd)
|
||||
pri = priorities[file];
|
||||
fileEnd += tf.length;
|
||||
if (tf.priority > pri && oldFileEnd < pcEnd)
|
||||
pri = tf.priority;
|
||||
}
|
||||
rv[i] = pri;
|
||||
}
|
||||
@@ -487,13 +488,18 @@ public class Storage
|
||||
|
||||
/**
|
||||
* Creates (and/or checks) all files from the metainfo file list.
|
||||
* Only call this once, and only after the constructor with the metainfo.
|
||||
*/
|
||||
public void check(String rootDir) throws IOException
|
||||
{
|
||||
check(rootDir, 0, null);
|
||||
}
|
||||
|
||||
/** use a saved bitfield and timestamp from a config file */
|
||||
/**
|
||||
* Creates (and/or checks) all files from the metainfo file list.
|
||||
* Use a saved bitfield and timestamp from a config file.
|
||||
* Only call this once, and only after the constructor with the metainfo.
|
||||
*/
|
||||
public void check(String rootDir, long savedTime, BitField savedBitField) throws IOException
|
||||
{
|
||||
File base;
|
||||
@@ -504,31 +510,27 @@ public class Storage
|
||||
base = new SecureFile(rootDir, filterName(metainfo.getName()));
|
||||
boolean useSavedBitField = savedTime > 0 && savedBitField != null;
|
||||
|
||||
if (!_torrentFiles.isEmpty())
|
||||
throw new IllegalStateException();
|
||||
List<List<String>> files = metainfo.getFiles();
|
||||
if (files == null)
|
||||
{
|
||||
// Create base as file.
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Creating/Checking file: " + base);
|
||||
if (!base.createNewFile() && !base.exists())
|
||||
// createNewFile() can throw a "Permission denied" IOE even if the file exists???
|
||||
// so do it second
|
||||
if (!base.exists() && !base.createNewFile())
|
||||
throw new IOException("Could not create file " + base);
|
||||
|
||||
lengths = new long[1];
|
||||
rafs = new RandomAccessFile[1];
|
||||
names = new String[1];
|
||||
RAFlock = new Object[1];
|
||||
RAFtime = new long[1];
|
||||
RAFfile = new File[1];
|
||||
isSparse = new boolean[1];
|
||||
lengths[0] = metainfo.getTotalLength();
|
||||
RAFlock[0] = new Object();
|
||||
RAFfile[0] = base;
|
||||
_torrentFiles.add(new TorrentFile(base, base, metainfo.getTotalLength()));
|
||||
if (useSavedBitField) {
|
||||
long lm = base.lastModified();
|
||||
if (lm <= 0 || lm > savedTime)
|
||||
useSavedBitField = false;
|
||||
else if (base.length() != metainfo.getTotalLength())
|
||||
useSavedBitField = false;
|
||||
}
|
||||
names[0] = base.getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -541,23 +543,16 @@ public class Storage
|
||||
List<Long> ls = metainfo.getLengths();
|
||||
int size = files.size();
|
||||
long total = 0;
|
||||
lengths = new long[size];
|
||||
rafs = new RandomAccessFile[size];
|
||||
names = new String[size];
|
||||
RAFlock = new Object[size];
|
||||
RAFtime = new long[size];
|
||||
RAFfile = new File[size];
|
||||
isSparse = new boolean[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
List<String> path = files.get(i);
|
||||
File f = createFileFromNames(base, path, areFilesPublic);
|
||||
// dup file name check after filtering
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (f.equals(RAFfile[j])) {
|
||||
if (f.equals(_torrentFiles.get(j).RAFfile)) {
|
||||
// Rename and start the check over again
|
||||
// Copy path since metainfo list is unmodifiable
|
||||
path = new ArrayList(path);
|
||||
path = new ArrayList<String>(path);
|
||||
int last = path.size() - 1;
|
||||
String lastPath = path.get(last);
|
||||
int dot = lastPath.lastIndexOf('.');
|
||||
@@ -571,16 +566,16 @@ public class Storage
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
lengths[i] = ls.get(i).longValue();
|
||||
RAFlock[i] = new Object();
|
||||
RAFfile[i] = f;
|
||||
total += lengths[i];
|
||||
long len = ls.get(i).longValue();
|
||||
_torrentFiles.add(new TorrentFile(base, f, len));
|
||||
total += len;
|
||||
if (useSavedBitField) {
|
||||
long lm = f.lastModified();
|
||||
if (lm <= 0 || lm > savedTime)
|
||||
useSavedBitField = false;
|
||||
else if (f.length() != len)
|
||||
useSavedBitField = false;
|
||||
}
|
||||
names[i] = f.getName();
|
||||
}
|
||||
|
||||
// Sanity check for metainfo file.
|
||||
@@ -598,6 +593,8 @@ public class Storage
|
||||
} else {
|
||||
// the following sets the needed variable
|
||||
changed = true;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Forcing check");
|
||||
checkCreateFiles(false);
|
||||
}
|
||||
if (complete()) {
|
||||
@@ -605,8 +602,6 @@ public class Storage
|
||||
_log.info("Torrent is complete");
|
||||
} else {
|
||||
// fixme saved priorities
|
||||
if (files != null)
|
||||
priorities = new int[files.size()];
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Still need " + needed + " out of " + metainfo.getPieces() + " pieces");
|
||||
}
|
||||
@@ -621,11 +616,11 @@ public class Storage
|
||||
*/
|
||||
public void reopen(String rootDir) throws IOException
|
||||
{
|
||||
if (RAFfile == null)
|
||||
if (_torrentFiles.isEmpty())
|
||||
throw new IOException("Storage not checked yet");
|
||||
for (int i = 0; i < RAFfile.length; i++) {
|
||||
if (!RAFfile[i].exists())
|
||||
throw new IOException("File does not exist: " + RAFfile[i]);
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
if (!tf.RAFfile.exists())
|
||||
throw new IOException("File does not exist: " + tf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,7 +716,9 @@ public class Storage
|
||||
f = new File(base, name);
|
||||
else
|
||||
f = new SecureFile(base, name);
|
||||
if (!f.createNewFile() && !f.exists())
|
||||
// createNewFile() can throw a "Permission denied" IOE even if the file exists???
|
||||
// so do it second
|
||||
if (!f.exists() && !f.createNewFile())
|
||||
throw new IOException("Could not create file " + f);
|
||||
}
|
||||
}
|
||||
@@ -779,10 +776,10 @@ public class Storage
|
||||
|
||||
// Make sure all files are available and of correct length
|
||||
// The files should all exist as they have been created with zero length by createFilesFromNames()
|
||||
for (int i = 0; i < rafs.length; i++)
|
||||
for (TorrentFile tf : _torrentFiles)
|
||||
{
|
||||
long length = RAFfile[i].length();
|
||||
if(RAFfile[i].exists() && length == lengths[i])
|
||||
long length = tf.RAFfile.length();
|
||||
if(tf.RAFfile.exists() && length == tf.length)
|
||||
{
|
||||
if (listener != null)
|
||||
listener.storageAllocated(this, length);
|
||||
@@ -790,27 +787,27 @@ public class Storage
|
||||
}
|
||||
else if (length == 0) {
|
||||
changed = true;
|
||||
synchronized(RAFlock[i]) {
|
||||
allocateFile(i);
|
||||
synchronized(tf) {
|
||||
allocateFile(tf);
|
||||
// close as we go so we don't run out of file descriptors
|
||||
try {
|
||||
closeRAF(i);
|
||||
tf.closeRAF();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
} else {
|
||||
String msg = "File '" + names[i] + "' exists, but has wrong length (expected " +
|
||||
lengths[i] + " but found " + length + ") - repairing corruption";
|
||||
String msg = "File '" + tf.name + "' exists, but has wrong length (expected " +
|
||||
tf.length + " but found " + length + ") - repairing corruption";
|
||||
if (listener != null)
|
||||
listener.addMessage(msg);
|
||||
_log.error(msg);
|
||||
changed = true;
|
||||
resume = true;
|
||||
_probablyComplete = false; // to force RW
|
||||
synchronized(RAFlock[i]) {
|
||||
checkRAF(i);
|
||||
rafs[i].setLength(lengths[i]);
|
||||
synchronized(tf) {
|
||||
RandomAccessFile raf = tf.checkRAF();
|
||||
raf.setLength(tf.length);
|
||||
try {
|
||||
closeRAF(i);
|
||||
tf.closeRAF();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
@@ -821,7 +818,7 @@ public class Storage
|
||||
{
|
||||
byte[] piece = new byte[piece_size];
|
||||
int file = 0;
|
||||
long fileEnd = lengths[0];
|
||||
long fileEnd = _torrentFiles.get(0).length;
|
||||
long pieceEnd = 0;
|
||||
for (int i = 0; i < pieces; i++)
|
||||
{
|
||||
@@ -830,14 +827,15 @@ public class Storage
|
||||
// close as we go so we don't run out of file descriptors
|
||||
pieceEnd += length;
|
||||
while (fileEnd <= pieceEnd) {
|
||||
synchronized(RAFlock[file]) {
|
||||
TorrentFile tf = _torrentFiles.get(file);
|
||||
synchronized(tf) {
|
||||
try {
|
||||
closeRAF(file);
|
||||
tf.closeRAF();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
if (++file >= rafs.length)
|
||||
if (++file >= _torrentFiles.size())
|
||||
break;
|
||||
fileEnd += lengths[file];
|
||||
fileEnd += _torrentFiles.get(file).length;
|
||||
}
|
||||
if (correctHash)
|
||||
{
|
||||
@@ -883,59 +881,17 @@ public class Storage
|
||||
* Sets isSparse[nr] = true. balloonFile(nr) should be called later to
|
||||
* defrag the file.
|
||||
*
|
||||
* This calls openRAF(); caller must synchronize and call closeRAF().
|
||||
* This calls OpenRAF(); caller must synchronize and call closeRAF().
|
||||
*/
|
||||
private void allocateFile(int nr) throws IOException
|
||||
private void allocateFile(TorrentFile tf) throws IOException
|
||||
{
|
||||
// caller synchronized
|
||||
openRAF(nr, false); // RW
|
||||
long remaining = lengths[nr];
|
||||
if (listener != null)
|
||||
listener.storageCreateFile(this, names[nr], remaining);
|
||||
rafs[nr].setLength(remaining);
|
||||
// don't bother ballooning later on Windows since there is no sparse file support
|
||||
// until JDK7 using the JSR-203 interface.
|
||||
// RAF seeks/writes do not create sparse files.
|
||||
// Windows will zero-fill up to the point of the write, which
|
||||
// will make the file fairly unfragmented, on average, at least until
|
||||
// near the end where it will get exponentially more fragmented.
|
||||
if (!_isWindows)
|
||||
isSparse[nr] = true;
|
||||
// caller will close rafs[nr]
|
||||
if (listener != null)
|
||||
listener.storageAllocated(this, lengths[nr]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This "balloons" the file with zeros to eliminate disk fragmentation.,
|
||||
* Overwrites the entire file with zeros. Sets isSparse[nr] = false.
|
||||
*
|
||||
* Caller must synchronize and call checkRAF() or openRAF().
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private void balloonFile(int nr) throws IOException
|
||||
{
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Ballooning " + nr + ": " + RAFfile[nr]);
|
||||
long remaining = lengths[nr];
|
||||
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
|
||||
byte[] zeros = new byte[ZEROBLOCKSIZE];
|
||||
rafs[nr].seek(0);
|
||||
// don't bother setting flag for small files
|
||||
if (remaining > 20*1024*1024)
|
||||
_allocateCount.incrementAndGet();
|
||||
try {
|
||||
while (remaining > 0) {
|
||||
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
|
||||
rafs[nr].write(zeros, 0, size);
|
||||
remaining -= size;
|
||||
}
|
||||
} finally {
|
||||
remaining = lengths[nr];
|
||||
if (remaining > 20*1024*1024)
|
||||
_allocateCount.decrementAndGet();
|
||||
tf.allocateFile();
|
||||
if (listener != null) {
|
||||
listener.storageCreateFile(this, tf.name, tf.length);
|
||||
listener.storageAllocated(this, tf.length);
|
||||
}
|
||||
isSparse[nr] = false;
|
||||
// caller will close rafs[nr]
|
||||
}
|
||||
|
||||
|
||||
@@ -945,18 +901,14 @@ public class Storage
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (rafs == null) return;
|
||||
for (int i = 0; i < rafs.length; i++)
|
||||
for (TorrentFile tf : _torrentFiles)
|
||||
{
|
||||
// if we had an IOE in check(), the RAFlock may be null
|
||||
if (RAFlock[i] == null)
|
||||
continue;
|
||||
try {
|
||||
synchronized(RAFlock[i]) {
|
||||
closeRAF(i);
|
||||
synchronized(tf) {
|
||||
tf.closeRAF();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error closing " + RAFfile[i], ioe);
|
||||
_log.error("Error closing " + tf, ioe);
|
||||
// gobble gobble
|
||||
}
|
||||
}
|
||||
@@ -1021,40 +973,50 @@ public class Storage
|
||||
// Early typecast, avoid possibly overflowing a temp integer
|
||||
long start = (long) piece * (long) piece_size;
|
||||
int i = 0;
|
||||
long raflen = lengths[i];
|
||||
long raflen = _torrentFiles.get(i).length;
|
||||
while (start > raflen) {
|
||||
i++;
|
||||
start -= raflen;
|
||||
raflen = lengths[i];
|
||||
raflen = _torrentFiles.get(i).length;
|
||||
}
|
||||
|
||||
int written = 0;
|
||||
int off = 0;
|
||||
int length = metainfo.getPieceLength(piece);
|
||||
while (written < length) {
|
||||
int need = length - written;
|
||||
int len = (start + need < raflen) ? need : (int)(raflen - start);
|
||||
synchronized(RAFlock[i]) {
|
||||
checkRAF(i);
|
||||
if (isSparse[i]) {
|
||||
// If the file is a newly created sparse file,
|
||||
// AND we aren't skipping it, balloon it with all
|
||||
// zeros to un-sparse it by allocating the space.
|
||||
// Obviously this could take a while.
|
||||
// Once we have written to it, it isn't empty/sparse any more.
|
||||
if (priorities == null || priorities[i] >= 0)
|
||||
balloonFile(i);
|
||||
else
|
||||
isSparse[i] = false;
|
||||
TorrentFile tf = _torrentFiles.get(i);
|
||||
synchronized(tf) {
|
||||
try {
|
||||
RandomAccessFile raf = tf.checkRAF();
|
||||
if (tf.isSparse) {
|
||||
// If the file is a newly created sparse file,
|
||||
// AND we aren't skipping it, balloon it with all
|
||||
// zeros to un-sparse it by allocating the space.
|
||||
// Obviously this could take a while.
|
||||
// Once we have written to it, it isn't empty/sparse any more.
|
||||
if (tf.priority >= 0) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Ballooning " + tf);
|
||||
tf.balloonFile();
|
||||
} else {
|
||||
tf.isSparse = false;
|
||||
}
|
||||
}
|
||||
raf.seek(start);
|
||||
//rafs[i].write(bs, off + written, len);
|
||||
pp.write(raf, written, len);
|
||||
} catch (IOException ioe) {
|
||||
// get the file name in the logs
|
||||
IOException ioe2 = new IOException("Error writing " + tf.RAFfile.getAbsolutePath());
|
||||
ioe2.initCause(ioe);
|
||||
throw ioe2;
|
||||
}
|
||||
rafs[i].seek(start);
|
||||
//rafs[i].write(bs, off + written, len);
|
||||
pp.write(rafs[i], off + written, len);
|
||||
}
|
||||
written += len;
|
||||
if (need - len > 0) {
|
||||
i++;
|
||||
raflen = lengths[i];
|
||||
raflen = _torrentFiles.get(i).length;
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
@@ -1131,12 +1093,12 @@ public class Storage
|
||||
long start = ((long) piece * (long) piece_size) + off;
|
||||
|
||||
int i = 0;
|
||||
long raflen = lengths[i];
|
||||
long raflen = _torrentFiles.get(i).length;
|
||||
while (start > raflen)
|
||||
{
|
||||
i++;
|
||||
start -= raflen;
|
||||
raflen = lengths[i];
|
||||
raflen = _torrentFiles.get(i).length;
|
||||
}
|
||||
|
||||
int read = 0;
|
||||
@@ -1144,17 +1106,24 @@ public class Storage
|
||||
{
|
||||
int need = length - read;
|
||||
int len = (start + need < raflen) ? need : (int)(raflen - start);
|
||||
synchronized(RAFlock[i])
|
||||
{
|
||||
checkRAF(i);
|
||||
rafs[i].seek(start);
|
||||
rafs[i].readFully(bs, read, len);
|
||||
}
|
||||
TorrentFile tf = _torrentFiles.get(i);
|
||||
synchronized(tf) {
|
||||
try {
|
||||
RandomAccessFile raf = tf.checkRAF();
|
||||
raf.seek(start);
|
||||
raf.readFully(bs, read, len);
|
||||
} catch (IOException ioe) {
|
||||
// get the file name in the logs
|
||||
IOException ioe2 = new IOException("Error reading " + tf.RAFfile.getAbsolutePath());
|
||||
ioe2.initCause(ioe);
|
||||
throw ioe2;
|
||||
}
|
||||
}
|
||||
read += len;
|
||||
if (need - len > 0)
|
||||
{
|
||||
i++;
|
||||
raflen = lengths[i];
|
||||
raflen = _torrentFiles.get(i).length;
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
@@ -1162,58 +1131,191 @@ public class Storage
|
||||
return length;
|
||||
}
|
||||
|
||||
private static final long RAFCloseDelay = 4*60*1000;
|
||||
|
||||
/**
|
||||
* Close unused RAFs - call periodically
|
||||
*/
|
||||
private static final long RAFCloseDelay = 4*60*1000;
|
||||
public void cleanRAFs() {
|
||||
long cutoff = System.currentTimeMillis() - RAFCloseDelay;
|
||||
for (int i = 0; i < RAFlock.length; i++) {
|
||||
synchronized(RAFlock[i]) {
|
||||
if (RAFtime[i] > 0 && RAFtime[i] < cutoff) {
|
||||
try {
|
||||
closeRAF(i);
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
synchronized(tf) {
|
||||
tf.closeRAF(cutoff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each of the following,
|
||||
* caller must synchronize on RAFlock[i]
|
||||
* ... except at the beginning if you're careful
|
||||
*/
|
||||
|
||||
/**
|
||||
* This must be called before using the RAF to ensure it is open
|
||||
* A single file in a torrent.
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private void checkRAF(int i) throws IOException {
|
||||
if (RAFtime[i] > 0) {
|
||||
RAFtime[i] = System.currentTimeMillis();
|
||||
return;
|
||||
}
|
||||
openRAF(i);
|
||||
}
|
||||
private class TorrentFile implements Comparable<TorrentFile> {
|
||||
public final long length;
|
||||
public final String name;
|
||||
public final File RAFfile;
|
||||
/**
|
||||
* when was RAF last accessed, or 0 if closed
|
||||
* locking: this
|
||||
*/
|
||||
private long RAFtime;
|
||||
/**
|
||||
* null when closed
|
||||
* locking: this
|
||||
*/
|
||||
private RandomAccessFile raf;
|
||||
/**
|
||||
* is the file empty and sparse?
|
||||
* locking: this
|
||||
*/
|
||||
public boolean isSparse;
|
||||
/** priority by file; default 0 */
|
||||
public volatile int priority;
|
||||
|
||||
private void openRAF(int i) throws IOException {
|
||||
openRAF(i, _probablyComplete);
|
||||
}
|
||||
/**
|
||||
* For new metainfo from files;
|
||||
* use base == f for single-file torrent
|
||||
*/
|
||||
public TorrentFile(File base, File f) {
|
||||
this(base, f, f.length());
|
||||
}
|
||||
|
||||
private void openRAF(int i, boolean readonly) throws IOException {
|
||||
rafs[i] = new RandomAccessFile(RAFfile[i], (readonly || !RAFfile[i].canWrite()) ? "r" : "rw");
|
||||
RAFtime[i] = System.currentTimeMillis();
|
||||
}
|
||||
/**
|
||||
* For existing metainfo with specified file length;
|
||||
* use base == f for single-file torrent
|
||||
*/
|
||||
public TorrentFile(File base, File f, long len) {
|
||||
String n = f.getPath();
|
||||
if (base.isDirectory() && n.startsWith(base.getPath()))
|
||||
n = n.substring(base.getPath().length() + 1);
|
||||
name = n;
|
||||
length = len;
|
||||
RAFfile = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called even if not open
|
||||
*/
|
||||
private void closeRAF(int i) throws IOException {
|
||||
RAFtime[i] = 0;
|
||||
if (rafs[i] == null)
|
||||
return;
|
||||
rafs[i].close();
|
||||
rafs[i] = null;
|
||||
/*
|
||||
* For each of the following,
|
||||
* caller must synchronize on RAFlock[i]
|
||||
* ... except at the beginning if you're careful
|
||||
*/
|
||||
|
||||
/**
|
||||
* This must be called before using the RAF to ensure it is open
|
||||
* locking: this
|
||||
*/
|
||||
public synchronized RandomAccessFile checkRAF() throws IOException {
|
||||
if (raf != null)
|
||||
RAFtime = System.currentTimeMillis();
|
||||
else
|
||||
openRAF();
|
||||
return raf;
|
||||
}
|
||||
|
||||
/**
|
||||
* locking: this
|
||||
*/
|
||||
private synchronized void openRAF() throws IOException {
|
||||
openRAF(_probablyComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* locking: this
|
||||
*/
|
||||
private synchronized void openRAF(boolean readonly) throws IOException {
|
||||
raf = new RandomAccessFile(RAFfile, (readonly || !RAFfile.canWrite()) ? "r" : "rw");
|
||||
RAFtime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close if last used time older than cutoff.
|
||||
* locking: this
|
||||
*/
|
||||
public synchronized void closeRAF(long cutoff) {
|
||||
if (RAFtime > 0 && RAFtime < cutoff) {
|
||||
try {
|
||||
closeRAF();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called even if not open
|
||||
* locking: this
|
||||
*/
|
||||
public synchronized void closeRAF() throws IOException {
|
||||
RAFtime = 0;
|
||||
if (raf == null)
|
||||
return;
|
||||
raf.close();
|
||||
raf = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This creates a (presumably) sparse file so that reads won't fail with IOE.
|
||||
* Sets isSparse[nr] = true. balloonFile(nr) should be called later to
|
||||
* defrag the file.
|
||||
*
|
||||
* This calls openRAF(); caller must synchronize and call closeRAF().
|
||||
*/
|
||||
public synchronized void allocateFile() throws IOException {
|
||||
// caller synchronized
|
||||
openRAF(false); // RW
|
||||
raf.setLength(length);
|
||||
// don't bother ballooning later on Windows since there is no sparse file support
|
||||
// until JDK7 using the JSR-203 interface.
|
||||
// RAF seeks/writes do not create sparse files.
|
||||
// Windows will zero-fill up to the point of the write, which
|
||||
// will make the file fairly unfragmented, on average, at least until
|
||||
// near the end where it will get exponentially more fragmented.
|
||||
if (!_isWindows)
|
||||
isSparse = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This "balloons" the file with zeros to eliminate disk fragmentation.,
|
||||
* Overwrites the entire file with zeros. Sets isSparse[nr] = false.
|
||||
*
|
||||
* Caller must synchronize and call checkRAF() or openRAF().
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public synchronized void balloonFile() throws IOException
|
||||
{
|
||||
long remaining = length;
|
||||
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
|
||||
byte[] zeros = new byte[ZEROBLOCKSIZE];
|
||||
raf.seek(0);
|
||||
// don't bother setting flag for small files
|
||||
if (remaining > 20*1024*1024)
|
||||
_allocateCount.incrementAndGet();
|
||||
try {
|
||||
while (remaining > 0) {
|
||||
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
|
||||
raf.write(zeros, 0, size);
|
||||
remaining -= size;
|
||||
}
|
||||
} finally {
|
||||
remaining = length;
|
||||
if (remaining > 20*1024*1024)
|
||||
_allocateCount.decrementAndGet();
|
||||
}
|
||||
isSparse = false;
|
||||
}
|
||||
|
||||
public int compareTo(TorrentFile tf) {
|
||||
return name.compareTo(tf.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() { return RAFfile.getAbsolutePath().hashCode(); }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof TorrentFile) &&
|
||||
RAFfile.getAbsolutePath().equals(((TorrentFile)o).RAFfile.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return name; }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -21,8 +21,6 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -38,7 +36,6 @@ import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.ConvertToHash;
|
||||
@@ -74,6 +71,7 @@ public class TrackerClient implements Runnable {
|
||||
private static final String COMPLETED_EVENT = "completed";
|
||||
private static final String STOPPED_EVENT = "stopped";
|
||||
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
|
||||
private static final String NOT_REGISTERED_2 = "torrent not found"; // diftracker
|
||||
/** this is our equivalent to router.utorrent.com for bootstrap */
|
||||
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
|
||||
|
||||
@@ -85,7 +83,11 @@ public class TrackerClient implements Runnable {
|
||||
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
|
||||
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
|
||||
private final static long MIN_TRACKER_ANNOUNCE_INTERVAL = 15*60*1000;
|
||||
private final static long MIN_DHT_ANNOUNCE_INTERVAL = 10*60*1000;
|
||||
private final static long MIN_DHT_ANNOUNCE_INTERVAL = 39*60*1000;
|
||||
/** No guidance in BEP 5; standard practice is K (=8) */
|
||||
private static final int DHT_ANNOUNCE_PEERS = 4;
|
||||
public static final int PORT = 6881;
|
||||
private static final int MAX_TRACKERS = 12;
|
||||
|
||||
private final I2PSnarkUtil _util;
|
||||
private final MetaInfo meta;
|
||||
@@ -108,11 +110,14 @@ public class TrackerClient implements Runnable {
|
||||
// these 2 used in loop()
|
||||
private volatile boolean runStarted;
|
||||
private volatile int consecutiveFails;
|
||||
// if we don't want anything else.
|
||||
// Not necessarily seeding, as we may have skipped some files.
|
||||
private boolean completed;
|
||||
private volatile boolean _fastUnannounce;
|
||||
private long lastDHTAnnounce;
|
||||
private final List<TCTracker> trackers;
|
||||
private final List<TCTracker> backupTrackers;
|
||||
private long _startedOn;
|
||||
|
||||
/**
|
||||
* Call start() to start it.
|
||||
@@ -134,11 +139,11 @@ public class TrackerClient implements Runnable {
|
||||
this.coordinator = coordinator;
|
||||
this.snark = snark;
|
||||
|
||||
this.port = 6881; //(port == -1) ? 9 : port;
|
||||
this.port = PORT; //(port == -1) ? 9 : port;
|
||||
this.infoHash = urlencode(snark.getInfoHash());
|
||||
this.peerID = urlencode(snark.getID());
|
||||
this.trackers = new ArrayList(2);
|
||||
this.backupTrackers = new ArrayList(2);
|
||||
this.trackers = new ArrayList<TCTracker>(2);
|
||||
this.backupTrackers = new ArrayList<TCTracker>(2);
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
@@ -272,7 +277,7 @@ public class TrackerClient implements Runnable {
|
||||
primary = meta.getAnnounce();
|
||||
else if (additionalTrackerURL != null)
|
||||
primary = additionalTrackerURL;
|
||||
Set<Hash> trackerHashes = new HashSet(8);
|
||||
Set<Hash> trackerHashes = new HashSet<Hash>(8);
|
||||
|
||||
// primary tracker
|
||||
if (primary != null) {
|
||||
@@ -289,6 +294,7 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
|
||||
// announce list
|
||||
// We completely ignore the BEP 12 processing rules
|
||||
if (meta != null && !meta.isPrivate()) {
|
||||
List<List<String>> list = meta.getAnnounceList();
|
||||
if (list != null) {
|
||||
@@ -301,6 +307,12 @@ public class TrackerClient implements Runnable {
|
||||
_log.debug("Additional announce (list): [" + url + "] for infoHash: " + infoHash);
|
||||
}
|
||||
}
|
||||
if (trackers.size() > 2) {
|
||||
// shuffle everything but the primary
|
||||
TCTracker pri = trackers.remove(0);
|
||||
Collections.shuffle(trackers, _util.getContext().random());
|
||||
trackers.add(0, pri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +346,7 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
this.completed = coordinator.getLeft() == 0;
|
||||
_startedOn = _util.getContext().clock().now();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +358,13 @@ public class TrackerClient implements Runnable {
|
||||
private boolean isNewValidTracker(Set<Hash> existing, String ann) {
|
||||
Hash h = getHostHash(ann);
|
||||
if (h == null) {
|
||||
_log.error("Bad announce URL: [" + ann + ']');
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Bad announce URL: [" + ann + ']');
|
||||
return false;
|
||||
}
|
||||
if (existing.size() >= MAX_TRACKERS) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not using announce URL, we have enough: [" + ann + ']');
|
||||
return false;
|
||||
}
|
||||
boolean rv = existing.add(h);
|
||||
@@ -375,17 +394,26 @@ public class TrackerClient implements Runnable {
|
||||
// Local DHT tracker announce
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null && (meta == null || !meta.isPrivate()))
|
||||
dht.announce(snark.getInfoHash());
|
||||
dht.announce(snark.getInfoHash(), coordinator.completed());
|
||||
|
||||
int oldSeenPeers = snark.getTrackerSeenPeers();
|
||||
int maxSeenPeers = 0;
|
||||
if (!trackers.isEmpty())
|
||||
if (!trackers.isEmpty()) {
|
||||
maxSeenPeers = getPeersFromTrackers(trackers);
|
||||
// fast update for UI at startup
|
||||
if (maxSeenPeers > oldSeenPeers)
|
||||
snark.setTrackerSeenPeers(maxSeenPeers);
|
||||
}
|
||||
int p = getPeersFromPEX();
|
||||
if (p > maxSeenPeers)
|
||||
maxSeenPeers = p;
|
||||
p = getPeersFromDHT();
|
||||
if (p > maxSeenPeers)
|
||||
if (p > maxSeenPeers) {
|
||||
maxSeenPeers = p;
|
||||
// fast update for UI at startup
|
||||
if (maxSeenPeers > oldSeenPeers)
|
||||
snark.setTrackerSeenPeers(maxSeenPeers);
|
||||
}
|
||||
// backup if DHT needs bootstrapping
|
||||
if (trackers.isEmpty() && !backupTrackers.isEmpty() && dht != null && dht.size() < 16) {
|
||||
p = getPeersFromTrackers(backupTrackers);
|
||||
@@ -461,6 +489,9 @@ public class TrackerClient implements Runnable {
|
||||
{
|
||||
long uploaded = coordinator.getUploaded();
|
||||
long downloaded = coordinator.getDownloaded();
|
||||
long len = snark.getTotalLength();
|
||||
if (len > 0 && downloaded > len)
|
||||
downloaded = len;
|
||||
left = coordinator.getLeft();
|
||||
String event;
|
||||
if (!tr.started) {
|
||||
@@ -482,24 +513,44 @@ public class TrackerClient implements Runnable {
|
||||
consecutiveFails = 0;
|
||||
runStarted = true;
|
||||
tr.started = true;
|
||||
|
||||
Set<Peer> peers = info.getPeers();
|
||||
tr.seenPeers = info.getPeerCount();
|
||||
if (snark.getTrackerSeenPeers() < tr.seenPeers) // update rising number quickly
|
||||
snark.setTrackerSeenPeers(tr.seenPeers);
|
||||
|
||||
// auto stop
|
||||
// These are very high thresholds for now, not configurable,
|
||||
// just for update torrent
|
||||
if (completed &&
|
||||
tr.isPrimary &&
|
||||
snark.isAutoStoppable() &&
|
||||
!snark.isChecking() &&
|
||||
info.getSeedCount() > 100 &&
|
||||
coordinator.getPeerCount() <= 0 &&
|
||||
_util.getContext().clock().now() > _startedOn + 2*60*60*1000 &&
|
||||
snark.getTotalLength() > 0 &&
|
||||
uploaded >= snark.getTotalLength() * 3 / 2) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Auto stopping " + snark.getBaseName());
|
||||
snark.setAutoStoppable(false);
|
||||
snark.stopTorrent();
|
||||
return tr.seenPeers;
|
||||
}
|
||||
|
||||
Set<Peer> peers = info.getPeers();
|
||||
|
||||
// pass everybody over to our tracker
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null) {
|
||||
for (Peer peer : peers) {
|
||||
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash(),
|
||||
false); // TODO actual seed/leech status
|
||||
}
|
||||
}
|
||||
|
||||
if (coordinator.needOutboundPeers()) {
|
||||
// we only want to talk to new people if we need things
|
||||
// from them (duh)
|
||||
List<Peer> ordered = new ArrayList(peers);
|
||||
List<Peer> ordered = new ArrayList<Peer>(peers);
|
||||
Random r = _util.getContext().random();
|
||||
Collections.shuffle(ordered, r);
|
||||
Iterator<Peer> it = ordered.iterator();
|
||||
@@ -525,13 +576,15 @@ public class TrackerClient implements Runnable {
|
||||
// don't show secondary tracker problems to the user
|
||||
if (tr.isPrimary)
|
||||
snark.setTrackerProblems(tr.trackerProblems);
|
||||
if (tr.trackerProblems.toLowerCase(Locale.US).startsWith(NOT_REGISTERED)) {
|
||||
String tplc = tr.trackerProblems.toLowerCase(Locale.US);
|
||||
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2)) {
|
||||
// Give a guy some time to register it if using opentrackers too
|
||||
//if (trckrs.size() == 1) {
|
||||
// stop = true;
|
||||
// snark.stopTorrent();
|
||||
//} else { // hopefully each on the opentrackers list is really open
|
||||
if (tr.registerFails++ > MAX_REGISTER_FAILS)
|
||||
if (tr.registerFails++ > MAX_REGISTER_FAILS ||
|
||||
(!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
|
||||
tr.stop = true;
|
||||
//
|
||||
}
|
||||
@@ -564,7 +617,7 @@ public class TrackerClient implements Runnable {
|
||||
if (!pids.isEmpty()) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + pids.size() + " from PEX");
|
||||
List<Peer> peers = new ArrayList(pids.size());
|
||||
List<Peer> peers = new ArrayList<Peer>(pids.size());
|
||||
for (PeerID pID : pids) {
|
||||
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
|
||||
}
|
||||
@@ -596,33 +649,31 @@ public class TrackerClient implements Runnable {
|
||||
// FIXME this needs to be in its own thread
|
||||
int rv = 0;
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null && (meta == null || !meta.isPrivate()) && (!stop) &&
|
||||
_util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL) {
|
||||
if (dht != null &&
|
||||
(meta == null || !meta.isPrivate()) &&
|
||||
(!stop) &&
|
||||
(meta == null || _util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL)) {
|
||||
int numwant;
|
||||
if (!coordinator.needOutboundPeers())
|
||||
numwant = 1;
|
||||
else
|
||||
numwant = _util.getMaxConnections();
|
||||
Collection<Hash> hashes = dht.getPeers(snark.getInfoHash(), numwant, 2*60*1000);
|
||||
Collection<Hash> hashes = dht.getPeersAndAnnounce(snark.getInfoHash(), numwant,
|
||||
5*60*1000, DHT_ANNOUNCE_PEERS, 3*60*1000,
|
||||
coordinator.completed(), numwant <= 1);
|
||||
if (!hashes.isEmpty()) {
|
||||
runStarted = true;
|
||||
lastDHTAnnounce = _util.getContext().clock().now();
|
||||
rv = hashes.size();
|
||||
} else {
|
||||
lastDHTAnnounce = 0;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + hashes + " from DHT");
|
||||
// announce ourselves while the token is still good
|
||||
// FIXME this needs to be in its own thread
|
||||
if (!stop) {
|
||||
// announce only to the 1 closest
|
||||
int good = dht.announce(snark.getInfoHash(), 1, 5*60*1000);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sent " + good + " good announces to DHT");
|
||||
}
|
||||
|
||||
// now try these peers
|
||||
if ((!stop) && !hashes.isEmpty()) {
|
||||
List<Peer> peers = new ArrayList(hashes.size());
|
||||
List<Peer> peers = new ArrayList<Peer>(hashes.size());
|
||||
for (Hash h : hashes) {
|
||||
try {
|
||||
PeerID pID = new PeerID(h.getData(), _util);
|
||||
@@ -689,6 +740,9 @@ public class TrackerClient implements Runnable {
|
||||
_log.debug("Running unannounce " + _threadName + " to " + tr.announce);
|
||||
long uploaded = coordinator.getUploaded();
|
||||
long downloaded = coordinator.getDownloaded();
|
||||
long len = snark.getTotalLength();
|
||||
if (len > 0 && downloaded > len)
|
||||
downloaded = len;
|
||||
long left = coordinator.getLeft();
|
||||
try
|
||||
{
|
||||
@@ -806,8 +860,7 @@ public class TrackerClient implements Runnable {
|
||||
return false;
|
||||
}
|
||||
return url.getProtocol().equals("http") &&
|
||||
(url.getHost().endsWith(".i2p") || url.getHost().equals("i2p")) &&
|
||||
url.getPort() < 0;
|
||||
(url.getHost().endsWith(".i2p") || url.getHost().equals("i2p"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -822,7 +875,7 @@ public class TrackerClient implements Runnable {
|
||||
} catch (MalformedURLException mue) {
|
||||
return null;
|
||||
}
|
||||
if (url.getPort() >= 0 || !url.getProtocol().equals("http"))
|
||||
if (!url.getProtocol().equals("http"))
|
||||
return null;
|
||||
String host = url.getHost();
|
||||
if (host.endsWith(".i2p"))
|
||||
|
@@ -59,10 +59,10 @@ class TrackerInfo
|
||||
this(be.bdecodeMap().getMap(), my_id, infohash, metainfo, util);
|
||||
}
|
||||
|
||||
private TrackerInfo(Map m, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
|
||||
private TrackerInfo(Map<String, BEValue> m, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
|
||||
throws IOException
|
||||
{
|
||||
BEValue reason = (BEValue)m.get("failure reason");
|
||||
BEValue reason = m.get("failure reason");
|
||||
if (reason != null)
|
||||
{
|
||||
failure_reason = reason.getString();
|
||||
@@ -72,15 +72,15 @@ class TrackerInfo
|
||||
else
|
||||
{
|
||||
failure_reason = null;
|
||||
BEValue beInterval = (BEValue)m.get("interval");
|
||||
BEValue beInterval = m.get("interval");
|
||||
if (beInterval == null)
|
||||
throw new InvalidBEncodingException("No interval given");
|
||||
else
|
||||
interval = beInterval.getInt();
|
||||
|
||||
BEValue bePeers = (BEValue)m.get("peers");
|
||||
BEValue bePeers = m.get("peers");
|
||||
if (bePeers == null) {
|
||||
peers = Collections.EMPTY_SET;
|
||||
peers = Collections.emptySet();
|
||||
} else {
|
||||
Set<Peer> p;
|
||||
try {
|
||||
@@ -93,14 +93,14 @@ class TrackerInfo
|
||||
peers = p;
|
||||
}
|
||||
|
||||
BEValue bev = (BEValue)m.get("complete");
|
||||
BEValue bev = m.get("complete");
|
||||
if (bev != null) try {
|
||||
complete = bev.getInt();
|
||||
if (complete < 0)
|
||||
complete = 0;
|
||||
} catch (InvalidBEncodingException ibe) {}
|
||||
|
||||
bev = (BEValue)m.get("incomplete");
|
||||
bev = m.get("incomplete");
|
||||
if (bev != null) try {
|
||||
incomplete = bev.getInt();
|
||||
if (incomplete < 0)
|
||||
@@ -127,7 +127,7 @@ class TrackerInfo
|
||||
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
|
||||
throws IOException
|
||||
{
|
||||
Set<Peer> peers = new HashSet(l.size());
|
||||
Set<Peer> peers = new HashSet<Peer>(l.size());
|
||||
|
||||
for (BEValue bev : l) {
|
||||
PeerID peerID;
|
||||
@@ -161,7 +161,7 @@ class TrackerInfo
|
||||
throws IOException
|
||||
{
|
||||
int count = l.length / HASH_LENGTH;
|
||||
Set<Peer> peers = new HashSet(count);
|
||||
Set<Peer> peers = new HashSet<Peer>(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
PeerID peerID;
|
||||
@@ -190,6 +190,12 @@ class TrackerInfo
|
||||
return Math.max(pc, complete + incomplete - 1);
|
||||
}
|
||||
|
||||
/** @since 0.9.9 */
|
||||
public int getSeedCount()
|
||||
{
|
||||
return complete;
|
||||
}
|
||||
|
||||
public String getFailureReason()
|
||||
{
|
||||
return failure_reason;
|
||||
|
@@ -42,10 +42,10 @@ class UpdateHandler implements Updater {
|
||||
*/
|
||||
public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
|
||||
String id, String newVersion, long maxTime) {
|
||||
if (type != UpdateType.ROUTER_SIGNED ||
|
||||
if ((type != UpdateType.ROUTER_SIGNED && type != UpdateType.ROUTER_SIGNED_SU3) ||
|
||||
method != UpdateMethod.TORRENT || updateSources.isEmpty())
|
||||
return null;
|
||||
UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, updateSources, newVersion);
|
||||
UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, type, updateSources, newVersion);
|
||||
_umgr.notifyProgress(update, "<b>" + _smgr.util().getString("Updating") + "</b>");
|
||||
return update;
|
||||
}
|
||||
|
@@ -6,11 +6,9 @@ import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.update.*;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* The downloader for router signed updates.
|
||||
@@ -22,6 +20,7 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
private final Log _log;
|
||||
private final UpdateManager _umgr;
|
||||
private final SnarkManager _smgr;
|
||||
private final UpdateType _type;
|
||||
private final List<URI> _urls;
|
||||
private volatile boolean _isRunning;
|
||||
private volatile boolean _hasMetaInfo;
|
||||
@@ -36,11 +35,12 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
private static final long CHECK_INTERVAL = 3*60*1000;
|
||||
|
||||
public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr,
|
||||
List<URI> uris, String newVersion) {
|
||||
UpdateType type, List<URI> uris, String newVersion) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(getClass());
|
||||
_umgr = umgr;
|
||||
_smgr = smgr;
|
||||
_type = type;
|
||||
_urls = uris;
|
||||
_newVersion = newVersion;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
}
|
||||
}
|
||||
|
||||
public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
|
||||
public UpdateType getType() { return _type; }
|
||||
|
||||
public UpdateMethod getMethod() { return UpdateMethod.TORRENT; }
|
||||
|
||||
@@ -111,7 +111,7 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
}
|
||||
_snark = _smgr.addMagnet(name, ih, trackerURL, true, true, this);
|
||||
if (_snark != null) {
|
||||
updateStatus("<b>" + _smgr.util().getString("Updating from {0}", updateURL) + "</b>");
|
||||
updateStatus("<b>" + _smgr.util().getString("Updating from {0}", linkify(updateURL)) + "</b>");
|
||||
new Timeout();
|
||||
break;
|
||||
}
|
||||
@@ -264,6 +264,7 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
}
|
||||
_hasMetaInfo = true;
|
||||
notifyProgress();
|
||||
snark.setAutoStoppable(true);
|
||||
return _smgr.gotMetaInfo(snark);
|
||||
}
|
||||
|
||||
@@ -291,6 +292,12 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
|
||||
//////// end CompleteListener methods
|
||||
|
||||
private static String linkify(String url) {
|
||||
String durl = url.length() <= 28 ? url :
|
||||
url.substring(0, 25) + "…";
|
||||
return "<a target=\"_blank\" href=\"" + url + "\"/>" + durl + "</a>";
|
||||
}
|
||||
|
||||
private void updateStatus(String s) {
|
||||
_umgr.notifyProgress(this, s);
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
package org.klomp.snark.bencode;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
@@ -60,7 +61,7 @@ public class BDecoder
|
||||
private int indicator = 0;
|
||||
|
||||
// Used for ugly hack to get SHA hash over the metainfo info map
|
||||
private final String special_map = "info";
|
||||
private static final String special_map = "info";
|
||||
private boolean in_special_map = false;
|
||||
/** creation deferred until we encounter the special map, to make processing of announce replies more efficient */
|
||||
private MessageDigest sha_digest;
|
||||
@@ -221,46 +222,49 @@ public class BDecoder
|
||||
{
|
||||
c = read();
|
||||
if (c == 'e')
|
||||
return new BEValue(BigInteger.ZERO);
|
||||
return new BEValue(Integer.valueOf(0));
|
||||
else
|
||||
throw new InvalidBEncodingException("'e' expected after zero,"
|
||||
+ " not '" + (char)c + "'");
|
||||
}
|
||||
|
||||
// XXX - We don't support more the 255 char big integers
|
||||
char[] chars = new char[256];
|
||||
int off = 0;
|
||||
StringBuilder chars = new StringBuilder(16);
|
||||
|
||||
if (c == '-')
|
||||
{
|
||||
chars.append((char)c);
|
||||
c = read();
|
||||
if (c == '0')
|
||||
throw new InvalidBEncodingException("Negative zero not allowed");
|
||||
chars[off] = (char)c;
|
||||
off++;
|
||||
}
|
||||
|
||||
if (c < '1' || c > '9')
|
||||
throw new InvalidBEncodingException("Invalid Integer start '"
|
||||
+ (char)c + "'");
|
||||
chars[off] = (char)c;
|
||||
off++;
|
||||
chars.append((char)c);
|
||||
|
||||
c = read();
|
||||
int i = c - '0';
|
||||
while(i >= 0 && i <= 9)
|
||||
while(c >= '0' && c <= '9')
|
||||
{
|
||||
chars[off] = (char)c;
|
||||
off++;
|
||||
chars.append((char)c);
|
||||
c = read();
|
||||
i = c - '0';
|
||||
}
|
||||
|
||||
if (c != 'e')
|
||||
throw new InvalidBEncodingException("Integer should end with 'e'");
|
||||
|
||||
String s = new String(chars, 0, off);
|
||||
return new BEValue(new BigInteger(s));
|
||||
String s = chars.toString();
|
||||
int len = s.length();
|
||||
// save a little space if we're sure it will fit
|
||||
Number num;
|
||||
if (len < 10)
|
||||
num = Integer.valueOf(s);
|
||||
else if (len < 19)
|
||||
num = Long.valueOf(s);
|
||||
else if (len > 256)
|
||||
throw new InvalidBEncodingException("Too many digits: " + len);
|
||||
else
|
||||
num = new BigInteger(s);
|
||||
return new BEValue(num);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +280,7 @@ public class BDecoder
|
||||
+ (char)c + "'");
|
||||
indicator = 0;
|
||||
|
||||
List result = new ArrayList();
|
||||
List<BEValue> result = new ArrayList<BEValue>();
|
||||
c = getNextIndicator();
|
||||
while (c != 'e')
|
||||
{
|
||||
@@ -303,7 +307,7 @@ public class BDecoder
|
||||
+ (char)c + "'");
|
||||
indicator = 0;
|
||||
|
||||
Map result = new HashMap();
|
||||
Map<String, BEValue> result = new HashMap<String, BEValue>();
|
||||
c = getNextIndicator();
|
||||
while (c != 'e')
|
||||
{
|
||||
@@ -371,4 +375,21 @@ public class BDecoder
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* prints out the decoded data
|
||||
* @since 0.9.14
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: BDecoder file.torrent");
|
||||
System.exit(1);
|
||||
}
|
||||
try {
|
||||
BEValue bev = bdecode(new FileInputStream(args[0]));
|
||||
System.out.println(bev.toString());
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user