forked from I2P_Developers/i2p.i2p
Compare commits
705 Commits
i2p_post_g
...
i2p_0_3_4_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c9b0273d4 | ||
|
|
5122f9989c | ||
|
|
8ebd22da96 | ||
|
|
c2d55013a6 | ||
|
|
25eda1378e | ||
|
|
dfac7bde9c | ||
|
|
348168d6c0 | ||
|
|
a1c772c8d8 | ||
|
|
f1ce1b5361 | ||
|
|
ebdc7d70a1 | ||
|
|
c5947c23bb | ||
|
|
eeb1852d95 | ||
|
|
2f28a635a9 | ||
|
|
d524c77560 | ||
|
|
0025d94aa4 | ||
|
|
bb5ae2922d | ||
|
|
fbe9fe1ba8 | ||
|
|
007194d674 | ||
|
|
cdd74505d7 | ||
|
|
0aa023189d | ||
|
|
79aa10dfcb | ||
|
|
9ecfda0110 | ||
|
|
b89e26c460 | ||
|
|
97e5952544 | ||
|
|
8627328047 | ||
|
|
ec0c912c6f | ||
|
|
953de3f1f2 | ||
|
|
e1264de514 | ||
|
|
5abd2b400c | ||
|
|
2c2a103676 | ||
|
|
44af799b66 | ||
|
|
ec22ba3248 | ||
|
|
7fcc05c037 | ||
|
|
edf17d0a46 | ||
|
|
9cccd0bfc9 | ||
|
|
e57c010e3d | ||
|
|
4dfcf1c1c8 | ||
|
|
8d7786e97d | ||
|
|
2cb519cd06 | ||
|
|
bc46ad4331 | ||
|
|
be08e8f23b | ||
|
|
f937809903 | ||
|
|
c0f32c942d | ||
|
|
39c5c830bb | ||
|
|
83c8953d1b | ||
|
|
4b100a5a64 | ||
|
|
b7e50e0b3a | ||
|
|
6933052de7 | ||
|
|
22d945f7b7 | ||
|
|
b81c5628ce | ||
|
|
cdb4576bd7 | ||
|
|
4859cd7dcf | ||
|
|
3f70593ca8 | ||
|
|
676288e6c0 | ||
|
|
1aa3e0cc5a | ||
|
|
b0f8064d0d | ||
|
|
e5e85732d4 | ||
|
|
f97c1ef0d9 | ||
|
|
83cf815160 | ||
|
|
fea62a529b | ||
|
|
2cff5ae2bb | ||
|
|
8aa29f5340 | ||
|
|
8051bfef1d | ||
|
|
85bc79ab1b | ||
|
|
97e5588184 | ||
|
|
e622fdc885 | ||
|
|
4f81e1debe | ||
|
|
9ccfd852d8 | ||
|
|
9df57a47d5 | ||
|
|
f2cadb7278 | ||
|
|
3f6e7cb84c | ||
|
|
4ed4ce8240 | ||
|
|
4373956a3f | ||
|
|
36fb99a00d | ||
|
|
8f5d325c4d | ||
|
|
8d8b6da0bf | ||
|
|
3a61d260d7 | ||
|
|
5bc433d1c8 | ||
|
|
a0e4bbac6f | ||
|
|
d44d8cc53d | ||
|
|
1305969247 | ||
|
|
94becebafa | ||
|
|
8add433966 | ||
|
|
c5b289fb1f | ||
|
|
f85ce180ed | ||
|
|
8101fa1c92 | ||
|
|
8a091e0205 | ||
|
|
edc3a54ad3 | ||
|
|
a3cd7d1068 | ||
|
|
337441b8de | ||
|
|
bd78a66bd4 | ||
|
|
96f9618081 | ||
|
|
cf7be2d601 | ||
|
|
598732915e | ||
|
|
99c18396ab | ||
|
|
6d5dd81066 | ||
|
|
7cd9451a22 | ||
|
|
29b5a7c5c2 | ||
|
|
393a04165e | ||
|
|
e97e834a5b | ||
|
|
bec685682b | ||
|
|
34f119ca23 | ||
|
|
09ed1b1f9e | ||
|
|
fcb109f46d | ||
|
|
f30823e4ac | ||
|
|
c04885449d | ||
|
|
8c31e47eeb | ||
|
|
d8ee5c180b | ||
|
|
823f4a26b3 | ||
|
|
a05e8a446d | ||
|
|
21126f766c | ||
|
|
8f46ead756 | ||
|
|
75652fc2c4 | ||
|
|
7cdc46f007 | ||
|
|
ed9f9625ae | ||
|
|
7b60d3dab9 | ||
|
|
a6993fa489 | ||
|
|
bc2774bde4 | ||
|
|
d10dc1e8d3 | ||
|
|
48556de92b | ||
|
|
7f6b477d2e | ||
|
|
11d8c67d12 | ||
|
|
fd2a4029e7 | ||
|
|
4467928845 | ||
|
|
cc85a00bfd | ||
|
|
15d58ecdcd | ||
|
|
08d93b9a78 | ||
|
|
a75a999e3b | ||
|
|
684ef709f5 | ||
|
|
2e98dd09e7 | ||
|
|
6635425bbc | ||
|
|
5d4bdc5697 | ||
|
|
0fdb286005 | ||
|
|
59a8493aa7 | ||
|
|
25378e894b | ||
|
|
3b9fea20b6 | ||
|
|
c6bb8f09ca | ||
|
|
4a9bd84bf0 | ||
|
|
c02522b0fe | ||
|
|
c2a71ef756 | ||
|
|
e669110cf4 | ||
|
|
f4cf31c13d | ||
|
|
7b23a5dcce | ||
|
|
b2fda0c79d | ||
|
|
5af96f5ccb | ||
|
|
ca445ac178 | ||
|
|
16fb31b6eb | ||
|
|
a1ff325b7b | ||
|
|
5eaec4c841 | ||
|
|
ffcc34c4f9 | ||
|
|
2dbe33e769 | ||
|
|
60c7db0733 | ||
|
|
0ed95bbdf1 | ||
|
|
c901bcf9b7 | ||
|
|
0ccf915a18 | ||
|
|
52b1c0a926 | ||
|
|
399865e6c8 | ||
|
|
54aeab1524 | ||
|
|
91f83277e2 | ||
|
|
c937cb2f07 | ||
|
|
ebd150e473 | ||
|
|
9218f7b82c | ||
|
|
edaf7aee5d | ||
|
|
43c18d0f4d | ||
|
|
65d85f7479 | ||
|
|
476e23db5b | ||
|
|
abaa5d87f6 | ||
|
|
ce3e7e623c | ||
|
|
3fd35a9c18 | ||
|
|
f170ae741e | ||
|
|
03562b037d | ||
|
|
472312709a | ||
|
|
b68463249e | ||
|
|
740a2da702 | ||
|
|
85c8e56417 | ||
|
|
481ef56e74 | ||
|
|
008795770f | ||
|
|
834fb7e317 | ||
|
|
da4827f287 | ||
|
|
9f4439583d | ||
|
|
69981e4d78 | ||
|
|
a857c6a88f | ||
|
|
e8d19439f8 | ||
|
|
56216250a7 | ||
|
|
bea331db26 | ||
|
|
bc4e833a47 | ||
|
|
83f399fffc | ||
|
|
5214436d18 | ||
|
|
8603250d73 | ||
|
|
9a8a099701 | ||
|
|
a5a0c8c837 | ||
|
|
604bcd5874 | ||
|
|
d29f9409bf | ||
|
|
b5a0f5910d | ||
|
|
ccb2600e67 | ||
|
|
f06e21ff5a | ||
|
|
bb0817a2ec | ||
|
|
6911f865ca | ||
|
|
fe28b2732c | ||
|
|
e8e8c37496 | ||
|
|
ef0f1ca1e7 | ||
|
|
31ca34b954 | ||
|
|
c4e6a2f0a8 | ||
|
|
b56845e200 | ||
|
|
d7a1fee781 | ||
|
|
b1f802c42d | ||
|
|
5f022e6e1f | ||
|
|
392cbb817e | ||
|
|
130399a1e7 | ||
|
|
37d5531737 | ||
|
|
f0b6cbaf89 | ||
|
|
707b173e77 | ||
|
|
4381bb5026 | ||
|
|
5850ad1217 | ||
|
|
806d598a04 | ||
|
|
e737e5c950 | ||
|
|
bbcde2f52b | ||
|
|
f6ef77429c | ||
|
|
44491c1514 | ||
|
|
71a6cf4ee6 | ||
|
|
744ce6966f | ||
|
|
d25cec02c2 | ||
|
|
f02bf37fd3 | ||
|
|
304b9d41d7 | ||
|
|
2d6af89f60 | ||
|
|
d6425973e2 | ||
|
|
d5ad56c4de | ||
|
|
4f1f2cc99e | ||
|
|
da439dd127 | ||
|
|
1375d01bdf | ||
|
|
7b9db07f13 | ||
|
|
f2f26136c1 | ||
|
|
0f60ac5acf | ||
|
|
c28f19fe8a | ||
|
|
09a6dbc755 | ||
|
|
3bc0e0fc8a | ||
|
|
eb0e187a54 | ||
|
|
a788d30f34 | ||
|
|
591dfc961e | ||
|
|
809e12b034 | ||
|
|
1669d174e1 | ||
|
|
3cfd28de43 | ||
|
|
4888207eca | ||
|
|
294cb96107 | ||
|
|
b648fa2b70 | ||
|
|
ab99122211 | ||
|
|
dd014fee88 | ||
|
|
c81f864de3 | ||
|
|
90fe7dceec | ||
|
|
3a568096f2 | ||
|
|
94e694fc61 | ||
|
|
bdfa6e4af5 | ||
|
|
8e64ffb4f6 | ||
|
|
6c162643cb | ||
|
|
ff7742bca3 | ||
|
|
9685884279 | ||
|
|
a8b0d7f999 | ||
|
|
dd84233085 | ||
|
|
fe3eac07f4 | ||
|
|
0948686989 | ||
|
|
4c82970319 | ||
|
|
fe2fede8ed | ||
|
|
b23b1e5f1f | ||
|
|
dca66c8de8 | ||
|
|
49090014cc | ||
|
|
fa4f100705 | ||
|
|
bbf68cd9a8 | ||
|
|
bbc5f6588a | ||
|
|
b3632a6a35 | ||
|
|
3943c51bb4 | ||
|
|
4c19ddde69 | ||
|
|
d8f0f1a1d3 | ||
|
|
121c0d89f2 | ||
|
|
badfb9088e | ||
|
|
ff392fee14 | ||
|
|
a13693161a | ||
|
|
4b8ac81669 | ||
|
|
219a704ee0 | ||
|
|
3996cd1f08 | ||
|
|
c636b0a0ec | ||
|
|
aae9f671f0 | ||
|
|
aec6e901ee | ||
|
|
f49be25288 | ||
|
|
f9a96126e1 | ||
|
|
8c9f58b939 | ||
|
|
8a7e787f42 | ||
|
|
148dcc084d | ||
|
|
15b1cbd762 | ||
|
|
e9b7ca3697 | ||
|
|
1b03e9a3ee | ||
|
|
2b951e3f61 | ||
|
|
f51e064cf6 | ||
|
|
9640e93895 | ||
|
|
d5bd22040c | ||
|
|
dcdcb7521a | ||
|
|
4058c63884 | ||
|
|
dd34548cc6 | ||
|
|
a6b5211fa7 | ||
|
|
4e89b9c363 | ||
|
|
f3e267d2d0 | ||
|
|
2fd87dc1f1 | ||
|
|
40b6b77cfa | ||
|
|
d0c61dbf4d | ||
|
|
1cd5a3fcf7 | ||
|
|
af81cf2c50 | ||
|
|
04373c5d1b | ||
|
|
e9cdb0f78d | ||
|
|
021b933ad3 | ||
|
|
9fd067c9da | ||
|
|
d3f3f3bdf7 | ||
|
|
72727dacd8 | ||
|
|
caeb2bc4e3 | ||
|
|
13974b601f | ||
|
|
cbc6aea8b4 | ||
|
|
290a2f7ccd | ||
|
|
349e80f206 | ||
|
|
5c1e001a73 | ||
|
|
f312318fab | ||
|
|
dc04b7cf09 | ||
|
|
77a8a46d8e | ||
|
|
95c7cd55c2 | ||
|
|
5f0ef5e0e8 | ||
|
|
1f26c603e0 | ||
|
|
7e2227ad42 | ||
|
|
9b4899da07 | ||
|
|
83c88ac0c6 | ||
|
|
44623065b4 | ||
|
|
47c7c8177d | ||
|
|
bde7a5ff59 | ||
|
|
a8ad8644c8 | ||
|
|
4e91bb88a5 | ||
|
|
f60a90e2da | ||
|
|
784dc0f6a7 | ||
|
|
e80e627fba | ||
|
|
d5987c51c9 | ||
|
|
5ced441b17 | ||
|
|
57801202fd | ||
|
|
a019399c3c | ||
|
|
e6f610a86c | ||
|
|
7ef528bbde | ||
|
|
a351a29bf3 | ||
|
|
983d258bce | ||
|
|
f6d38dd5e0 | ||
|
|
d51245aada | ||
|
|
56cf51f0f9 | ||
|
|
eb40fb9c5d | ||
|
|
085da0cea7 | ||
|
|
5539b19938 | ||
|
|
94feb762ca | ||
|
|
40b59d5a5a | ||
|
|
9ffd147470 | ||
|
|
3fea4ad2ba | ||
|
|
1ab5536879 | ||
|
|
9690a89a6d | ||
|
|
8f895f4349 | ||
|
|
980c0aa1d7 | ||
|
|
52fd6ca513 | ||
|
|
eb5dd2ff2e | ||
|
|
7ca35452eb | ||
|
|
dd781e256c | ||
|
|
551a7ab82f | ||
|
|
2901287d9e | ||
|
|
2b714967aa | ||
|
|
e8734ef1e7 | ||
|
|
14b9f9509f | ||
|
|
b1f973d304 | ||
|
|
2f17bfd71c | ||
|
|
b6670ee23a | ||
|
|
f1036df1f6 | ||
|
|
5c3e815757 | ||
|
|
55e780d885 | ||
|
|
d502df7d56 | ||
|
|
beb6cc8c0f | ||
|
|
c99db5e75c | ||
|
|
65cd70a85b | ||
|
|
5166eab5ee | ||
|
|
232f6f158d | ||
|
|
2a07ceba62 | ||
|
|
3e4b8c7dd4 | ||
|
|
26138e213f | ||
|
|
d82796e3ad | ||
|
|
cdcb81c867 | ||
|
|
5669e8f060 | ||
|
|
d84a40b4dc | ||
|
|
591be43763 | ||
|
|
97d0686354 | ||
|
|
e2da05b197 | ||
|
|
4f0052043d | ||
|
|
cfc1d1a2db | ||
|
|
9957e6ef17 | ||
|
|
6a02c8383c | ||
|
|
bc0a4ee68d | ||
|
|
1ca615da77 | ||
|
|
7da0cee29a | ||
|
|
f25bccd19f | ||
|
|
4e5a2e012c | ||
|
|
c9ee2a92a3 | ||
|
|
95a7938328 | ||
|
|
baedcdb2c1 | ||
|
|
bc06b3671a | ||
|
|
a9172811ca | ||
|
|
91b1fd6d07 | ||
|
|
bab7b8b9ed | ||
|
|
1b7fb96ca8 | ||
|
|
6d84b8c02f | ||
|
|
3e3749f011 | ||
|
|
52384fb3a5 | ||
|
|
e401670087 | ||
|
|
ae0b4c59cc | ||
|
|
0a8dc8afcc | ||
|
|
d59b94df66 | ||
|
|
e28502454b | ||
|
|
bbf73f0937 | ||
|
|
592519c45c | ||
|
|
cc904ba9dc | ||
|
|
1679ba6719 | ||
|
|
07fadd4a6c | ||
|
|
57e1ff39e0 | ||
|
|
51e259c198 | ||
|
|
de334b003d | ||
|
|
a61ff12390 | ||
|
|
f4697be159 | ||
|
|
3835fe3960 | ||
|
|
76c374ef06 | ||
|
|
57d24bd948 | ||
|
|
deff14dfd8 | ||
|
|
0a479be370 | ||
|
|
ba6a2e3fd2 | ||
|
|
c3a395a41e | ||
|
|
a3136a19e9 | ||
|
|
b631568003 | ||
|
|
1d0c03eca4 | ||
|
|
eb30525a26 | ||
|
|
3e66ea3f56 | ||
|
|
9f1189e606 | ||
|
|
698927bed4 | ||
|
|
8fd02ee8dd | ||
|
|
f3154e8f5e | ||
|
|
878af163a9 | ||
|
|
da8341d014 | ||
|
|
95c33e88ed | ||
|
|
fed8369a5f | ||
|
|
d85806e3d5 | ||
|
|
097660ce53 | ||
|
|
b08cfbbb35 | ||
|
|
97ee3c47a0 | ||
|
|
05918de6ab | ||
|
|
8d7abd8298 | ||
|
|
727f4c3bb5 | ||
|
|
7372ad0cc4 | ||
|
|
ca6884dbca | ||
|
|
1ebb0ac5fb | ||
|
|
bf0e53f13b | ||
|
|
8888a960c0 | ||
|
|
04be41aac5 | ||
|
|
fd1313d49f | ||
|
|
3599dba5c3 | ||
|
|
67edc437d2 | ||
|
|
7a39d9240c | ||
|
|
6d2d9aed7e | ||
|
|
3c2e5f22b6 | ||
|
|
ddb6348bfd | ||
|
|
d70c5df5a0 | ||
|
|
b2799d198c | ||
|
|
f2fa2038b1 | ||
|
|
bfd59e64ea | ||
|
|
60e05e270a | ||
|
|
242b9a6af9 | ||
|
|
e7e8ad9bdc | ||
|
|
0e5d164a8a | ||
|
|
7293a8d3c0 | ||
|
|
097a4647a8 | ||
|
|
0942a7f3ff | ||
|
|
2df4370477 | ||
|
|
7243963106 | ||
|
|
9f17654052 | ||
|
|
1a65d7061d | ||
|
|
292363eb65 | ||
|
|
07e79ce61a | ||
|
|
1cf7dac82b | ||
|
|
6003b2902f | ||
|
|
ff0023a889 | ||
|
|
8c6bf5a1cc | ||
|
|
61c97ab940 | ||
|
|
b0a1b3b5ca | ||
|
|
4c7af01edc | ||
|
|
0d431213cd | ||
|
|
ad9dd9a2e2 | ||
|
|
c7895ed905 | ||
|
|
57d7979d51 | ||
|
|
61f6871cd1 | ||
|
|
406048f7b9 | ||
|
|
6dd5b0fe45 | ||
|
|
fd4bc5e3cf | ||
|
|
3bab2d8957 | ||
|
|
af2f5cd2e1 | ||
|
|
d4bb32da82 | ||
|
|
08aca6ca61 | ||
|
|
697b3c6772 | ||
|
|
878525ced8 | ||
|
|
418531736b | ||
|
|
6c175440c6 | ||
|
|
723a2f2008 | ||
|
|
ea9b9fbf17 | ||
|
|
303e257841 | ||
|
|
07b6a8ba92 | ||
|
|
e216e18368 | ||
|
|
e57c5b4bc2 | ||
|
|
f772d6ddeb | ||
|
|
cd37c301d9 | ||
|
|
f5fa26639e | ||
|
|
45ec73c115 | ||
|
|
13952ebd8b | ||
|
|
2df0007a10 | ||
|
|
89bc5db3e1 | ||
|
|
4021deec7f | ||
|
|
a3977f37f7 | ||
|
|
766c12242e | ||
|
|
a82b951aff | ||
|
|
997a94eecc | ||
|
|
635535aac2 | ||
|
|
25314fd91a | ||
|
|
9a06a5758d | ||
|
|
e5a2a9644f | ||
|
|
e0e7211852 | ||
|
|
cdaeb4d176 | ||
|
|
07aa2e280d | ||
|
|
6c4bc67ff3 | ||
|
|
d9f0cc27ef | ||
|
|
59aec9d289 | ||
|
|
451f4c503d | ||
|
|
cd82089d4d | ||
|
|
3db8b63cde | ||
|
|
6edf5d1e4f | ||
|
|
a23fa6fadd | ||
|
|
51eb77e409 | ||
|
|
691326cea8 | ||
|
|
3cac1238ed | ||
|
|
b04512a4f6 | ||
|
|
3a4d0549aa | ||
|
|
d7467f5dc3 | ||
|
|
141902b86d | ||
|
|
5aa680fc93 | ||
|
|
a790117f5a | ||
|
|
2a5a52c810 | ||
|
|
2156f4c2f3 | ||
|
|
2585460286 | ||
|
|
1b4af66986 | ||
|
|
0324bac044 | ||
|
|
2bfbe1ca27 | ||
|
|
60584228d9 | ||
|
|
44e34f7b11 | ||
|
|
7912050647 | ||
|
|
2231abd407 | ||
|
|
8d17ba4d66 | ||
|
|
8244bdb440 | ||
|
|
bc3b7ffd86 | ||
|
|
e22cb62493 | ||
|
|
e923aa1f72 | ||
|
|
68a21f1fbb | ||
|
|
74209e2607 | ||
|
|
1a38271104 | ||
|
|
e5ab5d6a5a | ||
|
|
2745ff727f | ||
|
|
24ea383937 | ||
|
|
9cb11d4d5f | ||
|
|
7202ea3340 | ||
|
|
d234ea01d0 | ||
|
|
e246cd37dd | ||
|
|
0a4ddedac9 | ||
|
|
0e4b80b002 | ||
|
|
a460a0dc44 | ||
|
|
f7212112b8 | ||
|
|
86d55b32a6 | ||
|
|
4b0d1aac15 | ||
|
|
fb7c06aa01 | ||
|
|
5c41be3470 | ||
|
|
a78df1a152 | ||
|
|
34e8db0fe3 | ||
|
|
70faecb8b5 | ||
|
|
237f278479 | ||
|
|
e766a00a12 | ||
|
|
ea03637ec1 | ||
|
|
d0f6d47b14 | ||
|
|
5bf1658d9a | ||
|
|
4ce9fb5b5a | ||
|
|
f80f02da73 | ||
|
|
52ece833a7 | ||
|
|
1ad6dde146 | ||
|
|
64bcfd23bd | ||
|
|
d659447879 | ||
|
|
e73eb55d75 | ||
|
|
a52cea29f4 | ||
|
|
3d91e59386 | ||
|
|
393b1d7674 | ||
|
|
c29a6b95ae | ||
|
|
567a4e8361 | ||
|
|
4d3e4c1a15 | ||
|
|
afeecdf4af | ||
|
|
4fe7105e2f | ||
|
|
d7c3a53f2d | ||
|
|
58e7574a6a | ||
|
|
94ab703c7c | ||
|
|
90350786e6 | ||
|
|
8038e1ee7d | ||
|
|
65f1a5fed6 | ||
|
|
64b94ab124 | ||
|
|
c03cb1de5e | ||
|
|
f0004290b4 | ||
|
|
7e1b49a742 | ||
|
|
d26c56e467 | ||
|
|
a51e0c26e5 | ||
|
|
180d39534c | ||
|
|
203d0e870a | ||
|
|
bed7d09764 | ||
|
|
3c762c9a02 | ||
|
|
ba5f0fb70b | ||
|
|
ebc3e05f23 | ||
|
|
674ad899f9 | ||
|
|
d945eb6fcf | ||
|
|
fb170e3c42 | ||
|
|
3658cca3e5 | ||
|
|
5e78a41b75 | ||
|
|
c23d8efe08 | ||
|
|
0d3d4b60ce | ||
|
|
38091c3c25 | ||
|
|
f0cd04ebc3 | ||
|
|
3295c18829 | ||
|
|
ccb309fd92 | ||
|
|
8206a26267 | ||
|
|
8c7b91bd79 | ||
|
|
061460f978 | ||
|
|
a47c7b8f27 | ||
|
|
a859908e83 | ||
|
|
86759d2f9c | ||
|
|
58c145ba08 | ||
|
|
c0bb3da22f | ||
|
|
031338d84d | ||
|
|
2a619f3fba | ||
|
|
1c145cbc09 | ||
|
|
5d71fde51b | ||
|
|
eec29f5c68 | ||
|
|
8fbd7acf2a | ||
|
|
7b824e6178 | ||
|
|
24c69a26ea | ||
|
|
7b03c95cfd | ||
|
|
d2b09ecfda | ||
|
|
4cdd42f391 | ||
|
|
4d0b3b287f | ||
|
|
0d7f784773 | ||
|
|
66ad54fbf0 | ||
|
|
33782859b8 | ||
|
|
3d294d5771 | ||
|
|
c889a83707 | ||
|
|
6a55af1950 | ||
|
|
a85cf2c2af | ||
|
|
4c0e3f92d3 | ||
|
|
e3354a805e | ||
|
|
ceb9a935de | ||
|
|
d3ad111b85 | ||
|
|
de740b1d9d | ||
|
|
7c155545ae | ||
|
|
a7597b2a6d | ||
|
|
22916c1904 | ||
|
|
a72e479e50 | ||
|
|
60c1776994 | ||
|
|
fbddb24728 | ||
|
|
e716f9e63a | ||
|
|
51c49d7c1b | ||
|
|
17a1b11f66 | ||
|
|
8a8e68146f | ||
|
|
dbe5dea525 | ||
|
|
604af822aa | ||
|
|
435759c21c | ||
|
|
847f094975 | ||
|
|
b939d86975 | ||
|
|
3e5f56b19b | ||
|
|
d81f42e3e9 | ||
|
|
4fb3d34786 | ||
|
|
9a0a527b2b | ||
|
|
ba8fb23b9d | ||
|
|
99790695a2 | ||
|
|
e3a86bb150 | ||
|
|
0ac1e885bd | ||
|
|
36aca1d39b | ||
|
|
d0192b4cab | ||
|
|
a3a7a585d7 | ||
|
|
b437d858f0 | ||
|
|
06f78178da | ||
|
|
06412cc5c0 | ||
|
|
1b86b9170f | ||
|
|
6e71d34390 | ||
|
|
0e880f2479 | ||
|
|
400a35de1d | ||
|
|
c47bfce010 | ||
|
|
73db7b399e | ||
|
|
f8a47c3c6a | ||
|
|
ee119de6c4 | ||
|
|
f37c0ed612 | ||
|
|
6b1d671aed | ||
|
|
44bbcd7033 | ||
|
|
e56dcba9d3 | ||
|
|
e8a2130094 | ||
|
|
be13c14376 | ||
|
|
6f0d0bed0b |
2
apps/bogobot/.cvsignore
Normal file
2
apps/bogobot/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.classpath
|
||||
.project
|
||||
214
apps/bogobot/Bogobot.java
Normal file
214
apps/bogobot/Bogobot.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* bogobot - A simple join/part stats logger bot for I2P IRC.
|
||||
*
|
||||
* Bogobot.java
|
||||
* 2004 The I2P Project
|
||||
* This code is public domain.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.log4j.DailyRollingFileAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
|
||||
import org.jibble.pircbot.IrcException;
|
||||
import org.jibble.pircbot.NickAlreadyInUseException;
|
||||
import org.jibble.pircbot.PircBot;
|
||||
import org.jibble.pircbot.User;
|
||||
|
||||
/**
|
||||
* TODO 0.4 Implement java.util.Properties for configuration.
|
||||
* TODO 0.4 Add NickServ interface.
|
||||
* TODO 0.5 Add multi-server capability.
|
||||
*
|
||||
* @author hypercubus
|
||||
* @version 0.3.1
|
||||
*/
|
||||
public class Bogobot extends PircBot {
|
||||
|
||||
private static final String INTERVAL_DAILY = "daily";
|
||||
private static final String INTERVAL_MONTHLY = "monthly";
|
||||
private static final String INTERVAL_WEEKLY = "weekly";
|
||||
|
||||
private boolean _isIntentionalDisconnect = false;
|
||||
private long _lastUserlistCommandTimestamp = 0;
|
||||
private Logger _logger = Logger.getLogger(Bogobot.class);
|
||||
/*
|
||||
* The following will soon be moved to bogo.config and loaded via
|
||||
* java.util.Properties when I get some time.
|
||||
*/
|
||||
private String _botPrimaryNick = "somebot";
|
||||
private String _botSecondaryNick = "somebot_";
|
||||
private String _botShutdownPassword = "take off eh";
|
||||
private long _commandAntiFloodInterval = 60;
|
||||
private String _ircChannel = "#i2p-chat";
|
||||
private String _ircServer = "irc.duck.i2p";
|
||||
private int _ircServerPort = 6668;
|
||||
private boolean _isLoggerEnabled = true;
|
||||
private boolean _isUserlistCommandEnabled = true;
|
||||
private String _logFilePrefix = "irc.duck.i2p.i2p-chat";
|
||||
private String _logFileRotationInterval = INTERVAL_DAILY;
|
||||
private String _ownerPrimaryNick = "somenick";
|
||||
private String _ownerSecondaryNick = "somenick_";
|
||||
private String _userlistCommandTrigger = "!who";
|
||||
|
||||
public Bogobot() {
|
||||
this.setName(_botPrimaryNick);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Bogobot bogobot = new Bogobot();
|
||||
|
||||
bogobot.setVerbose(true);
|
||||
|
||||
if (bogobot._isLoggerEnabled)
|
||||
bogobot.initLogger();
|
||||
|
||||
bogobot.connectToServer();
|
||||
}
|
||||
|
||||
protected void onDisconnect() {
|
||||
|
||||
if (_isIntentionalDisconnect)
|
||||
System.exit(0);
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " *** (Lost connection)");
|
||||
|
||||
try {
|
||||
Thread.sleep(60000);
|
||||
} catch (InterruptedException e) {
|
||||
// No worries.
|
||||
}
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
protected void onJoin(String channel, String sender, String login, String hostname) {
|
||||
if (sender.equals(this.getName())) {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " joins *** " + _botPrimaryNick + " ***");
|
||||
|
||||
} else {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " joins " + sender);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void onMessage(String channel, String sender, String login, String hostname, String message) {
|
||||
message = message.replaceFirst("<.+?> ", "");
|
||||
if (_isUserlistCommandEnabled && message.equals(_userlistCommandTrigger)) {
|
||||
|
||||
if (System.currentTimeMillis() - _lastUserlistCommandTimestamp < _commandAntiFloodInterval * 1000)
|
||||
return;
|
||||
|
||||
Object[] users = getUsers(_ircChannel);
|
||||
String output = "Userlist for " + _ircChannel + ": ";
|
||||
|
||||
for (int i = 0; i < users.length; i++)
|
||||
output += "[" + ((User) users[i]).getNick() + "] ";
|
||||
|
||||
sendMessage(_ircChannel, output);
|
||||
_lastUserlistCommandTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPart(String channel, String sender, String login, String hostname) {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " parts " + sender);
|
||||
|
||||
}
|
||||
|
||||
protected void onPrivateMessage(String sender, String login, String hostname, String message) {
|
||||
/*
|
||||
* Nobody else except the bot's owner can shut it down, unless of
|
||||
* course the owner's nick isn't registered and someone's spoofing it.
|
||||
*/
|
||||
if ((sender.equals(_ownerPrimaryNick) || sender.equals(_ownerSecondaryNick)) && message.equals(_botShutdownPassword)) {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " quits *** " + this.getName() + " ***");
|
||||
|
||||
_isIntentionalDisconnect = true;
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
|
||||
|
||||
if (_isLoggerEnabled)
|
||||
_logger.info(System.currentTimeMillis() + " quits " + sourceNick + " " + reason);
|
||||
|
||||
}
|
||||
|
||||
private void connectToServer() {
|
||||
|
||||
int loginAttempts = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
connect(_ircServer, _ircServerPort);
|
||||
break;
|
||||
} catch (NickAlreadyInUseException e) {
|
||||
if (loginAttempts == 1) {
|
||||
System.out.println("Sorry, the primary and secondary bot nicks are already taken. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
loginAttempts++;
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e1) {
|
||||
// Hmph.
|
||||
}
|
||||
|
||||
if (getName().equals(_botPrimaryNick))
|
||||
setName(_botSecondaryNick);
|
||||
else
|
||||
setName(_botPrimaryNick);
|
||||
|
||||
continue;
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error during login: ");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (IrcException e) {
|
||||
System.out.println("Error during login: ");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
joinChannel(_ircChannel);
|
||||
}
|
||||
|
||||
private void initLogger() {
|
||||
|
||||
String logFilePath = "logs" + File.separator + _logFilePrefix;
|
||||
DailyRollingFileAppender rollingFileAppender = null;
|
||||
|
||||
if (!(new File("logs").exists()))
|
||||
(new File("logs")).mkdirs();
|
||||
|
||||
try {
|
||||
|
||||
if (_logFileRotationInterval.equals("monthly"))
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM'.log'");
|
||||
else if (_logFileRotationInterval.equals("weekly"))
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-ww'.log'");
|
||||
else
|
||||
rollingFileAppender = new DailyRollingFileAppender(new PatternLayout("%m%n"), logFilePath, "'.'yyyy-MM-dd'.log'");
|
||||
|
||||
rollingFileAppender.setThreshold(Level.INFO);
|
||||
_logger.addAppender(rollingFileAppender);
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Error: Couldn't create or open an existing log file. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
352
apps/bogobot/Bogoparser.java
Normal file
352
apps/bogobot/Bogoparser.java
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* bogoparser - A simple logfile analyzer for bogobot.
|
||||
*
|
||||
* Bogoparser.java
|
||||
* 2004 The I2P Project
|
||||
* This code is public domain.
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author hypercubus
|
||||
* @version 0.3.1
|
||||
*/
|
||||
public class Bogoparser {
|
||||
|
||||
private static void displayUsageAndExit() {
|
||||
System.out.println("\r\nUsage:\r\n\r\n java Bogoparser [--by-duration] <logfile>\r\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Bogoparser bogoparser;
|
||||
|
||||
if (args.length < 1 || args.length > 2)
|
||||
displayUsageAndExit();
|
||||
|
||||
if (args.length == 2) {
|
||||
if (!args[0].equals("--by-duration"))
|
||||
displayUsageAndExit();
|
||||
bogoparser = new Bogoparser(args[1], true);
|
||||
}
|
||||
|
||||
if (args.length == 1)
|
||||
bogoparser = new Bogoparser(args[0], false);
|
||||
}
|
||||
|
||||
private Bogoparser(String logfile, boolean sortByDuration) {
|
||||
|
||||
ArrayList sortedSessions;
|
||||
|
||||
if (sortByDuration) {
|
||||
sortedSessions = sortSessionsByDuration(calculateSessionDurations(sortSessionsByTime(readLogfile(logfile))));
|
||||
formatAndOutputByDuration(sortedSessions);
|
||||
} else {
|
||||
sortedSessions = calculateSessionDurations(sortSessionsByQuitReason(sortSessionsByNick(sortSessionsByTime(readLogfile(logfile)))));
|
||||
formatAndOutput(sortedSessions);
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList calculateSessionDurations(ArrayList sortedSessionsByQuitReasonOrDuration) {
|
||||
|
||||
ArrayList calculatedSessionDurations = new ArrayList();
|
||||
|
||||
for (int i = 0; i+1 < sortedSessionsByQuitReasonOrDuration.size(); i += 2) {
|
||||
|
||||
String joinsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i);
|
||||
String[] joinsEntryFields = joinsEntry.split(" ");
|
||||
|
||||
String quitsEntry = (String) sortedSessionsByQuitReasonOrDuration.get(i+1);
|
||||
Pattern p = Pattern.compile("^([^ ]+) [^ ]+ ([^ ]+) (.*)$");
|
||||
Matcher m = p.matcher(quitsEntry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
String currentJoinTime = joinsEntryFields[0];
|
||||
String currentNick = m.group(2);
|
||||
String currentQuitReason = m.group(3);
|
||||
String currentQuitTime = m.group(1);
|
||||
long joinsTimeInMilliseconds;
|
||||
long quitsTimeInMilliseconds;
|
||||
long sessionLengthInMilliseconds;
|
||||
|
||||
joinsTimeInMilliseconds = Long.parseLong(currentJoinTime);
|
||||
quitsTimeInMilliseconds = Long.parseLong(currentQuitTime);
|
||||
sessionLengthInMilliseconds = quitsTimeInMilliseconds - joinsTimeInMilliseconds;
|
||||
|
||||
String hours = "" + sessionLengthInMilliseconds/1000/60/60;
|
||||
String minutes = "" + (sessionLengthInMilliseconds/1000/60)%60;
|
||||
|
||||
if (hours.length() < 2)
|
||||
hours = "0" + hours;
|
||||
|
||||
if (hours.length() < 3)
|
||||
hours = "0" + hours;
|
||||
|
||||
if (minutes.length() < 2)
|
||||
minutes = "0" + minutes;
|
||||
|
||||
int columnPadding = 19-currentNick.length();
|
||||
String columnPaddingString = " ";
|
||||
|
||||
for (int j = 0; j < columnPadding; j++)
|
||||
columnPaddingString = columnPaddingString + " ";
|
||||
|
||||
calculatedSessionDurations.add(sessionLengthInMilliseconds + " " + currentNick + columnPaddingString + " online " + hours + " hours " + minutes + " minutes " + currentQuitReason);
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + quitsEntry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return calculatedSessionDurations;
|
||||
}
|
||||
|
||||
private void formatAndOutput(ArrayList sortedSessions) {
|
||||
|
||||
String quitReason = null;
|
||||
|
||||
for (int i = 0; i < sortedSessions.size(); i++) {
|
||||
|
||||
String entry = (String) sortedSessions.get(i);
|
||||
Pattern p = Pattern.compile("^[\\d]+ ([^ ]+ +online [\\d]+ hours [\\d]+ minutes) (.*)$");
|
||||
Matcher m = p.matcher(entry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
if (quitReason == null) {
|
||||
quitReason = m.group(2);
|
||||
System.out.println("\r\nQUIT: " + ((m.group(2).equals("")) ? "No Reason Given" : quitReason) + "\r\n");
|
||||
}
|
||||
|
||||
String tempQuitReason = m.group(2);
|
||||
String tempSession = m.group(1);
|
||||
|
||||
if (tempQuitReason.equals(quitReason)) {
|
||||
System.out.println(" " + tempSession);
|
||||
} else {
|
||||
quitReason = null;
|
||||
i -= 1;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
System.out.println("\r\n");
|
||||
}
|
||||
|
||||
private void formatAndOutputByDuration(ArrayList sortedSessions) {
|
||||
System.out.println("\r\n");
|
||||
|
||||
for (int i = 0; i < sortedSessions.size(); i++) {
|
||||
String[] columns = ((String) sortedSessions.get(i)).split(" ", 2);
|
||||
System.out.println(columns[1]);
|
||||
}
|
||||
|
||||
System.out.println("\r\n");
|
||||
}
|
||||
|
||||
private ArrayList readLogfile(String logfile) {
|
||||
|
||||
ArrayList log = new ArrayList();
|
||||
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(logfile)));
|
||||
|
||||
for (String line; (line = in.readLine()) != null; )
|
||||
log.add(line);
|
||||
|
||||
in.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("\r\nError: Can't find logfile '" + logfile + "'.\r\n");
|
||||
System.exit(1);
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("\r\nError: Can't read logfile '" + logfile + "'.\r\n");
|
||||
System.exit(1);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs an odd-even transposition sort.
|
||||
*/
|
||||
private ArrayList sortSessionsByDuration(ArrayList calculatedSessionDurations) {
|
||||
|
||||
for (int i = 0; i < calculatedSessionDurations.size()/2; i++) {
|
||||
for (int j = 0; j+1 < calculatedSessionDurations.size(); j += 2) {
|
||||
|
||||
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
|
||||
long currentDuration = Long.parseLong(currentDurationString[0]);
|
||||
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
|
||||
long nextDuration = Long.parseLong(nextDurationString[0]);
|
||||
|
||||
if (currentDuration > nextDuration) {
|
||||
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
|
||||
calculatedSessionDurations.remove(j+2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 1; j+1 < calculatedSessionDurations.size(); j += 2) {
|
||||
|
||||
String[] currentDurationString = ((String) calculatedSessionDurations.get(j)).split(" ", 2);
|
||||
long currentDuration = Long.parseLong(currentDurationString[0]);
|
||||
String[] nextDurationString = ((String) calculatedSessionDurations.get(j+1)).split(" ", 2);
|
||||
long nextDuration = Long.parseLong(nextDurationString[0]);
|
||||
|
||||
if (currentDuration > nextDuration) {
|
||||
calculatedSessionDurations.add(j, calculatedSessionDurations.get(j+1));
|
||||
calculatedSessionDurations.remove(j+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return calculatedSessionDurations;
|
||||
}
|
||||
|
||||
private ArrayList sortSessionsByNick(ArrayList sortedSessionsByTime) {
|
||||
|
||||
ArrayList sortedSessionsByNick = new ArrayList();
|
||||
|
||||
while (sortedSessionsByTime.size() != 0) {
|
||||
|
||||
String entry = (String) sortedSessionsByTime.get(0);
|
||||
String[] entryFields = entry.split(" ");
|
||||
String currentNick = entryFields[2];
|
||||
|
||||
sortedSessionsByNick.add(entry);
|
||||
sortedSessionsByNick.add(sortedSessionsByTime.get(1));
|
||||
sortedSessionsByTime.remove(0);
|
||||
sortedSessionsByTime.remove(0);
|
||||
for (int i = 0; i+1 < sortedSessionsByTime.size(); i += 2) {
|
||||
|
||||
String nextEntry = (String) sortedSessionsByTime.get(i);
|
||||
String[] nextEntryFields = nextEntry.split(" ");
|
||||
|
||||
if (nextEntryFields[2].equals(currentNick)) {
|
||||
sortedSessionsByNick.add(nextEntry);
|
||||
sortedSessionsByNick.add(sortedSessionsByTime.get(i+1));
|
||||
sortedSessionsByTime.remove(i);
|
||||
sortedSessionsByTime.remove(i);
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sortedSessionsByNick;
|
||||
}
|
||||
|
||||
private ArrayList sortSessionsByQuitReason(ArrayList sortedSessionsByNick) {
|
||||
|
||||
ArrayList sortedSessionsByQuitReason = new ArrayList();
|
||||
|
||||
while (sortedSessionsByNick.size() != 0) {
|
||||
|
||||
String entry = (String) sortedSessionsByNick.get(1);
|
||||
Pattern p = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
|
||||
Matcher m = p.matcher(entry);
|
||||
|
||||
if (m.matches()) {
|
||||
|
||||
String currentQuitReason = m.group(1);
|
||||
|
||||
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(0));
|
||||
sortedSessionsByQuitReason.add(entry);
|
||||
sortedSessionsByNick.remove(0);
|
||||
sortedSessionsByNick.remove(0);
|
||||
for (int i = 0; i+1 < sortedSessionsByNick.size(); i += 2) {
|
||||
|
||||
String nextEntry = (String) sortedSessionsByNick.get(i+1);
|
||||
Pattern p2 = Pattern.compile("^[^ ]+ [^ ]+ [^ ]+ (.*)$");
|
||||
Matcher m2 = p2.matcher(nextEntry);
|
||||
|
||||
if (m2.matches()) {
|
||||
|
||||
String nextQuitReason = m2.group(1);
|
||||
|
||||
if (nextQuitReason.equals(currentQuitReason)) {
|
||||
sortedSessionsByQuitReason.add(sortedSessionsByNick.get(i));
|
||||
sortedSessionsByQuitReason.add(nextEntry);
|
||||
sortedSessionsByNick.remove(i);
|
||||
sortedSessionsByNick.remove(i);
|
||||
i -= 2;
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + nextEntry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("\r\nError: Unexpected entry in logfile: " + entry);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return sortedSessionsByQuitReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sessions terminated with "parts" messages instead of "quits" are filtered
|
||||
* out.
|
||||
*/
|
||||
private ArrayList sortSessionsByTime(ArrayList log) {
|
||||
|
||||
ArrayList sortedSessionsByTime = new ArrayList();
|
||||
|
||||
mainLoop:
|
||||
while (log.size() > 0) {
|
||||
|
||||
String entry = (String) log.get(0);
|
||||
String[] entryFields = entry.split(" ");
|
||||
|
||||
if (entryFields[1].equals("quits") && !entryFields[1].equals("joins")) {
|
||||
/*
|
||||
* Discard entry. The specified log either doesn't contain
|
||||
* the corresponding "joins" time for this quit entry or the
|
||||
* entry is a "parts" or unknown message, and in both cases
|
||||
* the entry's data is useless.
|
||||
*/
|
||||
log.remove(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 1; i < log.size(); i++) { // Find corresponding "quits" entry.
|
||||
|
||||
String tempEntry = (String) log.get(i);
|
||||
String[] tempEntryFields = tempEntry.split(" ");
|
||||
|
||||
if (tempEntryFields[2].equals(entryFields[2])) { // Check if the nick fields for the two entries match.
|
||||
if (!tempEntryFields[1].equals("quits")) {
|
||||
if (tempEntryFields[1].equals("joins")) { // Don't discard a subsequent "joins" entry.
|
||||
log.remove(0);
|
||||
continue mainLoop;
|
||||
}
|
||||
log.remove(i);
|
||||
continue;
|
||||
}
|
||||
sortedSessionsByTime.add(entry);
|
||||
sortedSessionsByTime.add(tempEntry);
|
||||
log.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Discard "joins" entry. The specified log doesn't contain the
|
||||
* corresponding "quits" time for this entry so the entry's
|
||||
* data is useless.
|
||||
*/
|
||||
|
||||
log.remove(0);
|
||||
}
|
||||
|
||||
return sortedSessionsByTime;
|
||||
}
|
||||
}
|
||||
48
apps/bogobot/LICENSE_log4j.txt
Normal file
48
apps/bogobot/LICENSE_log4j.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ============================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
* ============================================================================
|
||||
*
|
||||
* Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if any, must
|
||||
* include the following acknowledgment: "This product includes software
|
||||
* developed by the Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself, if
|
||||
* and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "log4j" and "Apache Software Foundation" must not be used to
|
||||
* endorse or promote products derived from this software without prior
|
||||
* written permission. For written permission, please contact
|
||||
* apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache", nor may
|
||||
* "Apache" appear in their name, without prior written permission of the
|
||||
* Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
|
||||
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* on behalf of the Apache Software Foundation. For more information on the
|
||||
* Apache Software Foundation, please see <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
340
apps/bogobot/LICENSE_pircbot.txt
Normal file
340
apps/bogobot/LICENSE_pircbot.txt
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
70
apps/bogobot/bogo.config
Normal file
70
apps/bogobot/bogo.config
Normal file
@@ -0,0 +1,70 @@
|
||||
#####
|
||||
# Bogobot user configuration (This file is not yet used.)
|
||||
#####
|
||||
|
||||
###
|
||||
# The bot's nick and backup nick. You will probably want to register these with
|
||||
# the IRC server's NickServ.(a NickServ interface is forthcoming).
|
||||
#
|
||||
botPrimaryNick=somebot
|
||||
botSecondaryNick=somebot_
|
||||
|
||||
#####
|
||||
# The bot owner's nick and backup nick. One of these must match the owner's
|
||||
# currently-used nick or else remote shutdown will not be possible. You will
|
||||
# probably want to register these with the IRC server's NickServ.
|
||||
#
|
||||
ownerPrimaryNick=somenick
|
||||
ownerSecondaryNick=somenick_
|
||||
|
||||
###
|
||||
# The bot will disconnect and shut down when sent this password via private
|
||||
# message (aka query) from either of the owner nicks specified above. DO NOT USE
|
||||
# THIS DEFAULT VALUE!
|
||||
#
|
||||
botShutdownPassword=take off eh
|
||||
|
||||
###
|
||||
# The server, channel, and port the bot will connect to.
|
||||
#
|
||||
ircChannel=#i2p-chat
|
||||
ircServer=irc.duck.i2p
|
||||
ircServerPort=6668
|
||||
|
||||
###
|
||||
# Set to "true" to enable logging, else "false" (but don't use quotation marks).
|
||||
#
|
||||
isLoggerEnabled=true
|
||||
|
||||
###
|
||||
# The prefix to be used for the filenames of logs.
|
||||
#
|
||||
logFilePrefix=irc.duck.i2p.i2p-chat
|
||||
|
||||
###
|
||||
# How often the logs should be rotated. Either "daily", "weekly", or "monthly"
|
||||
# (but don't use quotation marks).
|
||||
#
|
||||
logFileRotationInterval=daily
|
||||
|
||||
###
|
||||
# Set to "true" to enable the userlist command, else "false" (but don't use
|
||||
# quotation marks).
|
||||
#
|
||||
isUserlistCommandEnabled=true
|
||||
|
||||
###
|
||||
# The userlist trigger command to listen for. It is a good idea to prefix
|
||||
# triggers with some non-alphanumeric character in order to avoid accidental
|
||||
# trigger use during normal channel conversation. In most cases you will
|
||||
# probably want to choose a unique trigger here that no other bots in the
|
||||
# channel will respond to.
|
||||
#
|
||||
userlistCommandTrigger=!who
|
||||
|
||||
###
|
||||
# The number of seconds to rest after replying to a userlist command issued by
|
||||
# a user in the channel. The bot will ignore subsequent userlist commands during
|
||||
# this period. This helps prevent flooding.
|
||||
#
|
||||
commandAntiFloodInterval=60
|
||||
1
apps/bogobot/bogobot.bat
Normal file
1
apps/bogobot/bogobot.bat
Normal file
@@ -0,0 +1 @@
|
||||
java -cp .;log4j-1.2.8.jar;pircbot.jar Bogobot
|
||||
2
apps/bogobot/bogobot.sh
Normal file
2
apps/bogobot/bogobot.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
java -cp .:log4j-1.2.8.jar:pircbot.jar Bogobot
|
||||
63
apps/bogobot/build.xml
Normal file
63
apps/bogobot/build.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ********************************************************** -->
|
||||
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
|
||||
<!-- -->
|
||||
<!-- build.xml -->
|
||||
<!-- 2004 The I2P Project -->
|
||||
<!-- This code is public domain. -->
|
||||
<!-- -->
|
||||
<!-- author hypercubus -->
|
||||
<!-- version 0.3.1 -->
|
||||
<!-- ********************************************************** -->
|
||||
|
||||
<project basedir="." default="compile" name="Bogobot">
|
||||
|
||||
<!-- init:
|
||||
Create distribution directory if missing and initialize time stamp for
|
||||
archive naming -->
|
||||
<target name="init">
|
||||
<mkdir dir="dist" />
|
||||
<tstamp>
|
||||
<format pattern="yyyy-MM-dd" property="DSTAMP" />
|
||||
</tstamp>
|
||||
</target>
|
||||
|
||||
<!-- compile:
|
||||
Compile source code -->
|
||||
<target depends="init" description="Compile source code" name="compile">
|
||||
<javac classpath="${basedir}" source="1.4" srcdir="." />
|
||||
</target>
|
||||
|
||||
<!-- dist.bin:
|
||||
Create the binary distribution archive -->
|
||||
<target depends="init,compile" description="Create the binary distribution archive" name="dist.bin">
|
||||
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat Bogobot.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist.source:
|
||||
Create the source distribution archive -->
|
||||
<target depends="init" description="Create the source distribution archive" name="dist.source">
|
||||
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist:
|
||||
Create both the binary and source distribution archives -->
|
||||
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
|
||||
<echo message="Successfully created binary and source distribution archives in directory 'dist'." />
|
||||
</target>
|
||||
|
||||
<!-- clean:
|
||||
Delete all class files and temporary directories -->
|
||||
<target description="Delete all class files and temporary directories" name="clean">
|
||||
<delete>
|
||||
<fileset dir="${basedir}" includes="**/*.class" />
|
||||
</delete>
|
||||
<echo message="Clean successful." />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
57
apps/bogobot/build_eclipse.xml
Normal file
57
apps/bogobot/build_eclipse.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ********************************************************** -->
|
||||
<!-- bogobot - A simple join/part stats logger bot for I2P IRC. -->
|
||||
<!-- -->
|
||||
<!-- build_eclipse.xml -->
|
||||
<!-- 2004 The I2P Project -->
|
||||
<!-- This code is public domain. -->
|
||||
<!-- -->
|
||||
<!-- author hypercubus -->
|
||||
<!-- version 0.3.1 -->
|
||||
<!-- ********************************************************** -->
|
||||
|
||||
<project basedir="." default="dist" name="Bogobot">
|
||||
|
||||
<!-- init:
|
||||
Create distribution directory if missing and initialize time stamp for
|
||||
archive naming -->
|
||||
<target name="init">
|
||||
<mkdir dir="dist" />
|
||||
<tstamp>
|
||||
<format pattern="yyyy-MM-dd" property="DSTAMP" />
|
||||
</tstamp>
|
||||
</target>
|
||||
|
||||
<!-- dist.bin:
|
||||
Create the binary distribution archive -->
|
||||
<target depends="init" description="Create the binary distribution archive" name="dist.bin">
|
||||
<zip destfile="dist/Bogobot_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat Bogobot.class bogobot.sh Bogoparser.class LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist.source:
|
||||
Create the source distribution archive -->
|
||||
<target depends="init" description="Create the source distribution archive" name="dist.source">
|
||||
<zip destfile="dist/Bogobot_source_${DSTAMP}.zip">
|
||||
<zipfileset dir="${basedir}" includes="bogobot.bat Bogobot.java bogobot.sh Bogoparser.java build.xml build_eclipse.xml LICENSE_log4j.txt LICENSE_pircbot.txt log4j-1.2.8.jar pircbot.jar" />
|
||||
</zip>
|
||||
</target>
|
||||
|
||||
<!-- dist:
|
||||
Create both the binary and source distribution archives -->
|
||||
<target depends="dist.bin,dist.source" description="Create both the binary and source distribution archives" name="dist">
|
||||
<echo message="Successfully created binary and source distribution archives in directory 'dist'." />
|
||||
</target>
|
||||
|
||||
<!-- clean:
|
||||
Delete all class files and temporary directories -->
|
||||
<target description="Delete all class files and temporary directories" name="clean">
|
||||
<delete>
|
||||
<fileset dir="${basedir}" includes="**/*.class" />
|
||||
</delete>
|
||||
<echo message="Clean successful." />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
BIN
apps/bogobot/log4j-1.2.8.jar
Normal file
BIN
apps/bogobot/log4j-1.2.8.jar
Normal file
Binary file not shown.
BIN
apps/bogobot/pircbot.jar
Normal file
BIN
apps/bogobot/pircbot.jar
Normal file
Binary file not shown.
27
apps/enclave/LICENSE
Normal file
27
apps/enclave/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
87
apps/enclave/Makefile.cygwin
Normal file
87
apps/enclave/Makefile.cygwin
Normal file
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Cygwin
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating environment
|
||||
#
|
||||
|
||||
OS = CYGWIN
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
BINDIR = bin
|
||||
LOGDIR = log
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
SAMINCDIR = ../sam/c/inc
|
||||
SAMLIBDIR = ../sam/c/lib
|
||||
TOMCRYPTDIR = $(HOME)/libtomcrypt-0.96
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = g++
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -pipe -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
|
||||
#
|
||||
# Libraries
|
||||
#
|
||||
|
||||
CFLAGS += -I$(SAMINCDIR) -I$(TOMCRYPTDIR)
|
||||
LDFLAGS = -L$(SAMLIBDIR) -L$(TOMCRYPTDIR)
|
||||
LIBS = -lsam -ltomcrypt -lpthread
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/bigint.o \
|
||||
$(OBJDIR)/chk.o \
|
||||
$(OBJDIR)/config.o \
|
||||
$(OBJDIR)/logger.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/mutex.o \
|
||||
$(OBJDIR)/peers.o \
|
||||
$(OBJDIR)/random.o \
|
||||
$(OBJDIR)/rpc.o \
|
||||
$(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/sha1.o \
|
||||
$(OBJDIR)/thread.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend enclave
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.cpp > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
enclave: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(BINDIR)/enclave $(OBJS) $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(BINDIR)/* $(OBJDIR)/* .depend
|
||||
|
||||
clean-logs:
|
||||
-rm -f $(LOGDIR)/*
|
||||
|
||||
tidy: clean clean-logs
|
||||
87
apps/enclave/Makefile.linux
Normal file
87
apps/enclave/Makefile.linux
Normal file
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Linux (generic)
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating environment
|
||||
#
|
||||
|
||||
OS = LINUX
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
BINDIR = bin
|
||||
LOGDIR = log
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
SAMINCDIR = ../sam/c/inc
|
||||
SAMLIBDIR = ../sam/c/lib
|
||||
TOMCRYPTDIR = $(HOME)/libtomcrypt-0.96
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = g++
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -pipe -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
|
||||
#
|
||||
# Libraries
|
||||
#
|
||||
|
||||
CFLAGS += -I$(SAMINCDIR) -I$(TOMCRYPTDIR)
|
||||
LDFLAGS = -L$(SAMLIBDIR) -L$(TOMCRYPTDIR)
|
||||
LIBS = -lsam -ltomcrypt -lpthread
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/bigint.o \
|
||||
$(OBJDIR)/chk.o \
|
||||
$(OBJDIR)/config.o \
|
||||
$(OBJDIR)/logger.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/mutex.o \
|
||||
$(OBJDIR)/peers.o \
|
||||
$(OBJDIR)/random.o \
|
||||
$(OBJDIR)/rpc.o \
|
||||
$(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/sha1.o \
|
||||
$(OBJDIR)/thread.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend enclave
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.cpp > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
enclave: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(BINDIR)/enclave $(OBJS) $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(BINDIR)/* $(OBJDIR)/* .depend
|
||||
|
||||
clean-logs:
|
||||
-rm -f $(LOGDIR)/*
|
||||
|
||||
tidy: clean clean-logs
|
||||
87
apps/enclave/Makefile.mingw
Normal file
87
apps/enclave/Makefile.mingw
Normal file
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Windows (Mingw)
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating environment
|
||||
#
|
||||
|
||||
OS = MINGW
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
BINDIR = bin
|
||||
LOGDIR = log
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
SAMINCDIR = C:\cygwin\home\Administrator\cvs\i2p\apps\sam\c\inc
|
||||
SAMLIBDIR = C:\cygwin\home\Administrator\cvs\i2p\apps\sam\c\lib
|
||||
TOMCRYPTDIR = C:\cygwin\home\Administrator\libtomcrypt-0.96
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = C:\Dev-Cpp\bin\g++
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -pipe -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
|
||||
#
|
||||
# Libraries
|
||||
#
|
||||
|
||||
CFLAGS += -I$(SAMINCDIR) -I$(TOMCRYPTDIR)
|
||||
LDFLAGS = -L$(SAMLIBDIR) -L$(TOMCRYPTDIR)
|
||||
LIBS = -lsam -ltomcrypt
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/bigint.o \
|
||||
$(OBJDIR)/chk.o \
|
||||
$(OBJDIR)/config.o \
|
||||
$(OBJDIR)/logger.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/mutex.o \
|
||||
$(OBJDIR)/peers.o \
|
||||
$(OBJDIR)/random.o \
|
||||
$(OBJDIR)/rpc.o \
|
||||
$(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/sha1.o \
|
||||
$(OBJDIR)/thread.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend enclave
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.cpp > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
enclave: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(BINDIR)/enclave $(OBJS) $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(BINDIR)/* $(OBJDIR)/* .depend
|
||||
|
||||
clean-logs:
|
||||
-rm -f $(LOGDIR)/*
|
||||
|
||||
tidy: clean clean-logs
|
||||
32
apps/enclave/cfg/enclave.cfg
Normal file
32
apps/enclave/cfg/enclave.cfg
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is the Enclave configuration file. Lines starting with # and blank lines
|
||||
# are ignored.
|
||||
#
|
||||
|
||||
# The DNS name or IP address of the SAM server you will be using
|
||||
samhost=localhost
|
||||
|
||||
# The TCP port the SAM server is listening on
|
||||
samport=7656
|
||||
|
||||
# The destination name of this program. This can be anything. If you run
|
||||
# multiple copies of Enclave off the same SAM server then each one has to have a
|
||||
# unique name.
|
||||
samname=enclave
|
||||
|
||||
# The depth used for incoming and outgoing I2P tunnels. Using a depth of 2 is
|
||||
# the default and a good choice. You can set it to 0 if you don't care about
|
||||
# anonymity and just want speed.
|
||||
tunneldepth=0
|
||||
|
||||
# The location of the peer references file. You can use an absolute or relative
|
||||
# path, but absolute paths are safer.
|
||||
references=cfg/peers.ref
|
||||
|
||||
# Record every log message at or above this priority level
|
||||
# debug = 0, minor = 1, info = 2, warn = 3, error = 4
|
||||
loglevel=0
|
||||
|
||||
# The location of the Enclave log file. You can use an absolute or relative
|
||||
# path, but absolute paths are safer.
|
||||
logfile=log/enclave.log
|
||||
2
apps/enclave/cfg/peers.ref
Normal file
2
apps/enclave/cfg/peers.ref
Normal file
@@ -0,0 +1,2 @@
|
||||
4KpEG0uUvTM~IZKuWZZifdmh5UU6evIPG0tE3ppoqy37AY2NJrsM8BU0EkT1SG-g18qSW9UHDp7qs7m~WzeWTXyYggEb6k6-e0GYC2Cj8ED8JV58-2~cFZumVNJ2d1hns-MGX7RZv2lz3Cz2ZVhfZxSIw9UnpV-kwVn7sQ7PBCvJYE4INbp5OlRQH1-3lXiUheoJfeZpegGTUSHUwIRWglX7w87YF~LCbJMYXDgMyA3SaxsZaun7Wc8ku4bqtbmG9u15XlmqimLUUmDG0cw77HJzqxnR1C1hx0wf-9zgH6u4jwTWk92w5tZJZSv1SHKejlPkIbRNAhZv5wroyZsn6T0koV~kTVCvbUEwILho-rHn4A6C2jLQifwE9aucziBTVq3YLK2urf1wI1jLh98iFNav40S~B2w-4xZFAQ49bOdWzY4KmVIjocVhfGi~RLl5bHD1TEJS7nOaDhI8qCSe7mR0XzZgQ~iROR~XowlwKXBzNPjKED7yN8GgV2pWRGNYAAAA
|
||||
WiotuvEjGpSz7q14eZGYFpD0xNt3V~nxZdDDgKc~whkW-pardZyz~wZipHXLIOvniThDL2rxJ~OW7RxgUycCph4x--NL51kEJhMWZ~bgxPioxw-T4JGQ9LSNndt9xNOf6yhEqyokqyEOEeJjw6m2e7RX7mTRffmTlCdu6uH6rVEk22o4Uu5S26p6-LS2k9lRyMWitFd~t9cnOgLTZTE~h4d-UlAd1BGxpCTlGWcaynOQzKKtljZknZMF9Qv19MxT83t18~3IURb6aOLlC4oih9pMt1pHouZuOaStKA7cGLsXUAhSB31BvK8l4R7VhgcudwJ9EQZkZQee51hcng7K1Yqmd4lnjHHuf1mDk0YXBAWDZOM0-oEwkJWumGuYl0NUtLhNlFrBjenbjACx88qhfy6mkXfo8c-c2QqEXuD2xt4OVqrWxBTIrr1pR-E1NdIxzIvOlCbrRXaqxqu-wnrrG2vCO-1zu9NHacCVjXD7AR7p3T628wPdCUzj2~rZRcCkAAAA
|
||||
27
apps/enclave/libsockthread/LICENSE
Normal file
27
apps/enclave/libsockthread/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
160
apps/enclave/libsockthread/src/logger.cpp
Normal file
160
apps/enclave/libsockthread/src/logger.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include "time.hpp"
|
||||
#include "logger.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
/*
|
||||
* Closes the log file
|
||||
*/
|
||||
void Logger::close()
|
||||
{
|
||||
logf_m.lock();
|
||||
if (logf == NULL) {
|
||||
logf_m.unlock();
|
||||
return;
|
||||
}
|
||||
if (fclose(logf) == EOF) {
|
||||
cerr_m.lock();
|
||||
cerr << "fclose() failed: " << strerror(errno) << '\n';
|
||||
cerr_m.unlock();
|
||||
}
|
||||
logf = NULL;
|
||||
logf_m.unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a line to the log file. Uses variable arguments just like printf().
|
||||
*/
|
||||
void Logger::log(priority_t priority, const char* format, ...)
|
||||
{
|
||||
if (priority < get_loglevel())
|
||||
return;
|
||||
|
||||
char ll;
|
||||
switch (priority) {
|
||||
case Logger::DEBUG:
|
||||
ll = 'D';
|
||||
break;
|
||||
case Logger::MINOR:
|
||||
ll = 'M';
|
||||
break;
|
||||
case Logger::INFO:
|
||||
ll = 'I';
|
||||
break;
|
||||
case Logger::WARN:
|
||||
ll = 'W';
|
||||
break;
|
||||
case Logger::ERROR:
|
||||
ll = 'E';
|
||||
break;
|
||||
default:
|
||||
ll = '?';
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
Time t;
|
||||
logf_m.lock();
|
||||
|
||||
if (logf != NULL) {
|
||||
/*
|
||||
* Remember! If you change the format here, change it in the else too
|
||||
*/
|
||||
fprintf(logf, "%c %s ", ll, t.utc().c_str());
|
||||
vfprintf(logf, format, ap);
|
||||
fputc('\n', logf);
|
||||
if (fflush(logf) == EOF) {
|
||||
cerr_m.lock();
|
||||
cerr << "fflush() failed: " << strerror(errno) << '\n';
|
||||
cerr_m.unlock();
|
||||
}
|
||||
} else {
|
||||
// if they don't have an open log file, just use stderr
|
||||
fprintf(stderr, "%c %s ", ll, t.utc().c_str());
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
logf_m.unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a log file for appending. If a log file is already open, then it is
|
||||
* closed and the new one is opened.
|
||||
*
|
||||
* file - file location to open
|
||||
*/
|
||||
bool Logger::open(const string& file)
|
||||
{
|
||||
close();
|
||||
logf_m.lock();
|
||||
logf = fopen(file.c_str(), "a");
|
||||
if (logf != NULL) {
|
||||
logf_m.unlock();
|
||||
return true;
|
||||
} else {
|
||||
logf_m.unlock();
|
||||
cerr_m.lock();
|
||||
cerr << "fopen() failed (" << file << "): " << strerror(errno) << '\n';
|
||||
cerr_m.unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
// g++ -Wall -c thread.cpp -o thread.o
|
||||
// g++ -Wall -c mutex.cpp -o mutex.o
|
||||
// g++ -Wall -c time.cpp -o time.o
|
||||
// g++ -Wall -DUNIT_TEST -c logger.cpp -o logger.o
|
||||
// g++ -Wall -DUNIT_TEST logger.o mutex.o thread.o time.o -o logger -pthread
|
||||
int main()
|
||||
{
|
||||
Logger logger;
|
||||
|
||||
logger.open("delete.me");
|
||||
logger.set_loglevel(Logger::MINOR);
|
||||
logger.close();
|
||||
LWARNS("This should appear on stderr");
|
||||
logger.open("delete.me.also");
|
||||
LINFO("%s\n", "hey it works");
|
||||
LDEBUGS("This shouldn't be saved in the file.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
98
apps/enclave/libsockthread/src/logger.hpp
Normal file
98
apps/enclave/libsockthread/src/logger.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_LOGGER_HPP
|
||||
#define LIBSOCKTHREAD_LOGGER_HPP
|
||||
|
||||
/*
|
||||
* Some helpful macros:
|
||||
*
|
||||
* LDEBUG - debugging messages
|
||||
* LMINOR - unimportant messages
|
||||
* LINFO - informational messages
|
||||
* LWARN - errors we automatically recover from
|
||||
* LERROR - major, important errors
|
||||
*
|
||||
* These only work if your Logger object is called "logger"
|
||||
*/
|
||||
// Prints out the file name, function name, and line number before the message
|
||||
#define LDEBUG(format, ...) logger.log(Logger::DEBUG, "%s:%s:%d:" \
|
||||
format, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
// This is the same as above, except it doesn't accept varargs
|
||||
#define LDEBUGS(str) logger.log(Logger::DEBUG, "%s:%s:%d:" \
|
||||
str, __FILE__, __func__, __LINE__);
|
||||
#define LMINOR(format, ...) logger.log(Logger::MINOR, "%s:%s:%d:" \
|
||||
format, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define LMINORS(str) logger.log(Logger::MINOR, "%s:%s:%d:" \
|
||||
str, __FILE__, __func__, __LINE__);
|
||||
#define LINFO(format, ...) logger.log(Logger::INFO, "%s:%s:%d:" \
|
||||
format, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define LINFOS(str) logger.log(Logger::INFO, "%s:%s:%d:" \
|
||||
str, __FILE__, __func__, __LINE__);
|
||||
#define LWARN(format, ...) logger.log(Logger::WARN, "%s:%s:%d:" \
|
||||
format, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define LWARNS(str) logger.log(Logger::WARN, "%s:%s:%d:" \
|
||||
str, __FILE__, __func__, __LINE__);
|
||||
#define LERROR(format, ...) logger.log(Logger::ERROR, "%s:%s:%d:" \
|
||||
format, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define LERRORS(str) logger.log(Logger::ERROR, "%s:%s:%d:" \
|
||||
str, __FILE__, __func__, __LINE__);
|
||||
|
||||
namespace Libsockthread {
|
||||
class Logger {
|
||||
public:
|
||||
enum priority_t {DEBUG = 0, MINOR = 1, INFO = 2, WARN = 3,
|
||||
ERROR = 4};
|
||||
|
||||
Logger()
|
||||
: logf(NULL), loglevel(Logger::DEBUG) { }
|
||||
~Logger()
|
||||
{ close(); }
|
||||
|
||||
void close();
|
||||
void log(priority_t priority, const char* format, ...);
|
||||
priority_t get_loglevel()
|
||||
{ loglevel_m.lock(); priority_t ll = loglevel;
|
||||
loglevel_m.unlock(); return ll; }
|
||||
bool open(const string& file);
|
||||
void set_loglevel(priority_t priority)
|
||||
{ loglevel_m.lock(); loglevel = priority; loglevel_m.unlock(); }
|
||||
private:
|
||||
Mutex cerr_m;
|
||||
FILE* logf;
|
||||
Mutex logf_m;
|
||||
priority_t loglevel;
|
||||
Mutex loglevel_m;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_LOGGER_HPP
|
||||
134
apps/enclave/libsockthread/src/mutex.cpp
Normal file
134
apps/enclave/libsockthread/src/mutex.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modelled after JThread by Jori Liesenborgs
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "mutex.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
/*
|
||||
* Creates a mutex
|
||||
*/
|
||||
Mutex::Mutex()
|
||||
{
|
||||
#ifdef WINTHREAD
|
||||
mutex = CreateMutex(NULL, false, NULL);
|
||||
assert(mutex != NULL);
|
||||
#else
|
||||
int rc = pthread_mutex_init(&mutex, NULL);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys a mutex
|
||||
*/
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
#ifdef WINTHREAD
|
||||
BOOL rc = CloseHandle(mutex);
|
||||
assert(rc);
|
||||
#else
|
||||
int rc = pthread_mutex_destroy(&mutex);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Locks the mutex
|
||||
*/
|
||||
void Mutex::lock()
|
||||
{
|
||||
#ifdef WINTHREAD
|
||||
DWORD rc = WaitForSingleObject(mutex, INFINITE);
|
||||
assert(rc != WAIT_FAILED);
|
||||
#else
|
||||
int rc = pthread_mutex_lock(&mutex);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlocks the mutex
|
||||
*/
|
||||
void Mutex::unlock()
|
||||
{
|
||||
#ifdef WINTHREAD
|
||||
BOOL rc = ReleaseMutex(mutex);
|
||||
assert(rc);
|
||||
#else
|
||||
int rc = pthread_mutex_unlock(&mutex);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
// g++ -Wall -c thread.cpp -o thread.o
|
||||
// g++ -Wall -DUNIT_TEST -c mutex.cpp -o mutex.o
|
||||
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o mutex -pthread
|
||||
#include "thread.hpp"
|
||||
|
||||
Mutex widget;
|
||||
|
||||
int main()
|
||||
{
|
||||
class Mutex_test : public Thread
|
||||
{
|
||||
public:
|
||||
Mutex_test(int n)
|
||||
: testval(n) {}
|
||||
|
||||
void* thread()
|
||||
{
|
||||
widget.lock();
|
||||
cout << "I got it! thread #" << testval << '\n';
|
||||
// If this works, only one thread should be able to lock the
|
||||
// widget, since it is never unlocked
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int testval;
|
||||
};
|
||||
|
||||
Mutex_test t1(1);
|
||||
Mutex_test t2(2);
|
||||
Mutex_test t3(3);
|
||||
t1.start(); t2.start(); t3.start();
|
||||
while (true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
57
apps/enclave/libsockthread/src/mutex.hpp
Normal file
57
apps/enclave/libsockthread/src/mutex.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modelled after JThread by Jori Liesenborgs
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_MUTEX_HPP
|
||||
#define LIBSOCKTHREAD_MUTEX_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
#ifdef WINTHREAD
|
||||
HANDLE mutex;
|
||||
#else
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_MUTEX_HPP
|
||||
77
apps/enclave/libsockthread/src/platform.hpp
Normal file
77
apps/enclave/libsockthread/src/platform.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: platform.hpp,v 1.5 2004/07/22 03:54:01 mpc Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Global includes and platform configuration. This is used to compile the
|
||||
* library, but is not intended for use by users of the library in their
|
||||
* own programs.
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_PLATFORM_HPP
|
||||
#define LIBSOCKTHREAD_PLATFORM_HPP
|
||||
|
||||
/*
|
||||
* Operating system
|
||||
*/
|
||||
#define FREEBSD 0 // FreeBSD
|
||||
#define WIN32 1 // Windows
|
||||
#define LINUX 2 // Linux
|
||||
|
||||
#if OS == WIN32
|
||||
#define WINSOCK
|
||||
#define WINTHREAD
|
||||
#endif
|
||||
|
||||
#ifndef WINSOCK
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#ifndef WINSOCK
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifndef WINTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stdint.h> // TODO replace with Boost's version
|
||||
#include <string>
|
||||
#if defined WINSOCK || defined WINTHREAD
|
||||
#include <windows.h>
|
||||
#endif
|
||||
using namespace std;
|
||||
#include "types.hpp"
|
||||
|
||||
#endif // LIBSOCKTHREAD_PLATFORM_HPP
|
||||
72
apps/enclave/libsockthread/src/socket.cpp
Normal file
72
apps/enclave/libsockthread/src/socket.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: socket.cpp,v 1.8 2004/07/22 22:08:20 mpc Exp $
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "socket_error.hpp"
|
||||
#include "socket.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
/*
|
||||
* Closes the socket
|
||||
*/
|
||||
void Socket::close()
|
||||
{
|
||||
if (sock != SERR) {
|
||||
if (close(sock) == -1)
|
||||
; // FIXME log the error
|
||||
}
|
||||
sock = SERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes the address associated with the socket
|
||||
*/
|
||||
void Socket::set_addr(Socket_addr& addr)
|
||||
{
|
||||
close();
|
||||
this->addr = addr;
|
||||
setup_socket();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepares the socket for use
|
||||
*/
|
||||
void Socket::setup_socket()
|
||||
{
|
||||
assert(sock == SERR); // the descriptor shouldn't be active
|
||||
if (!addr.is_ready())
|
||||
throw Socket_error("Couldn't create socket: address isn't ready");
|
||||
|
||||
sock = socket(addr.get_family(), addr.get_type(), 0);
|
||||
if (sock == SERR)
|
||||
throw Socket_error(strerror(errno));
|
||||
}
|
||||
68
apps/enclave/libsockthread/src/socket.hpp
Normal file
68
apps/enclave/libsockthread/src/socket.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: socket.hpp,v 1.8 2004/07/22 22:08:20 mpc Exp $
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_SOCKET_HPP
|
||||
#define LIBSOCKTHREAD_SOCKET_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Socket {
|
||||
public:
|
||||
#ifdef WINSOCK
|
||||
typedef SOCKET socket_t;
|
||||
enum { SERR = SOCKET_ERROR };
|
||||
#else
|
||||
typedef int socket_t;
|
||||
enum { SERR = -1 };
|
||||
#endif
|
||||
|
||||
Socket()
|
||||
: addr(), sock(SERR) {}
|
||||
Socket(Socket_addr& addr) // throws Socket_error
|
||||
: addr(addr), sock(SERR) { setup_socket(); }
|
||||
|
||||
void close();
|
||||
size_t read(vector<uchar_t>& buf, size_t max = 0);
|
||||
size_t read_until(vector<uchar_t>& buf, uchar_t delim = '\n');
|
||||
void set_addr(Socket_addr& addr); // throws Socket_error
|
||||
void set_blocking(bool blocking);
|
||||
size_t write(vector<uchar_t>& buf);
|
||||
void write_all(vector<uchar_t>& buf);
|
||||
size_t write_until(vector<uchar_t& buf, uchar_t delim = '\n');
|
||||
private:
|
||||
void setup_socket(); // throws Socket_error
|
||||
|
||||
Socket_addr addr;
|
||||
socket_t sock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_SOCKET_HPP
|
||||
108
apps/enclave/libsockthread/src/socket_addr.cpp
Normal file
108
apps/enclave/libsockthread/src/socket_addr.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: socket_addr.cpp,v 1.4 2004/07/22 19:10:59 mpc Exp $
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "socket_error.hpp"
|
||||
#include "socket_addr.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
Socket_addr::Socket_addr(Socket_addr& rhs)
|
||||
{
|
||||
delete[] ip;
|
||||
if (rhs.resolved) {
|
||||
if (rhs.family == AF_INET) {
|
||||
ip = new char[INET_ADDRSTRLEN];
|
||||
else
|
||||
ip = new char[INET6_ADDRSTRLEN];
|
||||
strcpy(ip, rhs.ip);
|
||||
}
|
||||
family = rhs.family;
|
||||
host = rhs.host;
|
||||
port = rhs.port;
|
||||
resolved = rhs.resolved;
|
||||
type = rhs.type;
|
||||
}
|
||||
|
||||
Socket_addr& Socket_addr::operator=(const Socket_addr& rhs)
|
||||
{
|
||||
if (this == &rhs) // check for self-assignment: a = a
|
||||
return *this;
|
||||
|
||||
delete[] ip;
|
||||
if (rhs.resolved) {
|
||||
if (rhs.family == AF_INET)
|
||||
ip = new char[INET_ADDRSTRLEN];
|
||||
else
|
||||
ip = new char[INET6_ADDRSTRLEN];
|
||||
strcpy(ip, rhs.ip);
|
||||
}
|
||||
family = rhs.family;
|
||||
host = rhs.host;
|
||||
port = rhs.port;
|
||||
type = rhs.type;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a DNS lookup
|
||||
*/
|
||||
void Socket_addr::resolve()
|
||||
{
|
||||
resolved = false; // in case they already had a host name but just set a
|
||||
// new one with set_host()
|
||||
hostent* hent = gethostbyname(host.c_str());
|
||||
if (hent == NULL)
|
||||
throw Dns_error(hstrerror(h_errno));
|
||||
assert(hent->h_addrtype == AF_INET || hent->h_addrtype == AF_INET6);
|
||||
family = hent->h_addrtype;
|
||||
delete[] ip;
|
||||
if (family == AF_INET) {
|
||||
ip = new char[INET_ADDRSTRLEN];
|
||||
else
|
||||
ip = new char[INET6_ADDRSTRLEN];
|
||||
strcpy(ip, hent->h_addr_list[0]);
|
||||
resolved = true;
|
||||
}
|
||||
|
||||
bool Socket_addr::operator==(const Socket_addr& rhs)
|
||||
{
|
||||
if (rhs.family == family
|
||||
&& rhs.host == host
|
||||
&& strcmp(rhs.ip, ip) == 0
|
||||
&& rhs.port == port
|
||||
&& rhs.resolved == resolved
|
||||
&& rhs.type == type)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
78
apps/enclave/libsockthread/src/socket_addr.hpp
Normal file
78
apps/enclave/libsockthread/src/socket_addr.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: socket_addr.hpp,v 1.4 2004/07/22 19:10:59 mpc Exp $
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_SOCKET_ADDR_HPP
|
||||
#define LIBSOCKTHREAD_SOCKET_ADDR_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Socket_addr {
|
||||
public:
|
||||
Socket_addr()
|
||||
: family(AF_INET), resolved(false) { }
|
||||
Socket_addr(Socket_addr& rhs);
|
||||
Socket_addr(int type, string& host, uint16_t port)
|
||||
: family(AF_INET), host(host), type(type), port(port)
|
||||
{ resolve(); } // throws Dns_error
|
||||
~Socket_addr()
|
||||
{ delete[] ip; }
|
||||
|
||||
int get_family() const
|
||||
{ return family; }
|
||||
const char* get_ip() const // Warning! This can be NULL!
|
||||
{ return ip; }
|
||||
uint16_t get_port() const
|
||||
{ return port; }
|
||||
int get_type() const
|
||||
{ return type;
|
||||
bool is_ready() const
|
||||
{ return resolved; }
|
||||
Socket_addr& operator=(const Socket_addr& rhs);
|
||||
bool operator==(const Socket_addr& rhs);
|
||||
void set_host(string& host) // throws Dns_error
|
||||
{ this->host = host; resolve(); }
|
||||
void set_port(uint16_t port)
|
||||
{ this->port = port; }
|
||||
void set_type(int type)
|
||||
{ this->type = type; }
|
||||
private:
|
||||
void resolve(); // throws Dns_error
|
||||
|
||||
int family; // AF_INET or AF_INET6
|
||||
string host;
|
||||
char* ip;
|
||||
uint16_t port;
|
||||
bool resolved;
|
||||
int type; // SOCK_STREAM or SOCK_DGRAM
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_SOCKET_ADDR_HPP
|
||||
35
apps/enclave/libsockthread/src/socket_connector.cpp
Normal file
35
apps/enclave/libsockthread/src/socket_connector.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "socket_connector.hpp"
|
||||
using namespace Libsockthread;
|
||||
46
apps/enclave/libsockthread/src/socket_connector.hpp
Normal file
46
apps/enclave/libsockthread/src/socket_connector.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP
|
||||
#define LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Socket_connector : public Socket {
|
||||
public:
|
||||
Socket_connector(Socket_addr& addr)
|
||||
: Socket(addr);
|
||||
|
||||
void connect();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP
|
||||
47
apps/enclave/libsockthread/src/socket_error.hpp
Normal file
47
apps/enclave/libsockthread/src/socket_error.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_SOCKET_ERROR_HPP
|
||||
#define LIBSOCKTHREAD_SOCKET_ERROR_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Socket_error : public runtime_error {
|
||||
public:
|
||||
Socket_error(const string& s)
|
||||
: runtime_error(s) { }
|
||||
};
|
||||
class Dns_error : public Socket_error {
|
||||
public:
|
||||
Dns_error(const string& s)
|
||||
: Socket_error(s) { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_SOCKET_ERROR_HPP
|
||||
35
apps/enclave/libsockthread/src/socket_listener.cpp
Normal file
35
apps/enclave/libsockthread/src/socket_listener.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "socket_listener.hpp"
|
||||
using namespace Libsockthread;
|
||||
47
apps/enclave/libsockthread/src/socket_listener.hpp
Normal file
47
apps/enclave/libsockthread/src/socket_listener.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_SOCKET_LISTENER_HPP
|
||||
#define LIBSOCKTHREAD_SOCKET_LISTENER_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Socket_listener {
|
||||
public:
|
||||
Socket_listener(Socket_addr& addr)
|
||||
: Socket(addr);
|
||||
|
||||
void accept();
|
||||
void listen();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_SOCKET_LISTENER_HPP
|
||||
86
apps/enclave/libsockthread/src/strl.c
Normal file
86
apps/enclave/libsockthread/src/strl.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
49
apps/enclave/libsockthread/src/strl.h
Normal file
49
apps/enclave/libsockthread/src/strl.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: The strl.c file retains its original license (at the top of strl.c)
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_STRL_H
|
||||
#define LIBSOCKTHREAD_STRL_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern size_t strlcat(char *dst, const char *src, size_t siz);
|
||||
extern size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* LIBSOCKTHREAD_STRL_H */
|
||||
194
apps/enclave/libsockthread/src/thread.cpp
Normal file
194
apps/enclave/libsockthread/src/thread.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modelled after JThread by Jori Liesenborgs
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include "thread.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
/*
|
||||
* Gets the return value of a finished thread
|
||||
*/
|
||||
void* Thread::get_retval()
|
||||
{
|
||||
void* val;
|
||||
running_m.lock();
|
||||
if (running)
|
||||
val = NULL;
|
||||
else
|
||||
val = retval;
|
||||
running_m.unlock();
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the thread is running
|
||||
*/
|
||||
bool Thread::is_running()
|
||||
{
|
||||
running_m.lock();
|
||||
bool r = running;
|
||||
running_m.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stops the thread
|
||||
* Generally NOT a good idea
|
||||
*/
|
||||
void Thread::kill()
|
||||
{
|
||||
running_m.lock();
|
||||
#ifndef NDEBUG
|
||||
// make sure it as actually running first
|
||||
if (!running) {
|
||||
running_m.unlock();
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
#ifdef WINTHREAD
|
||||
BOOL rc = TerminateThread(handle, NULL);
|
||||
assert(rc);
|
||||
#else
|
||||
int rc = pthread_cancel(id);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
running = false;
|
||||
running_m.unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts the thread
|
||||
*/
|
||||
void Thread::start()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// check whether the thread is already running
|
||||
running_m.lock();
|
||||
assert(!running);
|
||||
running_m.unlock();
|
||||
#endif
|
||||
continue_m.lock();
|
||||
#ifdef WINTHREAD
|
||||
handle = CreateThread(NULL, 0, &the_thread, this, 0, &id);
|
||||
assert(handle != NULL);
|
||||
#else
|
||||
int rc = pthread_create(&id, 0, &the_thread, this);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
// Wait until `running' is set
|
||||
running_m.lock();
|
||||
while (!running) {
|
||||
running_m.unlock();
|
||||
running_m.lock();
|
||||
}
|
||||
running_m.unlock();
|
||||
continue_m.unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for the thread
|
||||
*/
|
||||
void* Thread::the_thread(void *param)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(param);
|
||||
t->running_m.lock();
|
||||
t->running = true;
|
||||
t->running_m.unlock();
|
||||
// wait until we can continue
|
||||
t->continue_m.lock();
|
||||
t->continue_m.unlock();
|
||||
void* ret = t->thread();
|
||||
t->running_m.lock();
|
||||
t->running = false;
|
||||
t->retval = ret;
|
||||
t->running_m.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
// g++ -Wall -c mutex.cpp -o mutex.o
|
||||
// g++ -Wall -DUNIT_TEST -c thread.cpp -o thread.o
|
||||
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o thread -pthread
|
||||
int main()
|
||||
{
|
||||
class Thread_test : public Thread
|
||||
{
|
||||
public:
|
||||
Thread_test(int testval)
|
||||
: testval(testval) { }
|
||||
|
||||
int get_testval()
|
||||
{
|
||||
testval_m.lock();
|
||||
int rc = testval;
|
||||
testval_m.unlock();
|
||||
return rc;
|
||||
}
|
||||
void *thread()
|
||||
{
|
||||
// just do something
|
||||
while (true) {
|
||||
testval_m.lock();
|
||||
++testval;
|
||||
testval_m.unlock();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int testval;
|
||||
Mutex testval_m;
|
||||
};
|
||||
|
||||
Thread_test t1(1);
|
||||
t1.start();
|
||||
Thread_test t2(1000000);
|
||||
t2.start();
|
||||
Thread_test t3(-1000000);
|
||||
t3.start();
|
||||
while (true) {
|
||||
if (t1.is_running())
|
||||
cout << "t1 is running..." << t1.get_testval() << '\n';
|
||||
if (t2.is_running())
|
||||
cout << "t2 is running..." << t2.get_testval() << '\n';
|
||||
if (t3.is_running())
|
||||
cout << "t3 is running..." << t3.get_testval() << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
69
apps/enclave/libsockthread/src/thread.hpp
Normal file
69
apps/enclave/libsockthread/src/thread.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modelled after JThread by Jori Liesenborgs
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_THREAD_HPP
|
||||
#define LIBSOCKTHREAD_THREAD_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Thread {
|
||||
public:
|
||||
Thread()
|
||||
: retval(NULL), running(false) { }
|
||||
virtual ~Thread()
|
||||
{ kill(); }
|
||||
|
||||
void* get_retval();
|
||||
bool is_running();
|
||||
void kill();
|
||||
void start();
|
||||
virtual void* thread() = 0;
|
||||
private:
|
||||
#ifdef WINTHREAD
|
||||
static DWORD WINAPI the_thread(void* param);
|
||||
HANDLE handle;
|
||||
DWORD id;
|
||||
#else
|
||||
static void* the_thread(void* param);
|
||||
pthread_t id;
|
||||
#endif
|
||||
Mutex continue_m;
|
||||
void* retval;
|
||||
bool running;
|
||||
Mutex running_m;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_THREAD_HPP
|
||||
85
apps/enclave/libsockthread/src/time.cpp
Normal file
85
apps/enclave/libsockthread/src/time.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "time.hpp"
|
||||
using namespace Libsockthread;
|
||||
|
||||
/*
|
||||
* Converts the time to an ISO 8601 standard date and time
|
||||
* Example: 2004-07-01T19:03:47Z
|
||||
*/
|
||||
string& Time::utc()
|
||||
{
|
||||
struct tm* tm = gmtime(&unixtime);
|
||||
char t[21];
|
||||
strftime(t, sizeof t, "%Y-%m-%dT%H:%M:%SZ", tm);
|
||||
return formatted = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts the time to an ISO 8601 standard date
|
||||
* Example: 2004-07-01Z
|
||||
*/
|
||||
string& Time::utc_date()
|
||||
{
|
||||
struct tm* tm = gmtime(&unixtime);
|
||||
char t[12];
|
||||
strftime(t, sizeof t, "%Y-%m-%dZ", tm);
|
||||
return formatted = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts the time to an ISO 8601 standard time
|
||||
* Example: 19:03:47Z
|
||||
*/
|
||||
string& Time::utc_time()
|
||||
{
|
||||
struct tm* tm = gmtime(&unixtime);
|
||||
char t[10];
|
||||
strftime(t, sizeof t, "%H:%M:%SZ", tm);
|
||||
return formatted = t;
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
// g++ -Wall -DUNIT_TEST time.cpp -o time
|
||||
int main()
|
||||
{
|
||||
Time t;
|
||||
cout << "Current date and time is " << t.utc() << '\n';
|
||||
cout << "Current date is " << t.utc_date() << '\n';
|
||||
cout << "Current time is " << t.utc_time() << '\n';
|
||||
cout << "Formatted time is " << t.get_formatted() << " (should be the same)\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
55
apps/enclave/libsockthread/src/time.hpp
Normal file
55
apps/enclave/libsockthread/src/time.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_TIME_HPP
|
||||
#define LIBSOCKTHREAD_TIME_HPP
|
||||
|
||||
namespace Libsockthread {
|
||||
class Time {
|
||||
public:
|
||||
Time()
|
||||
{ now(); }
|
||||
|
||||
string& get_formatted()
|
||||
{ return formatted; }
|
||||
void now()
|
||||
{ unixtime = time(0); }
|
||||
string& utc();
|
||||
string& utc_date();
|
||||
string& utc_time();
|
||||
private:
|
||||
string formatted;
|
||||
time_t unixtime;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBSOCKTHREAD_TIME_HPP
|
||||
45
apps/enclave/libsockthread/src/types.hpp
Normal file
45
apps/enclave/libsockthread/src/types.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LIBSOCKTHREAD_TYPES_HPP
|
||||
#define LIBSOCKTHREAD_TYPES_HPP
|
||||
|
||||
/*
|
||||
* Shorten some standard variable types
|
||||
*/
|
||||
typedef signed char schar_t;
|
||||
typedef unsigned char uchar_t;
|
||||
typedef unsigned int uint_t;
|
||||
typedef unsigned long ulong_t;
|
||||
typedef unsigned short ushort_t;
|
||||
|
||||
#endif // LIBSOCKTHREAD_TYPES_HPP
|
||||
169
apps/enclave/src/bigint.cpp
Normal file
169
apps/enclave/src/bigint.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "bigint.hpp"
|
||||
|
||||
/******************************************************************************/
|
||||
// Note: All the const_casts below are necessary because libtomcrypt doesn't //
|
||||
// have its arguments as const, even when they are not changed //
|
||||
/******************************************************************************/
|
||||
|
||||
Bigint::Bigint(const Bigint& bigint)
|
||||
{
|
||||
init();
|
||||
copyover_mp_int(bigint.mpi);
|
||||
}
|
||||
|
||||
Bigint::Bigint(const uchar_t* data, size_t size)
|
||||
{
|
||||
init();
|
||||
import_uraw(data, size);
|
||||
}
|
||||
|
||||
Bigint::Bigint(uint16_t i)
|
||||
{
|
||||
init();
|
||||
i = htons(i);
|
||||
import_uraw(reinterpret_cast<uchar_t*>(&i), 2);
|
||||
}
|
||||
|
||||
Bigint::Bigint(uint32_t i)
|
||||
{
|
||||
init();
|
||||
i = htonl(i);
|
||||
import_uraw(reinterpret_cast<uchar_t*>(&i), 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces our current mp_int with another one
|
||||
* (just a wrapper for mp_copy)
|
||||
*/
|
||||
void Bigint::copyover_mp_int(const mp_int& i)
|
||||
{
|
||||
int rc = mp_copy(const_cast<mp_int*>(&i), &mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves a Bigint to a raw unsigned big-endian integer
|
||||
* Note that the result must be freed with delete[]
|
||||
*
|
||||
* size - filled with the size of the output
|
||||
*
|
||||
* Returns: binary data
|
||||
*/
|
||||
uchar_t* Bigint::export_uraw(size_t& size) const
|
||||
{
|
||||
uchar_t* out;
|
||||
size = mp_unsigned_bin_size(const_cast<mp_int*>(&mpi));
|
||||
if (size != 0) {
|
||||
out = new uchar_t[size];
|
||||
int rc = mp_to_unsigned_bin(const_cast<mp_int*>(&mpi), out);
|
||||
assert(rc == MP_OKAY);
|
||||
} else { // size == 0
|
||||
size = 1;
|
||||
out = new uchar_t[1];
|
||||
out[0] = 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a raw unsigned big-endian integer into Bigint
|
||||
*
|
||||
* data - binary data
|
||||
* size - size of data
|
||||
*/
|
||||
void Bigint::import_uraw(const uchar_t* data, size_t size)
|
||||
{
|
||||
uchar_t tmp[size]; // mp_read_unsigned_bin() arg 2 is not const
|
||||
memcpy(tmp, data, sizeof tmp); // I'm not taking any chances
|
||||
int rc = mp_read_unsigned_bin(&mpi, tmp, sizeof tmp);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialises the object
|
||||
*/
|
||||
void Bigint::init(void)
|
||||
{
|
||||
int rc = mp_init(&mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
bool Bigint::operator<(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_LT)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
Bigint& Bigint::operator=(const Bigint& rhs)
|
||||
{
|
||||
if (this != &rhs) // check for self-assignment: a = a
|
||||
copyover_mp_int(rhs.mpi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Bigint::operator==(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_EQ)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bigint::operator>(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_GT)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xors another Bigint with this Bigint and puts the result in Bigint `result'.
|
||||
* We can't name it "xor" because that word is reserved in C++ (see Appendex C,
|
||||
* section 3.1 in TC++PL).
|
||||
*
|
||||
* rhs - the bigint to xor with
|
||||
* result - will be filled with the result of the xor
|
||||
*/
|
||||
void Bigint::x_or(const Bigint& rhs, Bigint& result) const
|
||||
{
|
||||
int rc = mp_xor(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi),
|
||||
&result.mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
60
apps/enclave/src/bigint.hpp
Normal file
60
apps/enclave/src/bigint.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BIGINT_HPP
|
||||
#define BIGINT_HPP
|
||||
|
||||
class Bigint {
|
||||
public:
|
||||
Bigint(void) { init(); }
|
||||
Bigint(const Bigint& bigint);
|
||||
Bigint(const uchar_t* data, size_t size);
|
||||
Bigint(uint16_t i);
|
||||
Bigint(uint32_t i);
|
||||
~Bigint(void) { mp_clear(&mpi); }
|
||||
|
||||
uchar_t* export_uraw(size_t& size) const;
|
||||
const mp_int& get_mp_int(void) const { return mpi; }
|
||||
void import_uraw(const uchar_t* data, size_t size);
|
||||
bool operator<(const Bigint& rhs) const;
|
||||
Bigint& operator=(const Bigint& rhs);
|
||||
bool operator==(const Bigint& rhs) const;
|
||||
bool operator>(const Bigint& rhs) const;
|
||||
void x_or(const Bigint& rhs, Bigint& result) const;
|
||||
|
||||
protected:
|
||||
mp_int mpi;
|
||||
|
||||
private:
|
||||
void copyover_mp_int(const mp_int& i);
|
||||
void init(void);
|
||||
};
|
||||
|
||||
#endif // BIGINT_HPP
|
||||
56
apps/enclave/src/chk.cpp
Normal file
56
apps/enclave/src/chk.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "chk.hpp"
|
||||
|
||||
Chk::Chk(const uchar_t* plaintext, size_t size, const string& mime_type)
|
||||
: data_size(size), mime_type(mime_type)
|
||||
{
|
||||
encrypt(plaintext);
|
||||
}
|
||||
|
||||
void Chk::encrypt(const uchar_t *pt)
|
||||
{
|
||||
int rc = register_cipher(&twofish_desc);
|
||||
assert(rc != -1);
|
||||
|
||||
uchar_t key[CRYPT_KEY_SIZE], iv[CRYPT_BLOCK_SIZE];
|
||||
prng->get_bytes(key, CRYPT_KEY_SIZE);
|
||||
prng->get_bytes(iv, CRYPT_BLOCK_SIZE);
|
||||
|
||||
symmetric_CTR ctr;
|
||||
rc = ctr_start(find_cipher("twofish"), iv, key, CRYPT_KEY_SIZE, 0, &ctr);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
ct = new uchar_t[data_size];
|
||||
rc = ctr_encrypt(pt, ct, data_size, &ctr);
|
||||
assert(rc == CRYPT_OK);
|
||||
}
|
||||
51
apps/enclave/src/chk.hpp
Normal file
51
apps/enclave/src/chk.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CHK_HPP
|
||||
#define CHK_HPP
|
||||
|
||||
class Chk {
|
||||
public:
|
||||
//Chk(const uchar_t* cypertext, size_t size);
|
||||
Chk(const uchar_t* plaintext, size_t size, const string& mime_type);
|
||||
~Chk(void) { delete[] ct; }
|
||||
|
||||
private:
|
||||
static const size_t CRYPT_BLOCK_SIZE = 16;
|
||||
static const size_t CRYPT_KEY_SIZE = 32;
|
||||
|
||||
void encrypt(const uchar_t *pt);
|
||||
|
||||
uchar_t* ct; // cyphertext
|
||||
const size_t data_size;
|
||||
const string& mime_type; // I hate mimes.
|
||||
};
|
||||
|
||||
#endif // CHK_HPP
|
||||
148
apps/enclave/src/config.cpp
Normal file
148
apps/enclave/src/config.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "bigint.hpp"
|
||||
|
||||
Config::Config(const string& file)
|
||||
: file(file)
|
||||
{
|
||||
set_defaults();
|
||||
parse();
|
||||
configf.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up a configuration option in the table and returns a constant value.
|
||||
* This is the same as get_property() except the value returned is a constant.
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns the value associated with the key
|
||||
*/
|
||||
const string& Config::get_cproperty(const string& key) const
|
||||
{
|
||||
for (cfgmap_ci i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return i->second;
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
// this should never occur, it's just to silence a compiler warning
|
||||
string* s = new string;
|
||||
return *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a property as an integer (they are all stored as strings)
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns an integer of the value associated with the key
|
||||
*/
|
||||
int Config::get_iproperty(const string& key) const
|
||||
{
|
||||
for (cfgmap_ci i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return atoi(i->second.c_str());
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up a configuration option in the table and returns the value
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns the value associated with the key
|
||||
*/
|
||||
string& Config::get_property(const string& key)
|
||||
{
|
||||
for (cfgmap_i i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return i->second;
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
// this should never occur, it's just to silence a compiler warning
|
||||
string* s = new string;
|
||||
return *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the configuration file, replacing default values with user defined
|
||||
* values
|
||||
*/
|
||||
void Config::parse(void)
|
||||
{
|
||||
configf.open(file.c_str());
|
||||
if (!configf) {
|
||||
cerr << "Error opening configuration file (" << file.c_str() << ")\n";
|
||||
throw runtime_error("Error opening configuration file");
|
||||
}
|
||||
size_t line = 0;
|
||||
string s;
|
||||
for (getline(configf, s); configf; getline(configf, s)) {
|
||||
line++;
|
||||
if (s.size() == 0 || s[0] == '#') // blank line or comment
|
||||
continue;
|
||||
size_t eqpos = s.find("=");
|
||||
if (eqpos == string::npos) {
|
||||
cerr << "Error parsing line #" << line << " in " << file << ": "
|
||||
<< s << '\n';
|
||||
continue;
|
||||
}
|
||||
string key = s.substr(0, eqpos);
|
||||
string value = s.substr(eqpos + 1);
|
||||
//cout << "Inserting key = " << key << " value = " << value << '\n';
|
||||
cfgmap.erase(key); // erase the default value created by set_defaults()
|
||||
cfgmap.insert(make_pair(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If you (the programmer) add something to the config file you should also add
|
||||
* it here, and vice versa
|
||||
*/
|
||||
void Config::set_defaults(void)
|
||||
{
|
||||
cfgmap.insert(make_pair("samhost", "localhost"));
|
||||
cfgmap.insert(make_pair("samport", "7656"));
|
||||
cfgmap.insert(make_pair("samname", "enclave"));
|
||||
cfgmap.insert(make_pair("tunneldepth", "2"));
|
||||
cfgmap.insert(make_pair("references", "cfg/peers.ref"));
|
||||
cfgmap.insert(make_pair("loglevel", "1"));
|
||||
cfgmap.insert(make_pair("logfile", "log/enclave.log"));
|
||||
}
|
||||
54
apps/enclave/src/config.hpp
Normal file
54
apps/enclave/src/config.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_HPP
|
||||
#define CONFIG_HPP
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config(const string& file);
|
||||
|
||||
const string& get_cproperty(const string& key) const;
|
||||
int get_iproperty(const string& key) const;
|
||||
string& get_property(const string& key);
|
||||
|
||||
private:
|
||||
typedef map<const string, string>::const_iterator cfgmap_ci;
|
||||
typedef map<const string, string>::iterator cfgmap_i;
|
||||
|
||||
void parse(void);
|
||||
void set_defaults(void);
|
||||
|
||||
ifstream configf;
|
||||
const string file;
|
||||
map<const string, string> cfgmap;
|
||||
};
|
||||
|
||||
#endif // CONFIG_HPP
|
||||
61
apps/enclave/src/logger.cpp
Normal file
61
apps/enclave/src/logger.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
Logger::Logger(const string& file)
|
||||
: file(file)
|
||||
{
|
||||
set_pri(debug);
|
||||
set_loglevel(static_cast<priority_t>(config->get_iproperty("loglevel")));
|
||||
logf.open(file.c_str(), ios::app);
|
||||
if (!logf) {
|
||||
cerr << "Error opening log file (" << file.c_str() << ")\n";
|
||||
throw runtime_error("Error opening log file");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN_STRERROR
|
||||
/*
|
||||
* strerror() for primitive operating systems
|
||||
*/
|
||||
TCHAR* win_strerror(TCHAR* str, size_t size)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
snprintf(str, size, "%s", lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
88
apps/enclave/src/logger.hpp
Normal file
88
apps/enclave/src/logger.hpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_HPP
|
||||
#define LOGGER_HPP
|
||||
|
||||
/*
|
||||
* LDEBUG - debugging messages
|
||||
* LMINOR - unimportant messages
|
||||
* LINFO - informational messages
|
||||
* LWARN - errors we automatically recover from
|
||||
* LERROR - major, important errors
|
||||
*/
|
||||
#if VERBOSE_LOGS
|
||||
#define LDEBUG logger->set_pri(Logger::debug); (*logger) << "(D)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LMINOR logger->set_pri(Logger::minor); (*logger) << "(M)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LINFO logger->set_pri(Logger::info); (*logger) << "(I)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LWARN logger->set_pri(Logger::warn); (*logger) << "(W)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LERROR logger->set_pri(Logger::error); (*logger) << "(E)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#else
|
||||
#define LDEBUG logger->set_pri(Logger::debug); (*logger) << "(D)"
|
||||
#define LMINOR logger->set_pri(Logger::minor); (*logger) << "(M)"
|
||||
#define LINFO logger->set_pri(Logger::info); (*logger) << "(I)"
|
||||
#define LWARN logger->set_pri(Logger::warn); (*logger) << "(W)"
|
||||
#define LERROR logger->set_pri(Logger::error); (*logger) << "(E)"
|
||||
#endif
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
typedef enum {debug = 0, minor = 1, info = 2, warn = 3, error = 4}
|
||||
priority_t;
|
||||
|
||||
Logger(const string& file);
|
||||
|
||||
void flush(void) { logf.flush(); }
|
||||
priority_t get_loglevel(void) const { return loglevel; }
|
||||
void set_loglevel(priority_t priority) { loglevel = priority; }
|
||||
Logger& operator<<(char c)
|
||||
{ if (priority >= loglevel) { logf << c; flush(); } return *this; }
|
||||
Logger& operator<<(const char* c)
|
||||
{ if (priority >= loglevel) { logf << c; flush(); } return *this; }
|
||||
Logger& operator<<(int i)
|
||||
{ if (priority >= loglevel) { logf << i; flush(); } return *this; }
|
||||
Logger& operator<<(const string& s)
|
||||
{ if (priority >= loglevel) { logf << s; flush(); } return *this; }
|
||||
Logger& operator<<(unsigned int i)
|
||||
{ if (priority >= loglevel) { logf << i; flush(); } return *this; }
|
||||
void set_pri(priority_t priority) { this->priority = priority; }
|
||||
|
||||
private:
|
||||
priority_t priority; // importance of the following log message(s)
|
||||
string file;
|
||||
priority_t loglevel; // write log messsages at or above this priority
|
||||
ofstream logf;
|
||||
};
|
||||
|
||||
#ifdef WIN_STRERROR
|
||||
TCHAR* win_strerror(TCHAR* str, size_t size);
|
||||
#endif
|
||||
|
||||
#endif // LOGGER_HPP
|
||||
84
apps/enclave/src/main.cpp
Normal file
84
apps/enclave/src/main.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
Config *config; // Configuration options
|
||||
Logger *logger; // Logging mechanism
|
||||
Random *prng; // Random number generator
|
||||
Sam *sam; // SAM connection
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 2) { // put some getopts stuff in here later
|
||||
cerr << "Please specify the configuration file location.\n" \
|
||||
"e.g. 'bin/enclave cfg/enclave.cfg'\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
config = new Config(argv[1]);
|
||||
} catch (const runtime_error& x) {
|
||||
return 0;
|
||||
}
|
||||
logger = new Logger(config->get_cproperty("logfile"));
|
||||
LINFO << "Enclave DHT - Built on " << __DATE__ << ' ' << __TIME__ << '\n';
|
||||
prng = new Random;
|
||||
try {
|
||||
sam = new Sam(config->get_cproperty("samhost"),
|
||||
config->get_iproperty("samport"), config->get_cproperty("samname"),
|
||||
config->get_iproperty("tunneldepth"));
|
||||
} catch (const Sam_error& x) {
|
||||
LERROR << "SAM error: " << x.what() << '\n';
|
||||
cerr << "SAM error: " << x.what() << '\n';
|
||||
if (x.code() == SAM_SOCKET_ERROR) {
|
||||
LERROR << "Check whether you have specified the correct SAM host " \
|
||||
"and port number, and that I2P is running.\n";
|
||||
cerr << "Check whether you have specified the correct SAM host " \
|
||||
"and port number, and that\nI2P is running.\n";
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
sam->naming_lookup();
|
||||
while (sam->get_my_dest() == "")
|
||||
sam->read_buffer(); // wait until we get our own dest back from lookup
|
||||
|
||||
sam->peers->advertise_self();
|
||||
|
||||
while (true)
|
||||
sam->read_buffer();
|
||||
|
||||
delete sam;
|
||||
delete prng;
|
||||
delete logger;
|
||||
delete config;
|
||||
return 0;
|
||||
}
|
||||
36
apps/enclave/src/main.hpp
Normal file
36
apps/enclave/src/main.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MAIN_HPP
|
||||
#define MAIN_HPP
|
||||
|
||||
// intentionally left blank
|
||||
|
||||
#endif // MAIN_HPP
|
||||
54
apps/enclave/src/near_peer.hpp
Normal file
54
apps/enclave/src/near_peer.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef NEAR_PEER_HPP
|
||||
#define NEAR_PEER_HPP
|
||||
|
||||
//
|
||||
// Used for finding the closest peers to a sha1
|
||||
//
|
||||
|
||||
class Near_peer {
|
||||
public:
|
||||
Near_peer(const Bigint& distance, Peer* peer)
|
||||
: distance(distance), peer(peer) {}
|
||||
|
||||
Peer* get_peer(void) const { return peer; }
|
||||
bool operator<(const Near_peer& rhs) const
|
||||
{ if (distance < rhs.distance) return true; else return false; }
|
||||
|
||||
protected:
|
||||
const Bigint distance;
|
||||
|
||||
private:
|
||||
Peer* peer;
|
||||
};
|
||||
|
||||
#endif // NEAR_PEER_HPP
|
||||
52
apps/enclave/src/peer.hpp
Normal file
52
apps/enclave/src/peer.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PEER_HPP
|
||||
#define PEER_HPP
|
||||
|
||||
class Peer {
|
||||
public:
|
||||
Peer(const string& dest, const Sha1& kaddr)
|
||||
: dest(dest), kaddr(kaddr), lag(-1) {}
|
||||
|
||||
const string& get_b64kaddr(void) const { return kaddr.b64hash(); }
|
||||
const uchar_t* get_binkaddr(void) const { return kaddr.binhash(); }
|
||||
const string& get_dest(void) const { return dest; }
|
||||
int get_lag(void) const { return lag; }
|
||||
const string get_sdest(void) const { return dest.substr(0, 8); }
|
||||
void set_lag(int lag) { this->lag = lag; }
|
||||
|
||||
private:
|
||||
const string dest;
|
||||
const Sha1 kaddr;
|
||||
int lag; // if -1, then it is unknown
|
||||
};
|
||||
|
||||
#endif // PEER_HPP
|
||||
220
apps/enclave/src/peers.cpp
Normal file
220
apps/enclave/src/peers.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "near_peer.hpp"
|
||||
#include "rpc.hpp"
|
||||
#include "sha1.hpp"
|
||||
#include "peers.hpp"
|
||||
|
||||
/*
|
||||
* Inform other peers of our existence and collect the destination addresses of
|
||||
* nearby peers
|
||||
*/
|
||||
void Peers::advertise_self(void)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
get_nearest(sam->get_my_sha1(), PAR_RPCS, near_peers);
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
Rpc rpc(i->get_peer());
|
||||
rpc.find_peers(sam->get_my_sha1());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the `n' nearest peers by xoring a sha1 with a kaddr
|
||||
*
|
||||
* sha1 - sha1 to find nearness to
|
||||
* n - number of peers to find
|
||||
* near_peers - a list to put the found peers in
|
||||
*/
|
||||
void Peers::get_nearest(const Sha1& sha1, size_t n, list<Near_peer>& near_peers)
|
||||
{
|
||||
near_peers.clear(); // prevents duplicate peers in the list
|
||||
for (peersmap_i i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
const Sha1& kaddr = i->first;
|
||||
Bigint distance;
|
||||
sha1.x_or(kaddr, distance);
|
||||
Near_peer np(distance, &(i->second));
|
||||
near_peers.insert(near_peers.end(), np);
|
||||
}
|
||||
near_peers.sort();
|
||||
while (near_peers.size() > n)
|
||||
near_peers.pop_back();
|
||||
}
|
||||
|
||||
Peer* Peers::get_peer_by_dest(const sam_pubkey_t dest)
|
||||
{
|
||||
const string s = dest;
|
||||
return get_peer_by_dest(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a peer by its base 64 destination address
|
||||
*
|
||||
* dest - destination
|
||||
*
|
||||
* Returns: pointer to peer, or 0 if the peer wasn't found
|
||||
*/
|
||||
Peer* Peers::get_peer_by_dest(const string& dest)
|
||||
{
|
||||
for (peersmap_i i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
Peer& tmp = i->second;
|
||||
if (tmp.get_dest() == dest)
|
||||
return &(i->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a peer by its Kademlia address
|
||||
*
|
||||
* kaddr - Kademlia adddress
|
||||
*
|
||||
* Returns: pointer to peer, or 0 if the peer wasn't found
|
||||
*/
|
||||
Peer* Peers::get_peer_by_kaddr(const Sha1& kaddr)
|
||||
{
|
||||
peersmap_i i = peersmap.find(kaddr);
|
||||
if (i != peersmap.end())
|
||||
return &(i->second);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads peer addresses from a file
|
||||
*/
|
||||
void Peers::load(void)
|
||||
{
|
||||
string dest;
|
||||
|
||||
ifstream peersf(file.c_str());
|
||||
if (!peersf) {
|
||||
LERROR << "Couldn't load peers reference file (" << file.c_str()
|
||||
<< ")\n";
|
||||
if (peersmap.size() > 0)
|
||||
return;
|
||||
else
|
||||
throw runtime_error("No peer references in memory");
|
||||
}
|
||||
|
||||
for (getline(peersf, dest); peersf; getline(peersf, dest))
|
||||
new_peer(dest);
|
||||
|
||||
if (peersmap.size() > 0) {
|
||||
LMINOR << peersmap.size() << " peer references in memory\n";
|
||||
} else
|
||||
throw runtime_error("No peer references in memory");
|
||||
}
|
||||
|
||||
Peer* Peers::new_peer(const sam_pubkey_t dest)
|
||||
{
|
||||
const string s = dest;
|
||||
return new_peer(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a newly discovered peer to the peers map
|
||||
*
|
||||
* dest - destination address of the peer
|
||||
*
|
||||
* Returns: pointer to the peer
|
||||
*/
|
||||
Peer* Peers::new_peer(const string& dest)
|
||||
{
|
||||
// Check the destination address
|
||||
if (!sam->valid_dest(dest)) {
|
||||
LWARN << "Bad format in peer reference: " << dest.substr(0, 8) << '\n';
|
||||
return 0;
|
||||
}
|
||||
// Never add our own peer to the peers we can connect to
|
||||
if (dest == sam->get_my_dest()) {
|
||||
LDEBUG << "Not adding my own peer reference: " << dest.substr(0, 8)
|
||||
<< '\n';
|
||||
return 0;
|
||||
}
|
||||
// Be sure that the peer is not already known to us
|
||||
Peer *peer = get_peer_by_dest(dest);
|
||||
if (peer != 0) {
|
||||
LDEBUG << "Redundant peer reference: " << dest.substr(0, 8) << '\n';
|
||||
return peer;
|
||||
}
|
||||
|
||||
// Tests passed, add it
|
||||
Sha1 sha1(dest);
|
||||
pair<peersmap_i, bool> p = peersmap.insert(
|
||||
make_pair(sha1, Peer(dest, sha1)));
|
||||
assert(p.second);
|
||||
LMINOR << "New peer reference: " << dest.substr(0, 8)
|
||||
<< " (Kaddr: " << sha1.b64hash() << ")\n";
|
||||
peer = &(p.first->second);
|
||||
return peer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves peer destinations to a file
|
||||
*
|
||||
* file - the file to save to
|
||||
*/
|
||||
void Peers::save(void)
|
||||
{
|
||||
ofstream peersf(file.c_str());
|
||||
if (!peersf) {
|
||||
LERROR << "Error opening peers reference file (" << file.c_str()
|
||||
<< ")\n";
|
||||
return;
|
||||
}
|
||||
|
||||
LDEBUG << "Saving " << peersmap.size() + 1 << " peer references\n";
|
||||
peersf << sam->get_my_dest() << '\n';
|
||||
for (peersmap_ci i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
const Peer& tmp = i->second;
|
||||
peersf << tmp.get_dest() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores data on some peers
|
||||
*
|
||||
* sha1 - the sha1 value for the data
|
||||
* data - the data
|
||||
*/
|
||||
void Peers::store(const Sha1& sha1)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
get_nearest(sam->get_my_sha1(), PAR_RPCS, near_peers);
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
Rpc rpc(i->get_peer());
|
||||
rpc.store(sha1);
|
||||
}
|
||||
}
|
||||
65
apps/enclave/src/peers.hpp
Normal file
65
apps/enclave/src/peers.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PEERS_HPP
|
||||
#define PEERS_HPP
|
||||
|
||||
class Peers {
|
||||
public:
|
||||
static const int PAR_RPCS = 3; // The number of parallel RPCs to send
|
||||
static const int RET_REFS = 20; // The number of peer refs to return on
|
||||
// failed requests
|
||||
Peers(const string& file)
|
||||
: file(file)
|
||||
{ load(); }
|
||||
~Peers(void) { save(); }
|
||||
|
||||
void advertise_self(void);
|
||||
void get_nearest(const Sha1& sha1, size_t n,
|
||||
list<Near_peer>& near_peers);
|
||||
Peer* get_peer_by_dest(const sam_pubkey_t dest);
|
||||
Peer* get_peer_by_dest(const string& dest);
|
||||
Peer* get_peer_by_kaddr(const Sha1& kaddr);
|
||||
Peer* new_peer(const sam_pubkey_t dest);
|
||||
Peer* new_peer(const string& dest);
|
||||
void store(const Sha1& sha1);
|
||||
|
||||
private:
|
||||
typedef map<const Sha1, Peer>::const_iterator peersmap_ci;
|
||||
typedef map<const Sha1, Peer>::iterator peersmap_i;
|
||||
|
||||
void load(void);
|
||||
void save(void);
|
||||
|
||||
const string file;
|
||||
map<const Sha1, Peer> peersmap;
|
||||
};
|
||||
|
||||
#endif // PEERS_HPP
|
||||
111
apps/enclave/src/platform.hpp
Normal file
111
apps/enclave/src/platform.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_HPP
|
||||
#define PLATFORM_HPP
|
||||
|
||||
/*
|
||||
* Operating system
|
||||
*/
|
||||
#define FREEBSD 0 // FreeBSD (untested)
|
||||
#define MINGW 1 // Windows native (Mingw)
|
||||
#define LINUX 2 // Linux
|
||||
#define CYGWIN 3 // Cygwin
|
||||
|
||||
#if OS == MINGW
|
||||
#define NO_SSIZE_T
|
||||
#define WIN_STRERROR
|
||||
#define WINSOCK
|
||||
#define WINTHREADS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* System includes
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#ifdef WINTHREADS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef NO_SSIZE_T
|
||||
typedef signed long ssize_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define this to '1' to cause the printing of source code file and line number
|
||||
* information with each log message. Set it to '0' for simple logging.
|
||||
*/
|
||||
#define VERBOSE_LOGS 0
|
||||
|
||||
/*
|
||||
* Library includes
|
||||
*/
|
||||
#include "mycrypt.h" // LibTomCrypt
|
||||
#include "sam.h" // LibSAM
|
||||
|
||||
/*
|
||||
* Local includes
|
||||
*/
|
||||
#include "mutex.hpp" // Mutex (for thread.hpp)
|
||||
#include "thread.hpp" // Thread
|
||||
#include "logger.hpp" // Logger
|
||||
#include "config.hpp" // Config
|
||||
#include "sam_error.hpp" // for sam.hpp
|
||||
#include "bigint.hpp" // for sha1.hpp
|
||||
#include "sha1.hpp" // for peers.hpp
|
||||
#include "peer.hpp" // for peers.hpp
|
||||
#include "near_peer.hpp" // for peers.hpp
|
||||
#include "peers.hpp" // for sam.hpp
|
||||
#include "sam.hpp" // SAM
|
||||
#include "random.hpp" // Random
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
extern Config *config; // Configuration options
|
||||
extern Logger *logger; // Logging mechanism
|
||||
extern Random *prng; // Random number generator
|
||||
extern Sam *sam; // Sam connection
|
||||
|
||||
#endif // PLATFORM_HPP
|
||||
65
apps/enclave/src/random.cpp
Normal file
65
apps/enclave/src/random.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "random.hpp"
|
||||
|
||||
/*
|
||||
* Prepares the Yarrow PRNG for use
|
||||
*/
|
||||
Random::Random(void)
|
||||
{
|
||||
LMINOR << "Initalising PRNG\n";
|
||||
|
||||
int rc = yarrow_start(&prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
uchar_t entropy[ENTROPY_SIZE];
|
||||
size_t sz = rng_get_bytes(entropy, ENTROPY_SIZE, NULL);
|
||||
assert(sz == ENTROPY_SIZE);
|
||||
|
||||
rc = yarrow_add_entropy(entropy, ENTROPY_SIZE, &prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
rc = yarrow_ready(&prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets `size' random bytes from the PRNG
|
||||
*
|
||||
* random - space to fill with random bytes
|
||||
* size - size of `random'
|
||||
*/
|
||||
void Random::get_bytes(uchar_t* random, size_t size)
|
||||
{
|
||||
size_t sz = yarrow_read(random, size, &prng);
|
||||
assert(sz == size);
|
||||
}
|
||||
45
apps/enclave/src/random.hpp
Normal file
45
apps/enclave/src/random.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RANDOM_HPP
|
||||
#define RANDOM_HPP
|
||||
|
||||
class Random {
|
||||
public:
|
||||
Random(void);
|
||||
|
||||
void get_bytes(uchar_t* random, size_t size);
|
||||
|
||||
private:
|
||||
static const size_t ENTROPY_SIZE = 32;
|
||||
prng_state prng;
|
||||
};
|
||||
|
||||
#endif // RNG_HPP
|
||||
233
apps/enclave/src/rpc.cpp
Normal file
233
apps/enclave/src/rpc.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "rpc.hpp"
|
||||
|
||||
// These can't be 'const' because I have to make them big-endian first
|
||||
uint16_t Rpc::VERSION = htons(1);
|
||||
uint16_t Rpc::OLDEST_GOOD_VERSION = htons(1);
|
||||
|
||||
/*
|
||||
* Requests a peer to find the addresses of the closest peers to the specified
|
||||
* sha1 and return them
|
||||
*
|
||||
* sha1 - closeness to this sha1
|
||||
*/
|
||||
void Rpc::find_peers(const Sha1& sha1)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FIND_PEERS\n";
|
||||
|
||||
// VERSION + command + bin sha1
|
||||
const size_t len = sizeof VERSION + 1 + Sha1::SHA1BIN_LEN;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = FIND_PEERS;
|
||||
p++;
|
||||
memcpy(p, sha1.binhash(), Sha1::SHA1BIN_LEN);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the closest peer references to a Sha1
|
||||
*
|
||||
* sha1 - sha1 to test nearness to
|
||||
*/
|
||||
void Rpc::found_peers(const Sha1& sha1)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
sam->peers->get_nearest(sha1, Peers::RET_REFS, near_peers);
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FOUND_PEERS (" << near_peers.size() << " peers)\n";
|
||||
|
||||
// VERSION + command + number of sha1s (0-255) + bin sha1s
|
||||
const size_t len = sizeof VERSION + 1 + 1 +
|
||||
(near_peers.size() * (SAM_PUBKEY_LEN - 1));
|
||||
assert(near_peers.size() <= 255);
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = FOUND_PEERS;
|
||||
p++;
|
||||
*p = near_peers.size();
|
||||
p++;
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
const Peer* peer = i->get_peer();
|
||||
memcpy(p, peer->get_dest().c_str(), (SAM_PUBKEY_LEN - 1));
|
||||
p += SAM_PUBKEY_LEN - 1;
|
||||
}
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse incoming data and invoke the appropriate RPC
|
||||
*
|
||||
* data - the data
|
||||
* size - the size of `data'
|
||||
*/
|
||||
void Rpc::parse(const void* data, size_t size)
|
||||
{
|
||||
uint16_t his_ver;
|
||||
|
||||
memcpy(&his_ver, data, sizeof VERSION);
|
||||
if (ntohs(his_ver) < ntohs(VERSION)) {
|
||||
LMINOR << "Ignored RPC from " << peer->get_sdest() << " ["
|
||||
<< peer->get_b64kaddr() << "] using obsolete protocol version "
|
||||
<< ntohs(his_ver) << '\n';
|
||||
return;
|
||||
} else if (size <= 4) {
|
||||
LWARN << "RPC too small from " << peer->get_sdest() << " ["
|
||||
<< peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
const uchar_t* p = static_cast<const uchar_t*>(data);
|
||||
|
||||
if (p[2] == PING) { //-----------------------------------------------------
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PING\n";
|
||||
uint32_t ptime;
|
||||
if (size != sizeof VERSION + 1 + sizeof ptime) {
|
||||
LWARN << "Malformed PING RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
p += sizeof VERSION + 1;
|
||||
memcpy(&ptime, p, sizeof ptime);
|
||||
pong(ptime); // no need to ntohl() it here because we're just copying it
|
||||
return;
|
||||
|
||||
} else if (p[2] == PONG) { //----------------------------------------------
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PONG\n";
|
||||
uint32_t ptime;
|
||||
if (size != sizeof VERSION + 1 + sizeof ptime) {
|
||||
LWARN << "Malformed PONG RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
p += sizeof VERSION + 1;
|
||||
memcpy(&ptime, p, sizeof ptime);
|
||||
ptime = ntohl(ptime);
|
||||
uint32_t now = time(NULL);
|
||||
peer->set_lag(now - ptime);
|
||||
LDEBUG << "Lag is " << peer->get_lag() << " seconds\n";
|
||||
return;
|
||||
|
||||
} else if (p[2] == FIND_PEERS) { //----------------------------------------
|
||||
if (size != sizeof VERSION + 1 + Sha1::SHA1BIN_LEN) {
|
||||
LWARN << "Malformed FIND_PEERS RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FIND_PEERS\n";
|
||||
found_peers(Sha1(p + 4));
|
||||
return;
|
||||
|
||||
} else if (p[2] == FOUND_PEERS) { //---------------------------------------
|
||||
const size_t refs = p[3];
|
||||
if (size != sizeof VERSION + 1 + 1 + (refs * (SAM_PUBKEY_LEN - 1))) {
|
||||
LWARN << "Malformed FOUND_PEERS RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FOUND_PEERS (" << refs << " peers)\n";
|
||||
p += sizeof VERSION + 1 + 1;
|
||||
for (size_t i = 1; i <= refs; i++) {
|
||||
sam_pubkey_t dest;
|
||||
memcpy(dest, p, SAM_PUBKEY_LEN - 1); // - 1 == no NUL in RPC
|
||||
dest[SAM_PUBKEY_LEN - 1] = '\0';
|
||||
//LDEBUG << "Message had: " << dest << '\n';
|
||||
sam->peers->new_peer(dest);
|
||||
p += SAM_PUBKEY_LEN - 1;
|
||||
}
|
||||
return;
|
||||
|
||||
} else //------------------------------------------------------------------
|
||||
LWARN << "Unknown RPC #" << static_cast<int>(p[2]) << " from "
|
||||
<< peer->get_sdest() << " [" << peer->get_b64kaddr() << "]\n";
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a ping to someone
|
||||
*/
|
||||
void Rpc::ping(void)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PING\n";
|
||||
|
||||
uint32_t now = htonl(time(NULL));
|
||||
// VERSION + command + seconds since 1970
|
||||
const size_t len = sizeof VERSION + 1 + sizeof now;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = PING;
|
||||
p++;
|
||||
memcpy(p, &now, sizeof now);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a ping reply to someone
|
||||
*
|
||||
* ptime - the time the peer sent us (we echo the same time back)
|
||||
*/
|
||||
void Rpc::pong(uint32_t ptime)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PONG\n";
|
||||
|
||||
// VERSION + command + pinger's seconds since 1970 echoed back
|
||||
const size_t len = sizeof VERSION + 1 + sizeof ptime;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = PONG;
|
||||
p++;
|
||||
memcpy(p, &ptime, sizeof ptime);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tells a peer to store some data
|
||||
*
|
||||
* sha1 - sha1 value for the data
|
||||
* data - the data
|
||||
*/
|
||||
void Rpc::store(const Sha1& sha1)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: STORE\n";
|
||||
}
|
||||
65
apps/enclave/src/rpc.hpp
Normal file
65
apps/enclave/src/rpc.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPC_HPP
|
||||
#define RPC_HPP
|
||||
|
||||
class Rpc {
|
||||
public:
|
||||
// The PROTOCOL version we are using
|
||||
static uint16_t VERSION;
|
||||
// The oldest version we will talk to
|
||||
static uint16_t OLDEST_GOOD_VERSION;
|
||||
// RPC identifiers (0-255)
|
||||
typedef enum {
|
||||
PING = 0,
|
||||
PONG = 1,
|
||||
FIND_PEERS = 2,
|
||||
FOUND_PEERS = 3,
|
||||
STORE = 4
|
||||
} rpc_t;
|
||||
|
||||
Rpc(Peer* peer)
|
||||
: peer(peer) {};
|
||||
|
||||
void find_peers(const Sha1& sha1);
|
||||
void parse(const void* data, size_t size);
|
||||
void ping(void);
|
||||
void store(const Sha1& sha1);
|
||||
|
||||
private:
|
||||
void found_peers(const Sha1& sha1);
|
||||
void pong(uint32_t ptime);
|
||||
|
||||
Peer* peer;
|
||||
basic_string<uchar_t> data;
|
||||
};
|
||||
|
||||
#endif // RPC_HPP
|
||||
249
apps/enclave/src/sam.cpp
Normal file
249
apps/enclave/src/sam.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "rpc.hpp"
|
||||
#include "sam.hpp"
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* Assorted callbacks required by LibSAM - ugly, but it works
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void* data, size_t size);
|
||||
static void diedback(void);
|
||||
static void logback(char* str);
|
||||
static void namingback(char* name, sam_pubkey_t pubkey, samerr_t result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents more than one Sam object from existing in the program at a time
|
||||
* (LibSAM limitation)
|
||||
*/
|
||||
bool Sam::exists = false;
|
||||
|
||||
Sam::Sam(const string& samhost, uint16_t samport, const string& destname,
|
||||
uint_t tunneldepth)
|
||||
{
|
||||
// Only allow one Sam object to exist at a time
|
||||
assert(!exists);
|
||||
exists = true;
|
||||
|
||||
// hook up callbacks
|
||||
sam_dgramback = &dgramback;
|
||||
sam_diedback = &diedback;
|
||||
sam_logback = &logback;
|
||||
sam_namingback = &namingback;
|
||||
|
||||
// we haven't connected to SAM yet
|
||||
set_connected(false);
|
||||
|
||||
// now try to connect to SAM
|
||||
connect(samhost.c_str(), samport, destname.c_str(), tunneldepth);
|
||||
}
|
||||
|
||||
Sam::~Sam(void)
|
||||
{
|
||||
delete peers; // this must be before set_connected(false)!
|
||||
if (is_connected()) {
|
||||
sam_close();
|
||||
set_connected(false);
|
||||
}
|
||||
exists = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connects to the SAM host
|
||||
*
|
||||
* samhost - host that SAM is running on (hostname or IP address)
|
||||
* samport - port number that SAM is running own
|
||||
* destname - the destination name of this program
|
||||
* tunneldepth - how long the tunnels should be
|
||||
*/
|
||||
void Sam::connect(const char* samhost, uint16_t samport, const char* destname,
|
||||
uint_t tunneldepth)
|
||||
{
|
||||
assert(!is_connected());
|
||||
LMINOR << "Connecting to SAM as '" << destname << "'\n";
|
||||
samerr_t rc = sam_connect(samhost, samport, destname, SAM_DGRAM, tunneldepth);
|
||||
if (rc == SAM_OK)
|
||||
set_connected(true);
|
||||
else
|
||||
throw Sam_error(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads peer references from disk
|
||||
* Note: this can only be called after my_dest has been set
|
||||
*/
|
||||
void Sam::load_peers(void)
|
||||
{
|
||||
peers = new Peers(config->get_cproperty("references"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts `name' to a base 64 destination
|
||||
*
|
||||
* name - name to lookup
|
||||
*/
|
||||
void Sam::naming_lookup(const string& name) const
|
||||
{
|
||||
assert(is_connected());
|
||||
sam_naming_lookup(name.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses an incoming datagram
|
||||
*
|
||||
* dest - source destination address
|
||||
* data - datagram payload
|
||||
* size - size of `data'
|
||||
*/
|
||||
void Sam::parse_dgram(const string& dest, void* data, size_t size)
|
||||
{
|
||||
assert(is_connected());
|
||||
Peer* peer = peers->new_peer(dest);
|
||||
Rpc rpc(peer);
|
||||
rpc.parse(data, size);
|
||||
rpc.ping();
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the SAM connection for incoming commands and invokes callbacks
|
||||
*/
|
||||
void Sam::read_buffer(void)
|
||||
{
|
||||
assert(is_connected());
|
||||
sam_read_buffer();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a datagram to a destination
|
||||
*
|
||||
* dest - destination to send to
|
||||
* data - data to send
|
||||
* size - size of `data'
|
||||
*/
|
||||
void Sam::send_dgram(const string& dest, uchar_t *data, size_t size)
|
||||
{
|
||||
assert(is_connected());
|
||||
samerr_t rc = sam_dgram_send(dest.c_str(), data, size);
|
||||
assert(rc == SAM_OK); // i.e. not SAM_TOO_BIG
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the connection status
|
||||
*
|
||||
* connected - true for connected, false for disconnected
|
||||
*/
|
||||
void Sam::set_connected(bool connected)
|
||||
{
|
||||
if (!connected)
|
||||
my_dest = "";
|
||||
this->connected = connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets my destination address
|
||||
*
|
||||
* pubkey - the base 64 destination
|
||||
*/
|
||||
void Sam::set_my_dest(const sam_pubkey_t pubkey)
|
||||
{
|
||||
my_dest = pubkey;
|
||||
my_sha1 = Sha1(my_dest);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the destination specified is of a valid base 64 syntax
|
||||
*
|
||||
* Returns: true if it is valid, false if it isn't
|
||||
*/
|
||||
bool Sam::valid_dest(const string& dest)
|
||||
{
|
||||
if (dest.size() != 516)
|
||||
return false;
|
||||
if (dest.substr(512, 4) == "AAAA") // Note this AAAA signifies a null
|
||||
return true; // certificate and doesn't actually have
|
||||
else // any bearing on validity, but we'll
|
||||
return false; // keep this check here for now anyway
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * Callbacks * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Unfortunately these aren't part of the "Sam" object because they are function
|
||||
* pointers to _C_ functions. As a hack, we just have them call the global Sam
|
||||
* object.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Callback: A datagram was received
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void* data, size_t size)
|
||||
{
|
||||
sam->parse_dgram(dest, data, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: The connection to SAM has failed
|
||||
*/
|
||||
static void diedback(void)
|
||||
{
|
||||
LERROR << "Connection to SAM lost!\n";
|
||||
sam->set_connected(false);
|
||||
throw Sam_error(SAM_SOCKET_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: A log message has been sent from LibSAM
|
||||
*/
|
||||
static void logback(char* str)
|
||||
{
|
||||
LINFO << "LibSAM: " << str << '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: A naming lookup has completed
|
||||
*/
|
||||
static void namingback(char* name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
Sam_error res(result);
|
||||
if (res.code() == SAM_OK) {
|
||||
if (strcmp(name, "ME") == 0) {
|
||||
sam->set_my_dest(pubkey);
|
||||
sam->load_peers();
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
LERROR << "Naming look failed for '" << name << "': " << res.what()
|
||||
<< '\n';
|
||||
}
|
||||
}
|
||||
66
apps/enclave/src/sam.hpp
Normal file
66
apps/enclave/src/sam.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SAM_HPP
|
||||
#define SAM_HPP
|
||||
|
||||
class Sam {
|
||||
public:
|
||||
Sam(const string& samhost, uint16_t samport, const string& destname,
|
||||
uint_t tunneldepth);
|
||||
~Sam(void);
|
||||
|
||||
const string& get_my_dest(void) const { return my_dest; }
|
||||
const Sha1& get_my_sha1(void) const { return my_sha1; }
|
||||
void naming_lookup(const string& name = "ME") const;
|
||||
void read_buffer(void);
|
||||
void send_dgram(const string& dest, uchar_t *data, size_t size);
|
||||
bool valid_dest(const string& dest);
|
||||
|
||||
Peers* peers;
|
||||
|
||||
//callback-private:
|
||||
void load_peers(void);
|
||||
void parse_dgram(const string& dest, void* data, size_t size);
|
||||
void set_connected(bool connected);
|
||||
void set_my_dest(const sam_pubkey_t pubkey);
|
||||
|
||||
private:
|
||||
void connect(const char* samhost, uint16_t samport,
|
||||
const char* destname, uint_t tunneldepth);
|
||||
bool is_connected(void) const { return connected; }
|
||||
|
||||
bool connected;
|
||||
static bool exists;
|
||||
string my_dest;
|
||||
Sha1 my_sha1;
|
||||
};
|
||||
|
||||
#endif // SAM_HPP
|
||||
46
apps/enclave/src/sam_error.hpp
Normal file
46
apps/enclave/src/sam_error.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SAM_ERROR_HPP
|
||||
#define SAM_ERROR_HPP
|
||||
|
||||
class Sam_error {
|
||||
public:
|
||||
Sam_error(samerr_t error)
|
||||
: errcode(error) {}
|
||||
|
||||
samerr_t code(void) const { return errcode; }
|
||||
const char* what(void) const { return sam_strerror(errcode); }
|
||||
|
||||
private:
|
||||
const samerr_t errcode;
|
||||
};
|
||||
|
||||
#endif // SAM_ERROR_HPP
|
||||
122
apps/enclave/src/sha1.cpp
Normal file
122
apps/enclave/src/sha1.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "sha1.hpp"
|
||||
|
||||
Sha1::Sha1(void)
|
||||
{
|
||||
b64hashed = "No value!";
|
||||
memset(binhashed, 0, sizeof binhashed);
|
||||
}
|
||||
|
||||
Sha1::Sha1(const string& data)
|
||||
{
|
||||
/* Hash it */
|
||||
hash_state md;
|
||||
sha1_init(&md);
|
||||
int rc = sha1_process(&md, reinterpret_cast<const uchar_t*>(data.c_str()),
|
||||
data.size());
|
||||
assert(rc == CRYPT_OK);
|
||||
rc = sha1_done(&md, binhashed);
|
||||
assert(rc == CRYPT_OK);
|
||||
b64();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialises the Sha1 object from a binary hash
|
||||
*/
|
||||
Sha1::Sha1(const uchar_t binary[SHA1BIN_LEN])
|
||||
{
|
||||
memcpy(binhashed, binary, sizeof binhashed);
|
||||
b64();
|
||||
}
|
||||
|
||||
/*
|
||||
* Base 64 the binary hash
|
||||
*/
|
||||
void Sha1::b64(void)
|
||||
{
|
||||
ulong_t outlen = 29;
|
||||
char tmp[outlen];
|
||||
// b64 FIXME: replace + with ~, and / with - to be like freenet
|
||||
int rc = base64_encode(binhashed, sizeof binhashed, reinterpret_cast<uchar_t*>(tmp), &outlen);
|
||||
assert(rc == CRYPT_OK);
|
||||
b64hashed = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two Sha1s, returning true if the this one is less than the right one
|
||||
*/
|
||||
bool Sha1::operator<(const Sha1& rhs) const
|
||||
{
|
||||
Bigint lhsnum(binhashed, SHA1BIN_LEN);
|
||||
Bigint rhsnum(rhs.binhash(), SHA1BIN_LEN);
|
||||
if (lhsnum < rhsnum)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assigns a value from another Sha1 to this one
|
||||
*/
|
||||
Sha1& Sha1::operator=(const Sha1& rhs)
|
||||
{
|
||||
if (this != &rhs) { // check for self-assignment: a = a
|
||||
b64hashed = rhs.b64hash();
|
||||
memcpy(binhashed, rhs.binhash(), sizeof binhashed);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares Sha1s for equality
|
||||
*/
|
||||
bool Sha1::operator==(const Sha1& rhs) const
|
||||
{
|
||||
if (memcmp(binhashed, rhs.binhash(), sizeof binhashed) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xors this Sha1 with another, and stores the result in a Bigint
|
||||
*
|
||||
* rhs - sha1 to xor this one with
|
||||
* result - will be filled with the result
|
||||
*/
|
||||
void Sha1::x_or(const Sha1& rhs, Bigint& result) const
|
||||
{
|
||||
Bigint lhsnum(binhashed, SHA1BIN_LEN);
|
||||
Bigint rhsnum(rhs.binhash(), SHA1BIN_LEN);
|
||||
lhsnum.x_or(rhsnum, result);
|
||||
}
|
||||
56
apps/enclave/src/sha1.hpp
Normal file
56
apps/enclave/src/sha1.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HPP
|
||||
#define SHA1_HPP
|
||||
|
||||
class Sha1 {
|
||||
public:
|
||||
static const size_t SHA1BIN_LEN = 20;
|
||||
|
||||
Sha1(void);
|
||||
Sha1(const string& data);
|
||||
Sha1(const uchar_t binary[SHA1BIN_LEN]);
|
||||
|
||||
const string& b64hash(void) const { return b64hashed; }
|
||||
const uchar_t* binhash(void) const { return binhashed; }
|
||||
bool operator<(const Sha1& rhs) const;
|
||||
Sha1& operator=(const Sha1& rhs);
|
||||
bool operator==(const Sha1& rhs) const;
|
||||
void x_or(const Sha1& rhs, Bigint& result) const;
|
||||
|
||||
private:
|
||||
void b64(void);
|
||||
|
||||
string b64hashed; // base 64 of the hash
|
||||
uchar_t binhashed[SHA1BIN_LEN]; // non-NUL terminated binary hash
|
||||
};
|
||||
|
||||
#endif // SHA1_HPP
|
||||
39
apps/heartbeat/doc/readme.gui.txt
Normal file
39
apps/heartbeat/doc/readme.gui.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
The Heartbeat GUI loads up the stat files generated by the Heartbeat
|
||||
engine and renders them visually, offering a way to drill through different
|
||||
data points and take snapshots as things change (by saving particular stat
|
||||
files for later). The GUI itself doesn't need to be on the same machine
|
||||
as the Heartbeat engine - it pulls the stat files through any URL - even
|
||||
through the EepProxy.
|
||||
|
||||
An example Heartbeat GUI config file follows
|
||||
|
||||
# how often do we want to pull new data to render
|
||||
refreshFrequency=60
|
||||
## for each peer test we may want to include in the GUI:
|
||||
# where to find the current stat file (URL or filename)
|
||||
stat.0.location=http://dev.i2p.net/stats/heartbeatStat_khWY_30s_1kb.txt
|
||||
## optional entries for each peer test describing what we want shown
|
||||
## (and how we want it shown)
|
||||
# do we want to plot the send time (from when the ping was sent until the pong server got it)?
|
||||
stat.0.plot.current.send=true
|
||||
# do we want to plot the receive time (from when the pong was sent until reception)?
|
||||
stat.0.plot.current.receive=true
|
||||
# do we want to plot the lost messages?
|
||||
stat.0.plot.current.lost=true
|
||||
# what color should the current lines be rendered in?
|
||||
stat.0.plot.current.color=BLUE
|
||||
## optional entries for each peer test describing what averages we want
|
||||
## rendered
|
||||
# plot 1 minute send average?
|
||||
stat.0.plot.1m.send=true
|
||||
# plot 1 minute receive average?
|
||||
stat.0.plot.1m.receive=true
|
||||
# plot 1 minute lost message average?
|
||||
stat.0.plot.1m.lost=true
|
||||
# what color should the 1 minute averages be rendered as?
|
||||
stat.0.plot.1m.color=GREEN
|
||||
## repeated for all of the averaged periods, e.g.
|
||||
## stat.0.plot.30m, .60m, 1440m (1 day)
|
||||
|
||||
There may be some other options, such as where to store snapshot files, whether
|
||||
to generate PNG images, etc.
|
||||
122
apps/heartbeat/doc/readme.txt
Normal file
122
apps/heartbeat/doc/readme.txt
Normal file
@@ -0,0 +1,122 @@
|
||||
Heartbeat
|
||||
|
||||
Application layer tool for monitoring the long term health of the
|
||||
network by periodically testing peers, generating stats, and
|
||||
rendering them visually. The engine (both server and client) should
|
||||
work headless and seperate from the GUI, exposing the data in a simple
|
||||
to parse (and human readable) text file for each peer being tested.
|
||||
The GUI then periodically refreshes itself by loading those files (
|
||||
either locally or from a URL) and renders the current state accordingly,
|
||||
giving users a way to check that the network is alive, devs a tool to
|
||||
both monitor the state of the network and to debug different situations (by
|
||||
accessing the stat file - either live or archived).
|
||||
|
||||
The heartbeat configuration file is organized as a standard properties
|
||||
file (by default located at heartbeat.config, but that can be overridden by
|
||||
passing a filename as the first argument to the Heartbeat command):
|
||||
|
||||
# where the router is located (default is localhost)
|
||||
i2cpHost=localhost
|
||||
# I2CP port for the router (default is 7654)
|
||||
i2cpPort=4001
|
||||
# How many hops we want the router to put in our tunnels (default is 2)
|
||||
numHops=2
|
||||
# where our private destination keys are located - if this doesn't exist,
|
||||
# a new one will be created and saved there (by default, heartbeat.keys)
|
||||
privateDestinationFile=heartbeat_r2.keys
|
||||
|
||||
## peer tests configured below:
|
||||
|
||||
# destination peer for test 0
|
||||
peer.0.peer=[destination in base64]
|
||||
# where will we write out the stat data?
|
||||
peer.0.statFile=heartbeatStat_khWY_30s_1kb.txt
|
||||
# how many minutes will we keep stats for?
|
||||
peer.0.statDuration=30
|
||||
# how often will we write out new stat data (in seconds)?
|
||||
peer.0.statFrequency=60
|
||||
# how often will we send a ping to the peer (in seconds)?
|
||||
peer.0.sendFrequency=30
|
||||
# how many bytes will be included in the ping?
|
||||
peer.0.sendSize=1024
|
||||
# take a guess...
|
||||
peer.0.comment=Test with localhost sending 1KB of data every 30 seconds
|
||||
# we can keep track of a few moving averages - this value includes a whitespace
|
||||
# delimited list of numbers, each specifying a period to calculate the average
|
||||
# over (in minutes)
|
||||
peer.0.averagePeriods=1 5 30
|
||||
## repeat the peer.0.* for as many tests as desired, incrementing as necessary
|
||||
|
||||
If there are no peer.* lines, it will simply run a pong server. If any data is
|
||||
missing, it will use the defaults (though there are no defaults for peer.* lines) -
|
||||
running the Heartbeat app with no heartbeat configuration file whatsoever will create
|
||||
a new pong server (storing its keys at heartbeat.keys) and using the I2P router at
|
||||
localhost:7654.
|
||||
|
||||
The stat file generated for each set of peer.n.* lines contains the current state
|
||||
of the test, its averages, as well as any other interesting data points. An example
|
||||
stat file follows (hopefully it is self explanatory):
|
||||
|
||||
peer khWYqCETu9YtPUvGV92ocsbEW5DezhKlIG7ci8RLX3g=
|
||||
local u-9hlR1ik2hemXf0HvKMfeRgrS86CbNQh25e7XBhaQE=
|
||||
peerDest [base 64 of the full destination]
|
||||
localDest [base 64 of the full destination]
|
||||
numTunnelHops 2
|
||||
comment Test with localhost sending 30KB every 20 seconds
|
||||
sendFrequency 20
|
||||
sendSize 30720
|
||||
sessionStart 20040409.22:51:10.915
|
||||
currentTime 20040409.23:31:39.607
|
||||
numPending 2
|
||||
lifetimeSent 118
|
||||
lifetimeRecv 113
|
||||
#averages minutes sendMs recvMs numLost
|
||||
periodAverage 1 1843 771 0
|
||||
periodAverage 5 786 752 1
|
||||
periodAverage 30 855 735 3
|
||||
#action status date and time sent sendMs replyMs
|
||||
EVENT OK 20040409.23:21:44.742 691 670
|
||||
EVENT OK 20040409.23:22:05.201 671 581
|
||||
EVENT OK 20040409.23:22:26.301 1182 1452
|
||||
EVENT OK 20040409.23:22:47.322 24304 1723
|
||||
EVENT OK 20040409.23:23:08.232 2293 1081
|
||||
EVENT OK 20040409.23:23:29.332 1392 641
|
||||
EVENT OK 20040409.23:23:50.262 641 761
|
||||
EVENT OK 20040409.23:24:11.102 651 701
|
||||
EVENT OK 20040409.23:24:31.401 841 621
|
||||
EVENT OK 20040409.23:24:52.061 651 681
|
||||
EVENT OK 20040409.23:25:12.480 701 1623
|
||||
EVENT OK 20040409.23:25:32.990 1442 1212
|
||||
EVENT OK 20040409.23:25:54.230 591 631
|
||||
EVENT OK 20040409.23:26:14.620 620 691
|
||||
EVENT OK 20040409.23:26:35.199 1793 1432
|
||||
EVENT OK 20040409.23:26:56.570 661 641
|
||||
EVENT OK 20040409.23:27:17.200 641 660
|
||||
EVENT OK 20040409.23:27:38.120 611 921
|
||||
EVENT OK 20040409.23:27:58.699 831 621
|
||||
EVENT OK 20040409.23:28:19.559 801 661
|
||||
EVENT OK 20040409.23:28:40.279 601 611
|
||||
EVENT OK 20040409.23:29:00.648 601 621
|
||||
EVENT OK 20040409.23:29:21.288 701 661
|
||||
EVENT LOST 20040409.23:29:41.828
|
||||
EVENT LOST 20040409.23:30:02.327
|
||||
EVENT LOST 20040409.23:30:22.656
|
||||
EVENT OK 20040409.23:31:24.305 1843 771
|
||||
|
||||
The actual ping and pong messages sent are formatted trivially -
|
||||
ping messages contain
|
||||
$from $series $type $sentOn $size $payload
|
||||
while pong messages contain
|
||||
$from $series $type $sentOn $receivedOn $size $payload
|
||||
|
||||
$series is a number describing the sending client's test (so that you can
|
||||
ping the same peer with different configurations concurrently, varying things
|
||||
like the frequency and size of the message, window, etc).
|
||||
|
||||
They are sent as raw binary messages though, so see I2PAdapter.sendPing(..)
|
||||
and I2PAdapter.sendPong(..) for the details.
|
||||
|
||||
To get valid measurements, of course, you will want to make sure that
|
||||
both the heartbeat client and pong server have synchronized clocks (even
|
||||
more so than I2P requires). It is highly recommended that only NTP
|
||||
synchronized peers be used for heartbeat tests.
|
||||
66
apps/heartbeat/java/build.xml
Normal file
66
apps/heartbeat/java/build.xml
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="heartbeat">
|
||||
<target name="all" depends="clean, buildGUI" />
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="buildGUI" depends="build, jarGUI" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../../core/java/" target="build" />
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac srcdir="./src" debug="true" deprecation="on" source="1.3" target="1.3" destdir="./build/obj" includes="**/*.java" excludes="net/i2p/heartbeat/gui/**" classpath="../../../core/java/build/i2p.jar" />
|
||||
</target>
|
||||
<target name="compileGUI">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac debug="true" source="1.3" target="1.3" deprecation="on" destdir="./build/obj">
|
||||
<src path="src/" />
|
||||
<classpath path="../../../core/java/build/i2p.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/lib/log4j-1.2.8.jar" />
|
||||
<classpath path="../../jfreechart/jfreechart-0.9.17/jfreechart-0.9.17.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="./build/heartbeat.jar" basedir="./build/obj" includes="**/*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.heartbeat.Heartbeat" />
|
||||
<attribute name="Class-Path" value="i2p.jar heartbeat.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="jarGUI" depends="compileGUI">
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/jfreechart-0.9.17.jar" todir="build/" />
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/lib/log4j-1.2.8.jar" todir="build/" />
|
||||
<copy file="../../jfreechart/jfreechart-0.9.17/lib/jcommon-0.9.2.jar" todir="build/" />
|
||||
<jar destfile="./build/heartbeatGUI.jar" basedir="./build/obj" includes="**">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.heartbeat.gui.HeartbeatMonitor" />
|
||||
<attribute name="Class-Path" value="log4j-1.2.8.jar jcommon-0.9.2.jar jfreechart-0.9.17.jar heartbeatGUI.jar i2p.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
<echo message="You will need to copy the log4j, jcommon, and jfreechart jar files into your lib dir" />
|
||||
</target>
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc
|
||||
sourcepath="./src:../../../core/java/src:../../../core/java/test" destdir="./build/javadoc"
|
||||
packagenames="*"
|
||||
use="true"
|
||||
access="package"
|
||||
splitindex="true"
|
||||
windowtitle="I2P heartbeat monitor" />
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<ant dir="../../../core/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
468
apps/heartbeat/java/src/net/i2p/heartbeat/ClientConfig.java
Normal file
468
apps/heartbeat/java/src/net/i2p/heartbeat/ClientConfig.java
Normal file
@@ -0,0 +1,468 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Define the configuration for testing against one particular peer as a client
|
||||
*/
|
||||
public class ClientConfig {
|
||||
private static final Log _log = new Log(ClientConfig.class);
|
||||
private Destination _peer;
|
||||
private Destination _us;
|
||||
private String _statFile;
|
||||
private int _statDuration;
|
||||
private int _statFrequency;
|
||||
private int _sendFrequency;
|
||||
private int _sendSize;
|
||||
private int _numHops;
|
||||
private String _comment;
|
||||
private int _averagePeriods[];
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_PREFIX = "peer.";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_PEER = ".peer";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATFILE = ".statFile";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATDURATION = ".statDuration";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_STATFREQUENCY = ".statFrequency";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_SENDFREQUENCY = ".sendFrequency";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_SENDSIZE = ".sendSize";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_COMMENT = ".comment";
|
||||
|
||||
/**
|
||||
* @seeRoutine ClientConfig#load
|
||||
* @seeRoutine ClientConfig#store
|
||||
*/
|
||||
public static final String PROP_AVERAGEPERIODS = ".averagePeriods";
|
||||
|
||||
/**
|
||||
* Default constructor...
|
||||
*/
|
||||
public ClientConfig() {
|
||||
this(null, null, null, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dummy client config to be fetched from the specified location
|
||||
* @param location the location to fetch from
|
||||
*/
|
||||
public ClientConfig(String location) {
|
||||
this(null, null, location, -1, -1, -1, -1, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param peer who we will test against
|
||||
* @param us who we are
|
||||
* @param statLocation where the stat data should be stored/fetched
|
||||
* @param duration how many minutes to keep events for
|
||||
* @param statFreq how often to write out stats
|
||||
* @param sendFreq how often to send pings
|
||||
* @param sendSize how large the pings should be
|
||||
* @param numHops how many hops is the current Heartbeat app using
|
||||
* @param comment describe this test
|
||||
* @param averagePeriods list of minutes to summarize over
|
||||
*/
|
||||
public ClientConfig(Destination peer, Destination us, String statLocation, int duration, int statFreq, int sendFreq,
|
||||
int sendSize, int numHops, String comment, int averagePeriods[]) {
|
||||
_peer = peer;
|
||||
_us = us;
|
||||
_statFile = statLocation;
|
||||
_statDuration = duration;
|
||||
_statFrequency = statFreq;
|
||||
_sendFrequency = sendFreq;
|
||||
_sendSize = sendSize;
|
||||
_numHops = numHops;
|
||||
_comment = comment;
|
||||
_averagePeriods = averagePeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the peer to test against
|
||||
*
|
||||
* @return the Destination (peer)
|
||||
*/
|
||||
public Destination getPeer() {
|
||||
return _peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the peer to test against
|
||||
*
|
||||
* @param peer the Destination (peer)
|
||||
*/
|
||||
public void setPeer(Destination peer) {
|
||||
_peer = peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves who we are when we test
|
||||
*
|
||||
* @return the Destination (us)
|
||||
*/
|
||||
public Destination getUs() {
|
||||
return _us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets who we are when we test
|
||||
*
|
||||
* @param us the Destination (us)
|
||||
*/
|
||||
public void setUs(Destination us) {
|
||||
_us = us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the location to write the current stats to
|
||||
*
|
||||
* @return the name of the file
|
||||
*/
|
||||
public String getStatFile() {
|
||||
return _statFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the location we write the current stats to
|
||||
*
|
||||
* @param statFile the name of the file
|
||||
*/
|
||||
public void setStatFile(String statFile) {
|
||||
_statFile = statFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many minutes of statistics should be maintained within the window for this client
|
||||
*
|
||||
* @return the number of minutes
|
||||
*/
|
||||
public int getStatDuration() {
|
||||
return _statDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many minutes of statistics should be maintained within the window for this client
|
||||
*
|
||||
* @param durationMinutes the number of minutes
|
||||
*/
|
||||
public void setStatDuration(int durationMinutes) {
|
||||
_statDuration = durationMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how frequently the stats are written out (in seconds)
|
||||
*
|
||||
* @return the frequency in seconds
|
||||
*/
|
||||
public int getStatFrequency() {
|
||||
return _statFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how frequently the stats are written out (in seconds)
|
||||
*
|
||||
* @param freqSeconds the frequency in seconds
|
||||
*/
|
||||
public void setStatFrequency(int freqSeconds) {
|
||||
_statFrequency = freqSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how frequenty we send messages to the peer (in seconds)
|
||||
*
|
||||
* @return the frequency in seconds
|
||||
*/
|
||||
public int getSendFrequency() {
|
||||
return _sendFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how frequenty we send messages to the peer (in seconds)
|
||||
*
|
||||
* @param freqSeconds the frequency in seconds
|
||||
*/
|
||||
public void setSendFrequency(int freqSeconds) {
|
||||
_sendFrequency = freqSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many bytes the ping messages should be (min values ~700, max ~32KB)
|
||||
*
|
||||
* @return the size in bytes
|
||||
*/
|
||||
public int getSendSize() {
|
||||
return _sendSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many bytes the ping messages should be (min values ~700, max ~32KB)
|
||||
*
|
||||
* @param numBytes the size in bytes
|
||||
*/
|
||||
public void setSendSize(int numBytes) {
|
||||
_sendSize = numBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the brief, 1 line description of the test. Useful comments are along the lines of "The peer is located on a fast router and connection with 2
|
||||
* hop tunnels".
|
||||
*
|
||||
* @return the brief comment
|
||||
*/
|
||||
public String getComment() {
|
||||
return _comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a brief, 1 line description (comment) of the test.
|
||||
*
|
||||
* @param comment the brief comment
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
_comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the periods that the client's tests should be averaged over.
|
||||
*
|
||||
* @return list of periods (in minutes) that the data should be averaged over, or null
|
||||
*/
|
||||
public int[] getAveragePeriods() {
|
||||
return _averagePeriods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the periods that the client's tests should be averaged over.
|
||||
*
|
||||
* @param periods the list of periods (in minutes) that the data should be averaged over, or null
|
||||
*/
|
||||
public void setAveragePeriods(int periods[]) {
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we're keeping track of the average over the given time period.
|
||||
*
|
||||
* @param minutes how many minutes to monitor
|
||||
*/
|
||||
public void addAveragePeriod(int minutes) {
|
||||
if (_averagePeriods != null) {
|
||||
for (int i = 0; i < _averagePeriods.length; i++) {
|
||||
if (_averagePeriods[i] == minutes)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int numPeriods = 1;
|
||||
if (_averagePeriods != null)
|
||||
numPeriods += _averagePeriods.length;
|
||||
int periods[] = new int[numPeriods];
|
||||
if (_averagePeriods != null)
|
||||
System.arraycopy(_averagePeriods, 0, periods, 0, _averagePeriods.length);
|
||||
periods[periods.length-1] = minutes;
|
||||
Arrays.sort(periods);
|
||||
_averagePeriods = periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves how many hops this test engine is configured to use for its outbound and inbound tunnels
|
||||
*
|
||||
* @return the number of hops
|
||||
*/
|
||||
public int getNumHops() {
|
||||
return _numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many hops this test engine is configured to use for its outbound and inbound tunnels
|
||||
*
|
||||
* @param numHops the number of hops
|
||||
*/
|
||||
public void setNumHops(int numHops) {
|
||||
_numHops = numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the client config from the properties specified, deriving the current config entry from the peer number.
|
||||
*
|
||||
* @param clientConfig the properties to load from
|
||||
* @param peerNum the number associated with the peer
|
||||
* @return true if it was loaded correctly, false if there were errors
|
||||
*/
|
||||
public boolean load(Properties clientConfig, int peerNum) {
|
||||
if ((clientConfig == null) || (peerNum < 0)) return false;
|
||||
String peerVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_PEER);
|
||||
String statFileVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATFILE);
|
||||
String statDurationVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATDURATION);
|
||||
String statFrequencyVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_STATFREQUENCY);
|
||||
String sendFrequencyVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_SENDFREQUENCY);
|
||||
String sendSizeVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_SENDSIZE);
|
||||
String commentVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_COMMENT);
|
||||
String periodsVal = clientConfig.getProperty(PROP_PREFIX + peerNum + PROP_AVERAGEPERIODS);
|
||||
|
||||
if ((peerVal == null) || (statFileVal == null) || (statDurationVal == null) || (statFrequencyVal == null)
|
||||
|| (sendFrequencyVal == null) || (sendSizeVal == null)) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Peer number " + peerNum + " does not exist");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
int duration = getInt(statDurationVal);
|
||||
int statFreq = getInt(statFrequencyVal);
|
||||
int sendFreq = getInt(sendFrequencyVal);
|
||||
int sendSize = getInt(sendSizeVal);
|
||||
|
||||
if ((duration <= 0) || (statFreq <= 0) || (sendFreq < 0) || (sendSize <= 0)) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid client config: duration [" + statDurationVal + "] stat frequency ["
|
||||
+ statFrequencyVal + "] send frequency [" + sendFrequencyVal + "] send size ["
|
||||
+ sendSizeVal + "]");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
statFileVal = statFileVal.trim();
|
||||
if (statFileVal.length() <= 0) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Stat file is blank for peer " + peerNum);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(peerVal);
|
||||
|
||||
if (commentVal == null) {
|
||||
commentVal = "";
|
||||
}
|
||||
|
||||
commentVal = commentVal.trim();
|
||||
commentVal = commentVal.replace('\n', '_');
|
||||
|
||||
List periods = new ArrayList(4);
|
||||
if (periodsVal != null) {
|
||||
StringTokenizer tok = new StringTokenizer(periodsVal);
|
||||
while (tok.hasMoreTokens()) {
|
||||
String periodVal = tok.nextToken();
|
||||
int minutes = getInt(periodVal);
|
||||
if (minutes > 0) {
|
||||
periods.add(new Integer(minutes));
|
||||
}
|
||||
}
|
||||
}
|
||||
int avgPeriods[] = new int[periods.size()];
|
||||
for (int i = 0; i < periods.size(); i++) {
|
||||
avgPeriods[i] = ((Integer) periods.get(i)).intValue();
|
||||
}
|
||||
|
||||
_comment = commentVal;
|
||||
_statDuration = duration;
|
||||
_statFrequency = statFreq;
|
||||
_sendFrequency = sendFreq;
|
||||
_sendSize = sendSize;
|
||||
_statFile = statFileVal;
|
||||
_peer = d;
|
||||
_averagePeriods = avgPeriods;
|
||||
return true;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Peer destination for " + peerNum + " was invalid: " + peerVal);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the client config to the properties specified, deriving the current config entry from the peer number.
|
||||
*
|
||||
* @param clientConfig the properties to store to
|
||||
* @param peerNum the number associated with the peer
|
||||
* @return true if it was stored correctly, false if there were errors
|
||||
*/
|
||||
public boolean store(Properties clientConfig, int peerNum) {
|
||||
if ((_peer == null) || (_sendFrequency < 0) || (_sendSize <= 0) || (_statDuration <= 0)
|
||||
|| (_statFrequency <= 0) || (_statFile == null)) { return false; }
|
||||
|
||||
String comment = _comment;
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
|
||||
comment = comment.trim();
|
||||
comment = comment.replace('\n', '_');
|
||||
|
||||
StringBuffer buf = new StringBuffer(32);
|
||||
if (_averagePeriods != null) {
|
||||
for (int i = 0; i < _averagePeriods.length; i++) {
|
||||
buf.append(_averagePeriods[i]).append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_PEER, _peer.toBase64());
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATFILE, _statFile);
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATDURATION, _statDuration + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_STATFREQUENCY, _statFrequency + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_SENDFREQUENCY, _sendFrequency + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_SENDSIZE, _sendSize + "");
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_COMMENT, comment);
|
||||
clientConfig.setProperty(PROP_PREFIX + peerNum + PROP_AVERAGEPERIODS, buf.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final int getInt(String val) {
|
||||
if (val == null) return -1;
|
||||
try {
|
||||
int i = Integer.parseInt(val);
|
||||
return i;
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Value [" + val + "] is not a valid integer");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
133
apps/heartbeat/java/src/net/i2p/heartbeat/ClientEngine.java
Normal file
133
apps/heartbeat/java/src/net/i2p/heartbeat/ClientEngine.java
Normal file
@@ -0,0 +1,133 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Responsible for actually conducting the tests, coordinating the storing of the
|
||||
* stats, and the management of the rates. This has its own thread specific for
|
||||
* pumping data around as well.
|
||||
*
|
||||
*/
|
||||
class ClientEngine {
|
||||
private static final Log _log = new Log(ClientEngine.class);
|
||||
/** who can send our pings? */
|
||||
private Heartbeat _heartbeat;
|
||||
/** actual test state */
|
||||
private PeerData _data;
|
||||
/** have we been stopped? */
|
||||
private boolean _active;
|
||||
/** used to generate engine IDs */
|
||||
private static int __id = 0;
|
||||
/** this engine's id, unique to the {test,sendingClient,startTime} */
|
||||
private int _id;
|
||||
private static PeerDataWriter writer = new PeerDataWriter();
|
||||
|
||||
/**
|
||||
* Create a new engine that will send its pings through the given heartbeat
|
||||
* system, and will coordinate the test according to the configuration specified.
|
||||
* @param heartbeat the Heartbeat to send pings through
|
||||
* @param config the Configuration to load configuration from =p
|
||||
*/
|
||||
public ClientEngine(Heartbeat heartbeat, ClientConfig config) {
|
||||
_heartbeat = heartbeat;
|
||||
_data = new PeerData(config);
|
||||
_active = false;
|
||||
_id = ++__id;
|
||||
}
|
||||
|
||||
/** stop sending any more pings or writing any more state */
|
||||
public void stopEngine() {
|
||||
_active = false;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Stopping engine talking to peer " + _data.getConfig().getPeer().calculateHash().toBase64());
|
||||
}
|
||||
|
||||
/** start up the test (this does not block, as it fires up the test thread) */
|
||||
public void startEngine() {
|
||||
_active = true;
|
||||
I2PThread t = new I2PThread(new ClientRunner());
|
||||
t.setName("HeartbeatClient " + _id);
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Who are we testing?
|
||||
* @return the Destination (peer) we're testing
|
||||
*/
|
||||
public Destination getPeer() {
|
||||
return _data.getConfig().getPeer();
|
||||
}
|
||||
|
||||
/**
|
||||
* What is our series identifier (used to locally identify a test)
|
||||
* @return the series identifier
|
||||
*/
|
||||
public int getSeriesNum() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive notification from the heartbeat system that a pong was received in
|
||||
* reply to a ping we have sent.
|
||||
*
|
||||
* @param sentOn when did we send the ping?
|
||||
* @param replyOn when did the peer send the pong?
|
||||
*/
|
||||
public void receivePong(long sentOn, long replyOn) {
|
||||
_data.pongReceived(sentOn, replyOn);
|
||||
}
|
||||
|
||||
/** fire off a new ping */
|
||||
private void doSend() {
|
||||
long now = Clock.getInstance().now();
|
||||
_data.addPing(now);
|
||||
_heartbeat.sendPing(_data.getConfig().getPeer(), _id, now, _data.getConfig().getSendSize());
|
||||
}
|
||||
|
||||
/** our actual heartbeat pumper - this drives the test */
|
||||
private class ClientRunner implements Runnable {
|
||||
|
||||
/**
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting engine talking to peer " + _data.getConfig().getPeer().calculateHash().toBase64());
|
||||
|
||||
// when do we need to send the next PING?
|
||||
long nextSend = Clock.getInstance().now();
|
||||
// when do we need to write out the next state data?
|
||||
long nextWrite = Clock.getInstance().now();
|
||||
|
||||
while (_active) {
|
||||
|
||||
if (Clock.getInstance().now() >= nextSend) {
|
||||
doSend();
|
||||
nextSend = Clock.getInstance().now() + _data.getConfig().getSendFrequency() * 1000;
|
||||
}
|
||||
|
||||
if (Clock.getInstance().now() >= nextWrite) {
|
||||
boolean written = writer.persist(_data);
|
||||
if (!written) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Unable to write the client state data");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Client state data written");
|
||||
}
|
||||
}
|
||||
|
||||
_data.cleanup();
|
||||
|
||||
long timeToWait = nextSend - Clock.getInstance().now();
|
||||
if (timeToWait > 0) {
|
||||
try {
|
||||
Thread.sleep(timeToWait);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
254
apps/heartbeat/java/src/net/i2p/heartbeat/Heartbeat.java
Normal file
254
apps/heartbeat/java/src/net/i2p/heartbeat/Heartbeat.java
Normal file
@@ -0,0 +1,254 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Main driver for the heartbeat engine, loading 0 or more tests, firing
|
||||
* up a ClientEngine for each, and serving as a pong server. If there isn't
|
||||
* a configuration file, or if the configuration file doesn't specify any tests,
|
||||
* it simply sits around as a pong server, passively responding to whatever is
|
||||
* sent its way. <p />
|
||||
*
|
||||
* The config file format is examplified below:
|
||||
* <pre>
|
||||
* # where the router is located (default is localhost)
|
||||
* i2cpHost=localhost
|
||||
* # I2CP port for the router (default is 7654)
|
||||
* i2cpPort=4001
|
||||
* # How many hops we want the router to put in our tunnels (default is 2)
|
||||
* numHops=2
|
||||
* # where our private destination keys are located - if this doesn't exist,
|
||||
* # a new one will be created and saved there (by default, heartbeat.keys)
|
||||
* privateDestinationFile=heartbeat_r2.keys
|
||||
* # where do we want to export the plain base64 of our destination?
|
||||
* publicDestinationFile=heartbeat_r2.txt
|
||||
*
|
||||
* ## peer tests configured below:
|
||||
*
|
||||
* # destination peer for test 0
|
||||
* peer.0.peer=[destination in base64]
|
||||
* # where will we write out the stat data?
|
||||
* peer.0.statFile=heartbeatStat_khWY_30s_1kb.txt
|
||||
* # how many minutes will we keep stats for?
|
||||
* peer.0.statDuration=30
|
||||
* # how often will we write out new stat data (in seconds)?
|
||||
* peer.0.statFrequency=60
|
||||
* # how often will we send a ping to the peer (in seconds)?
|
||||
* peer.0.sendFrequency=30
|
||||
* # how many bytes will be included in the ping?
|
||||
* peer.0.sendSize=1024
|
||||
* # take a guess...
|
||||
* peer.0.comment=Test with localhost sending 1KB of data every 30 seconds
|
||||
* # we can keep track of a few moving averages - this value includes a whitespace
|
||||
* # delimited list of numbers, each specifying a period to calculate the average
|
||||
* # over (in minutes)
|
||||
* peer.0.averagePeriods=1 5 30
|
||||
* ## repeat the peer.0.* for as many tests as desired, incrementing as necessary
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class Heartbeat {
|
||||
private static final Log _log = new Log(Heartbeat.class);
|
||||
/** location containing this heartbeat's config */
|
||||
private String _configFile;
|
||||
/** clientNum (Integer) to ClientConfig mapping */
|
||||
private Map _clientConfigs;
|
||||
/** series num (Integer) to ClientEngine mapping */
|
||||
private Map _clientEngines;
|
||||
/** helper class for managing our I2P send/receive and message formatting */
|
||||
private I2PAdapter _adapter;
|
||||
/** our own callback that the I2PAdapter notifies on ping or pong messages */
|
||||
private PingPongAdapter _eventAdapter;
|
||||
|
||||
/** if there are no command line arguments, load the config from "heartbeat.config" */
|
||||
public static final String CONFIG_FILE_DEFAULT = "heartbeat.config";
|
||||
|
||||
/**
|
||||
* build up a new heartbeat manager, but don't actually do anything
|
||||
* @param configFile the name of the configuration file
|
||||
*/
|
||||
public Heartbeat(String configFile) {
|
||||
_configFile = configFile;
|
||||
_clientConfigs = new HashMap();
|
||||
_clientEngines = new HashMap();
|
||||
_eventAdapter = new PingPongAdapter();
|
||||
_adapter = new I2PAdapter();
|
||||
_adapter.setListener(_eventAdapter);
|
||||
}
|
||||
|
||||
private Heartbeat() {
|
||||
}
|
||||
|
||||
/** load up the config data (but don't build any engines or start them up) */
|
||||
public void loadConfig() {
|
||||
Properties props = new Properties();
|
||||
FileInputStream fin = null;
|
||||
File configFile = new File(_configFile);
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
fin = new FileInputStream(_configFile);
|
||||
props.load(fin);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error reading the config data", ioe);
|
||||
}
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadBaseConfig(props);
|
||||
loadClientConfigs(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* send a ping message to the peer
|
||||
*
|
||||
* @param peer peer to ping
|
||||
* @param seriesNum id used to keep track of multiple pings (of different size/frequency) to a peer
|
||||
* @param now current time to be sent in the ping (so we can watch for it in the pong)
|
||||
* @param size total message size to send
|
||||
*/
|
||||
void sendPing(Destination peer, int seriesNum, long now, int size) {
|
||||
if (_adapter.getIsConnected()) _adapter.sendPing(peer, seriesNum, now, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* load up the base data (I2CP config, etc)
|
||||
* @param props the properties to load from
|
||||
*/
|
||||
private void loadBaseConfig(Properties props) {
|
||||
_adapter.loadConfig(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* load up all of the test config data
|
||||
* @param props the properties to load from
|
||||
* */
|
||||
private void loadClientConfigs(Properties props) {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ClientConfig config = new ClientConfig();
|
||||
if (!config.load(props, i)) {
|
||||
break;
|
||||
}
|
||||
_clientConfigs.put(new Integer(i), config);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/** connect to the network */
|
||||
private void connect() {
|
||||
boolean connected = _adapter.connect();
|
||||
if (!connected) _log.error("Unable to connect to the router");
|
||||
}
|
||||
|
||||
/** disconnect from the network */
|
||||
private void disconnect() { /* UNUSED */
|
||||
_adapter.disconnect();
|
||||
}
|
||||
|
||||
/** start up all of the tests */
|
||||
public void startEngines() {
|
||||
for (Iterator iter = _clientConfigs.values().iterator(); iter.hasNext();) {
|
||||
ClientConfig config = (ClientConfig) iter.next();
|
||||
ClientEngine engine = new ClientEngine(this, config);
|
||||
config.setUs(_adapter.getLocalDestination());
|
||||
config.setNumHops(_adapter.getNumHops());
|
||||
_clientEngines.put(new Integer(engine.getSeriesNum()), engine);
|
||||
engine.startEngine();
|
||||
}
|
||||
}
|
||||
|
||||
/** stop all of the tests */
|
||||
public void stopEngines() {
|
||||
for (Iterator iter = _clientEngines.values().iterator(); iter.hasNext();) {
|
||||
ClientEngine engine = (ClientEngine) iter.next();
|
||||
engine.stopEngine();
|
||||
}
|
||||
_clientEngines.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire up a new heartbeat system, waiting until, well, forever. Builds
|
||||
* a new heartbeat system, loads the config, connects to the network, starts
|
||||
* the engines, and then sits back and relaxes, responding to any pings and
|
||||
* running any tests. <p />
|
||||
*
|
||||
* <code> <b>Usage: </b> Heartbeat [<i>configFileName</i>]</code> <p />
|
||||
* @param args the list of args passed to the program from the command-line
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
String configFile = CONFIG_FILE_DEFAULT;
|
||||
if (args.length == 1) {
|
||||
configFile = args[0];
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Starting up with config file " + configFile);
|
||||
}
|
||||
Heartbeat heartbeat = new Heartbeat(configFile);
|
||||
heartbeat.loadConfig();
|
||||
heartbeat.connect();
|
||||
heartbeat.startEngines();
|
||||
Object o = new Object();
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (o) {
|
||||
o.wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive event notification from the I2PAdapter
|
||||
*
|
||||
*/
|
||||
private class PingPongAdapter implements I2PAdapter.PingPongEventListener {
|
||||
/**
|
||||
* We were pinged, so always just send a pong back.
|
||||
*
|
||||
* @param from who sent us the ping?
|
||||
* @param seriesNum what series did the sender specify?
|
||||
* @param sentOn when did the sender say they sent their ping?
|
||||
* @param data arbitrary payload data
|
||||
*/
|
||||
public void receivePing(Destination from, int seriesNum, Date sentOn, byte[] data) {
|
||||
if (_adapter.getIsConnected()) {
|
||||
_adapter.sendPong(from, seriesNum, sentOn, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We received a pong, so find the right client engine and tell it about the pong.
|
||||
*
|
||||
* @param from who sent us the pong
|
||||
* @param seriesNum our client ID
|
||||
* @param sentOn when did we send the ping?
|
||||
* @param replyOn when did they send their pong?
|
||||
* @param data the arbitrary data we sent in the ping (that they sent back in the pong)
|
||||
*/
|
||||
public void receivePong(Destination from, int seriesNum, Date sentOn, Date replyOn, byte[] data) {
|
||||
ClientEngine engine = (ClientEngine) _clientEngines.get(new Integer(seriesNum));
|
||||
if (engine.getPeer().equals(from)) {
|
||||
engine.receivePong(sentOn.getTime(), replyOn.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
604
apps/heartbeat/java/src/net/i2p/heartbeat/I2PAdapter.java
Normal file
604
apps/heartbeat/java/src/net/i2p/heartbeat/I2PAdapter.java
Normal file
@@ -0,0 +1,604 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Tie-in to the I2P SDK for the Heartbeat system, talking to the I2PSession and
|
||||
* dealing with the raw ping and pong messages.
|
||||
*
|
||||
*/
|
||||
class I2PAdapter {
|
||||
private final static Log _log = new Log(I2PAdapter.class);
|
||||
/** I2CP host */
|
||||
private String _i2cpHost;
|
||||
/** I2CP port */
|
||||
private int _i2cpPort;
|
||||
/** how long do we want our tunnels to be? */
|
||||
private int _numHops;
|
||||
/** filename containing the heartbeat engine's private destination info */
|
||||
private String _privateDestFile;
|
||||
/** filename to store the heartbeat engine's public destination in base64*/
|
||||
private String _publicDestFile;
|
||||
/** our destination */
|
||||
private Destination _localDest;
|
||||
/** who do we tell? */
|
||||
private PingPongEventListener _listener;
|
||||
/** how do we talk to the router */
|
||||
private I2PSession _session;
|
||||
/** object that receives our i2cp notifications from the session and tells us */
|
||||
private I2PListener _i2pListener; /* UNUSED */
|
||||
|
||||
/**
|
||||
* This config property tells us where the private destination data for our
|
||||
* connection (or if it doesn't exist, where will we save it)
|
||||
*/
|
||||
private static final String DEST_FILE_PROP = "privateDestinationFile";
|
||||
/** by default, the private destination data is in "heartbeat.keys" */
|
||||
private static final String DEST_FILE_DEFAULT = "heartbeat.keys";
|
||||
/** where will we export the public destination in base 64? */
|
||||
private static final String PUBLIC_DEST_FILE_PROP = "publicDestinationFile";
|
||||
/** where will we export the public destination in base 64? */
|
||||
private static final String PUBLIC_DEST_FILE_DEFAULT = "heartbeat.txt";
|
||||
/** This config property defines where the I2P router is */
|
||||
private static final String I2CP_HOST_PROP = "i2cpHost";
|
||||
/** by default, the I2P host is "localhost" */
|
||||
private static final String I2CP_HOST_DEFAULT = "localhost";
|
||||
/** This config property defines the I2CP port on the router */
|
||||
private static final String I2CP_PORT_PROP = "i2cpPort";
|
||||
/** by default, the I2CP port is 7654 */
|
||||
private static final int I2CP_PORT_DEFAULT = 7654;
|
||||
|
||||
/** This property defines how many hops we want in our tunnels. */
|
||||
public static final String NUMHOPS_PROP = "numHops";
|
||||
/** by default, use 2 hop tunnels */
|
||||
public static final int NUMHOPS_DEFAULT = 2;
|
||||
|
||||
/**
|
||||
* Constructs an I2PAdapter . . .
|
||||
*/
|
||||
public I2PAdapter() {
|
||||
_privateDestFile = null;
|
||||
_publicDestFile = null;
|
||||
_i2cpHost = null;
|
||||
_i2cpPort = -1;
|
||||
_localDest = null;
|
||||
_listener = null;
|
||||
_session = null;
|
||||
_numHops = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* who are we?
|
||||
* @return the destination (us)
|
||||
*/
|
||||
public Destination getLocalDestination() {
|
||||
return _localDest;
|
||||
}
|
||||
|
||||
/**
|
||||
* who gets notified when we receive a ping or a pong?
|
||||
* @return the event listener who gets notified
|
||||
*/
|
||||
public PingPongEventListener getListener() {
|
||||
return _listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets who gets notified when we receive a ping or a pong
|
||||
* @param listener the event listener to get notified
|
||||
*/
|
||||
public void setListener(PingPongEventListener listener) {
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many hops do we want in our tunnels?
|
||||
* @return the number of hops
|
||||
*/
|
||||
public int getNumHops() {
|
||||
return _numHops;
|
||||
}
|
||||
|
||||
/**
|
||||
* are we connected?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getIsConnected() {
|
||||
return _session != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in all of the config data
|
||||
* @param props the properties to load from
|
||||
*/
|
||||
void loadConfig(Properties props) {
|
||||
String privDestFile = props.getProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||
String pubDestFile = props.getProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||
String host = props.getProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
||||
String port = props.getProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
||||
String numHops = props.getProperty(NUMHOPS_PROP, "" + NUMHOPS_DEFAULT);
|
||||
|
||||
int portNum = -1;
|
||||
try {
|
||||
portNum = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid I2CP port specified [" + port + "]");
|
||||
}
|
||||
portNum = I2CP_PORT_DEFAULT;
|
||||
}
|
||||
int hops = -1;
|
||||
try {
|
||||
hops = Integer.parseInt(numHops);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
_log.warn("Invalid # hops specified [" + numHops + "]");
|
||||
}
|
||||
hops = NUMHOPS_DEFAULT;
|
||||
}
|
||||
|
||||
_numHops = hops;
|
||||
_privateDestFile = privDestFile;
|
||||
_publicDestFile = pubDestFile;
|
||||
_i2cpHost = host;
|
||||
_i2cpPort = portNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* write out the config to the props
|
||||
* @param props the properties to write to
|
||||
*/
|
||||
void storeConfig(Properties props) {
|
||||
if (_privateDestFile != null) {
|
||||
props.setProperty(DEST_FILE_PROP, _privateDestFile);
|
||||
} else {
|
||||
props.setProperty(DEST_FILE_PROP, DEST_FILE_DEFAULT);
|
||||
}
|
||||
|
||||
if (_publicDestFile != null) {
|
||||
props.setProperty(PUBLIC_DEST_FILE_PROP, _publicDestFile);
|
||||
} else {
|
||||
props.setProperty(PUBLIC_DEST_FILE_PROP, PUBLIC_DEST_FILE_DEFAULT);
|
||||
}
|
||||
|
||||
if (_i2cpHost != null) {
|
||||
props.setProperty(I2CP_HOST_PROP, _i2cpHost);
|
||||
} else {
|
||||
props.setProperty(I2CP_HOST_PROP, I2CP_HOST_DEFAULT);
|
||||
}
|
||||
|
||||
if (_i2cpPort > 0) {
|
||||
props.setProperty(I2CP_PORT_PROP, "" + _i2cpPort);
|
||||
} else {
|
||||
props.setProperty(I2CP_PORT_PROP, "" + I2CP_PORT_DEFAULT);
|
||||
}
|
||||
|
||||
props.setProperty(NUMHOPS_PROP, "" + _numHops);
|
||||
}
|
||||
|
||||
private static final int TYPE_PING = 0;
|
||||
private static final int TYPE_PONG = 1;
|
||||
|
||||
/**
|
||||
* send a ping message to the peer
|
||||
*
|
||||
* @param peer peer to ping
|
||||
* @param seriesNum id used to keep track of multiple pings (of different size/frequency) to a peer
|
||||
* @param now current time to be sent in the ping (so we can watch for it in the pong)
|
||||
* @param size total message size to send
|
||||
*
|
||||
* @throws IllegalStateException if we are not connected to the router
|
||||
*/
|
||||
public void sendPing(Destination peer, int seriesNum, long now, int size) {
|
||||
if (_session == null) throw new IllegalStateException("Not connected to the router");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
|
||||
try {
|
||||
_localDest.writeBytes(baos);
|
||||
DataHelper.writeLong(baos, 2, seriesNum);
|
||||
DataHelper.writeLong(baos, 1, TYPE_PING);
|
||||
DataHelper.writeDate(baos, new Date(now));
|
||||
int padding = size - baos.size();
|
||||
byte paddingData[] = new byte[padding];
|
||||
I2PAppContext.getGlobalContext().random().nextBytes(paddingData);
|
||||
//Arrays.fill(paddingData, (byte) 0x2A);
|
||||
DataHelper.writeLong(baos, 2, padding);
|
||||
baos.write(paddingData);
|
||||
boolean sent = _session.sendMessage(peer, baos.toByteArray());
|
||||
if (!sent) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping to " + peer.calculateHash().toBase64() + " for series "
|
||||
+ seriesNum);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Ping sent to " + peer.calculateHash().toBase64() + " for series " + seriesNum);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the ping message", dfe);
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the ping message", ise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send a pong message to the peer
|
||||
*
|
||||
* @param peer peer to pong
|
||||
* @param seriesNum id given to us in the ping
|
||||
* @param sentOn date the peer said they sent us the message
|
||||
* @param data payload the peer sent us in the ping
|
||||
*
|
||||
* @throws IllegalStateException if we are not connected to the router
|
||||
*/
|
||||
public void sendPong(Destination peer, int seriesNum, Date sentOn, byte data[]) {
|
||||
if (_session == null) throw new IllegalStateException("Not connected to the router");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length + 768);
|
||||
try {
|
||||
_localDest.writeBytes(baos);
|
||||
DataHelper.writeLong(baos, 2, seriesNum);
|
||||
DataHelper.writeLong(baos, 1, TYPE_PONG);
|
||||
DataHelper.writeDate(baos, sentOn);
|
||||
DataHelper.writeDate(baos, new Date(Clock.getInstance().now()));
|
||||
DataHelper.writeLong(baos, 2, data.length);
|
||||
baos.write(data);
|
||||
boolean sent = _session.sendMessage(peer, baos.toByteArray());
|
||||
if (!sent) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the pong to " + peer.calculateHash().toBase64() + " for series "
|
||||
+ seriesNum + " which was sent on " + sentOn);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Pong sent to " + peer.calculateHash().toBase64() + " for series " + seriesNum
|
||||
+ " which was sent on " + sentOn);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error sending the ping", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the pong message", dfe);
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the pong message", ise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received this data from I2P - parse it into a ping or a pong
|
||||
* and notify accordingly
|
||||
* @param data the data to handle
|
||||
*/
|
||||
private void handleMessage(byte data[]) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
try {
|
||||
Destination from = new Destination();
|
||||
from.readBytes(bais);
|
||||
int series = (int) DataHelper.readLong(bais, 2);
|
||||
long type = DataHelper.readLong(bais, 1);
|
||||
Date sentOn = DataHelper.readDate(bais);
|
||||
Date receivedOn = null;
|
||||
if (type == TYPE_PONG) {
|
||||
receivedOn = DataHelper.readDate(bais);
|
||||
}
|
||||
int size = (int) DataHelper.readLong(bais, 2);
|
||||
byte payload[] = new byte[size];
|
||||
int read = DataHelper.read(bais, payload);
|
||||
if (read != size) { throw new IOException("Malformed payload - read " + read + " instead of " + size); }
|
||||
|
||||
if (_listener == null) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Listener isn't set, but we received a valid message of type " + type + " sent from "
|
||||
+ from.calculateHash().toBase64());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == TYPE_PING) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Ping received from " + from.calculateHash().toBase64() + " on series " + series
|
||||
+ " sent on " + sentOn + " containing " + size + " bytes");
|
||||
}
|
||||
_listener.receivePing(from, series, sentOn, payload);
|
||||
} else if (type == TYPE_PONG) {
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Pong received from " + from.calculateHash().toBase64() + " on series " + series
|
||||
+ " sent on " + sentOn + " with pong sent on " + receivedOn + " containing " + size
|
||||
+ " bytes");
|
||||
}
|
||||
_listener.receivePong(from, series, sentOn, receivedOn, payload);
|
||||
} else {
|
||||
throw new IOException("Invalid message type " + type);
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error handling the message", ioe);
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error parsing the message", dfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to the I2P router and either authenticate ourselves with the
|
||||
* destination we're given, or create a new one and write that to the
|
||||
* destination file.
|
||||
*
|
||||
* @return true if we connect successfully, false otherwise
|
||||
*/
|
||||
boolean connect() {
|
||||
I2PClient client = I2PClientFactory.createClient();
|
||||
Destination us = null;
|
||||
File destFile = new File(_privateDestFile);
|
||||
us = verifyDestination(client, destFile);
|
||||
if (us == null) return false;
|
||||
|
||||
// if we're here, we got a destination. lets connect
|
||||
FileInputStream fin = null;
|
||||
try {
|
||||
fin = new FileInputStream(destFile);
|
||||
Properties options = getOptions();
|
||||
I2PSession session = client.createSession(fin, options);
|
||||
I2PListener lsnr = new I2PListener();
|
||||
session.setSessionListener(lsnr);
|
||||
session.connect();
|
||||
_localDest = session.getMyDestination();
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("I2CP Session created and connected as " + _localDest.calculateHash().toBase64());
|
||||
}
|
||||
_session = session;
|
||||
_i2pListener = lsnr;
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error connecting", ise);
|
||||
}
|
||||
return false;
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error loading the destionation", ioe);
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* load, verify, or create a destination
|
||||
*
|
||||
* @param client the client
|
||||
* @param destFile the file holding the destination
|
||||
* @return the destination loaded, or null if there was an error
|
||||
*/
|
||||
private Destination verifyDestination(I2PClient client, File destFile) {
|
||||
Destination us = null;
|
||||
FileInputStream fin = null;
|
||||
if (destFile.exists()) {
|
||||
try {
|
||||
fin = new FileInputStream(destFile);
|
||||
us = new Destination();
|
||||
us.readBytes(fin);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Existing destination loaded: [" + us.toBase64() + "]");
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(_publicDestFile);
|
||||
fos.write(us.toBase64().getBytes());
|
||||
fos.flush();
|
||||
} catch (IOException fioe) {
|
||||
_log.error("Error writing out the plain destination to [" + _publicDestFile + "]", fioe);
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException fioe) {}
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
destFile.delete();
|
||||
us = null;
|
||||
} catch (DataFormatException dfe) {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
destFile.delete();
|
||||
us = null;
|
||||
} finally {
|
||||
if (fin != null) try {
|
||||
fin.close();
|
||||
} catch (IOException ioe2) {
|
||||
}
|
||||
fin = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (us == null) {
|
||||
// need to create a new one
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(destFile);
|
||||
us = client.createDestination(fos);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("New destination created: [" + us.toBase64() + "]");
|
||||
}
|
||||
fos.close();
|
||||
|
||||
try {
|
||||
fos = new FileOutputStream(_publicDestFile);
|
||||
fos.write(us.toBase64().getBytes());
|
||||
fos.flush();
|
||||
} catch (IOException fioe) {
|
||||
_log.error("Error writing out the plain destination to [" + _publicDestFile + "]", fioe);
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException fioe) {}
|
||||
fos = null;
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error writing out the destination keys being created", ioe);
|
||||
}
|
||||
return null;
|
||||
} catch (I2PException ie) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error creating the destination", ie);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (fos != null) try {
|
||||
fos.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return us;
|
||||
}
|
||||
|
||||
/**
|
||||
* I2PSession connect options
|
||||
* @return the options as Properties
|
||||
*/
|
||||
private Properties getOptions() {
|
||||
Properties props = new Properties();
|
||||
// this should be BEST_EFFORT, but i'm too lazy to update the code to handle tracking
|
||||
// sessionTags and sessionKeys, marking them as delivered on pong.
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
||||
props.setProperty(I2PClient.PROP_TCP_HOST, _i2cpHost);
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, _i2cpPort + "");
|
||||
props.setProperty("tunnels.depthInbound", "" + _numHops);
|
||||
props.setProperty("tunnels.depthOutbound", "" + _numHops);
|
||||
return props;
|
||||
}
|
||||
|
||||
/** disconnect from the I2P router */
|
||||
void disconnect() {
|
||||
if (_session != null) {
|
||||
try {
|
||||
_session.destroySession();
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Error destroying the session", ise);
|
||||
}
|
||||
}
|
||||
_session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an event notification system for receiving pings and pongs
|
||||
*
|
||||
*/
|
||||
public interface PingPongEventListener {
|
||||
/**
|
||||
* receive a ping message from the peer
|
||||
*
|
||||
* @param from peer that sent us the ping
|
||||
* @param seriesNum id the peer sent us in the ping
|
||||
* @param sentOn date the peer said they sent us the message
|
||||
* @param data payload from the ping
|
||||
*/
|
||||
void receivePing(Destination from, int seriesNum, Date sentOn, byte data[]);
|
||||
|
||||
/**
|
||||
* receive a pong message from the peer
|
||||
*
|
||||
* @param from peer that sent us the pong
|
||||
* @param seriesNum id the peer sent us in the pong (that we sent them in the ping)
|
||||
* @param sentOn when we sent out the ping
|
||||
* @param replyOn when they sent out the pong
|
||||
* @param data payload from the ping/pong
|
||||
*/
|
||||
void receivePong(Destination from, int seriesNum, Date sentOn, Date replyOn, byte data[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data from the session and pass it along to handleMessage for parsing/dispersal
|
||||
*
|
||||
*/
|
||||
private class I2PListener implements I2PSessionListener {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#disconnected(net.i2p.client.I2PSession)
|
||||
*/
|
||||
public void disconnected(I2PSession session) {
|
||||
if (_log.shouldLog(Log.ERROR)) {
|
||||
_log.error("Session disconnected");
|
||||
}
|
||||
disconnect();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#errorOccurred(net.i2p.client.I2PSession, java.lang.String, java.lang.Throwable)
|
||||
*/
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Error occurred: " + message, error);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#reportAbuse(net.i2p.client.I2PSession, int)
|
||||
*/
|
||||
public void reportAbuse(I2PSession session, int severity) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Abuse reported with severity " + String.valueOf(severity));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.client.I2PSessionListener#messageAvailable(net.i2p.client.I2PSession, int, long)
|
||||
*/
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
try {
|
||||
byte data[] = session.receiveMessage(msgId);
|
||||
handleMessage(data);
|
||||
} catch (I2PSessionException ise) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Error receiving the message", ise);
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
412
apps/heartbeat/java/src/net/i2p/heartbeat/PeerData.java
Normal file
412
apps/heartbeat/java/src/net/i2p/heartbeat/PeerData.java
Normal file
@@ -0,0 +1,412 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.stat.Rate;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Contain the current window of data for a particular series of ping/pong stats
|
||||
* sent to a peer. This should be periodically kept clean by calling cleanup()
|
||||
* to timeout expired pings and to drop data outside the window.
|
||||
*
|
||||
*/
|
||||
public class PeerData {
|
||||
private final static Log _log = new Log(PeerData.class);
|
||||
/** peer / sequence / config in this data series */
|
||||
private ClientConfig _peer;
|
||||
/** date sent (Long) to EventDataPoint containing the datapoints sent in the current period */
|
||||
private Map _dataPoints;
|
||||
/** date sent (Long) to EventDataPoint containing pings that haven't yet timed out or been ponged */
|
||||
private TreeMap _pendingPings;
|
||||
private long _sessionStart;
|
||||
private long _lifetimeSent;
|
||||
private long _lifetimeReceived;
|
||||
/** rate averaging the time to send over a variety of periods */
|
||||
private RateStat _sendRate;
|
||||
/** rate averaging the time to receive over a variety of periods */
|
||||
private RateStat _receiveRate;
|
||||
/** rate averaging the frequency of lost messages over a variety of periods */
|
||||
private RateStat _lostRate;
|
||||
|
||||
/** how long we wait before timing out pending pings (30 seconds) */
|
||||
private static final long TIMEOUT_PERIOD = 60 * 1000;
|
||||
|
||||
/** synchronize on this when updating _dataPoints or _pendingPings */
|
||||
private Object _updateLock = new Object();
|
||||
|
||||
/**
|
||||
* Creates a PeerData . . .
|
||||
* @param config configuration to load from
|
||||
*/
|
||||
public PeerData(ClientConfig config) {
|
||||
_peer = config;
|
||||
_dataPoints = new TreeMap();
|
||||
_pendingPings = new TreeMap();
|
||||
_sessionStart = Clock.getInstance().now();
|
||||
_lifetimeSent = 0;
|
||||
_lifetimeReceived = 0;
|
||||
_sendRate = new RateStat("sendRate", "How long it takes to send", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
_receiveRate = new RateStat("receiveRate", "How long it takes to receive", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
_lostRate = new RateStat("lostRate", "How frequently we lose messages", "peer",
|
||||
getPeriods(config.getAveragePeriods()));
|
||||
}
|
||||
|
||||
/**
|
||||
* turn the periods (# minutes) into rate periods (# milliseconds)
|
||||
* @param periods (in minutes)
|
||||
* @return an array of periods (in milliseconds)
|
||||
*/
|
||||
private static long[] getPeriods(int periods[]) {
|
||||
long rv[] = null;
|
||||
if (periods == null) periods = new int[0];
|
||||
rv = new long[periods.length];
|
||||
for (int i = 0; i < periods.length; i++)
|
||||
rv[i] = (long) periods[i] * 60 * 1000; // they're in minutes
|
||||
Arrays.sort(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many pings are still outstanding?
|
||||
* @return the number of pings outstanding
|
||||
*/
|
||||
public int getPendingCount() {
|
||||
synchronized (_updateLock) {
|
||||
return _pendingPings.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* how many data points are available in the current window?
|
||||
* @return the number of datapoints available
|
||||
*/
|
||||
public int getDataPointCount() {
|
||||
synchronized (_updateLock) {
|
||||
return _dataPoints.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* when did this test begin?
|
||||
* @return when the test began
|
||||
*/
|
||||
public long getSessionStart() { return _sessionStart; }
|
||||
|
||||
/**
|
||||
* sets when the test began
|
||||
* @param when when it began
|
||||
*/
|
||||
public void setSessionStart(long when) { _sessionStart = when; }
|
||||
|
||||
/**
|
||||
* how many pings have we sent for this test?
|
||||
* @return the number of pings sent
|
||||
*/
|
||||
public long getLifetimeSent() { return _lifetimeSent; }
|
||||
|
||||
/**
|
||||
* how many pongs have we received for this test?
|
||||
* @return the number of pings received
|
||||
*/
|
||||
public long getLifetimeReceived() { return _lifetimeReceived; }
|
||||
|
||||
/**
|
||||
* @return the client configuration
|
||||
*/
|
||||
public ClientConfig getConfig() {
|
||||
return _peer;
|
||||
}
|
||||
|
||||
/**
|
||||
* What periods are we averaging the data over (in minutes)?
|
||||
* @return the periods as an array of ints (in minutes)
|
||||
*/
|
||||
public int[] getAveragePeriods() {
|
||||
return (_peer.getAveragePeriods() != null ? _peer.getAveragePeriods() : new int[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* average time to send over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageSendTime(int period) {
|
||||
return getAverage(_sendRate, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* average time to receive over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageReceiveTime(int period) {
|
||||
return getAverage(_receiveRate, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* number of lost messages over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||
*/
|
||||
public double getLostMessages(int period) {
|
||||
Rate rate = _lostRate.getRate(period * 60 * 1000);
|
||||
if (rate == null) return -1;
|
||||
return rate.getCurrentTotalValue();
|
||||
}
|
||||
|
||||
private double getAverage(RateStat stat, int period) {
|
||||
Rate rate = stat.getRate(period * 60 * 1000);
|
||||
if (rate == null) return -1;
|
||||
return rate.getAverageValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ordered list of data points in the current window (after doing a cleanup)
|
||||
*
|
||||
* @return list of EventDataPoint objects
|
||||
*/
|
||||
public List getDataPoints() {
|
||||
cleanup();
|
||||
synchronized (_updateLock) {
|
||||
return new ArrayList(_dataPoints.values());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We have sent the peer a ping on this series (using the send time as given)
|
||||
* @param dateSent when the ping was sent
|
||||
*/
|
||||
public void addPing(long dateSent) {
|
||||
EventDataPoint sent = new EventDataPoint(dateSent);
|
||||
synchronized (_updateLock) {
|
||||
_pendingPings.put(new Long(dateSent), sent);
|
||||
}
|
||||
_lifetimeSent++;
|
||||
}
|
||||
|
||||
/**
|
||||
* we have received a pong from the peer on this series
|
||||
*
|
||||
* @param dateSent when we sent the ping
|
||||
* @param pongSent when the peer received the ping and sent the pong
|
||||
*/
|
||||
public void pongReceived(long dateSent, long pongSent) {
|
||||
long now = Clock.getInstance().now();
|
||||
synchronized (_updateLock) {
|
||||
if (_pendingPings.size() <= 0) {
|
||||
_log.warn("Pong received (sent at " + dateSent + ", " + (now-dateSent)
|
||||
+ "ms ago, pong delay " + (pongSent-dateSent) + "ms, pong receive delay "
|
||||
+ (now-pongSent) + "ms)");
|
||||
return;
|
||||
}
|
||||
Long first = (Long)_pendingPings.firstKey();
|
||||
EventDataPoint data = (EventDataPoint)_pendingPings.remove(new Long(dateSent));
|
||||
|
||||
if (data != null) {
|
||||
data.setPongReceived(now);
|
||||
data.setPongSent(pongSent);
|
||||
data.setWasPonged(true);
|
||||
locked_addDataPoint(data);
|
||||
|
||||
if (dateSent != first.longValue()) {
|
||||
_log.error("Out of order delivery: received " + dateSent
|
||||
+ " but the first pending is " + first.longValue()
|
||||
+ " (delta " + (dateSent - first.longValue()) + ")");
|
||||
} else {
|
||||
_log.info("In order delivery for " + dateSent + " in ping "
|
||||
+ _peer.getComment());
|
||||
}
|
||||
} else {
|
||||
_log.warn("Pong received, but no matching ping? ping sent at = " + dateSent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_sendRate.addData(pongSent - dateSent, 0);
|
||||
_receiveRate.addData(now - pongSent, 0);
|
||||
_lifetimeReceived++;
|
||||
}
|
||||
|
||||
protected void addDataPoint(EventDataPoint data) {
|
||||
synchronized (_updateLock) {
|
||||
locked_addDataPoint(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void locked_addDataPoint(EventDataPoint data) {
|
||||
Object val = _dataPoints.put(new Long(data.getPingSent()), data);
|
||||
if (val != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Duplicate data point received: " + data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drop all datapoints outside the window we're watching, and timeout all
|
||||
* pending pings not ponged in the TIMEOUT_PERIOD, both updating the lost message
|
||||
* rate and coallescing all of the rates.
|
||||
*
|
||||
*/
|
||||
public void cleanup() {
|
||||
long dropBefore = Clock.getInstance().now() - _peer.getStatDuration() * 60 * 1000;
|
||||
long timeoutBefore = Clock.getInstance().now() - TIMEOUT_PERIOD;
|
||||
long numDropped = 0;
|
||||
long numTimedOut = 0;
|
||||
|
||||
synchronized (_updateLock) {
|
||||
numDropped = locked_dropExpired(dropBefore);
|
||||
numTimedOut = locked_timeoutPending(timeoutBefore);
|
||||
}
|
||||
|
||||
_lostRate.addData(numTimedOut, 0);
|
||||
|
||||
_receiveRate.coallesceStats();
|
||||
_sendRate.coallesceStats();
|
||||
_lostRate.coallesceStats();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peer data cleaned up " + numTimedOut + " timed out pings and removed " + numDropped
|
||||
+ " old entries");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all data points that are already too old for us to be interested in
|
||||
*
|
||||
* @param when the earliest ping send time we care about
|
||||
* @return number of data points dropped
|
||||
*/
|
||||
private int locked_dropExpired(long when) {
|
||||
Set toDrop = new HashSet(4);
|
||||
// drop the failed and really old
|
||||
for (Iterator iter = _dataPoints.keySet().iterator(); iter.hasNext(); ) {
|
||||
Long pingTime = (Long)iter.next();
|
||||
if (pingTime.longValue() < when)
|
||||
toDrop.add(pingTime);
|
||||
}
|
||||
for (Iterator iter = toDrop.iterator(); iter.hasNext(); ) {
|
||||
_dataPoints.remove(iter.next());
|
||||
}
|
||||
return toDrop.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* timeout and remove all pings that were sent before the given time,
|
||||
* moving them from the set of pending pings to the set of data points
|
||||
*
|
||||
* @param when the earliest ping send time we care about
|
||||
* @return number of pings timed out
|
||||
*/
|
||||
private int locked_timeoutPending(long when) {
|
||||
Set toDrop = new HashSet(4);
|
||||
for (Iterator iter = _pendingPings.keySet().iterator(); iter.hasNext(); ) {
|
||||
Long pingTime = (Long)iter.next();
|
||||
if (pingTime.longValue() < when) {
|
||||
toDrop.add(pingTime);
|
||||
EventDataPoint point = (EventDataPoint)_pendingPings.get(pingTime);
|
||||
point.setWasPonged(false);
|
||||
locked_addDataPoint(point);
|
||||
}
|
||||
}
|
||||
for (Iterator iter = toDrop.iterator(); iter.hasNext(); ) {
|
||||
_pendingPings.remove(iter.next());
|
||||
}
|
||||
return toDrop.size();
|
||||
}
|
||||
|
||||
/** actual data point for the peer */
|
||||
public class EventDataPoint {
|
||||
private boolean _wasPonged;
|
||||
private long _pingSent;
|
||||
private long _pongSent;
|
||||
private long _pongReceived;
|
||||
|
||||
/**
|
||||
* Creates an EventDataPoint
|
||||
*/
|
||||
public EventDataPoint() { this(-1); }
|
||||
|
||||
/**
|
||||
* Creates an EventDataPoint with pingtime associated with it =)
|
||||
* @param pingSentOn the time a ping was sent
|
||||
*/
|
||||
public EventDataPoint(long pingSentOn) {
|
||||
_wasPonged = false;
|
||||
_pingSent = pingSentOn;
|
||||
_pongSent = -1;
|
||||
_pongReceived = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we send this ping?
|
||||
* @return the time the ping was sent
|
||||
*/
|
||||
public long getPingSent() { return _pingSent; }
|
||||
|
||||
/**
|
||||
* sets when we sent this ping
|
||||
* @param when when we sent the ping
|
||||
*/
|
||||
public void setPingSent(long when) { _pingSent = when; }
|
||||
|
||||
/**
|
||||
* when did the peer receive the ping?
|
||||
* @return the time the ping was receieved
|
||||
*/
|
||||
public long getPongSent() {
|
||||
return _pongSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time the peer received the ping
|
||||
* @param when the time to set
|
||||
*/
|
||||
public void setPongSent(long when) {
|
||||
_pongSent = when;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we receive the peer's pong?
|
||||
* @return the time we receieved the pong
|
||||
*/
|
||||
public long getPongReceived() {
|
||||
return _pongReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time the peer's pong was receieved
|
||||
* @param when the time to set
|
||||
*/
|
||||
public void setPongReceived(long when) {
|
||||
_pongReceived = when;
|
||||
}
|
||||
|
||||
/**
|
||||
* did the peer reply in time?
|
||||
* @return true or false, whether we got a reply in time */
|
||||
public boolean getWasPonged() {
|
||||
return _wasPonged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we receieved the peer's reply in time
|
||||
* @param pong true or false
|
||||
*/
|
||||
public void setWasPonged(boolean pong) {
|
||||
_wasPonged = pong;
|
||||
}
|
||||
}
|
||||
}
|
||||
142
apps/heartbeat/java/src/net/i2p/heartbeat/PeerDataWriter.java
Normal file
142
apps/heartbeat/java/src/net/i2p/heartbeat/PeerDataWriter.java
Normal file
@@ -0,0 +1,142 @@
|
||||
package net.i2p.heartbeat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Actually write out the stats for peer test
|
||||
*
|
||||
*/
|
||||
public class PeerDataWriter {
|
||||
private final static Log _log = new Log(PeerDataWriter.class);
|
||||
|
||||
/**
|
||||
* persist the peer state to the location specified in the peer config
|
||||
*
|
||||
* @param data the peer data to persist
|
||||
* @return true if it was persisted correctly, false on error
|
||||
*/
|
||||
public boolean persist(PeerData data) {
|
||||
String filename = data.getConfig().getStatFile();
|
||||
File statFile = new File(filename);
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(statFile);
|
||||
persist(data, fos);
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error persisting the peer data for "
|
||||
+ data.getConfig().getPeer().calculateHash().toBase64(), ioe);
|
||||
return false;
|
||||
} finally {
|
||||
if (fos != null) try {
|
||||
fos.close();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* persists the peer state to the output stream
|
||||
* @param data the peer data to persist
|
||||
* @param out where to persist the data
|
||||
* @return true if it was persisted correctly [always (as implemented)], false on error
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean persist(PeerData data, OutputStream out) throws IOException {
|
||||
String header = getHeader(data);
|
||||
|
||||
out.write(header.getBytes());
|
||||
out.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\troundTrip\n".getBytes());
|
||||
for (Iterator iter = data.getDataPoints().iterator(); iter.hasNext();) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint) iter.next();
|
||||
String line = getEvent(point);
|
||||
out.write(line.getBytes());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getHeader(PeerData data) {
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
buf.append("peer \t").append(data.getConfig().getPeer().calculateHash().toBase64()).append('\n');
|
||||
buf.append("local \t").append(data.getConfig().getUs().calculateHash().toBase64()).append('\n');
|
||||
buf.append("peerDest \t").append(data.getConfig().getPeer().toBase64()).append('\n');
|
||||
buf.append("localDest \t").append(data.getConfig().getUs().toBase64()).append('\n');
|
||||
buf.append("numTunnelHops\t").append(data.getConfig().getNumHops()).append('\n');
|
||||
buf.append("comment \t").append(data.getConfig().getComment()).append('\n');
|
||||
buf.append("sendFrequency\t").append(data.getConfig().getSendFrequency()).append('\n');
|
||||
buf.append("sendSize \t").append(data.getConfig().getSendSize()).append('\n');
|
||||
buf.append("sessionStart \t").append(getTime(data.getSessionStart())).append('\n');
|
||||
buf.append("currentTime \t").append(getTime(Clock.getInstance().now())).append('\n');
|
||||
buf.append("numPending \t").append(data.getPendingCount()).append('\n');
|
||||
buf.append("lifetimeSent \t").append(data.getLifetimeSent()).append('\n');
|
||||
buf.append("lifetimeRecv \t").append(data.getLifetimeReceived()).append('\n');
|
||||
int periods[] = data.getAveragePeriods();
|
||||
buf.append("#averages\tminutes\tsendMs\trecvMs\tnumLost\troundTrip\n");
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
buf.append("periodAverage\t").append(periods[i]).append('\t');
|
||||
buf.append(getNum(data.getAverageSendTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getAverageReceiveTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getLostMessages(periods[i]))).append('\t');
|
||||
double rtt = data.getAverageSendTime(periods[i])
|
||||
+ data.getAverageReceiveTime(periods[i]);
|
||||
buf.append(getNum(rtt)).append('\n');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getEvent(PeerData.EventDataPoint point) {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
buf.append("EVENT\t");
|
||||
if (point.getWasPonged())
|
||||
buf.append("OK\t");
|
||||
else
|
||||
buf.append("LOST\t");
|
||||
buf.append(getTime(point.getPingSent())).append('\t');
|
||||
if (point.getWasPonged()) {
|
||||
buf.append(point.getPongSent() - point.getPingSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPongSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPingSent()).append('\t');
|
||||
}
|
||||
buf.append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private final SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd.HH:mm:ss.SSS", Locale.UK);
|
||||
|
||||
/**
|
||||
* Converts a time (long) to text
|
||||
* @param when the time to convert
|
||||
* @return the textual representation
|
||||
*/
|
||||
public String getTime(long when) {
|
||||
synchronized (_fmt) {
|
||||
return _fmt.format(new Date(when));
|
||||
}
|
||||
}
|
||||
|
||||
private final DecimalFormat _numFmt = new DecimalFormat("#0", new DecimalFormatSymbols(Locale.UK));
|
||||
|
||||
/**
|
||||
* Converts a number (double) to text
|
||||
* @param val the number to convert
|
||||
* @return the textual representation
|
||||
*/
|
||||
public String getNum(double val) {
|
||||
synchronized (_numFmt) {
|
||||
return _numFmt.format(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the control widgets (refresh/load/snapshot and the
|
||||
* tabbed panel with the plot config data)
|
||||
*
|
||||
*/
|
||||
class HeartbeatControlPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatControlPane.class);
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JTabbedPane _configPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private final static Color LIGHT_BLUE = new Color(180, 180, 255); /* UNUSED */
|
||||
private final static Color BLACK = new Color(0, 0, 0);
|
||||
private Color _background = WHITE;
|
||||
private Color _foreground = BLACK;
|
||||
|
||||
/**
|
||||
* Constructs a control panel onto the gui
|
||||
* @param gui the gui the panel is associated with
|
||||
*/
|
||||
public HeartbeatControlPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a test to the panel
|
||||
* @param config the configuration for the test
|
||||
*/
|
||||
public void addTest(PeerPlotConfig config) {
|
||||
_configPane.addTab(config.getTitle(), null, new JScrollPane(new PeerPlotConfigPane(config, this)), config.getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
_gui.pack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a test from the panel
|
||||
* @param config the configuration for the test
|
||||
*/
|
||||
public void removeTest(PeerPlotConfig config) {
|
||||
_gui.getMonitor().getState().removeTest(config);
|
||||
int index = _configPane.indexOfTab(config.getTitle());
|
||||
if (index >= 0)
|
||||
_configPane.removeTabAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when tests have changed
|
||||
*/
|
||||
public void testsUpdated() {
|
||||
List knownNames = new ArrayList(8);
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
PeerPlotState state = _gui.getMonitor().getState().getTest(i);
|
||||
String title = state.getPlotConfig().getTitle();
|
||||
knownNames.add(state.getPlotConfig().getTitle());
|
||||
if (_configPane.indexOfTab(title) >= 0) {
|
||||
_log.debug("We already know about [" + title + "]");
|
||||
} else {
|
||||
_log.info("The test [" + title + "] is new to us");
|
||||
PeerPlotConfigPane pane = new PeerPlotConfigPane(state.getPlotConfig(), this);
|
||||
_configPane.addTab(state.getPlotConfig().getTitle(), null, new JScrollPane(pane), state.getPlotConfig().getSummary());
|
||||
_configPane.setBackgroundAt(_configPane.getTabCount()-1, _background);
|
||||
_configPane.setForegroundAt(_configPane.getTabCount()-1, _foreground);
|
||||
}
|
||||
}
|
||||
List toRemove = new ArrayList(4);
|
||||
for (int i = 0; i < _configPane.getTabCount(); i++) {
|
||||
if (knownNames.contains(_configPane.getTitleAt(i))) {
|
||||
// noop
|
||||
} else {
|
||||
toRemove.add(_configPane.getTitleAt(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < toRemove.size(); i++) {
|
||||
String title = (String)toRemove.get(i);
|
||||
_log.info("Removing test [" + title + "]");
|
||||
_configPane.removeTabAt(_configPane.indexOfTab(title));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
if (_gui != null)
|
||||
setBackground(_gui.getBackground());
|
||||
else
|
||||
setBackground(_background);
|
||||
setLayout(new BorderLayout());
|
||||
HeartbeatMonitorCommandBar bar = new HeartbeatMonitorCommandBar(_gui);
|
||||
bar.setBackground(getBackground());
|
||||
add(bar, BorderLayout.NORTH);
|
||||
_configPane = new JTabbedPane(JTabbedPane.LEFT);
|
||||
_configPane.setBackground(_background);
|
||||
//add(_configPane, BorderLayout.CENTER);
|
||||
add(_configPane, BorderLayout.SOUTH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* The HeartbeatMonitor, complete with main()! Act now, and it's only 5 easy
|
||||
* payments of $19.95 (plus shipping and handling)! You heard me, only _5_
|
||||
* easy payments of $19.95 (plus shipping and handling)! <p />
|
||||
*
|
||||
* (fine print: something about some states in the US requiring the addition
|
||||
* of sales tax... or something) <p />
|
||||
*
|
||||
* (finer print: Satan owns you. Deal with it.) <p />
|
||||
*
|
||||
* (even finer print: usage: <code>HeartbeatMonitor [configFilename]</code>)
|
||||
*/
|
||||
public class HeartbeatMonitor implements PeerPlotStateFetcher.FetchStateReceptor, PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(HeartbeatMonitor.class);
|
||||
private HeartbeatMonitorState _state;
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
|
||||
/**
|
||||
* Delegating constructor.
|
||||
* @see HeartbeatMonitor#HeartbeatMonitor(String)
|
||||
*/
|
||||
public HeartbeatMonitor() { this(null); }
|
||||
|
||||
/**
|
||||
* Creates a HeartbeatMonitor . . .
|
||||
* @param configFilename the configuration file to read from
|
||||
*/
|
||||
public HeartbeatMonitor(String configFilename) {
|
||||
_state = new HeartbeatMonitorState(configFilename);
|
||||
_gui = new HeartbeatMonitorGUI(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the game rollin'
|
||||
*/
|
||||
public void runMonitor() {
|
||||
loadConfig();
|
||||
I2PThread t = new I2PThread(new HeartbeatMonitorRunner(this));
|
||||
t.setName("HeartbeatMonitor");
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
_log.debug("Monitor started");
|
||||
}
|
||||
|
||||
/**
|
||||
* give us all the data/config available
|
||||
* @return the current state (data/config)
|
||||
*/
|
||||
HeartbeatMonitorState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/** for all of the peer tests being monitored, refetch the data and rerender */
|
||||
void refetchData() {
|
||||
_log.debug("Refetching data");
|
||||
for (int i = 0; i < _state.getTestCount(); i++)
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, _state.getTest(i));
|
||||
}
|
||||
|
||||
/** (re)load the config defining what peer tests we are monitoring (and how to render) */
|
||||
void loadConfig() {
|
||||
//for (int i = 0; i < 10; i++) {
|
||||
// load("fake" + i);
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads config data
|
||||
* @param location the name of the location to load data from
|
||||
*/
|
||||
public void load(String location) {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig(location);
|
||||
cfg.addListener(this);
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see PeerPlotStateFetcher.FetchStateReceptor#peerPlotStateFetched
|
||||
*/
|
||||
public synchronized void peerPlotStateFetched(PeerPlotState state) {
|
||||
_state.addTest(state);
|
||||
_gui.stateUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* store the config defining what peer tests we are monitoring (and how to render)
|
||||
*/
|
||||
void storeConfig() {}
|
||||
|
||||
/**
|
||||
* And now, the main function, the one you've all been waiting for! . . .
|
||||
* @param args da args. Should take 1, which is the location to load config data from
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
Thread.currentThread().setName("HeartbeatMonitor.main");
|
||||
if (args.length == 1)
|
||||
new HeartbeatMonitor(args[0]).runMonitor();
|
||||
else
|
||||
new HeartbeatMonitor().runMonitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the config is updated
|
||||
* @param config the updated config
|
||||
*/
|
||||
public void configUpdated(PeerPlotConfig config) {
|
||||
_log.debug("Config updated, revamping the gui");
|
||||
_gui.stateUpdated();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
class HeartbeatMonitorCommandBar extends JPanel {
|
||||
private HeartbeatMonitorGUI _gui;
|
||||
private JComboBox _refreshRate;
|
||||
private JTextField _location;
|
||||
|
||||
/**
|
||||
* Constructs a command bar onto the gui
|
||||
* @param gui the gui the command bar is associated with
|
||||
*/
|
||||
public HeartbeatMonitorCommandBar(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
private void refreshChanged(ItemEvent evt) {}
|
||||
private void loadCalled() {
|
||||
_gui.getMonitor().load(_location.getText());
|
||||
}
|
||||
|
||||
private void browseCalled() {
|
||||
JFileChooser chooser = new JFileChooser(_location.getText());
|
||||
chooser.setBackground(_gui.getBackground());
|
||||
chooser.setMultiSelectionEnabled(false);
|
||||
int rv = chooser.showDialog(this, "Load");
|
||||
if (rv == JFileChooser.APPROVE_OPTION)
|
||||
_gui.getMonitor().load(chooser.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
_refreshRate = new JComboBox(new DefaultComboBoxModel(new Object[] {"10 second refresh", "30 second refresh", "1 minute refresh", "5 minute refresh"}));
|
||||
_refreshRate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { refreshChanged(evt); } });
|
||||
_refreshRate.setEnabled(false);
|
||||
_refreshRate.setBackground(_gui.getBackground());
|
||||
//add(_refreshRate);
|
||||
JLabel loadLabel = new JLabel("Load from: ");
|
||||
loadLabel.setBackground(_gui.getBackground());
|
||||
add(loadLabel);
|
||||
_location = new JTextField(20);
|
||||
_location.setToolTipText("Either specify a local filename or a fully qualified URL");
|
||||
_location.setBackground(_gui.getBackground());
|
||||
add(_location);
|
||||
JButton browse = new JButton("Browse...");
|
||||
browse.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { browseCalled(); } });
|
||||
browse.setBackground(_gui.getBackground());
|
||||
add(browse);
|
||||
JButton load = new JButton("Load");
|
||||
load.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadCalled(); } });
|
||||
load.setBackground(_gui.getBackground());
|
||||
add(load);
|
||||
setBackground(_gui.getBackground());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
class HeartbeatMonitorGUI extends JFrame {
|
||||
private HeartbeatMonitor _monitor;
|
||||
private HeartbeatPlotPane _plotPane;
|
||||
private HeartbeatControlPane _controlPane;
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
/**
|
||||
* Creates the GUI for all youz who be too shoopid for text based shitz
|
||||
* @param monitor the monitor the gui operates over
|
||||
*/
|
||||
public HeartbeatMonitorGUI(HeartbeatMonitor monitor) {
|
||||
super("Heartbeat Monitor");
|
||||
_monitor = monitor;
|
||||
initializeComponents();
|
||||
pack();
|
||||
//setResizable(false);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
HeartbeatMonitor getMonitor() { return _monitor; }
|
||||
|
||||
/** build up all our widgets */
|
||||
private void initializeComponents() {
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
setBackground(_background);
|
||||
|
||||
_plotPane = new JFreeChartHeartbeatPlotPane(this); // new HeartbeatPlotPane(this);
|
||||
_plotPane.setBackground(_background);
|
||||
//JScrollPane pane = new JScrollPane(_plotPane);
|
||||
//pane.setBackground(_background);
|
||||
getContentPane().add(new JScrollPane(_plotPane), BorderLayout.CENTER);
|
||||
|
||||
_controlPane = new HeartbeatControlPane(this);
|
||||
_controlPane.setBackground(_background);
|
||||
getContentPane().add(_controlPane, BorderLayout.SOUTH);
|
||||
|
||||
//JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(_plotPane), new JScrollPane(_controlPane));
|
||||
//getContentPane().add(pane, BorderLayout.CENTER);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
initializeMenus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when the state of the world changes . . .
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
_controlPane.testsUpdated();
|
||||
_plotPane.stateUpdated();
|
||||
}
|
||||
|
||||
private void exitCalled() {
|
||||
_monitor.getState().setWasKilled(true);
|
||||
setVisible(false);
|
||||
System.exit(0);
|
||||
}
|
||||
private void loadConfigCalled() {}
|
||||
private void saveConfigCalled() {}
|
||||
private void loadSnapshotCalled() {}
|
||||
private void saveSnapshotCalled() {}
|
||||
|
||||
private void initializeMenus() {
|
||||
JMenuBar bar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
JMenuItem loadConfig = new JMenuItem("Load config");
|
||||
loadConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadConfigCalled(); } });
|
||||
JMenuItem saveConfig = new JMenuItem("Save config");
|
||||
saveConfig.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveConfigCalled(); } });
|
||||
JMenuItem saveSnapshot = new JMenuItem("Save snapshot");
|
||||
saveSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { saveSnapshotCalled(); } });
|
||||
JMenuItem loadSnapshot = new JMenuItem("Load snapshot");
|
||||
loadSnapshot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { loadSnapshotCalled(); } });
|
||||
JMenuItem exit = new JMenuItem("Exit");
|
||||
exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { exitCalled(); } });
|
||||
|
||||
fileMenu.add(loadConfig);
|
||||
fileMenu.add(saveConfig);
|
||||
fileMenu.add(loadSnapshot);
|
||||
fileMenu.add(saveSnapshot);
|
||||
fileMenu.add(exit);
|
||||
bar.add(fileMenu);
|
||||
setJMenuBar(bar);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Periodically fire off necessary events (instructing the heartbeat monitor when
|
||||
* to refetch the data, etc). This is the only active thread in the heartbeat
|
||||
* monitor (outside the swing/jvm threads)
|
||||
*/
|
||||
class HeartbeatMonitorRunner implements Runnable {
|
||||
private final static Log _log = new Log(HeartbeatMonitorRunner.class);
|
||||
private HeartbeatMonitor _monitor;
|
||||
|
||||
/**
|
||||
* Creates the thread . . .
|
||||
* @param monitor the monitor the thread runs over
|
||||
*/
|
||||
public HeartbeatMonitorRunner(HeartbeatMonitor monitor) {
|
||||
_monitor = monitor;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
while (!_monitor.getState().getWasKilled()) {
|
||||
_monitor.refetchData();
|
||||
try { Thread.sleep(_monitor.getState().getRefreshRateMs()); } catch (InterruptedException ie) {}
|
||||
}
|
||||
_log.info("Stopping the heartbeat monitor runner");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* manage the current state of the GUI - all data points, as well as any
|
||||
* rendering or configuration options.
|
||||
*/
|
||||
class HeartbeatMonitorState {
|
||||
private String _configFile;
|
||||
private List _peerPlotState;
|
||||
private int _currentPeerPlotConfig;
|
||||
private int _refreshRateMs;
|
||||
private boolean _killed;
|
||||
|
||||
/** by default, refresh every 30 seconds */
|
||||
private final static int DEFAULT_REFRESH_RATE = 30*1000;
|
||||
/** where do we load/store config info from? */
|
||||
private final static String DEFAULT_CONFIG_FILE = "heartbeatMonitor.config";
|
||||
|
||||
/**
|
||||
* A delegating constructor.
|
||||
* @see HeartbeatMonitorState#HeartbeatMonitorState(String)
|
||||
*/
|
||||
public HeartbeatMonitorState() { this(DEFAULT_CONFIG_FILE); }
|
||||
|
||||
/**
|
||||
* Constructs the state, loading from the specified location
|
||||
* @param configFile the name of the file to load info from
|
||||
*/
|
||||
public HeartbeatMonitorState(String configFile) {
|
||||
_peerPlotState = Collections.synchronizedList(new ArrayList());
|
||||
_refreshRateMs = DEFAULT_REFRESH_RATE;
|
||||
_configFile = configFile;
|
||||
_killed = false;
|
||||
_currentPeerPlotConfig = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* how many tests are we monitoring?
|
||||
* @return the number of tests
|
||||
*/
|
||||
public int getTestCount() { return _peerPlotState.size(); }
|
||||
|
||||
/**
|
||||
* Retrieves the current info of a test for a certain peer . . .
|
||||
* @param peer a number associated with a certain peer
|
||||
* @return the test data
|
||||
*/
|
||||
public PeerPlotState getTest(int peer) { return (PeerPlotState)_peerPlotState.get(peer); }
|
||||
|
||||
/**
|
||||
* Adds a test . . .
|
||||
* @param peerState the test (by state) to add . . .
|
||||
*/
|
||||
public void addTest(PeerPlotState peerState) {
|
||||
if (!_peerPlotState.contains(peerState))
|
||||
_peerPlotState.add(peerState);
|
||||
}
|
||||
/**
|
||||
* Removes a test . . .
|
||||
* @param peerState the test (by state) to remove . . .
|
||||
*/
|
||||
public void removeTest(PeerPlotState peerState) { _peerPlotState.remove(peerState); }
|
||||
|
||||
/**
|
||||
* Removes a test . . .
|
||||
* @param peerConfig the test (by config) to remove . . .
|
||||
*/
|
||||
public void removeTest(PeerPlotConfig peerConfig) {
|
||||
for (int i = 0; i < getTestCount(); i++) {
|
||||
PeerPlotState state = getTest(i);
|
||||
if (state.getPlotConfig() == peerConfig) {
|
||||
removeTest(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* which of the tests are we currently editing/viewing?
|
||||
* @return the number associated with the test
|
||||
*/
|
||||
public int getPeerPlotConfig() { return _currentPeerPlotConfig; }
|
||||
|
||||
/**
|
||||
* Sets the test we are currently editting/viewing
|
||||
* @param whichTest the number associated with the test
|
||||
*/
|
||||
public void setPeerPlotConfig(int whichTest) { _currentPeerPlotConfig = whichTest; }
|
||||
|
||||
/**
|
||||
* how frequently should we update the data?
|
||||
* @return the current frequency (in milliseconds)
|
||||
*/
|
||||
public int getRefreshRateMs() { return _refreshRateMs; }
|
||||
|
||||
/**
|
||||
* Sets how frequently we should update data
|
||||
* @param ms the frequency (in milliseconds)
|
||||
*/
|
||||
public void setRefreshRateMs(int ms) { _refreshRateMs = ms; }
|
||||
|
||||
/**
|
||||
* where is our config stored?
|
||||
* @return the name of the config file
|
||||
*/
|
||||
public String getConfigFile() { return _configFile; }
|
||||
|
||||
/**
|
||||
* Sets where our config is stored
|
||||
* @param filename the name of the config file
|
||||
*/
|
||||
public void setConfigFile(String filename) { _configFile = filename; }
|
||||
|
||||
/**
|
||||
* have we been shut down?
|
||||
* @return true if we have, false otherwise
|
||||
*/
|
||||
public boolean getWasKilled() { return _killed; }
|
||||
|
||||
/**
|
||||
* Sets if we have been shutdown or not
|
||||
* @param killed true if we've been shutdown, false otherwise
|
||||
*/
|
||||
public void setWasKilled(boolean killed) { _killed = killed; }
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
import net.i2p.heartbeat.PeerDataWriter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*/
|
||||
class HeartbeatPlotPane extends JPanel {
|
||||
private final static Log _log = new Log(HeartbeatPlotPane.class);
|
||||
protected HeartbeatMonitorGUI _gui;
|
||||
private JTextArea _text;
|
||||
|
||||
/**
|
||||
* Constructs the plot pane
|
||||
* @param gui the gui the pane is attached to
|
||||
*/
|
||||
public HeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||
_gui = gui;
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback: when things change . . .
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
StringBuffer buf = new StringBuffer(32*1024);
|
||||
PeerDataWriter writer = new PeerDataWriter();
|
||||
|
||||
for (int i = 0; i < _gui.getMonitor().getState().getTestCount(); i++) {
|
||||
StaticPeerData data = _gui.getMonitor().getState().getTest(i).getCurrentData();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
|
||||
try {
|
||||
writer.persist(data, baos);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("wtf, error writing to a byte array?", ioe);
|
||||
}
|
||||
buf.append(new String(baos.toByteArray())).append("\n\n\n");
|
||||
}
|
||||
|
||||
_text.setText(buf.toString());
|
||||
}
|
||||
|
||||
protected void initializeComponents() {
|
||||
setBackground(_gui.getBackground());
|
||||
//Dimension size = new Dimension(800, 600);
|
||||
_text = new JTextArea("",30,80); // 16, 60);
|
||||
_text.setAutoscrolls(true);
|
||||
_text.setEditable(false);
|
||||
// _text.setLineWrap(true);
|
||||
// add(new JScrollPane(_text));
|
||||
add(_text);
|
||||
// add(new JScrollPane(_text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
|
||||
// setPreferredSize(size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class JFreeChartAdapter {
|
||||
private final static Log _log = new Log(JFreeChartAdapter.class); /* UNUSED */
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
|
||||
ChartPanel createPanel(HeartbeatMonitorState state) {
|
||||
ChartPanel panel = new ChartPanel(createChart(state));
|
||||
panel.setDisplayToolTips(true);
|
||||
panel.setEnforceFileExtensions(true);
|
||||
panel.setHorizontalZoom(true);
|
||||
panel.setVerticalZoom(true);
|
||||
panel.setMouseZoomable(true, true);
|
||||
panel.getChart().setBackgroundPaint(WHITE);
|
||||
return panel;
|
||||
}
|
||||
|
||||
JFreeChart createChart(HeartbeatMonitorState state) {
|
||||
Plot plot = createPlot(state);
|
||||
JFreeChart chart = new JFreeChart("I2P Heartbeat performance", Font.getFont("arial"), plot, true);
|
||||
return chart;
|
||||
}
|
||||
|
||||
void updateChart(ChartPanel panel, HeartbeatMonitorState state) {
|
||||
XYPlot plot = (XYPlot)panel.getChart().getPlot();
|
||||
plot.setDataset(getCollection(state));
|
||||
updateLines(plot, state);
|
||||
}
|
||||
|
||||
private long getFirst(HeartbeatMonitorState state) { /* UNUSED */
|
||||
long first = -1;
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
List dataPoints = state.getTest(i).getCurrentData().getDataPoints();
|
||||
if ( (dataPoints != null) && (dataPoints.size() > 0) ) {
|
||||
PeerData.EventDataPoint data = (PeerData.EventDataPoint)dataPoints.get(0);
|
||||
if ( (first < 0) || (first > data.getPingSent()) )
|
||||
first = data.getPingSent();
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
Plot createPlot(HeartbeatMonitorState state) {
|
||||
XYItemRenderer renderer = new XYLineAndShapeRenderer(); // new XYDotRenderer(); //
|
||||
XYPlot plot = new XYPlot(getCollection(state), new DateAxis(), new NumberAxis("ms"), renderer);
|
||||
updateLines(plot, state);
|
||||
return plot;
|
||||
}
|
||||
|
||||
private void updateLines(XYPlot plot, HeartbeatMonitorState state) {
|
||||
if (true) return;
|
||||
if (state == null) return;
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
PeerPlotConfig config = state.getTest(i).getPlotConfig();
|
||||
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||
XYSeriesCollection col = ((XYSeriesCollection)plot.getDataset());
|
||||
for (int j = 0; j < col.getSeriesCount(); j++) {
|
||||
//XYItemRenderer renderer = plot.getRendererForDataset(col.getSeries(j));
|
||||
XYItemRenderer renderer = plot.getRendererForDataset(col);
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " send")) {
|
||||
if (curConfig.getPlotSendTime()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " receive")) {
|
||||
if (curConfig.getPlotReceiveTime()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
if (col.getSeriesName(j).startsWith(config.getTitle() + " lost")) {
|
||||
if (curConfig.getPlotLostMessages()) {
|
||||
//renderer.setPaint(curConfig.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XYSeriesCollection getCollection(HeartbeatMonitorState state) {
|
||||
XYSeriesCollection col = new XYSeriesCollection();
|
||||
if (state != null) {
|
||||
for (int i = 0; i < state.getTestCount(); i++) {
|
||||
addTest(col, state.getTest(i));
|
||||
}
|
||||
} else {
|
||||
XYSeries series = new XYSeries("latency", false, false);
|
||||
series.add(System.currentTimeMillis(), 0);
|
||||
col.addSeries(series);
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
void addTest(XYSeriesCollection col, PeerPlotState state) {
|
||||
PeerPlotConfig config = state.getPlotConfig();
|
||||
PeerPlotConfig.PlotSeriesConfig curConfig = config.getCurrentSeriesConfig();
|
||||
addLines(col, curConfig, config.getTitle(), state.getCurrentData().getDataPoints());
|
||||
addAverageLines(col, config, config.getTitle(), state.getCurrentData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param col the collection of xy series to add to
|
||||
* @param config preferences for how to display this test
|
||||
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||
*/
|
||||
void addLines(XYSeriesCollection col, PeerPlotConfig.PlotSeriesConfig config, String lineName, List data) {
|
||||
if (config.getPlotSendTime()) {
|
||||
XYSeries sendSeries = getSendSeries(data);
|
||||
sendSeries.setName(lineName + " send");
|
||||
sendSeries.setDescription("milliseconds for the ping to reach the peer");
|
||||
col.addSeries(sendSeries);
|
||||
}
|
||||
if (config.getPlotReceiveTime()) {
|
||||
XYSeries recvSeries = getReceiveSeries(data);
|
||||
recvSeries.setName(lineName + " receive");
|
||||
recvSeries.setDescription("milliseconds for the peer's pong to reach the sender");
|
||||
col.addSeries(recvSeries);
|
||||
}
|
||||
if (config.getPlotLostMessages()) {
|
||||
XYSeries lostSeries = getLostSeries(data);
|
||||
lostSeries.setName(lineName + " lost");
|
||||
lostSeries.setDescription("number of ping/pong messages lost");
|
||||
col.addSeries(lostSeries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a data series for each average that we're configured to render
|
||||
*
|
||||
* @param col the collection of xy series to add to
|
||||
* @param config preferences for how to display this test
|
||||
* @param lineName minimal name of the test (e.g. "jxHa.32KB.60s")
|
||||
* @param data List of PeerData.EventDataPoint describing all of the events in the test
|
||||
*/
|
||||
void addAverageLines(XYSeriesCollection col, PeerPlotConfig config, String lineName, StaticPeerData data) {
|
||||
if (data.getDataPointCount() <= 0) return;
|
||||
PeerData.EventDataPoint start = (PeerData.EventDataPoint)data.getDataPoints().get(0);
|
||||
PeerData.EventDataPoint finish = (PeerData.EventDataPoint)data.getDataPoints().get(data.getDataPointCount()-1);
|
||||
|
||||
List configs = config.getAverageSeriesConfigs();
|
||||
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||
int minutes = (int)cfg.getPeriod()/(60*1000);
|
||||
if (cfg.getPlotSendTime()) {
|
||||
double time = data.getAverageSendTime(minutes);
|
||||
if (time > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " send " + minutes + "m avg [" + time + "]", false, false);
|
||||
series.add(start.getPingSent(), time);
|
||||
series.add(finish.getPingSent(), time);
|
||||
series.setDescription("send time, averaged over the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
if (cfg.getPlotReceiveTime()) {
|
||||
double time = data.getAverageReceiveTime(minutes);
|
||||
if (time > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " receive " + minutes + "m avg[" + time + "]", false, false);
|
||||
series.add(start.getPingSent(), time);
|
||||
series.add(finish.getPingSent(), time);
|
||||
series.setDescription("receive time, averaged over the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
if (cfg.getPlotLostMessages()) {
|
||||
double num = data.getLostMessages(minutes);
|
||||
if (num > 0) {
|
||||
XYSeries series = new XYSeries(lineName + " lost messages (" + num + " in " + minutes + "m)", false, false);
|
||||
series.add(start.getPingSent(), num);
|
||||
series.add(finish.getPingSent(), num);
|
||||
series.setDescription("number of messages lost in the last " + minutes + " minutes");
|
||||
col.addSeries(series);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XYSeries getSendSeries(List data) {
|
||||
XYSeries series = new XYSeries("sent", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
series.add(point.getPingSent(), point.getPongSent()-point.getPingSent());
|
||||
} else {
|
||||
// series.add(data.getPingSent(), 0);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
XYSeries getReceiveSeries(List data) {
|
||||
XYSeries series = new XYSeries("receive", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
series.add(point.getPingSent(), point.getPongReceived()-point.getPongSent());
|
||||
} else {
|
||||
// series.add(data.getPingSent(), 0);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
XYSeries getLostSeries(List data) {
|
||||
XYSeries series = new XYSeries("lost", false, false);
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint)data.get(i);
|
||||
if (point.getWasPonged()) {
|
||||
//series.add(point.getPingSent(), 0);
|
||||
} else {
|
||||
series.add(point.getPingSent(), 1);
|
||||
}
|
||||
}
|
||||
return series;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*
|
||||
*/
|
||||
class JFreeChartHeartbeatPlotPane extends HeartbeatPlotPane {
|
||||
private final static Log _log = new Log(JFreeChartHeartbeatPlotPane.class); /* UNUSED */
|
||||
private ChartPanel _panel;
|
||||
private JFreeChartAdapter _adapter;
|
||||
|
||||
/**
|
||||
* Creates a JFreeChart plot pane for the given gui
|
||||
* @param gui the heartbeat monitor gui
|
||||
*/
|
||||
public JFreeChartHeartbeatPlotPane(HeartbeatMonitorGUI gui) {
|
||||
super(gui);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the state is updated
|
||||
*/
|
||||
public void stateUpdated() {
|
||||
if (_panel == null) {
|
||||
remove(0); // remove the dummy
|
||||
|
||||
_adapter = new JFreeChartAdapter();
|
||||
_panel = _adapter.createPanel(_gui.getMonitor().getState());
|
||||
_panel.setBackground(_gui.getBackground());
|
||||
add(new JScrollPane(_panel), BorderLayout.CENTER);
|
||||
_gui.pack();
|
||||
} else {
|
||||
_adapter.updateChart(_panel, _gui.getMonitor().getState());
|
||||
//_gui.pack();
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeComponents() {
|
||||
// noop
|
||||
setLayout(new BorderLayout());
|
||||
add(new JLabel(), BorderLayout.CENTER);
|
||||
//dummy.setBackground(_gui.getBackground());
|
||||
//dummy.setPreferredSize(new Dimension(800,600));
|
||||
//add(dummy);
|
||||
|
||||
//add(_panel);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Configure how we want to render a particular clientConfig in the GUI
|
||||
*/
|
||||
class PeerPlotConfig {
|
||||
private final static Log _log = new Log(PeerPlotConfig.class); /* UNUSED */
|
||||
/** where can we find the current state/data (either as a filename or a URL)? */
|
||||
private String _location;
|
||||
/** what test are we defining the plot data for? */
|
||||
private ClientConfig _config;
|
||||
/** how should we render the current data set? */
|
||||
private PlotSeriesConfig _currentSeriesConfig;
|
||||
/** how should we render the various averages available? */
|
||||
private List _averageSeriesConfigs;
|
||||
private Set _listeners;
|
||||
private boolean _disabled;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param location the name of the file/URL to get the data from
|
||||
*/
|
||||
public PeerPlotConfig(String location) {
|
||||
this(location, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a config =)
|
||||
* @param location the location of the file/URL to get the data from
|
||||
* @param config the client's configuration
|
||||
* @param currentSeriesConfig the series config
|
||||
* @param averageSeriesConfigs the average
|
||||
*/
|
||||
public PeerPlotConfig(String location, ClientConfig config, PlotSeriesConfig currentSeriesConfig, List averageSeriesConfigs) {
|
||||
_location = location;
|
||||
if (config == null)
|
||||
config = new ClientConfig(location);
|
||||
_config = config;
|
||||
if (currentSeriesConfig != null)
|
||||
_currentSeriesConfig = currentSeriesConfig;
|
||||
else
|
||||
_currentSeriesConfig = new PlotSeriesConfig(0);
|
||||
|
||||
if (averageSeriesConfigs != null) {
|
||||
_averageSeriesConfigs = averageSeriesConfigs;
|
||||
} else {
|
||||
rebuildAverageSeriesConfigs();
|
||||
}
|
||||
_listeners = Collections.synchronizedSet(new HashSet(2));
|
||||
_disabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Rebuilds' the average series stuff from the client configuration
|
||||
*/
|
||||
public void rebuildAverageSeriesConfigs() {
|
||||
int periods[] = _config.getAveragePeriods();
|
||||
if (periods == null) {
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(0));
|
||||
} else {
|
||||
Arrays.sort(periods);
|
||||
_averageSeriesConfigs = Collections.synchronizedList(new ArrayList(periods.length));
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
_averageSeriesConfigs.add(new PlotSeriesConfig(periods[i]*60*1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an average period
|
||||
* @param minutes the number of minutes averaged over
|
||||
*/
|
||||
public void addAverage(int minutes) {
|
||||
_config.addAveragePeriod(minutes);
|
||||
|
||||
TreeMap ordered = new TreeMap();
|
||||
for (int i = 0; i < _averageSeriesConfigs.size(); i++) {
|
||||
PlotSeriesConfig cfg = (PlotSeriesConfig)_averageSeriesConfigs.get(i);
|
||||
ordered.put(new Long(cfg.getPeriod()), cfg);
|
||||
}
|
||||
Long period = new Long(minutes*60*1000);
|
||||
if (!ordered.containsKey(period))
|
||||
ordered.put(period, new PlotSeriesConfig(minutes*60*1000));
|
||||
|
||||
List cfgs = Collections.synchronizedList(new ArrayList(ordered.size()));
|
||||
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); )
|
||||
cfgs.add(iter.next());
|
||||
|
||||
_averageSeriesConfigs = cfgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where is the current state data supposed to be found? This must either be a
|
||||
* local file path or a URL
|
||||
* @return the current location
|
||||
*/
|
||||
public String getLocation() { return _location; }
|
||||
|
||||
/**
|
||||
* The location the current state data is supposed to be found. This must either be
|
||||
* a local file path or a URL
|
||||
* @param location the location
|
||||
*/
|
||||
public void setLocation(String location) {
|
||||
_location = location;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* What are we configuring?
|
||||
* @return the client configuration
|
||||
*/
|
||||
public ClientConfig getClientConfig() { return _config; }
|
||||
|
||||
/**
|
||||
* Sets what we are currently configuring
|
||||
* @param config the new config
|
||||
*/
|
||||
public void setClientConfig(ClientConfig config) {
|
||||
_config = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* How do we want to render the current data set?
|
||||
* @return the way we currently render the data
|
||||
*/
|
||||
public PlotSeriesConfig getCurrentSeriesConfig() { return _currentSeriesConfig; }
|
||||
|
||||
/**
|
||||
* Sets how we want to render the current data set.
|
||||
* @param config the new config
|
||||
*/
|
||||
public void setCurrentSeriesConfig(PlotSeriesConfig config) {
|
||||
_currentSeriesConfig = config;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* How do we want to render the averages?
|
||||
* @return the way we currently render the averages
|
||||
*/
|
||||
public List getAverageSeriesConfigs() { return _averageSeriesConfigs; }
|
||||
|
||||
/**
|
||||
* Sets how we want to render the averages
|
||||
* @param configs the new configs
|
||||
*/
|
||||
public void setAverageSeriesConfigs(List configs) { _averageSeriesConfigs = configs; }
|
||||
|
||||
/**
|
||||
* four char description of the peer
|
||||
* @return the name
|
||||
*/
|
||||
public String getPeerName() {
|
||||
Destination peer = getClientConfig().getPeer();
|
||||
if (peer == null)
|
||||
return "????";
|
||||
|
||||
return peer.calculateHash().toBase64().substring(0, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* title: name.packetsize.sendfrequency
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return getPeerName() + '.' + getSize() + '.' + getClientConfig().getSendFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* summary. includes:name, size, sendfrequency, and # of hops
|
||||
* @return the summary
|
||||
*/
|
||||
public String getSummary() {
|
||||
return "Send peer " + getPeerName() + ' ' + getSize() + " every " +
|
||||
getClientConfig().getSendFrequency() + " seconds through " +
|
||||
getClientConfig().getNumHops() + "-hop tunnels";
|
||||
}
|
||||
|
||||
private String getSize() {
|
||||
int bytes = getClientConfig().getSendSize();
|
||||
if (bytes < 1024)
|
||||
return bytes + "b";
|
||||
|
||||
return bytes/1024 + "kb";
|
||||
}
|
||||
|
||||
/**
|
||||
* we've got someone who wants to be notified of changes to the plot config
|
||||
* @param lsnr the listener to be added
|
||||
*/
|
||||
public void addListener(UpdateListener lsnr) { _listeners.add(lsnr); }
|
||||
|
||||
/**
|
||||
* remove a listener
|
||||
* @param lsnr the listener to remove
|
||||
*/
|
||||
public void removeListener(UpdateListener lsnr) { _listeners.remove(lsnr); }
|
||||
|
||||
void fireUpdate() {
|
||||
if (_disabled) return;
|
||||
for (Iterator iter = _listeners.iterator(); iter.hasNext(); ) {
|
||||
((UpdateListener)iter.next()).configUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables notification of events listeners
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
public void disableEvents() { _disabled = true; }
|
||||
|
||||
/**
|
||||
* Enables notification of events listeners
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
public void enableEvents() { _disabled = false; }
|
||||
|
||||
/**
|
||||
* How do we want to render a particular dataset (either the current or the averaged values)?
|
||||
*/
|
||||
public class PlotSeriesConfig {
|
||||
private long _period;
|
||||
private boolean _plotSendTime;
|
||||
private boolean _plotReceiveTime;
|
||||
private boolean _plotLostMessages;
|
||||
private Color _plotLineColor;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param period the period for the config
|
||||
* (0 for current, otherwise # of milliseconds being averaged over)
|
||||
*/
|
||||
public PlotSeriesConfig(long period) {
|
||||
this(period, false, false, false, null);
|
||||
if (period <= 0) {
|
||||
_plotSendTime = true;
|
||||
_plotReceiveTime = true;
|
||||
_plotLostMessages = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a config for the rendering of a particular dataset)
|
||||
* @param period the period for the config
|
||||
* (0 for current, otherwise # of milliseconds being averaged over)
|
||||
* @param plotSend do we plot send times?
|
||||
* @param plotReceive do we plot receive times?
|
||||
* @param plotLost do we plot lost packets?
|
||||
* @param plotColor in what color?
|
||||
*/
|
||||
public PlotSeriesConfig(long period, boolean plotSend, boolean plotReceive, boolean plotLost, Color plotColor) {
|
||||
_period = period;
|
||||
_plotSendTime = plotSend;
|
||||
_plotReceiveTime = plotReceive;
|
||||
_plotLostMessages = plotLost;
|
||||
_plotLineColor = plotColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the plot config this plot series config is a part of
|
||||
* @return the plot config
|
||||
*/
|
||||
public PeerPlotConfig getPlotConfig() { return PeerPlotConfig.this; }
|
||||
|
||||
/**
|
||||
* What period is this series config describing?
|
||||
* @return 0 for current, otherwise # milliseconds that are being averaged over
|
||||
*/
|
||||
public long getPeriod() { return _period; }
|
||||
|
||||
/**
|
||||
* Sets the period this series config is describing
|
||||
* @param period the period
|
||||
* (0 for current, otherwise # milliseconds that are being averaged over)
|
||||
*/
|
||||
public void setPeriod(long period) {
|
||||
_period = period;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we render the time to send (ping to peer)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotSendTime() { return _plotSendTime; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the time to send (ping to peer) or not
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotSendTime(boolean shouldPlot) {
|
||||
_plotSendTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we render the time to receive (peer pong to us)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotReceiveTime() { return _plotReceiveTime; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the time to receive (peer pong to us)
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotReceiveTime(boolean shouldPlot) {
|
||||
_plotReceiveTime = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/**
|
||||
* Should we render the number of messages lost (ping sent, no pong received in time)?
|
||||
* @return true or false . . .
|
||||
*/
|
||||
public boolean getPlotLostMessages() { return _plotLostMessages; }
|
||||
|
||||
/**
|
||||
* Sets whether we render the number of messages lost (ping sent, no pong received in time) or not
|
||||
* @param shouldPlot true or false
|
||||
*/
|
||||
public void setPlotLostMessages(boolean shouldPlot) {
|
||||
_plotLostMessages = shouldPlot;
|
||||
fireUpdate();
|
||||
}
|
||||
/**
|
||||
* What color should we plot the data with?
|
||||
* @return the color
|
||||
*/
|
||||
public Color getPlotLineColor() { return _plotLineColor; }
|
||||
|
||||
/**
|
||||
* Sets the color we should plot the data with
|
||||
* @param color the color to use
|
||||
*/
|
||||
public void setPlotLineColor(Color color) {
|
||||
_plotLineColor = color;
|
||||
fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for listening to updates . . .
|
||||
*/
|
||||
public interface UpdateListener {
|
||||
/**
|
||||
* @param config the peer plot config that changes
|
||||
* @see PeerPlotConfig#fireUpdate()
|
||||
*/
|
||||
void configUpdated(PeerPlotConfig config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(PeerPlotConfigPane.class);
|
||||
private PeerPlotConfig _config;
|
||||
private HeartbeatControlPane _parent;
|
||||
private JLabel _title;
|
||||
private JButton _delete;
|
||||
private JLabel _fromLabel;
|
||||
private JTextField _from;
|
||||
private JTextArea _comments;
|
||||
private JLabel _peerLabel;
|
||||
private JTextField _peerKey;
|
||||
private JLabel _localLabel;
|
||||
private JTextField _localKey;
|
||||
private OptionLine _options[];
|
||||
private Random _rnd = new Random();
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
private Color _background = WHITE;
|
||||
|
||||
/**
|
||||
* Constructs a pane
|
||||
* @param config the plot config it represents
|
||||
* @param pane the pane this one is attached to
|
||||
*/
|
||||
public PeerPlotConfigPane(PeerPlotConfig config, HeartbeatControlPane pane) {
|
||||
_config = config;
|
||||
_parent = pane;
|
||||
if (_parent != null)
|
||||
_background = _parent.getBackground();
|
||||
_config.addListener(this);
|
||||
initializeComponents();
|
||||
}
|
||||
|
||||
/** called when the user wants to stop monitoring this test */
|
||||
private void delete() {
|
||||
_parent.removeTest(_config);
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
buildComponents();
|
||||
placeComponents(this);
|
||||
refreshView();
|
||||
//setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
setBackground(_background);
|
||||
}
|
||||
|
||||
/**
|
||||
* place all the gui components onto the given panel
|
||||
* @param body the panel to place the components on
|
||||
*/
|
||||
private void placeComponents(JPanel body) {
|
||||
body.setLayout(new GridBagLayout());
|
||||
GridBagConstraints cts = new GridBagConstraints();
|
||||
|
||||
// row 0: title + delete
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 0;
|
||||
cts.gridwidth = 5;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_title, cts);
|
||||
cts.gridx = 5;
|
||||
cts.gridwidth = 1;
|
||||
cts.anchor = GridBagConstraints.NORTHWEST;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_delete, cts);
|
||||
|
||||
// row 1: from + location
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 1;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_fromLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_from, cts);
|
||||
|
||||
// row 2: comment
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 2;
|
||||
cts.gridwidth = 6;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_comments, cts);
|
||||
|
||||
// row 3: peer + peerKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 3;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_peerLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_peerKey, cts);
|
||||
|
||||
// row 4: local + localKey
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 4;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
body.add(_localLabel, cts);
|
||||
cts.gridx = 1;
|
||||
cts.gridwidth = 5;
|
||||
cts.fill = GridBagConstraints.BOTH;
|
||||
body.add(_localKey, cts);
|
||||
|
||||
// row 5-N: data row
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
cts.gridx = 0;
|
||||
cts.gridy = 5 + i;
|
||||
cts.gridwidth = 1;
|
||||
cts.fill = GridBagConstraints.NONE;
|
||||
cts.anchor = GridBagConstraints.WEST;
|
||||
if (_options[i]._durationMinutes <= 0)
|
||||
body.add(new JLabel("Data: "), cts);
|
||||
else
|
||||
body.add(new JLabel(_options[i]._durationMinutes + "m avg: "), cts);
|
||||
|
||||
cts.gridx = 1;
|
||||
body.add(_options[i]._send, cts);
|
||||
cts.gridx = 2;
|
||||
body.add(_options[i]._recv, cts);
|
||||
cts.gridx = 3;
|
||||
body.add(_options[i]._lost, cts);
|
||||
cts.gridx = 4;
|
||||
body.add(_options[i]._all, cts);
|
||||
cts.gridx = 5;
|
||||
body.add(_options[i]._color, cts);
|
||||
}
|
||||
}
|
||||
|
||||
/** build all of the gui components */
|
||||
private void buildComponents() {
|
||||
_title = new JLabel(_config.getSummary());
|
||||
_title.setBackground(_background);
|
||||
_delete = new JButton("Delete");
|
||||
_delete.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { delete(); } });
|
||||
_delete.setEnabled(false);
|
||||
_delete.setBackground(_background);
|
||||
_fromLabel = new JLabel("Location: ");
|
||||
_fromLabel.setBackground(_background);
|
||||
_from = new JTextField(_config.getLocation());
|
||||
_from.setEditable(false);
|
||||
_from.setBackground(_background);
|
||||
_comments = new JTextArea(_config.getClientConfig().getComment(), 2, 20);
|
||||
// _comments = new JTextArea(_config.getClientConfig().getComment(), 2, 40);
|
||||
_comments.setEditable(false);
|
||||
_comments.setBackground(_background);
|
||||
_peerLabel = new JLabel("Peer: ");
|
||||
_peerLabel.setBackground(_background);
|
||||
_peerKey = new JTextField(_config.getClientConfig().getPeer().toBase64(), 8);
|
||||
_peerKey.setBackground(_background);
|
||||
_localLabel = new JLabel("Local: ");
|
||||
_localLabel.setBackground(_background);
|
||||
_localKey = new JTextField(_config.getClientConfig().getUs().toBase64(), 8);
|
||||
_localKey.setBackground(_background);
|
||||
|
||||
int averagedPeriods[] = _config.getClientConfig().getAveragePeriods();
|
||||
if (averagedPeriods == null)
|
||||
averagedPeriods = new int[0];
|
||||
|
||||
_options = new OptionLine[1 + averagedPeriods.length];
|
||||
_options[0] = new OptionLine(0);
|
||||
for (int i = 0; i < averagedPeriods.length; i++) {
|
||||
_options[1+i] = new OptionLine(averagedPeriods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** the settings have changed - revise */
|
||||
private void refreshView() {
|
||||
for (int i = 0; i < _options.length; i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_options[i]._durationMinutes);
|
||||
if (cfg == null) {
|
||||
_log.warn("Config for minutes " + _options[i]._durationMinutes + " was not found?");
|
||||
continue;
|
||||
}
|
||||
//_log.debug("Refreshing view for minutes ["+ _options[i]._durationMinutes + "]: send [" +
|
||||
// _options[i]._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
// _options[i]._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
// _options[i]._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]");
|
||||
_options[i]._send.setSelected(cfg.getPlotSendTime());
|
||||
_options[i]._recv.setSelected(cfg.getPlotReceiveTime());
|
||||
_options[i]._lost.setSelected(cfg.getPlotLostMessages());
|
||||
if (cfg.getPlotLineColor() != null)
|
||||
_options[i]._color.setBackground(cfg.getPlotLineColor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find the right config for the given period
|
||||
* @param minutes the minutes to locate the config by
|
||||
* @return the config for the given period, or null
|
||||
*/
|
||||
private PeerPlotConfig.PlotSeriesConfig getConfig(int minutes) {
|
||||
if (minutes <= 0)
|
||||
return _config.getCurrentSeriesConfig();
|
||||
|
||||
List configs = _config.getAverageSeriesConfigs();
|
||||
for (int i = 0; i < configs.size(); i++) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = (PeerPlotConfig.PlotSeriesConfig)configs.get(i);
|
||||
if (cfg.getPeriod() == minutes * 60*1000)
|
||||
return cfg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* notified that the config has been updated
|
||||
* @param config the config that was been updated
|
||||
*/
|
||||
public void configUpdated(PeerPlotConfig config) { refreshView(); }
|
||||
|
||||
private class ChooseColor implements ActionListener {
|
||||
private int _minutes;
|
||||
private JButton _button;
|
||||
|
||||
/**
|
||||
* @param minutes the minutes (line) to change the color of...
|
||||
* @param button the associated button
|
||||
*/
|
||||
public ChooseColor(int minutes, JButton button) {
|
||||
_minutes = minutes;
|
||||
_button = button;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||
Color origColor = null;
|
||||
if (cfg != null)
|
||||
origColor = cfg.getPlotLineColor();
|
||||
Color color = JColorChooser.showDialog(PeerPlotConfigPane.this, "What color should this line be?", origColor);
|
||||
if (color != null) {
|
||||
if (cfg != null)
|
||||
cfg.setPlotLineColor(color);
|
||||
_button.setBackground(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OptionLine {
|
||||
int _durationMinutes;
|
||||
JCheckBox _send;
|
||||
JCheckBox _recv;
|
||||
JCheckBox _lost;
|
||||
JCheckBox _all;
|
||||
JButton _color;
|
||||
|
||||
/**
|
||||
* Creates an OptionLine.
|
||||
* @param durationMinutes the minutes =)
|
||||
*/
|
||||
public OptionLine(int durationMinutes) {
|
||||
_durationMinutes = durationMinutes;
|
||||
_send = new JCheckBox("send time");
|
||||
_send.setBackground(_background);
|
||||
_recv = new JCheckBox("receive time");
|
||||
_recv.setBackground(_background);
|
||||
_lost = new JCheckBox("lost messages");
|
||||
_lost.setBackground(_background);
|
||||
_all = new JCheckBox("all");
|
||||
_all.setBackground(_background);
|
||||
_color = new JButton("color");
|
||||
int r = _rnd.nextInt(255);
|
||||
if (r < 0) r = -r;
|
||||
int g = _rnd.nextInt(255);
|
||||
if (g < 0) g = -g;
|
||||
int b = _rnd.nextInt(255);
|
||||
if (b < 0) b = -b;
|
||||
//_color.setBackground(new Color(r, g, b));
|
||||
_color.setBackground(_background);
|
||||
|
||||
_send.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_recv.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_lost.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_all.addActionListener(new UpdateListener(OptionLine.this, _durationMinutes));
|
||||
_color.addActionListener(new ChooseColor(durationMinutes, _color));
|
||||
_color.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateListener implements ActionListener {
|
||||
private OptionLine _line;
|
||||
private int _minutes;
|
||||
|
||||
/**
|
||||
* Update Listener constructor . . .
|
||||
* @param line the line
|
||||
* @param minutes the minutes
|
||||
*/
|
||||
public UpdateListener(OptionLine line, int minutes) {
|
||||
_line = line;
|
||||
_minutes = minutes;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
PeerPlotConfig.PlotSeriesConfig cfg = getConfig(_minutes);
|
||||
|
||||
cfg.getPlotConfig().disableEvents();
|
||||
_log.debug("Updating data for minutes ["+ _line._durationMinutes + "]: send [" +
|
||||
_line._send.isSelected() + "/" + cfg.getPlotSendTime() + "] recv [" +
|
||||
_line._recv.isSelected() + "/" + cfg.getPlotReceiveTime() + "] lost [" +
|
||||
_line._lost.isSelected() + "/" + cfg.getPlotLostMessages() + "]: config = " + cfg);
|
||||
|
||||
boolean force = _line._all.isSelected();
|
||||
cfg.setPlotSendTime(_line._send.isSelected() || force);
|
||||
cfg.setPlotReceiveTime(_line._recv.isSelected() || force);
|
||||
cfg.setPlotLostMessages(_line._lost.isSelected() || force);
|
||||
cfg.getPlotConfig().enableEvents();
|
||||
cfg.getPlotConfig().fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test stuff
|
||||
* @param args da arsg
|
||||
*/
|
||||
public final static void main(String args[]) {
|
||||
Test t = new Test();
|
||||
t.runTest();
|
||||
}
|
||||
|
||||
private final static class Test implements PeerPlotStateFetcher.FetchStateReceptor {
|
||||
/**
|
||||
* Runs da test
|
||||
*/
|
||||
public void runTest() {
|
||||
PeerPlotConfig cfg = new PeerPlotConfig("C:\\testnet\\r2\\heartbeatStat_10s_30kb.txt");
|
||||
PeerPlotState state = new PeerPlotState(cfg);
|
||||
PeerPlotStateFetcher.fetchPeerPlotState(this, state);
|
||||
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.gui.PeerPlotStateFetcher.FetchStateReceptor#peerPlotStateFetched(net.i2p.heartbeat.gui.PeerPlotState)
|
||||
*/
|
||||
public void peerPlotStateFetched(PeerPlotState state) {
|
||||
javax.swing.JFrame f = new javax.swing.JFrame("Test");
|
||||
f.getContentPane().add(new JScrollPane(new PeerPlotConfigPane(state.getPlotConfig(), null)));
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
|
||||
/**
|
||||
* Current data + plot config for a particular test
|
||||
*
|
||||
*/
|
||||
class PeerPlotState {
|
||||
private StaticPeerData _currentData;
|
||||
private PeerPlotConfig _plotConfig;
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @see PeerPlotState#PeerPlotState(PeerPlotConfig, StaticPeerData)
|
||||
*/
|
||||
public PeerPlotState() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegating constructor . . .
|
||||
* @param config plot config
|
||||
* @see PeerPlotState#PeerPlotState(PeerPlotConfig, StaticPeerData)
|
||||
*/
|
||||
public PeerPlotState(PeerPlotConfig config) {
|
||||
this(config, new StaticPeerData(config.getClientConfig()));
|
||||
}
|
||||
/**
|
||||
* Creates a PeerPlotState
|
||||
* @param config plot config
|
||||
* @param data peer data
|
||||
*/
|
||||
public PeerPlotState(PeerPlotConfig config, StaticPeerData data) {
|
||||
_plotConfig = config;
|
||||
_currentData = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an average
|
||||
* @param minutes mins averaged over
|
||||
* @param sendMs how much later did the peer receieve
|
||||
* @param recvMs how much later did we receieve
|
||||
* @param lost how many were lost
|
||||
*/
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
// make sure we've got the config entry for the average
|
||||
_plotConfig.addAverage(minutes);
|
||||
// add the data point...
|
||||
_currentData.addAverage(minutes, sendMs, recvMs, lost);
|
||||
}
|
||||
|
||||
/**
|
||||
* we successfully got a ping/pong through
|
||||
*
|
||||
* @param sendTime when did the ping get sent?
|
||||
* @param sendMs how much later did the peer receive the ping?
|
||||
* @param recvMs how much later than that did we receive the pong?
|
||||
*/
|
||||
public void addSuccess(long sendTime, int sendMs, int recvMs) {
|
||||
_currentData.addData(sendTime, sendMs, recvMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* we lost a ping/pong
|
||||
*
|
||||
* @param sendTime when did we send the ping?
|
||||
*/
|
||||
public void addLost(long sendTime) {
|
||||
_currentData.addData(sendTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* data set to render
|
||||
* @return the data set
|
||||
*/
|
||||
public StaticPeerData getCurrentData() { return _currentData; }
|
||||
|
||||
/**
|
||||
* Sets the data set to render
|
||||
* @param data the data set
|
||||
*/
|
||||
public void setCurrentData(StaticPeerData data) { _currentData = data; }
|
||||
|
||||
/**
|
||||
* configuration options on how to render the data set
|
||||
* @return the config options
|
||||
*/
|
||||
public PeerPlotConfig getPlotConfig() { return _plotConfig; }
|
||||
|
||||
/**
|
||||
* Sets the configuration options on how to render the data
|
||||
* @param config the config options
|
||||
*/
|
||||
public void setPlotConfig(PeerPlotConfig config) { _plotConfig = config; }
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class PeerPlotStateFetcher {
|
||||
private final static Log _log = new Log(PeerPlotStateFetcher.class);
|
||||
|
||||
/**
|
||||
* Fetch and fill the specified state structure
|
||||
* @param receptor the 'receptor' (callbacks)
|
||||
* @param state the state
|
||||
*/
|
||||
public static void fetchPeerPlotState(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
I2PThread t = new I2PThread(new Fetcher(receptor, state));
|
||||
t.setDaemon(true);
|
||||
t.setName("Fetch state from " + state.getPlotConfig().getLocation());
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback stuff . . .
|
||||
*/
|
||||
public interface FetchStateReceptor {
|
||||
/**
|
||||
* Called when a peer plot state is fetched
|
||||
* @param state state that was fetched
|
||||
*/
|
||||
void peerPlotStateFetched(PeerPlotState state);
|
||||
}
|
||||
|
||||
private static class Fetcher implements Runnable {
|
||||
private PeerPlotState _state;
|
||||
private FetchStateReceptor _receptor;
|
||||
|
||||
/**
|
||||
* Creates a Fetcher thread
|
||||
* @param receptor the 'receptor' (callbacks)
|
||||
* @param state the state
|
||||
*/
|
||||
public Fetcher(FetchStateReceptor receptor, PeerPlotState state) {
|
||||
_state = state;
|
||||
_receptor = receptor;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
String loc = _state.getPlotConfig().getLocation();
|
||||
_log.debug("Load called [" + loc + "]");
|
||||
InputStream in = null;
|
||||
try {
|
||||
try {
|
||||
URL location = new URL(loc);
|
||||
in = location.openStream();
|
||||
} catch (MalformedURLException mue) {
|
||||
_log.debug("Not a url [" + loc + "]");
|
||||
in = null;
|
||||
}
|
||||
|
||||
if (in == null)
|
||||
in = new FileInputStream(loc);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
handleLine(line);
|
||||
}
|
||||
|
||||
if (valid())
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error retrieving from the location [" + loc + "]", ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check to make sure we've got everything we need
|
||||
* @return true [always]
|
||||
*/
|
||||
boolean valid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a line from the data set - these can be formatted in one of the
|
||||
* following ways. <p />
|
||||
*
|
||||
* <pre>
|
||||
* peer khWYqCETu9YtPUvGV92ocsbEW5DezhKlIG7ci8RLX3g=
|
||||
* local u-9hlR1ik2hemXf0HvKMfeRgrS86CbNQh25e7XBhaQE=
|
||||
* peerDest [base 64 of the full destination]
|
||||
* localDest [base 64 of the full destination]
|
||||
* numTunnelHops 2
|
||||
* comment Test with localhost sending 30KB every 20 seconds
|
||||
* sendFrequency 20
|
||||
* sendSize 30720
|
||||
* sessionStart 20040409.22:51:10.915
|
||||
* currentTime 20040409.23:31:39.607
|
||||
* numPending 2
|
||||
* lifetimeSent 118
|
||||
* lifetimeRecv 113
|
||||
* #averages minutes sendMs recvMs numLost
|
||||
* periodAverage 1 1843 771 0
|
||||
* periodAverage 5 786 752 1
|
||||
* periodAverage 30 855 735 3
|
||||
* #action status date and time sent sendMs replyMs
|
||||
* EVENT OK 20040409.23:21:44.742 691 670
|
||||
* EVENT OK 20040409.23:22:05.201 671 581
|
||||
* EVENT OK 20040409.23:22:26.301 1182 1452
|
||||
* EVENT OK 20040409.23:22:47.322 24304 1723
|
||||
* EVENT OK 20040409.23:23:08.232 2293 1081
|
||||
* EVENT OK 20040409.23:23:29.332 1392 641
|
||||
* EVENT OK 20040409.23:23:50.262 641 761
|
||||
* EVENT OK 20040409.23:24:11.102 651 701
|
||||
* EVENT OK 20040409.23:24:31.401 841 621
|
||||
* EVENT OK 20040409.23:24:52.061 651 681
|
||||
* EVENT OK 20040409.23:25:12.480 701 1623
|
||||
* EVENT OK 20040409.23:25:32.990 1442 1212
|
||||
* EVENT OK 20040409.23:25:54.230 591 631
|
||||
* EVENT OK 20040409.23:26:14.620 620 691
|
||||
* EVENT OK 20040409.23:26:35.199 1793 1432
|
||||
* EVENT OK 20040409.23:26:56.570 661 641
|
||||
* EVENT OK 20040409.23:27:17.200 641 660
|
||||
* EVENT OK 20040409.23:27:38.120 611 921
|
||||
* EVENT OK 20040409.23:27:58.699 831 621
|
||||
* EVENT OK 20040409.23:28:19.559 801 661
|
||||
* EVENT OK 20040409.23:28:40.279 601 611
|
||||
* EVENT OK 20040409.23:29:00.648 601 621
|
||||
* EVENT OK 20040409.23:29:21.288 701 661
|
||||
* EVENT LOST 20040409.23:29:41.828
|
||||
* EVENT LOST 20040409.23:30:02.327
|
||||
* EVENT LOST 20040409.23:30:22.656
|
||||
* EVENT OK 20040409.23:31:24.305 1843 771
|
||||
* </pre>
|
||||
*
|
||||
* @param line (see above)
|
||||
*/
|
||||
private void handleLine(String line) {
|
||||
if (line.startsWith("peerDest"))
|
||||
handlePeerDest(line);
|
||||
else if (line.startsWith("localDest"))
|
||||
handleLocalDest(line);
|
||||
else if (line.startsWith("numTunnelHops"))
|
||||
handleNumTunnelHops(line);
|
||||
else if (line.startsWith("comment"))
|
||||
handleComment(line);
|
||||
else if (line.startsWith("sendFrequency"))
|
||||
handleSendFrequency(line);
|
||||
else if (line.startsWith("sendSize"))
|
||||
handleSendSize(line);
|
||||
else if (line.startsWith("periodAverage"))
|
||||
handlePeriodAverage(line);
|
||||
else if (line.startsWith("EVENT"))
|
||||
handleEvent(line);
|
||||
else if (line.startsWith("numPending"))
|
||||
handleNumPending(line);
|
||||
else if (line.startsWith("sessionStart"))
|
||||
handleSessionStart(line);
|
||||
else
|
||||
_log.debug("Not handled: " + line);
|
||||
}
|
||||
|
||||
private void handlePeerDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setPeer(d);
|
||||
_log.debug("Setting the peer to " + d.calculateHash().toBase64());
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the peerDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLocalDest(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String destKey = tok.nextToken();
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(destKey);
|
||||
_state.getPlotConfig().getClientConfig().setUs(d);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Unable to parse the localDest line: [" + line + "]", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComment(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
StringBuffer buf = new StringBuffer(line.length()-32);
|
||||
while (tok.hasMoreTokens())
|
||||
buf.append(tok.nextToken()).append(' ');
|
||||
_state.getPlotConfig().getClientConfig().setComment(buf.toString());
|
||||
}
|
||||
|
||||
private void handleNumTunnelHops(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numTunnelHops line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNumPending(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getCurrentData().setPendingCount(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the numPending line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendFrequency(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendFrequency line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendSize(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String num = tok.nextToken();
|
||||
try {
|
||||
int val = Integer.parseInt(num);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(val);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSessionStart(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
String date = tok.nextToken();
|
||||
try {
|
||||
long when = getDate(date);
|
||||
_state.getCurrentData().setSessionStart(when);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sessionStart line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePeriodAverage(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
tok.nextToken(); // ignore;
|
||||
try {
|
||||
// periodAverage minutes sendMs recvMs numLost
|
||||
int min = Integer.parseInt(tok.nextToken());
|
||||
int send = Integer.parseInt(tok.nextToken());
|
||||
int recv = Integer.parseInt(tok.nextToken());
|
||||
int lost = Integer.parseInt(tok.nextToken());
|
||||
_state.addAverage(min, send, recv, lost);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the sendSize line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEvent(String line) {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
|
||||
// * EVENT OK 20040409.23:29:21.288 701 661
|
||||
// * EVENT LOST 20040409.23:29:41.828
|
||||
tok.nextToken(); // ignore first two
|
||||
tok.nextToken();
|
||||
try {
|
||||
long when = getDate(tok.nextToken());
|
||||
if (when < 0) {
|
||||
_log.error("Invalid EVENT line: [" + line + "]");
|
||||
return;
|
||||
}
|
||||
if (tok.hasMoreTokens()) {
|
||||
int sendMs = Integer.parseInt(tok.nextToken());
|
||||
int recvMs = Integer.parseInt(tok.nextToken());
|
||||
_state.addSuccess(when, sendMs, recvMs);
|
||||
} else {
|
||||
_state.addLost(when);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Unable to parse the EVENT line: [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyyMMdd.HH:mm:ss.SSS", Locale.UK);
|
||||
private long getDate(String date) {
|
||||
synchronized (_fmt) {
|
||||
try {
|
||||
return _fmt.parse(date).getTime();
|
||||
} catch (ParseException pe) {
|
||||
_log.error("Unable to parse the date [" + date + "]", pe);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fakeRun() { /* UNUSED */
|
||||
try {
|
||||
Destination peer = new Destination();
|
||||
Destination us = new Destination();
|
||||
peer.fromBase64("3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJ" +
|
||||
"cS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7g" +
|
||||
"fqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teM" +
|
||||
"d5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA");
|
||||
us.fromBase64("W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYpp" +
|
||||
"K9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63" +
|
||||
"rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HC" +
|
||||
"VilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA");
|
||||
_state.getPlotConfig().getClientConfig().setPeer(peer);
|
||||
_state.getPlotConfig().getClientConfig().setUs(us);
|
||||
_state.getPlotConfig().getClientConfig().setNumHops(2);
|
||||
_state.getPlotConfig().getClientConfig().setComment("we do stuff\nreally nifty stuff. really");
|
||||
_state.getPlotConfig().getClientConfig().setAveragePeriods(new int[] { 1, 5, 30, 60 });
|
||||
int rnd = new java.util.Random().nextInt();
|
||||
if (rnd > 0)
|
||||
rnd = rnd % 10;
|
||||
else
|
||||
rnd = (-rnd) % 10;
|
||||
_state.getPlotConfig().getClientConfig().setSendFrequency(rnd);
|
||||
_state.getPlotConfig().getClientConfig().setSendSize(16*1024);
|
||||
_state.getPlotConfig().getClientConfig().setStatDuration(10);
|
||||
_state.getPlotConfig().rebuildAverageSeriesConfigs();
|
||||
_state.setCurrentData(new StaticPeerData(_state.getPlotConfig().getClientConfig()));
|
||||
|
||||
_receptor.peerPlotStateFetched(_state);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
|
||||
/**
|
||||
* Raw data points for a test
|
||||
*/
|
||||
class StaticPeerData extends PeerData {
|
||||
private int _pending;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for sending a ping */
|
||||
private Map _averageSendTimes;
|
||||
/** Integer (period, in minutes) to Integer (milliseconds) for receiving a pong */
|
||||
private Map _averageReceiveTimes;
|
||||
/** Integer (period, in minutes) to Integer (num messages) of how many messages were lost on average */
|
||||
private Map _lostMessages;
|
||||
|
||||
/**
|
||||
* Creates a static peer data with a specified client config ... duh
|
||||
* @param config the client config
|
||||
*/
|
||||
public StaticPeerData(ClientConfig config) {
|
||||
super(config);
|
||||
_averageSendTimes = new HashMap(4);
|
||||
_averageReceiveTimes = new HashMap(4);
|
||||
_lostMessages = new HashMap(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds averaged data
|
||||
* @param minutes the minutes (averaged over)
|
||||
* @param sendMs the send time (ping) in milliseconds
|
||||
* @param recvMs the receive time (pong) in milliseconds
|
||||
* @param lost the number lost
|
||||
*/
|
||||
public void addAverage(int minutes, int sendMs, int recvMs, int lost) {
|
||||
_averageSendTimes.put(new Integer(minutes), new Integer(sendMs));
|
||||
_averageReceiveTimes.put(new Integer(minutes), new Integer(recvMs));
|
||||
_lostMessages.put(new Integer(minutes), new Integer(lost));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number pending
|
||||
* @param numPending the number pending
|
||||
*/
|
||||
public void setPendingCount(int numPending) { _pending = numPending; }
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.PeerData#setSessionStart(long)
|
||||
*/
|
||||
public void setSessionStart(long when) { super.setSessionStart(when); }
|
||||
|
||||
/**
|
||||
* Adds data
|
||||
* @param sendTime the time it was sent
|
||||
* @param sendMs the send time (ping) in milliseconds
|
||||
* @param recvMs the receive time (pong) in milliseconds
|
||||
*/
|
||||
public void addData(long sendTime, int sendMs, int recvMs) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setPongSent(sendTime + sendMs);
|
||||
dataPoint.setPongReceived(sendTime + sendMs + recvMs);
|
||||
dataPoint.setWasPonged(true);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data
|
||||
* @param sendTime the time it was sent
|
||||
*/
|
||||
public void addData(long sendTime) {
|
||||
PeerData.EventDataPoint dataPoint = new PeerData.EventDataPoint(sendTime);
|
||||
dataPoint.setWasPonged(false);
|
||||
addDataPoint(dataPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* how many pings are still outstanding?
|
||||
* @return the number of pings outstanding
|
||||
*/
|
||||
public int getPendingCount() { return _pending; }
|
||||
|
||||
|
||||
/**
|
||||
* average time to send over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageSendTime(int period) {
|
||||
Integer i = (Integer)_averageSendTimes.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* average time to receive over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return milliseconds average, or -1 if we dont track that period
|
||||
*/
|
||||
public double getAverageReceiveTime(int period) {
|
||||
Integer i = (Integer)_averageReceiveTimes.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* number of lost messages over the given period.
|
||||
*
|
||||
* @param period number of minutes to retrieve the average for
|
||||
* @return number of lost messages in the period, or -1 if we dont track that period
|
||||
*/
|
||||
public double getLostMessages(int period) {
|
||||
Integer i = (Integer)_lostMessages.get(new Integer(period));
|
||||
if (i == null)
|
||||
return -1;
|
||||
|
||||
return i.doubleValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.heartbeat.PeerData#cleanup()
|
||||
*/
|
||||
public void cleanup() {}
|
||||
}
|
||||
@@ -4,14 +4,14 @@
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../ministreaming/java/" target="build" />
|
||||
<ant dir="../../../core/java/" target="build" />
|
||||
<!-- ministreaming will build core -->
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
srcdir="./src"
|
||||
debug="true"
|
||||
debug="true" deprecation="on" source="1.3" target="1.3"
|
||||
destdir="./build/obj"
|
||||
classpath="../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar" />
|
||||
</target>
|
||||
@@ -37,11 +37,11 @@
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<ant dir="../../../core/java/" target="distclean" />
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
|
||||
@@ -19,49 +19,69 @@ public class HTTPListener extends Thread {
|
||||
private String listenHost;
|
||||
private SocketManagerProducer smp;
|
||||
|
||||
public HTTPListener(SocketManagerProducer smp, int port,
|
||||
String listenHost) {
|
||||
this.smp = smp;
|
||||
this.port = port;
|
||||
start();
|
||||
/**
|
||||
* A public constructor. It contstructs things. In this case,
|
||||
* it constructs a nice HTTPListener, for all your listening on
|
||||
* HTTP needs. Yep. That's right.
|
||||
* @param smp A SocketManagerProducer, producing Sockets, no doubt
|
||||
* @param port A port, to connect to.
|
||||
* @param listenHost A host, to connect to.
|
||||
*/
|
||||
|
||||
public HTTPListener(SocketManagerProducer smp, int port, String listenHost) {
|
||||
this.smp = smp;
|
||||
this.port = port;
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
InetAddress lh = listenHost == null
|
||||
? null
|
||||
: InetAddress.getByName(listenHost);
|
||||
ServerSocket ss = new ServerSocket(port, 0, lh);
|
||||
while(true) {
|
||||
Socket s = ss.accept();
|
||||
new HTTPSocketHandler(this, s);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while accepting connections", ex);
|
||||
}
|
||||
try {
|
||||
InetAddress lh = listenHost == null ? null : InetAddress.getByName(listenHost);
|
||||
ServerSocket ss = new ServerSocket(port, 0, lh);
|
||||
while (true) {
|
||||
Socket s = ss.accept();
|
||||
new HTTPSocketHandler(this, s);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while accepting connections", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean proxyUsed=false;
|
||||
|
||||
private boolean proxyUsed = false;
|
||||
|
||||
/**
|
||||
* Query whether this is the first use of the proxy or not
|
||||
* @return Whether this is the first proxy use, no doubt.
|
||||
*/
|
||||
public boolean firstProxyUse() {
|
||||
// FIXME: check a config option here
|
||||
if (true) return false;
|
||||
if (proxyUsed) {
|
||||
return false;
|
||||
} else {
|
||||
proxyUsed=true;
|
||||
return true;
|
||||
}
|
||||
if (true) return false; // FIXME: check a config option here
|
||||
|
||||
if (proxyUsed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
proxyUsed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The SocketManagerProducer being used.
|
||||
*/
|
||||
public SocketManagerProducer getSMP() {
|
||||
return smp;
|
||||
return smp;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
* Outputs with HTTP 1.1 flair that a feature isn't implemented.
|
||||
* @param out The stream the text goes to.
|
||||
* @deprecated
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handleNotImplemented(OutputStream out) throws IOException {
|
||||
out.write(("HTTP/1.1 200 Document following\n\n"+
|
||||
"<h1>Feature not implemented</h1>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
out.write(("HTTP/1.1 200 Document following\n\n" + "<h1>Feature not implemented</h1>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,34 +21,42 @@ public class HTTPSocketHandler extends Thread {
|
||||
private HTTPListener httpl;
|
||||
private RootHandler h;
|
||||
|
||||
/**
|
||||
* A public constructor.
|
||||
* @param httpl An HTTPListener, to listen for HTTP, no doubt
|
||||
* @param s A socket.
|
||||
*/
|
||||
public HTTPSocketHandler(HTTPListener httpl, Socket s) {
|
||||
this.httpl = httpl;
|
||||
this.s=s;
|
||||
h = RootHandler.getInstance();
|
||||
start();
|
||||
this.httpl = httpl;
|
||||
this.s = s;
|
||||
h = RootHandler.getInstance();
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Thread#run()
|
||||
*/
|
||||
public void run() {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new BufferedInputStream(s.getInputStream());
|
||||
out = new BufferedOutputStream(s.getOutputStream());
|
||||
Request req = new Request(in);
|
||||
h.handle(req, httpl, out);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling data", ex);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("IOException in finalizer", ex);
|
||||
}
|
||||
}
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new BufferedInputStream(s.getInputStream());
|
||||
out = new BufferedOutputStream(s.getOutputStream());
|
||||
Request req = new Request(in);
|
||||
h.handle(req, httpl, out);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling data", ex);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("IOException in finalizer", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,13 +41,12 @@ public class HTTPTunnel {
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param mcDonaldsMode whether to throw away a manager after use
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers,
|
||||
boolean mcDonaldsMode, int listenPort) {
|
||||
this(initialManagers, maxManagers, mcDonaldsMode, listenPort,
|
||||
"127.0.0.1", 7654);
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
int listenPort) {
|
||||
this(initialManagers, maxManagers, shouldThrowAwayManagers, listenPort, "127.0.0.1", 7654);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,56 +54,55 @@ public class HTTPTunnel {
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param mcDonaldsMode whether to throw away a manager after use
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
* @param i2cpAddress the I2CP address
|
||||
* @param i2cpPort the I2CP port
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers,
|
||||
boolean mcDonaldsMode, int listenPort,
|
||||
String i2cpAddress, int i2cpPort) {
|
||||
SocketManagerProducer smp =
|
||||
new SocketManagerProducer(initialManagers, maxManagers,
|
||||
mcDonaldsMode, i2cpAddress, i2cpPort);
|
||||
new HTTPListener(smp, listenPort, "127.0.0.1");
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
int listenPort, String i2cpAddress, int i2cpPort) {
|
||||
SocketManagerProducer smp = new SocketManagerProducer(initialManagers, maxManagers, shouldThrowAwayManagers,
|
||||
i2cpAddress, i2cpPort);
|
||||
new HTTPListener(smp, listenPort, "127.0.0.1");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The all important main function, allowing HTTPTunnel to be
|
||||
* stand-alone, a program in it's own right, and all that jazz.
|
||||
* @param args A list of String passed to the program
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
String host = "127.0.0.1";
|
||||
int port = 7654, max = 1;
|
||||
boolean mc = false;
|
||||
if (args.length >1) {
|
||||
if (args.length == 4) {
|
||||
host = args[2];
|
||||
port = Integer.parseInt(args[3]);
|
||||
} else if (args.length != 2) {
|
||||
showInfo(); return;
|
||||
}
|
||||
max = Integer.parseInt(args[1]);
|
||||
} else if (args.length != 1) {
|
||||
showInfo(); return;
|
||||
}
|
||||
if (max == 0) {
|
||||
max = 1;
|
||||
} else if (max <0) {
|
||||
max = -max;
|
||||
mc = true;
|
||||
}
|
||||
new HTTPTunnel(null, max, mc, Integer.parseInt(args[0]), host, port);
|
||||
String host = "127.0.0.1";
|
||||
int port = 7654, max = 1;
|
||||
boolean throwAwayManagers = false;
|
||||
if (args.length > 1) {
|
||||
if (args.length == 4) {
|
||||
host = args[2];
|
||||
port = Integer.parseInt(args[3]);
|
||||
} else if (args.length != 2) {
|
||||
showInfo();
|
||||
return;
|
||||
}
|
||||
max = Integer.parseInt(args[1]);
|
||||
} else if (args.length != 1) {
|
||||
showInfo();
|
||||
return;
|
||||
}
|
||||
if (max == 0) {
|
||||
max = 1;
|
||||
} else if (max < 0) {
|
||||
max = -max;
|
||||
throwAwayManagers = true;
|
||||
}
|
||||
new HTTPTunnel(null, max, throwAwayManagers, Integer.parseInt(args[0]), host, port);
|
||||
}
|
||||
|
||||
|
||||
private static void showInfo() {
|
||||
System.out.println
|
||||
("Usage: java HTTPTunnel <listenPort> [<max> "+
|
||||
"[<i2cphost> <i2cpport>]]\n"+
|
||||
" <listenPort> port to listen for browsers\n"+
|
||||
" <max> max number of SocketMangers in pool, "+
|
||||
"use neg. number\n"+
|
||||
" to use each SocketManager only once "+
|
||||
"(default: 1)\n"+
|
||||
" <i2cphost> host to connect to the router "+
|
||||
"(default: 127.0.0.1)\n"+
|
||||
" <i2cpport> port to connect to the router "+
|
||||
"(default: 7654)");
|
||||
System.out.println("Usage: java HTTPTunnel <listenPort> [<max> " + "[<i2cphost> <i2cpport>]]\n"
|
||||
+ " <listenPort> port to listen for browsers\n"
|
||||
+ " <max> max number of SocketMangers in pool, " + "use neg. number\n"
|
||||
+ " to use each SocketManager only once " + "(default: 1)\n"
|
||||
+ " <i2cphost> host to connect to the router " + "(default: 127.0.0.1)\n"
|
||||
+ " <i2cpport> port to connect to the router " + "(default: 7654)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,109 +22,132 @@ public class Request {
|
||||
private String proto;
|
||||
private String params;
|
||||
private String postData;
|
||||
|
||||
|
||||
/**
|
||||
* A constructor, creating a request from an InputStream
|
||||
* @param in InputStream from which we "read-in" a Request
|
||||
* @throws IOException
|
||||
*/
|
||||
public Request(InputStream in) throws IOException {
|
||||
BufferedReader br = new BufferedReader
|
||||
(new InputStreamReader(in, "ISO-8859-1"));
|
||||
String line = br.readLine();
|
||||
if (line == null) { // no data at all
|
||||
method = null;
|
||||
_log.error("Connection but no data");
|
||||
return;
|
||||
}
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) {
|
||||
method = line;
|
||||
url="";
|
||||
_log.error("Malformed HTTP request: "+line);
|
||||
} else {
|
||||
method = line.substring(0,pos);
|
||||
url=line.substring(pos+1);
|
||||
}
|
||||
proto="";
|
||||
pos = url.indexOf(" ");
|
||||
if (pos != -1) {
|
||||
proto=url.substring(pos); // leading space intended
|
||||
url = url.substring(0,pos);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
while((line=br.readLine()) != null) {
|
||||
if (line.length() == 0) break;
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
params = sb.toString(); // no leading empty line!
|
||||
sb = new StringBuffer();
|
||||
// hack for POST requests, ripped from HttpClient
|
||||
// this won't work for large POSTDATA
|
||||
// FIXME: do this better, please.
|
||||
if (!method.equals("GET")) {
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i=br.read();
|
||||
if (i != -1) {
|
||||
sb.append((char)i);
|
||||
}
|
||||
}
|
||||
postData = sb.toString();
|
||||
} else {
|
||||
postData="";
|
||||
}
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in, "ISO-8859-1"));
|
||||
String line = br.readLine();
|
||||
if (line == null) { // no data at all
|
||||
method = null;
|
||||
_log.error("Connection but no data");
|
||||
return;
|
||||
}
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) {
|
||||
method = line;
|
||||
url = "";
|
||||
_log.error("Malformed HTTP request: " + line);
|
||||
} else {
|
||||
method = line.substring(0, pos);
|
||||
url = line.substring(pos + 1);
|
||||
}
|
||||
proto = "";
|
||||
pos = url.indexOf(" ");
|
||||
if (pos != -1) {
|
||||
proto = url.substring(pos); // leading space intended
|
||||
url = url.substring(0, pos);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.length() == 0) break;
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
params = sb.toString(); // no leading empty line!
|
||||
sb = new StringBuffer();
|
||||
// hack for POST requests, ripped from HttpClient
|
||||
// this won't work for large POSTDATA
|
||||
// FIXME: do this better, please.
|
||||
if (!method.equals("GET")) {
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i = br.read();
|
||||
if (i != -1) {
|
||||
sb.append((char) i);
|
||||
}
|
||||
}
|
||||
postData = sb.toString();
|
||||
} else {
|
||||
postData = "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A Request as an array of bytes of a String in ISO-8859-1 format
|
||||
* @throws IOException
|
||||
*/
|
||||
public byte[] toByteArray() throws IOException {
|
||||
if (method == null) return null;
|
||||
return toISO8859_1String().getBytes("ISO-8859-1");
|
||||
if (method == null) return null;
|
||||
return toISO8859_1String().getBytes("ISO-8859-1");
|
||||
|
||||
}
|
||||
|
||||
private String toISO8859_1String() throws IOException {
|
||||
if (method == null) return null;
|
||||
return method+" "+url+proto+"\r\n"+params+"\r\n"+postData;
|
||||
if (method == null) return null;
|
||||
return method + " " + url + proto + "\r\n" + params + "\r\n" + postData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the URL of the request
|
||||
*/
|
||||
public String getURL() {
|
||||
return url;
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL of the Request
|
||||
* @param newURL the new URL
|
||||
*/
|
||||
public void setURL(String newURL) {
|
||||
url=newURL;
|
||||
url = newURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a param.
|
||||
* @param name The name of the param
|
||||
* @return The value of the param, or null
|
||||
*/
|
||||
public String getParam(String name) {
|
||||
try {
|
||||
BufferedReader br= new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
return line.substring(name.length());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) { return line.substring(name.length()); }
|
||||
}
|
||||
return null;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a param.
|
||||
* @param name the name of the param
|
||||
* @param value the value to be set
|
||||
*/
|
||||
public void setParam(String name, String value) {
|
||||
try {
|
||||
StringBuffer sb = new StringBuffer(params.length()+value.length());
|
||||
BufferedReader br= new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
boolean replaced = false;
|
||||
while((line=br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
replaced=true;
|
||||
if (value == null) continue; // kill param
|
||||
line = name+value;
|
||||
}
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
if (!replaced && value != null) {
|
||||
sb.append(name).append(value).append("\r\n");
|
||||
}
|
||||
params=sb.toString();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
}
|
||||
try {
|
||||
StringBuffer sb = new StringBuffer(params.length() + value.length());
|
||||
BufferedReader br = new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
boolean replaced = false;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
replaced = true;
|
||||
if (value == null) continue; // kill param
|
||||
line = name + value;
|
||||
}
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
if (!replaced && value != null) {
|
||||
sb.append(name).append(value).append("\r\n");
|
||||
}
|
||||
params = sb.toString();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.client.streaming.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
|
||||
/**
|
||||
* Produces SocketManagers in a thread and gives them to those who
|
||||
@@ -14,57 +19,58 @@ public class SocketManagerProducer extends Thread {
|
||||
private int port;
|
||||
private String host;
|
||||
private int maxManagers;
|
||||
private boolean mcDonalds;
|
||||
private boolean shouldThrowAwayManagers;
|
||||
|
||||
public SocketManagerProducer(I2PSocketManager[] initialManagers,
|
||||
int maxManagers,
|
||||
boolean mcDonaldsMode,
|
||||
String host, int port) {
|
||||
if (maxManagers < 1) {
|
||||
throw new IllegalArgumentException("maxManagers < 1");
|
||||
}
|
||||
this.host=host;
|
||||
this.port=port;
|
||||
mcDonalds=mcDonaldsMode;
|
||||
if (initialManagers != null) {
|
||||
myManagers.addAll(Arrays.asList(initialManagers));
|
||||
}
|
||||
this.maxManagers=maxManagers;
|
||||
mcDonalds=mcDonaldsMode;
|
||||
setDaemon(true);
|
||||
start();
|
||||
/**
|
||||
* Public constructor creating a SocketManagerProducer
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param shouldThrowAwayManagers whether to throw away a manager after use
|
||||
* @param host which host to listen on
|
||||
* @param port which port to listen on
|
||||
*/
|
||||
public SocketManagerProducer(I2PSocketManager[] initialManagers, int maxManagers, boolean shouldThrowAwayManagers,
|
||||
String host, int port) {
|
||||
if (maxManagers < 1) { throw new IllegalArgumentException("maxManagers < 1"); }
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.shouldThrowAwayManagers = shouldThrowAwayManagers;
|
||||
if (initialManagers != null) {
|
||||
myManagers.addAll(Arrays.asList(initialManagers));
|
||||
}
|
||||
this.maxManagers = maxManagers;
|
||||
this.shouldThrowAwayManagers = shouldThrowAwayManagers;
|
||||
setDaemon(true);
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread producing new SocketManagers.
|
||||
*/
|
||||
public void run() {
|
||||
while (true) {
|
||||
synchronized(this) {
|
||||
// without mcDonalds mode, we most probably need no
|
||||
// new managers.
|
||||
while (!mcDonalds && myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
}
|
||||
// produce a new manager, regardless whether it is needed
|
||||
// or not. Do not synchronized this part, since it can be
|
||||
// quite time-consuming.
|
||||
I2PSocketManager newManager =
|
||||
I2PSocketManagerFactory.createManager(host, port,
|
||||
new Properties());
|
||||
// when done, check if it is needed.
|
||||
synchronized(this) {
|
||||
while(myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
myManagers.add(newManager);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
// without mcDonalds mode, we most probably need no
|
||||
// new managers.
|
||||
while (!shouldThrowAwayManagers && myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
}
|
||||
// produce a new manager, regardless whether it is needed
|
||||
// or not. Do not synchronized this part, since it can be
|
||||
// quite time-consuming.
|
||||
I2PSocketManager newManager = I2PSocketManagerFactory.createManager(host, port, new Properties());
|
||||
// when done, check if it is needed.
|
||||
synchronized (this) {
|
||||
while (myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
myManagers.add(newManager);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a manager for connecting to a given destination. Each
|
||||
* destination will always get the same manager.
|
||||
@@ -73,12 +79,12 @@ public class SocketManagerProducer extends Thread {
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager(String dest) {
|
||||
I2PSocketManager result = (I2PSocketManager) usedManagers.get(dest);
|
||||
if (result == null) {
|
||||
result = getManager();
|
||||
usedManagers.put(dest,result);
|
||||
}
|
||||
return result;
|
||||
I2PSocketManager result = (I2PSocketManager) usedManagers.get(dest);
|
||||
if (result == null) {
|
||||
result = getManager();
|
||||
usedManagers.put(dest, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,23 +95,26 @@ public class SocketManagerProducer extends Thread {
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager() {
|
||||
while (myManagers.size() == 0) {
|
||||
myWait(); // no manager here, so wait until one is produced
|
||||
}
|
||||
int which = (int)(Math.random()*myManagers.size());
|
||||
I2PSocketManager result = (I2PSocketManager) myManagers.get(which);
|
||||
if (mcDonalds) {
|
||||
myManagers.remove(which);
|
||||
notifyAll();
|
||||
}
|
||||
return result;
|
||||
while (myManagers.size() == 0) {
|
||||
myWait(); // no manager here, so wait until one is produced
|
||||
}
|
||||
int which = (int) (Math.random() * myManagers.size());
|
||||
I2PSocketManager result = (I2PSocketManager) myManagers.get(which);
|
||||
if (shouldThrowAwayManagers) {
|
||||
myManagers.remove(which);
|
||||
notifyAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until InterruptedException
|
||||
*/
|
||||
public void myWait() {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Chain multiple filters. Decorator pattern...
|
||||
@@ -11,40 +13,49 @@ import java.util.*;
|
||||
public class ChainFilter implements Filter {
|
||||
|
||||
private static final Log _log = new Log(ChainFilter.class);
|
||||
|
||||
public Collection filters;
|
||||
|
||||
|
||||
private Collection filters; // perhaps protected?
|
||||
|
||||
/**
|
||||
* @param filters A collection (list) of filters to chain to
|
||||
*/
|
||||
public ChainFilter(Collection filters) {
|
||||
this.filters=filters;
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#filter(byte[])
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
byte[] buf = toFilter;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
buf = f.filter(buf);
|
||||
}
|
||||
return buf;
|
||||
byte[] buf = toFilter;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
buf = f.filter(buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#finish()
|
||||
*/
|
||||
public byte[] finish() {
|
||||
// this is a bit complicated. Think about it...
|
||||
try {
|
||||
byte[] buf = EMPTY;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (buf.length != 0) {
|
||||
baos.write(f.filter(buf));
|
||||
}
|
||||
baos.write(f.finish());
|
||||
buf = baos.toByteArray();
|
||||
}
|
||||
return buf;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error chaining filters", ex);
|
||||
return EMPTY;
|
||||
}
|
||||
// this is a bit complicated. Think about it...
|
||||
try {
|
||||
byte[] buf = EMPTY;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (buf.length != 0) {
|
||||
baos.write(f.filter(buf));
|
||||
}
|
||||
baos.write(f.finish());
|
||||
buf = baos.toByteArray();
|
||||
}
|
||||
return buf;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error chaining filters", ex);
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,11 +12,14 @@ public interface Filter {
|
||||
|
||||
/**
|
||||
* Filter some data. Not all filtered data need to be returned.
|
||||
* @param toFilter the bytes that are to be filtered.
|
||||
* @return the filtered data
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter);
|
||||
|
||||
/**
|
||||
* Data stream has finished. Return all of the rest data.
|
||||
* @return the rest of the data
|
||||
*/
|
||||
public byte[] finish();
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,17 @@ package net.i2p.httptunnel.filter;
|
||||
*/
|
||||
public class NullFilter implements Filter {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#filter(byte[])
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
return toFilter;
|
||||
return toFilter;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see net.i2p.httptunnel.filter.Filter#finish()
|
||||
*/
|
||||
public byte[] finish() {
|
||||
return EMPTY;
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
@@ -24,70 +26,88 @@ import net.i2p.util.Log;
|
||||
public class EepHandler {
|
||||
|
||||
private static final Log _log = new Log(EepHandler.class);
|
||||
private static I2PAppContext _context = new I2PAppContext();
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
/* package private */ EepHandler(ErrorHandler eh) {
|
||||
errorHandler=eh;
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy, String destination)
|
||||
throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = NamingService.getInstance().lookup(destination);
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"Could not lookup host: "+destination);
|
||||
return;
|
||||
}
|
||||
I2PSocketManager sm = smp.getManager(destination);
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
req.setParam("Host: ", dest.toBase64());
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
|
||||
/* package private */EepHandler(ErrorHandler eh) {
|
||||
errorHandler = eh;
|
||||
}
|
||||
|
||||
public boolean handle(Request req, Filter f, OutputStream out,
|
||||
Destination dest, I2PSocketManager sm)
|
||||
throws IOException {
|
||||
I2PSocket s = null;
|
||||
boolean written = false;
|
||||
try {
|
||||
synchronized(sm) {
|
||||
s = sm.connect(dest, new I2PSocketOptions());
|
||||
}
|
||||
InputStream in = new BufferedInputStream(s.getInputStream());
|
||||
OutputStream sout = new BufferedOutputStream(s.getOutputStream());
|
||||
sout.write(req.toByteArray());
|
||||
sout.flush();
|
||||
byte[] buffer = new byte[16384], filtered;
|
||||
int len;
|
||||
while ((len=in.read(buffer)) != -1) {
|
||||
if (len != buffer.length) {
|
||||
byte[] b2 = new byte[len];
|
||||
System.arraycopy(buffer, 0, b2, 0, len);
|
||||
filtered=f.filter(b2);
|
||||
} else {
|
||||
filtered=f.filter(buffer);
|
||||
}
|
||||
written=true;
|
||||
out.write(filtered);
|
||||
}
|
||||
filtered=f.finish();
|
||||
written=true;
|
||||
out.write(filtered);
|
||||
out.flush();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} finally {
|
||||
if (s != null) s.close();
|
||||
}
|
||||
return true;
|
||||
/**
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @param destination destination as a string, (subject to naming
|
||||
* service lookup)
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
/* boolean fromProxy, */String destination) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = _context.namingService().lookup(destination);
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination);
|
||||
return;
|
||||
}
|
||||
I2PSocketManager sm = smp.getManager(destination);
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
req.setParam("Host: ", dest.toBase64());
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param req the Request to send out
|
||||
* @param f a Filter to apply to the bytes retrieved from the Destination
|
||||
* @param out where to write the results
|
||||
* @param dest the Destination of the Request
|
||||
* @param sm an I2PSocketManager, to get a socket for the Destination
|
||||
* @return boolean, true if something was written, false otherwise.
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean handle(Request req, Filter f, OutputStream out, Destination dest,
|
||||
I2PSocketManager sm) throws IOException {
|
||||
I2PSocket s = null;
|
||||
boolean written = false;
|
||||
try {
|
||||
synchronized (sm) {
|
||||
s = sm.connect(dest, new I2PSocketOptions());
|
||||
}
|
||||
InputStream in = new BufferedInputStream(s.getInputStream());
|
||||
OutputStream sout = new BufferedOutputStream(s.getOutputStream());
|
||||
sout.write(req.toByteArray());
|
||||
sout.flush();
|
||||
byte[] buffer = new byte[16384], filtered;
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
if (len != buffer.length) {
|
||||
byte[] b2 = new byte[len];
|
||||
System.arraycopy(buffer, 0, b2, 0, len);
|
||||
filtered = f.filter(b2);
|
||||
} else {
|
||||
filtered = f.filter(buffer);
|
||||
}
|
||||
written = true;
|
||||
out.write(filtered);
|
||||
}
|
||||
filtered = f.finish();
|
||||
written = true;
|
||||
out.write(filtered);
|
||||
out.flush();
|
||||
} catch (SocketException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} finally {
|
||||
if (s != null) s.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -11,26 +12,30 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class ErrorHandler {
|
||||
|
||||
private static final Log _log = new Log(ErrorHandler.class);
|
||||
private static final Log _log = new Log(ErrorHandler.class); /* UNUSED */
|
||||
|
||||
/* package private */ ErrorHandler() {
|
||||
/* package private */ErrorHandler() {
|
||||
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl,
|
||||
OutputStream out, String error) throws IOException {
|
||||
// FIXME: Make nicer messages for more likely errors.
|
||||
out.write(("HTTP/1.1 500 Internal Server Error\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.write(("<html><head><title>"+error+"</title></head><body><h1>"+
|
||||
error+"</h1>An internal error occurred while "+
|
||||
"handling a request by HTTPTunnel:<br><b>"+error+
|
||||
"</b><h2>Complete request:</h2><b>---</b><br><i><pre>\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.write(req.toByteArray());
|
||||
out.write(("</pre></i><br><b>---</b></body></html>")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
|
||||
/**
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @param error the error that happened
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out, String error) throws IOException {
|
||||
// FIXME: Make nicer messages for more likely errors.
|
||||
out
|
||||
.write(("HTTP/1.1 500 Internal Server Error\r\n" + "Content-Type: text/html; charset=iso-8859-1\r\n\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out
|
||||
.write(("<html><head><title>" + error + "</title></head><body><h1>" + error
|
||||
+ "</h1>An internal error occurred while " + "handling a request by HTTPTunnel:<br><b>" + error + "</b><h2>Complete request:</h2><b>---</b><br><i><pre>\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.write(req.toByteArray());
|
||||
out.write(("</pre></i><br><b>---</b></body></html>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -12,38 +13,55 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class LocalHandler {
|
||||
|
||||
private static final Log _log = new Log(LocalHandler.class);
|
||||
private static final Log _log = new Log(LocalHandler.class); /* UNUSED */
|
||||
|
||||
/* package private */ LocalHandler() {
|
||||
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy) throws IOException {
|
||||
//FIXME: separate multiple pages, not only a start page
|
||||
//FIXME: provide some info on this page
|
||||
out.write(("HTTP/1.1 200 Document following\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"+
|
||||
"<html><head><title>Welcome to I2P HTTPTunnel</title>"+
|
||||
"</head><body><h1>Welcome to I2P HTTPTunnel</h1>You can "+
|
||||
"browse Eepsites by adding an eepsite name to the request."+
|
||||
"</body></html>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
/* package private */LocalHandler() {
|
||||
}
|
||||
|
||||
public void handleProxyConfWarning(Request req, HTTPListener httpl,
|
||||
OutputStream out) throws IOException {
|
||||
//FIXME
|
||||
/**
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out
|
||||
/*, boolean fromProxy */) throws IOException {
|
||||
//FIXME: separate multiple pages, not only a start page
|
||||
//FIXME: provide some info on this page
|
||||
out
|
||||
.write(("HTTP/1.1 200 Document following\r\n" + "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
|
||||
+ "<html><head><title>Welcome to I2P HTTPTunnel</title>"
|
||||
+ "</head><body><h1>Welcome to I2P HTTPTunnel</h1>You can "
|
||||
+ "browse Eepsites by adding an eepsite name to the request." + "</body></html>")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently always throws an IO Exception
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handleProxyConfWarning(Request req, HTTPListener httpl, OutputStream out) throws IOException {
|
||||
//FIXME
|
||||
throw new IOException("jrandom ate the deprecated method. mooo");
|
||||
//httpl.handleNotImplemented(out);
|
||||
//httpl.handleNotImplemented(out);
|
||||
|
||||
}
|
||||
|
||||
public void handleHTTPWarning(Request req, HTTPListener httpl,
|
||||
OutputStream out, boolean fromProxy)
|
||||
throws IOException {
|
||||
// FIXME
|
||||
/**
|
||||
* Currently always throws an IO Exception
|
||||
* @param req the Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handleHTTPWarning(Request req, HTTPListener httpl, OutputStream out /*, boolean fromProxy */)
|
||||
throws IOException {
|
||||
// FIXME
|
||||
throw new IOException("jrandom ate the deprecated method. mooo");
|
||||
//httpl.handleNotImplemented(out);
|
||||
//httpl.handleNotImplemented(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
@@ -17,31 +18,37 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class ProxyHandler extends EepHandler {
|
||||
|
||||
private static final Log _log = new Log(ErrorHandler.class);
|
||||
private static final Log _log = new Log(ErrorHandler.class); /* UNUSED */
|
||||
private static I2PAppContext _context = new I2PAppContext();
|
||||
|
||||
/* package private */ ProxyHandler(ErrorHandler eh) {
|
||||
super(eh);
|
||||
/* package private */ProxyHandler(ErrorHandler eh) {
|
||||
super(eh);
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = findProxy();
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"Could not find proxy");
|
||||
return;
|
||||
}
|
||||
// one manager for all proxy requests
|
||||
I2PSocketManager sm = smp.getManager("--proxy--");
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param req a Request
|
||||
* @param httpl an HTTPListener
|
||||
* @param out where to write the results
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out
|
||||
/*, boolean fromProxy */) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = findProxy();
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out, "Could not find proxy");
|
||||
return;
|
||||
}
|
||||
// one manager for all proxy requests
|
||||
I2PSocketManager sm = smp.getManager("--proxy--");
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
}
|
||||
|
||||
private Destination findProxy() {
|
||||
//FIXME!
|
||||
return NamingService.getInstance().lookup("squid.i2p");
|
||||
//FIXME!
|
||||
return _context.namingService().lookup("squid.i2p");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user