Compare commits
2549 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fa7a48163 | ||
|
|
8adf76dcc9 | ||
|
|
15899c10b2 | ||
|
|
05ff05ea4b | ||
|
|
bd62df48c2 | ||
|
|
2366cbc833 | ||
|
|
25fb609544 | ||
|
|
af793395f0 | ||
|
|
8f41776858 | ||
|
|
139b13b8d1 | ||
|
|
4c611a5be1 | ||
|
|
5e7a21e177 | ||
|
|
5f7dda5ba8 | ||
|
|
2dfa1ca0f2 | ||
|
|
358cdcf4c4 | ||
|
|
c8f4ace5c4 | ||
|
|
5cac6ca8bb | ||
|
|
fccad71df1 | ||
|
|
97ae2674dc | ||
|
|
7c70affd7f | ||
|
|
52ff568d86 | ||
|
|
b917aeaa0b | ||
|
|
8de443ec4c | ||
|
|
7d9893c614 | ||
|
|
3540712517 | ||
|
|
a8b1a86bd7 | ||
|
|
1babd3a5a2 | ||
|
|
50399e5194 | ||
|
|
b734acf1b1 | ||
|
|
33aa8e2471 | ||
|
|
2c58fe736b | ||
|
|
6fe1de5d86 | ||
|
|
064460b95f | ||
|
|
2c3b19a539 | ||
|
|
dc30a4c1ae | ||
|
|
86e9901bf2 | ||
|
|
6519e0835a | ||
|
|
a52344fc01 | ||
|
|
b67424643d | ||
|
|
575a4c01c9 | ||
|
|
f0d4ee6618 | ||
|
|
8753186a0d | ||
|
|
ff8fb8000d | ||
|
|
9dd38b99d6 | ||
|
|
dfe08c1ec9 | ||
|
|
062d8d0f4f | ||
|
|
c0d1e2c07a | ||
|
|
e70feceafe | ||
|
|
71ac0286b1 | ||
|
|
022f4d2c11 | ||
|
|
a83a839cff | ||
|
|
b259ee89aa | ||
|
|
65cf14bfce | ||
|
|
d9476fb5ca | ||
|
|
9882365ab4 | ||
|
|
2d758ce963 | ||
|
|
1dd003d26a | ||
|
|
0df5b77595 | ||
|
|
e190a005db | ||
|
|
45596a0342 | ||
|
|
405429a300 | ||
|
|
d009a29426 | ||
|
|
f1fb42460a | ||
|
|
5e110e9f7b | ||
|
|
77a409935d | ||
|
|
863baeb68b | ||
|
|
11142690a0 | ||
|
|
02e8c5faca | ||
|
|
c41081d35c | ||
|
|
db4c26a400 | ||
|
|
331a23fc20 | ||
|
|
db5a40d743 | ||
|
|
e4ab51329d | ||
|
|
86782aeb1b | ||
|
|
49a44fc92e | ||
|
|
cd39a52c25 | ||
|
|
634101ceb5 | ||
|
|
55555c8787 | ||
|
|
d36d825ac1 | ||
|
|
9bb01cd67c | ||
|
|
29b91075d2 | ||
|
|
6d46fc9f9f | ||
|
|
a2c41c9e36 | ||
|
|
ee700ac861 | ||
|
|
9884a4336f | ||
|
|
5b83d4bef8 | ||
|
|
d320a89590 | ||
|
|
f7e4afc282 | ||
|
|
88e87d589b | ||
|
|
d8c6dede7e | ||
|
|
5cc84133e3 | ||
|
|
f7728aa1f6 | ||
|
|
2b61f9a731 | ||
|
|
f407022fe6 | ||
|
|
41b9f19b01 | ||
|
|
09c6faf923 | ||
|
|
26d0177c01 | ||
|
|
f7415c8a8f | ||
|
|
4cf79088f9 | ||
|
|
50cd321818 | ||
|
|
83bbe6a9d9 | ||
|
|
0a33c18e36 | ||
|
|
6cf158ac63 | ||
|
|
f96bfa6afa | ||
|
|
2b64cf9126 | ||
|
|
a8dcfc44f5 | ||
|
|
0ff9c9da27 | ||
|
|
07e7c2d852 | ||
|
|
10e4b5b2a3 | ||
|
|
998653ea9d | ||
|
|
1a38e925bf | ||
|
|
c8f51380e6 | ||
|
|
2406d57d51 | ||
|
|
cb1e47eb71 | ||
|
|
c0a650f28b | ||
|
|
460cf6fd20 | ||
|
|
5bedfc1c84 | ||
|
|
5001592fb4 | ||
|
|
f6495e59c5 | ||
|
|
66bf431481 | ||
|
|
d9685e991e | ||
|
|
e0790700cd | ||
|
|
910a9600bd | ||
|
|
fc52b2b940 | ||
|
|
b99f828583 | ||
|
|
f38891cace | ||
|
|
8c5111e11a | ||
|
|
5575b981c8 | ||
|
|
0b36732911 | ||
|
|
52f3081a40 | ||
|
|
00c71dc26a | ||
|
|
5218c8584f | ||
|
|
6054bd6621 | ||
|
|
55af4ed385 | ||
|
|
64aee9c8ae | ||
|
|
5233e72205 | ||
|
|
db5b45222a | ||
|
|
fc4787da4e | ||
|
|
4ffbb46cf9 | ||
|
|
c3c2550f17 | ||
|
|
41e8ab5383 | ||
|
|
a802940616 | ||
|
|
dec848f072 | ||
|
|
fc16e76af1 | ||
|
|
0dff636dbe | ||
|
|
00df3f8d4e | ||
|
|
34c45f2694 | ||
|
|
a188de2e5c | ||
|
|
27fbf67352 | ||
|
|
b226e22d2f | ||
|
|
5bc157eb19 | ||
|
|
f4122abbad | ||
|
|
f0b32e3f54 | ||
|
|
fe00999b2c | ||
|
|
39eed0f6fb | ||
|
|
510d29b381 | ||
|
|
0aa618b938 | ||
|
|
5884852612 | ||
|
|
5b29592174 | ||
|
|
96411cc93e | ||
|
|
7d862d8eba | ||
|
|
dd392941d0 | ||
|
|
3cec5235c9 | ||
|
|
b5682012d3 | ||
|
|
4351a2736c | ||
|
|
9c7cadb191 | ||
|
|
4d9143734f | ||
|
|
3cec923294 | ||
|
|
58c92b8405 | ||
|
|
985b618932 | ||
|
|
a027a42c46 | ||
|
|
bdc7acffbe | ||
|
|
6bd73cdea2 | ||
|
|
59954c1d7c | ||
|
|
a59cdcc9e0 | ||
|
|
e1bfa786fc | ||
|
|
d5214099c5 | ||
|
|
e05110ff44 | ||
|
|
706b976a28 | ||
|
|
2bd7a92d20 | ||
|
|
6b37a41e00 | ||
|
|
5447259e1a | ||
|
|
ee0ae0b74b | ||
|
|
966256ac32 | ||
|
|
6b9061515f | ||
|
|
df60e78766 | ||
|
|
bf1e1ad457 | ||
|
|
7fa5b06359 | ||
|
|
3b46e9f351 | ||
|
|
046a80cfe4 | ||
|
|
a8278fc78b | ||
|
|
7f3127ac89 | ||
|
|
7cdb021a1f | ||
|
|
74c0b729c2 | ||
|
|
5cb81f8532 | ||
|
|
4f23d7b7df | ||
|
|
a70d0edf2e | ||
|
|
8c9eaccc11 | ||
|
|
86c1984982 | ||
|
|
cd0f75106a | ||
|
|
b5291b5151 | ||
|
|
46283dc0ea | ||
|
|
56e76ec59f | ||
|
|
4cedaa9e80 | ||
|
|
516f140bef | ||
|
|
5d86c1c9a6 | ||
|
|
d289aa71eb | ||
|
|
ed2818eaa2 | ||
|
|
f8fe124428 | ||
|
|
5ec11c53e9 | ||
|
|
42d118d9a2 | ||
|
|
d8b4765f23 | ||
|
|
be69280d0d | ||
|
|
53a1a097a6 | ||
|
|
a22e9a2ca7 | ||
|
|
db03595473 | ||
|
|
8fadac0fdc | ||
|
|
a63bc1cdca | ||
|
|
6265d452e9 | ||
|
|
b095399770 | ||
|
|
db8a546b8f | ||
|
|
6e95318cba | ||
|
|
08a8ab9892 | ||
|
|
c7b796ff31 | ||
|
|
ad23ccb219 | ||
|
|
be7a84fdf3 | ||
|
|
2fbbbf298b | ||
|
|
0df68872ab | ||
|
|
0ced38cdcb | ||
|
|
b046c45a9e | ||
|
|
2ce1ab1634 | ||
|
|
7225231814 | ||
|
|
11dca2b352 | ||
|
|
97127e86dc | ||
|
|
cb81195959 | ||
|
|
adaff9f354 | ||
|
|
66de7ad049 | ||
|
|
1e1e4da144 | ||
|
|
623433099b | ||
|
|
73b3fbc2da | ||
|
|
5f525d0e43 | ||
|
|
60463fdafa | ||
|
|
b7a67b4b03 | ||
|
|
4643c92d33 | ||
|
|
396cba7339 | ||
|
|
a2b3ee53e0 | ||
|
|
2c67d2055c | ||
|
|
c8de7aa23c | ||
|
|
fa154cc4d6 | ||
|
|
d9b8731ddc | ||
|
|
6cebc1a2a2 | ||
|
|
faac35cd1e | ||
|
|
6916147dda | ||
|
|
e2da16e9c3 | ||
|
|
0c661e7373 | ||
|
|
413f8e8462 | ||
|
|
eefbbd4efe | ||
|
|
83932a6f02 | ||
|
|
c175dc30f8 | ||
|
|
17aa91803a | ||
|
|
48099a367e | ||
|
|
a9b64893d8 | ||
|
|
387e030d83 | ||
|
|
855cc9ed83 | ||
|
|
82534eef12 | ||
|
|
ff4e254618 | ||
|
|
571a13f0a7 | ||
|
|
2cb6283d00 | ||
|
|
f4056e57bb | ||
|
|
e80da3cbeb | ||
|
|
c0436297c2 | ||
|
|
0d05b4f095 | ||
|
|
f06c8710be | ||
|
|
f11266972e | ||
|
|
479edaf80d | ||
|
|
ff5c26adf2 | ||
|
|
5361e11395 | ||
|
|
b041bcdc65 | ||
|
|
b7c350202d | ||
|
|
b1a6c5ddf7 | ||
|
|
ac943b5712 | ||
|
|
ce8d701ecb | ||
|
|
182ffe4495 | ||
|
|
c13983d395 | ||
|
|
066f8863fd | ||
|
|
e58aaa3f32 | ||
|
|
ca1fa11cb1 | ||
|
|
64ed485cdf | ||
|
|
b0781668e2 | ||
|
|
f9fc744949 | ||
|
|
2661db23f6 | ||
|
|
7d78f60d29 | ||
|
|
1d934bd543 | ||
|
|
190435acd9 | ||
|
|
656236cb4d | ||
|
|
6d15be9a32 | ||
|
|
18d3c81018 | ||
|
|
12292afdec | ||
|
|
aef0f4d7b8 | ||
|
|
21545ab7da | ||
|
|
5a2b795440 | ||
|
|
1303dd478c | ||
|
|
7b4fc19fca | ||
|
|
008a064764 | ||
|
|
82a4630061 | ||
|
|
0f77b4810d | ||
|
|
2f7cfddfc4 | ||
|
|
84608c16b3 | ||
|
|
157411dcc6 | ||
|
|
59672d23cc | ||
|
|
ce30f89c60 | ||
|
|
ce9c9411b1 | ||
|
|
cf0d5b616d | ||
|
|
29e861d1e6 | ||
|
|
c7accd4a5c | ||
|
|
b469080cd7 | ||
|
|
547a0057e6 | ||
|
|
b980ca4a9e | ||
|
|
098b2e968e | ||
|
|
cd59ca8376 | ||
|
|
f2e6fad104 | ||
|
|
8d7fde0287 | ||
|
|
91fdb038d9 | ||
|
|
a0188765c5 | ||
|
|
b970a005de | ||
|
|
b64878f4fa | ||
|
|
c8936c79bf | ||
|
|
f876cc9079 | ||
|
|
a5cc2f3b5d | ||
|
|
9c93d6f931 | ||
|
|
a077d7671f | ||
|
|
6485ebe9a7 | ||
|
|
ecb6bb220a | ||
|
|
e3dc400d74 | ||
|
|
3bb4151074 | ||
|
|
1de4c2e8c6 | ||
|
|
fbcc4f28e7 | ||
|
|
30fb0f5a94 | ||
|
|
b02464990b | ||
|
|
4988a32d33 | ||
|
|
b3e5874631 | ||
|
|
f5349dcef9 | ||
|
|
486a4cfdd6 | ||
|
|
2277dcb069 | ||
|
|
a618a01b1e | ||
|
|
7e60069968 | ||
|
|
91e45d9a4a | ||
|
|
dea6fbf285 | ||
|
|
48cc0f4289 | ||
|
|
cdc5fce583 | ||
|
|
b41a17d548 | ||
|
|
606cbaa519 | ||
|
|
aaf8f527ef | ||
|
|
b7596b7f70 | ||
|
|
0309b574e8 | ||
|
|
ca057177c7 | ||
|
|
5d9bf18267 | ||
|
|
f1b8742782 | ||
|
|
7786c97330 | ||
|
|
f2a14047eb | ||
|
|
124a9cb030 | ||
|
|
3ec000d0f8 | ||
|
|
aac1141ca6 | ||
|
|
33cb96126a | ||
|
|
441db9ad7f | ||
|
|
5225e1d7d1 | ||
|
|
de849b3f6a | ||
|
|
fb4387c41f | ||
|
|
a9061a8f58 | ||
|
|
0c099dc52b | ||
|
|
713e92c28f | ||
|
|
d111025012 | ||
|
|
5f2e6b1262 | ||
|
|
b6d838731f | ||
|
|
56db8b40b2 | ||
|
|
f488c97a09 | ||
|
|
31df49a884 | ||
|
|
e5fdced4ac | ||
|
|
71546367cf | ||
|
|
857817dae8 | ||
|
|
ae3fca15c7 | ||
|
|
6bb7382dbd | ||
|
|
badb837b46 | ||
|
|
74f5b70a5d | ||
|
|
ac495da5fe | ||
|
|
56f6e57118 | ||
|
|
33735b343d | ||
|
|
1b56d66fc8 | ||
|
|
0994211a48 | ||
|
|
62d9a47c3d | ||
|
|
e77037c2b8 | ||
|
|
030a6ebb71 | ||
|
|
5a657cff89 | ||
|
|
f3488be7af | ||
|
|
4af0caa506 | ||
|
|
0728991821 | ||
|
|
21c35f770b | ||
|
|
f039af6eda | ||
|
|
eb3f703b46 | ||
|
|
b88b82a85c | ||
|
|
1d0791dbf5 | ||
|
|
87f2eefd35 | ||
|
|
b8a2c9f955 | ||
|
|
319d748639 | ||
|
|
4f84d687e4 | ||
|
|
fbb9991128 | ||
|
|
62bac24246 | ||
|
|
4aa8461bea | ||
|
|
ce57a130fc | ||
|
|
80567312ed | ||
|
|
180730f9cf | ||
|
|
fca2693488 | ||
|
|
b6e75e9c5a | ||
|
|
4901434209 | ||
|
|
13d174c09c | ||
|
|
5363c063d1 | ||
|
|
32d300248e | ||
|
|
3426906a4f | ||
|
|
3aaa942c94 | ||
|
|
95d8887ab0 | ||
|
|
6272e15b47 | ||
|
|
20b4f6b24d | ||
|
|
6ee279d83e | ||
|
|
b00ff43be7 | ||
|
|
dfbefee477 | ||
|
|
8c2de4973c | ||
|
|
e1527dc137 | ||
|
|
0957f6b143 | ||
|
|
7db2e9dc4a | ||
|
|
b1c701085b | ||
|
|
e8d6c803cd | ||
|
|
f4a2dda94e | ||
|
|
c4216379ed | ||
|
|
52195bf296 | ||
|
|
10fe75ed87 | ||
|
|
1c659d6ef6 | ||
|
|
3ac86db038 | ||
|
|
4a77a03033 | ||
|
|
3820b51960 | ||
|
|
e070ce4e34 | ||
|
|
0bb0adbf3e | ||
|
|
ddd25f0945 | ||
|
|
162bd592f8 | ||
|
|
85fa728d41 | ||
|
|
c7db9010ad | ||
|
|
be16545063 | ||
|
|
c730839989 | ||
|
|
4ee364640d | ||
|
|
56dd0db001 | ||
|
|
626ed720a6 | ||
|
|
b8fd9ba83f | ||
|
|
316a4457af | ||
|
|
347a2c2150 | ||
|
|
42d3770b14 | ||
|
|
39ca07bcc6 | ||
|
|
df304fb38b | ||
|
|
914566ece0 | ||
|
|
f537e7b2c6 | ||
|
|
06020b8f54 | ||
|
|
b486d1cd27 | ||
|
|
b3b38015c2 | ||
|
|
4c6988e3bc | ||
|
|
0bd4db4cc7 | ||
|
|
bc72800fef | ||
|
|
951f8972c7 | ||
|
|
38b694a055 | ||
|
|
44a9c3ca0c | ||
|
|
6bf823fb15 | ||
|
|
43a751ee0b | ||
|
|
207212557e | ||
|
|
fd1aeeac92 | ||
|
|
50ba52756f | ||
|
|
e630b8f8a8 | ||
|
|
cf5081d300 | ||
|
|
8864cbf80a | ||
|
|
81d7a832c0 | ||
|
|
d41fabbc9f | ||
|
|
46f62e1af9 | ||
|
|
b91efaa973 | ||
|
|
e3238ff75c | ||
|
|
9cc4e8d03a | ||
|
|
68b1afa2df | ||
|
|
34c98e03c1 | ||
|
|
41e40bbc0d | ||
|
|
80149342f2 | ||
|
|
1967dee50c | ||
|
|
ab80def94b | ||
|
|
254bf313a2 | ||
|
|
938d5d901a | ||
|
|
7b00d828b2 | ||
|
|
ca49944c85 | ||
|
|
d5e9fc7677 | ||
|
|
6db7c5733d | ||
|
|
418f86ecbd | ||
|
|
c68c5af856 | ||
|
|
950dffbe06 | ||
|
|
5d557003b6 | ||
|
|
3b8c3c1346 | ||
|
|
1853263f6c | ||
|
|
b0f6d81f57 | ||
|
|
9ba0329432 | ||
|
|
614101c4b8 | ||
|
|
50e4fb138a | ||
|
|
6dba0c6e0e | ||
|
|
0f2d2156e6 | ||
|
|
13b17c5a93 | ||
|
|
511499d950 | ||
|
|
6632b71273 | ||
|
|
60ef70cee4 | ||
|
|
b3ba0a7241 | ||
|
|
fc73dabc0b | ||
|
|
1121d45eb6 | ||
|
|
18b6353803 | ||
|
|
c0c0642bd1 | ||
|
|
3cf26a84dc | ||
|
|
44d6d4405e | ||
|
|
cafa027f0b | ||
|
|
1c970b0714 | ||
|
|
6636e432d7 | ||
|
|
158889b85c | ||
|
|
92bebb7ecc | ||
|
|
fff34e77f5 | ||
|
|
df18692af9 | ||
|
|
276a78cb2e | ||
|
|
a1e820182c | ||
|
|
272090fc8f | ||
|
|
ab6bc52a0f | ||
|
|
c69c369502 | ||
|
|
a5b1b24fee | ||
|
|
40cfbc5d61 | ||
|
|
ffad1ecd6d | ||
|
|
e1b5803902 | ||
|
|
492d71a924 | ||
|
|
6d01a3a7d1 | ||
|
|
b71e20dfa3 | ||
|
|
474158dd18 | ||
|
|
914db816c2 | ||
|
|
4485d6fdf4 | ||
|
|
2c394661a6 | ||
|
|
611c1a7502 | ||
|
|
4e8858a764 | ||
|
|
fb46de5ca6 | ||
|
|
65db96e663 | ||
|
|
5109d40d8e | ||
|
|
1ba1fa37f9 | ||
|
|
9c97ee6407 | ||
|
|
7477d2c219 | ||
|
|
a6fb3b602e | ||
|
|
d9b9457b56 | ||
|
|
cfb6ddbfc6 | ||
|
|
7de21c1f93 | ||
|
|
100f3380c4 | ||
|
|
20e484bb8b | ||
|
|
94fc1a1cee | ||
|
|
ae28df5276 | ||
|
|
3a4f1382f3 | ||
|
|
01a7e08585 | ||
|
|
847fd15af2 | ||
|
|
a21fb17d73 | ||
|
|
0c34bd440b | ||
|
|
1008510750 | ||
|
|
34d6eb52d0 | ||
|
|
5820425b6c | ||
|
|
a4b39a3648 | ||
|
|
3dc5542a28 | ||
|
|
dde4643e77 | ||
|
|
7a857e08c1 | ||
|
|
80a3bd6a3b | ||
|
|
7fb8ee60b4 | ||
|
|
dca4cf2edb | ||
|
|
2bc33f22df | ||
|
|
d14c6e2829 | ||
|
|
a4ce224cd1 | ||
|
|
ab1cd3f5cf | ||
|
|
1e75de9bb8 | ||
|
|
19a03c42a5 | ||
|
|
9e5d1bf0fc | ||
|
|
c5f784719d | ||
|
|
60aa459dfc | ||
|
|
53d71d29ff | ||
|
|
81658d2ff9 | ||
|
|
9fa67b0e0a | ||
|
|
88ba494701 | ||
|
|
efacfced45 | ||
|
|
b3c836f298 | ||
|
|
3330bf4f2f | ||
|
|
e634c89995 | ||
|
|
5aa53eee43 | ||
|
|
42483b6f32 | ||
|
|
00bbb81375 | ||
|
|
5271cdacf2 | ||
|
|
6d01726961 | ||
|
|
12feac1f50 | ||
|
|
39c1c3567b | ||
|
|
63ae6850d3 | ||
|
|
bec24e052c | ||
|
|
91eb2b2c4a | ||
|
|
0bae2a3397 | ||
|
|
42ec6db746 | ||
|
|
7a9dc0eec0 | ||
|
|
6441c9d5d8 | ||
|
|
2930d39ce7 | ||
|
|
1500e805dd | ||
|
|
b14d1801f0 | ||
|
|
bc11181d5e | ||
|
|
9739e677aa | ||
|
|
056f076ae8 | ||
|
|
7dfb6f4a13 | ||
|
|
b347b719f3 | ||
|
|
7b537a4e94 | ||
|
|
291f28fcce | ||
|
|
fa9c39732d | ||
|
|
bfdf006bd2 | ||
|
|
057d6ca05b | ||
|
|
7d7f5ff4e2 | ||
|
|
6e32f4bc85 | ||
|
|
8460a8f4ef | ||
|
|
8c09a7429c | ||
|
|
346bf14b7b | ||
|
|
8e3c9410dc | ||
|
|
cb0552e20d | ||
|
|
8c8127dda6 | ||
|
|
1d8a481d59 | ||
|
|
dd4f066e95 | ||
|
|
5e0d4163a2 | ||
|
|
7fb2d13a8b | ||
|
|
acde10b46e | ||
|
|
c0bcab8bc5 | ||
|
|
fd6d0922ab | ||
|
|
8179e7dbf8 | ||
|
|
eabeeaccfe | ||
|
|
94bba69dee | ||
|
|
4d23de96d5 | ||
|
|
681810ea38 | ||
|
|
d500fe66fd | ||
|
|
05c2adeefd | ||
|
|
d46e0fb474 | ||
|
|
330fab2efa | ||
|
|
d59d36f93c | ||
|
|
fd6827fdca | ||
|
|
dca94f17d7 | ||
|
|
d4e16881ff | ||
|
|
cd3f274763 | ||
|
|
1947be4957 | ||
|
|
21de4709ea | ||
|
|
ec76381a0b | ||
|
|
66661417d7 | ||
|
|
81b79e6e53 | ||
|
|
5ae93d852e | ||
|
|
96cb663fa8 | ||
|
|
1efc2a9b5d | ||
|
|
9441c1cffe | ||
|
|
ef30d2d3b6 | ||
|
|
1673966e36 | ||
|
|
1d8f913364 | ||
|
|
a549ebc25f | ||
|
|
ce853786b5 | ||
|
|
7e0ab6d0b1 | ||
|
|
d6f907a05b | ||
|
|
b2d1962b81 | ||
|
|
b0a6c9fa53 | ||
|
|
7a0337f3db | ||
|
|
c1dbd3ffd0 | ||
|
|
1ea6d2016d | ||
|
|
416589cc93 | ||
|
|
41ce9d47e5 | ||
|
|
d7e4deab4e | ||
|
|
27782ceddd | ||
|
|
a6f62a99b9 | ||
|
|
4e4def4fb9 | ||
|
|
7af3b751d4 | ||
|
|
897cfad399 | ||
|
|
f87a51034e | ||
|
|
3f409d0e28 | ||
|
|
543566840c | ||
|
|
1c3174a277 | ||
|
|
fc2ae6f887 | ||
|
|
63e175d389 | ||
|
|
9bfbba6fea | ||
|
|
69d245c4bd | ||
|
|
7738eae4b0 | ||
|
|
3d5fb07ca8 | ||
|
|
0f0fb266c7 | ||
|
|
5c3d6298b0 | ||
|
|
028f0bdb8d | ||
|
|
44bcdc6866 | ||
|
|
b9f6f92bad | ||
|
|
1607535416 | ||
|
|
f6ced9279b | ||
|
|
95af716a96 | ||
|
|
07fe51fa25 | ||
|
|
822995cbaf | ||
|
|
db0e02c05d | ||
|
|
856dda68db | ||
|
|
163cbcb89d | ||
|
|
a79f614e12 | ||
|
|
7d3a818565 | ||
|
|
978bb47b92 | ||
|
|
b791a6a348 | ||
|
|
c21c1f5225 | ||
|
|
d6253b1dee | ||
|
|
390bb07cca | ||
|
|
309822d933 | ||
|
|
8cb612c10c | ||
|
|
7e244455c4 | ||
|
|
907fe3d8d9 | ||
|
|
6420e33fb8 | ||
|
|
0b560fdd27 | ||
|
|
04297eda80 | ||
|
|
c13fd2261e | ||
|
|
034bff5b2f | ||
|
|
987ad214ff | ||
|
|
d11ac64b95 | ||
|
|
4c8c3b6947 | ||
|
|
d47d8d22a3 | ||
|
|
0ec9defc6e | ||
|
|
4776f11b6a | ||
|
|
3118d7bede | ||
|
|
a83be187f3 | ||
|
|
deb5e435e5 | ||
|
|
9f824f3aa9 | ||
|
|
032e68da05 | ||
|
|
486661d6c6 | ||
|
|
aa86ab97f0 | ||
|
|
a17f07495a | ||
|
|
16d3440a4c | ||
|
|
d7b412c1eb | ||
|
|
e5751334d6 | ||
|
|
1fb1d7e4e9 | ||
|
|
adc20e78da | ||
|
|
d499e250e0 | ||
|
|
68166c22b3 | ||
|
|
06b2b26e39 | ||
|
|
641ca3d49d | ||
|
|
6d259e00a3 | ||
|
|
2bc5b97662 | ||
|
|
676c61aa99 | ||
|
|
eade8003ef | ||
|
|
817bbefac6 | ||
|
|
cded6206dc | ||
|
|
c287fb58bd | ||
|
|
1b97f9b6c9 | ||
|
|
14ca3fc2f3 | ||
|
|
4bc1143418 | ||
|
|
4267063dba | ||
|
|
8f8b4536b6 | ||
|
|
8121ab5163 | ||
|
|
76fab1fea8 | ||
|
|
143b235a22 | ||
|
|
3a89f2c32f | ||
|
|
7bab92042a | ||
|
|
7379b4ddd2 | ||
|
|
298181999d | ||
|
|
61e1e7fe8f | ||
|
|
b3050af1a7 | ||
|
|
275da075e0 | ||
|
|
9925e2732a | ||
|
|
59b3daabc5 | ||
|
|
f2b0f64138 | ||
|
|
5df77eb474 | ||
|
|
f202fb9af6 | ||
|
|
5b769869d0 | ||
|
|
8e266058ae | ||
|
|
7c21712e80 | ||
|
|
193fc343fe | ||
|
|
a1e9c3d270 | ||
|
|
629261c4be | ||
|
|
f6d3a6239c | ||
|
|
83c5131b67 | ||
|
|
36afef3498 | ||
|
|
52c0485b0c | ||
|
|
8c23a091da | ||
|
|
ca121f80ee | ||
|
|
b48846506f | ||
|
|
a1c72be2a9 | ||
|
|
2098368417 | ||
|
|
4014d86a57 | ||
|
|
e84e8748bd | ||
|
|
bd8166e630 | ||
|
|
03d1519b39 | ||
|
|
36c4719570 | ||
|
|
7c970771c5 | ||
|
|
3f64c042bd | ||
|
|
e336cbfb2d | ||
|
|
24eec76428 | ||
|
|
71c9b15ff1 | ||
|
|
2940f0d67c | ||
|
|
cbb1d2d3b5 | ||
|
|
36dd11a899 | ||
|
|
be88969b79 | ||
|
|
d91ad54ed9 | ||
|
|
1330228080 | ||
|
|
3ea1eca350 | ||
|
|
a4e6d8120b | ||
|
|
3219de235c | ||
|
|
4e5c2ff620 | ||
|
|
63e25f0ff9 | ||
|
|
840225b580 | ||
|
|
bd221d60d6 | ||
|
|
8a3bb50143 | ||
|
|
e4cd1a465c | ||
|
|
2173a9f246 | ||
|
|
973a838e2a | ||
|
|
d95ee55497 | ||
|
|
124e2e759c | ||
|
|
ac918e3618 | ||
|
|
009a720c32 | ||
|
|
0dbfa43dad | ||
|
|
e0b4d36a74 | ||
|
|
a441474d75 | ||
|
|
cfd3c3628e | ||
|
|
474d52f805 | ||
|
|
7ee8bdf2f3 | ||
|
|
8a9757111f | ||
|
|
65dda4a70b | ||
|
|
1ed39dbbed | ||
|
|
8162c2e4e4 | ||
|
|
a7d74f3f98 | ||
|
|
ad83ae1e7a | ||
|
|
066374906e | ||
|
|
ec79a4a6f6 | ||
|
|
9fae215db4 | ||
|
|
92b40c9485 | ||
|
|
19fc59739f | ||
|
|
7e0ae4c601 | ||
|
|
81c2f4b30b | ||
|
|
e238f7ed37 | ||
|
|
2756f3332c | ||
|
|
14b3eefbaf | ||
|
|
dc946582a4 | ||
|
|
dfa14a73a8 | ||
|
|
112aa845f4 | ||
|
|
150a309175 | ||
|
|
55c14819a3 | ||
|
|
598897caa6 | ||
|
|
cf3f8a796a | ||
|
|
bffc294b13 | ||
|
|
4cc3b7f9fb | ||
|
|
b3161dde93 | ||
|
|
5550eabac1 | ||
|
|
b2b320174b | ||
|
|
dd79348b35 | ||
|
|
bd6ce7d4da | ||
|
|
7a67670e1a | ||
|
|
539bf482b9 | ||
|
|
ed67ce7f33 | ||
|
|
d91c7e5e79 | ||
|
|
4f1dfe2ef7 | ||
|
|
36ea6c13df | ||
|
|
3acb0aac98 | ||
|
|
fdf4b3878f | ||
|
|
2fe71782a7 | ||
|
|
89dfe2b763 | ||
|
|
9b62f238ed | ||
|
|
987688f196 | ||
|
|
46cb95f16c | ||
|
|
4e1fcbb706 | ||
|
|
e4c038762b | ||
|
|
86dfa200a6 | ||
|
|
165cf980d2 | ||
|
|
13ccb16a4a | ||
|
|
f4b5426865 | ||
|
|
c2f62ba52a | ||
|
|
b2d2c56a09 | ||
|
|
abf0f5ac87 | ||
|
|
fa1965deb4 | ||
|
|
1f76dc78d8 | ||
|
|
4448884a3e | ||
|
|
e3fc23bae8 | ||
|
|
29ceed74a2 | ||
|
|
382308c3fd | ||
|
|
3d1b6e29c6 | ||
|
|
3a9a5ec669 | ||
|
|
8c37c491a9 | ||
|
|
fdf11e6038 | ||
|
|
8e558f0826 | ||
|
|
69804c23f1 | ||
|
|
9aa9a62ed4 | ||
|
|
d9b79f47c8 | ||
|
|
249bc42667 | ||
|
|
644c184f7c | ||
|
|
66cfae7b3b | ||
|
|
bd2c2acd5f | ||
|
|
13aab750dd | ||
|
|
7a51abc2f9 | ||
|
|
44a3e08095 | ||
|
|
2aa8cf7104 | ||
|
|
1b1cfe1b92 | ||
|
|
199c2cdb66 | ||
|
|
726828a487 | ||
|
|
fcbf81a3d4 | ||
|
|
7637b51ba5 | ||
|
|
3afed3b316 | ||
|
|
3d6e334007 | ||
|
|
6c848a57b6 | ||
|
|
eb12d43800 | ||
|
|
465366e644 | ||
|
|
289e9c809f | ||
|
|
8b40354786 | ||
|
|
8de8de1b1e | ||
|
|
4b76c76712 | ||
|
|
6b9a270506 | ||
|
|
da2c49ab66 | ||
|
|
af2a3f3a65 | ||
|
|
6369a900da | ||
|
|
e877247032 | ||
|
|
5bcc5ff873 | ||
|
|
a52064463e | ||
|
|
6ed7f19673 | ||
|
|
9aba0ba5a8 | ||
|
|
5803a84bd7 | ||
|
|
ce0bf0f4b4 | ||
|
|
65ed57aff4 | ||
|
|
1317b80fca | ||
|
|
f0d6145fa6 | ||
|
|
c0c157ecef | ||
|
|
4bb607f180 | ||
|
|
2eec205e31 | ||
|
|
bd8cdd345a | ||
|
|
7caf3ea7d0 | ||
|
|
ba89c60b6d | ||
|
|
084e48d6dd | ||
|
|
1bed3f3936 | ||
|
|
cd860bfbf8 | ||
|
|
439c2d445c | ||
|
|
7f71d5dbd8 | ||
|
|
831c835106 | ||
|
|
5dfb7cb938 | ||
|
|
044d6a2207 | ||
|
|
955b46534d | ||
|
|
0e8d80e055 | ||
|
|
92fc736cfa | ||
|
|
60ed43c11b | ||
|
|
319f72ae2a | ||
|
|
04dc34260f | ||
|
|
a8196d1f33 | ||
|
|
1ce6ad5ccc | ||
|
|
145e36925f | ||
|
|
c07928144c | ||
|
|
d8c30f6cbb | ||
|
|
e968c6a2a4 | ||
|
|
ffc3a31d09 | ||
|
|
d6e037dd28 | ||
|
|
83b9b3bf4a | ||
|
|
1cb89ce20d | ||
|
|
d75b916153 | ||
|
|
192b484a8c | ||
|
|
85e2137d0e | ||
|
|
c1042c8f20 | ||
|
|
c91b05bd4b | ||
|
|
f8a09df5c0 | ||
|
|
9363db816c | ||
|
|
22af4da4d4 | ||
|
|
16fa10b056 | ||
|
|
f044851abb | ||
|
|
217e99a0e2 | ||
|
|
1bc4aea217 | ||
|
|
4997934bfe | ||
|
|
4905dded87 | ||
|
|
ff6447ae2b | ||
|
|
7f51857fa5 | ||
|
|
78c3babc37 | ||
|
|
83300044dd | ||
|
|
55f891e2aa | ||
|
|
7ae40d89c1 | ||
|
|
29cc1cf390 | ||
|
|
960d9a8534 | ||
|
|
bcc8529bfc | ||
|
|
d773647a20 | ||
|
|
3a5a0837c7 | ||
|
|
44cfe6af1c | ||
|
|
cf6d445080 | ||
|
|
422f8b3660 | ||
|
|
b097938f47 | ||
|
|
c231eff4b1 | ||
|
|
1ddc96f965 | ||
|
|
13111c4b42 | ||
|
|
7c70dbce65 | ||
|
|
25559f1772 | ||
|
|
c010c83654 | ||
|
|
2057531e8c | ||
|
|
277d4d9333 | ||
|
|
051e642c0c | ||
|
|
a8778e358d | ||
|
|
d2edbfd6fa | ||
|
|
d96dbe9365 | ||
|
|
35b5dcdb22 | ||
|
|
66f3bd186f | ||
|
|
7ae38a71cc | ||
|
|
2ed356be65 | ||
|
|
99436c1334 | ||
|
|
9e57a4ea28 | ||
|
|
19e5b8cc50 | ||
|
|
33310732a6 | ||
|
|
a03bf89190 | ||
|
|
1b089ca5e6 | ||
|
|
21e23d5511 | ||
|
|
8a2c4ab3de | ||
|
|
040585bf3d | ||
|
|
9030b3e04c | ||
|
|
0b46495afd | ||
|
|
ace16d473f | ||
|
|
925c51420d | ||
|
|
764b8ab7a5 | ||
|
|
cb6a1bfb1d | ||
|
|
775b9f30f0 | ||
|
|
76fd1c5c58 | ||
|
|
3e2605490f | ||
|
|
7094588c53 | ||
|
|
3523047243 | ||
|
|
bdcbaa031d | ||
|
|
f722b3e9cb | ||
|
|
2d46cb072e | ||
|
|
28cf450bfa | ||
|
|
4aa48fb4b6 | ||
|
|
aa86593702 | ||
|
|
faa368cc07 | ||
|
|
a840ed06b7 | ||
|
|
7196bfd157 | ||
|
|
a6785e9143 | ||
|
|
4d2f26b1cd | ||
|
|
188987a8ff | ||
|
|
14d74d3230 | ||
|
|
bcd6bd6b04 | ||
|
|
8e4bd7fe4a | ||
|
|
8ab552793a | ||
|
|
29944f6bf2 | ||
|
|
162b60a05b | ||
|
|
da50d92d1e | ||
|
|
a746f5657f | ||
|
|
65ccc5bfce | ||
|
|
34939f9381 | ||
|
|
26e7821aaa | ||
|
|
298c5f0de2 | ||
|
|
a6c2b25f6f | ||
|
|
3a8c90c0d4 | ||
|
|
a25ce2296a | ||
|
|
280407a553 | ||
|
|
32c98e2161 | ||
|
|
2cbdb0bc17 | ||
|
|
4317694c64 | ||
|
|
e0879fbccb | ||
|
|
9cb8e194b0 | ||
|
|
dc914b1806 | ||
|
|
c70817b21a | ||
|
|
77918fd412 | ||
|
|
90d02234c7 | ||
|
|
b0b1c5af71 | ||
|
|
a8bd87938d | ||
|
|
10d2f0a565 | ||
|
|
c68aca4ada | ||
|
|
f46d96c4c6 | ||
|
|
e7b1ded486 | ||
|
|
719de94821 | ||
|
|
7ea0249e6e | ||
|
|
feab95ce4b | ||
|
|
ca6f755634 | ||
|
|
70b30f7849 | ||
|
|
01ab027615 | ||
|
|
11f5db871f | ||
|
|
d83fc3181b | ||
|
|
b4657a0d05 | ||
|
|
a5d6820453 | ||
|
|
7b16aa6050 | ||
|
|
c5d3c0c6f8 | ||
|
|
43c1a87c48 | ||
|
|
3755002381 | ||
|
|
dba38408c9 | ||
|
|
5b2bc23d03 | ||
|
|
a4cfdcb5c4 | ||
|
|
b6097160f1 | ||
|
|
fde1c08945 | ||
|
|
417eb56a9b | ||
|
|
0b28812f7e | ||
|
|
5ad25376bb | ||
|
|
b3ab85f3b5 | ||
|
|
11231abe8a | ||
|
|
c577706415 | ||
|
|
f1eea6a0bf | ||
|
|
8ce55f90d3 | ||
|
|
723f35ec5a | ||
|
|
025d9d3276 | ||
|
|
4f0c1d11eb | ||
|
|
1aae921ce7 | ||
|
|
2e1c508bc4 | ||
|
|
cea6ea4344 | ||
|
|
57310fdbd6 | ||
|
|
62ca6212ce | ||
|
|
d4f5871e74 | ||
|
|
a739580d3f | ||
|
|
5203565175 | ||
|
|
c91f6db68a | ||
|
|
b776b85fc3 | ||
|
|
b35e5f1582 | ||
|
|
7d5a929b5e | ||
|
|
c2e7bc13a6 | ||
|
|
97818c6f32 | ||
|
|
a8973f5463 | ||
|
|
75d790137d | ||
|
|
7ef6c72fc0 | ||
|
|
c5f8e2249e | ||
|
|
585a6c29d4 | ||
|
|
6b6df15dd9 | ||
|
|
f4de68cb22 | ||
|
|
86d5cbc355 | ||
|
|
88f9b69e2a | ||
|
|
d77c782f69 | ||
|
|
c115131ed2 | ||
|
|
178dedf78c | ||
|
|
b0c64afc6e | ||
|
|
be0c1c0912 | ||
|
|
2e8fa88fcb | ||
|
|
b1b5904852 | ||
|
|
08f029850f | ||
|
|
f3d4077142 | ||
|
|
59dd479a6d | ||
|
|
76d9f1ea37 | ||
|
|
858b497199 | ||
|
|
cee9f1df95 | ||
|
|
5bc2001ce3 | ||
|
|
652226dbf0 | ||
|
|
4688e6d534 | ||
|
|
1b0fc180c4 | ||
|
|
2524972807 | ||
|
|
8f51dc2c22 | ||
|
|
b363b50320 | ||
|
|
88a48a5c79 | ||
|
|
7be951b962 | ||
|
|
3dcc4e6bc1 | ||
|
|
573ee0b584 | ||
|
|
213629ef52 | ||
|
|
27e1579e4c | ||
|
|
f2c401b6c0 | ||
|
|
442c63d7a4 | ||
|
|
5babfb0f1e | ||
|
|
0ad3078524 | ||
|
|
f765c25020 | ||
|
|
4145251afd | ||
|
|
88c3532162 | ||
|
|
84b3ad3221 | ||
|
|
e699d3d02d | ||
|
|
9da984b866 | ||
|
|
fc08d15a79 | ||
|
|
ffaabe8674 | ||
|
|
0233ab4deb | ||
|
|
c9dc010c0b | ||
|
|
557696b1d8 | ||
|
|
9fefbb0c4a | ||
|
|
eb9ea97e21 | ||
|
|
673b7a95b7 | ||
|
|
d5f27ecb0e | ||
|
|
8f8b928cc4 | ||
|
|
965896b932 | ||
|
|
042adb5e34 | ||
|
|
67927bd8f4 | ||
|
|
259a63e612 | ||
|
|
adcf2158bf | ||
|
|
05c914156a | ||
|
|
f69884d573 | ||
|
|
d097554f7d | ||
|
|
1e2fd57c4c | ||
|
|
8b8007695c | ||
|
|
68f3c877ee | ||
|
|
ae442ee015 | ||
|
|
99b5f1b7b8 | ||
|
|
8071df0e68 | ||
|
|
88d1aab7a3 | ||
|
|
08001ba373 | ||
|
|
ebc24cee55 | ||
|
|
ae3bb30d8a | ||
|
|
63d6b23344 | ||
|
|
c009e6bd04 | ||
|
|
38d85a49e7 | ||
|
|
0edc149ecc | ||
|
|
10d6cd9896 | ||
|
|
6913da7efa | ||
|
|
34df1b1646 | ||
|
|
992603496e | ||
|
|
b9552c42f1 | ||
|
|
37e4dfc5d5 | ||
|
|
15b7284a8f | ||
|
|
b57a62fece | ||
|
|
9c7de5ad03 | ||
|
|
c065fae422 | ||
|
|
cfde1f8c27 | ||
|
|
c45f72a63e | ||
|
|
e1d9eca7bd | ||
|
|
573e5eb5bd | ||
|
|
d9090486e3 | ||
|
|
b4e7a91645 | ||
|
|
92dd68fca1 | ||
|
|
82e955ec02 | ||
|
|
2e66c4c9f5 | ||
|
|
0c6ee5e139 | ||
|
|
9a19b5994b | ||
|
|
920586f56c | ||
|
|
919aa2895a | ||
|
|
75690598e3 | ||
|
|
ac2caf2787 | ||
|
|
5640c96fd5 | ||
|
|
0396c4a4de | ||
|
|
f061fe581a | ||
|
|
5405876d84 | ||
|
|
4b9de0777b | ||
|
|
a59e073536 | ||
|
|
67492bf024 | ||
|
|
77c83c4f42 | ||
|
|
259baa0e84 | ||
|
|
dca48c7eec | ||
|
|
0d83a34cfd | ||
|
|
7386b0a523 | ||
|
|
eda13f9023 | ||
|
|
d0e9fe1e3e | ||
|
|
2b7bab04dd | ||
|
|
ad5f890a1e | ||
|
|
fa191e2928 | ||
|
|
6d8a23ec16 | ||
|
|
12371650f9 | ||
|
|
79e1d54e4c | ||
|
|
447f5f69c9 | ||
|
|
e08a26d015 | ||
|
|
975265b0af | ||
|
|
4d5e9c52b2 | ||
|
|
d1b154c285 | ||
|
|
381f6b184e | ||
|
|
59681398cb | ||
|
|
adf887a06b | ||
|
|
42f70cd55d | ||
|
|
3704a4ff47 | ||
|
|
5b8d637f6a | ||
|
|
436621f79f | ||
|
|
0ea5fbfe0a | ||
|
|
f1acd122bc | ||
|
|
739b6645f8 | ||
|
|
7a7ae4cc83 | ||
|
|
db83cbe58f | ||
|
|
87228429d6 | ||
|
|
2651723b50 | ||
|
|
b8a01d2ff1 | ||
|
|
5c20751937 | ||
|
|
06b0a50462 | ||
|
|
0d589895f6 | ||
|
|
230c2aaf26 | ||
|
|
1d8807a6ba | ||
|
|
81978b214c | ||
|
|
8704234669 | ||
|
|
5699b7bae5 | ||
|
|
2756cb8b8f | ||
|
|
e726d216bb | ||
|
|
3480824290 | ||
|
|
c8b935151a | ||
|
|
5e5aefa290 | ||
|
|
0e14b54b6d | ||
|
|
c6ddae2d8e | ||
|
|
bc0aed186e | ||
|
|
d092b21da7 | ||
|
|
a8061003dd | ||
|
|
50f0099645 | ||
|
|
c270687223 | ||
|
|
a92652f4ad | ||
|
|
9ba961fa72 | ||
|
|
006e4526e8 | ||
|
|
55dbbb3546 | ||
|
|
c166bc9b18 | ||
|
|
e4fe18e435 | ||
|
|
cea38549da | ||
|
|
0487e730ba | ||
|
|
8fdd7205d7 | ||
|
|
1d8d71cfb6 | ||
|
|
10bd017e57 | ||
|
|
f36a9c4409 | ||
|
|
70f39eb959 | ||
|
|
3a3b0cc847 | ||
|
|
01da9e3ca2 | ||
|
|
f168e4586c | ||
|
|
03ff390685 | ||
|
|
2a77486567 | ||
|
|
32a5950aad | ||
|
|
f1370189b6 | ||
|
|
65d721285b | ||
|
|
565f844b7f | ||
|
|
248992b27b | ||
|
|
3125e05b49 | ||
|
|
bdd6037726 | ||
|
|
9d292bb6a4 | ||
|
|
12b9b49902 | ||
|
|
93b8bd7f02 | ||
|
|
cd8169c0a5 | ||
|
|
b4a9d4df8c | ||
|
|
d62525abb6 | ||
|
|
a4988fd7cb | ||
|
|
d91691c344 | ||
|
|
164d3566e3 | ||
|
|
058120d001 | ||
|
|
59f292333f | ||
|
|
b7a2c11e81 | ||
|
|
3d07ddfba5 | ||
|
|
9286e4794b | ||
|
|
81276cb7f5 | ||
|
|
e270f90f8d | ||
|
|
b1fdfec18c | ||
|
|
1dfa09cda9 | ||
|
|
913438e3ff | ||
|
|
1aa939ae73 | ||
|
|
a914608264 | ||
|
|
fb59d80897 | ||
|
|
5d0852c1e2 | ||
|
|
e0e50faa47 | ||
|
|
f6721a2ced | ||
|
|
e384ec32b8 | ||
|
|
d93361939c | ||
|
|
644c0e3d33 | ||
|
|
b1333b7d99 | ||
|
|
673a2acade | ||
|
|
752e74d33c | ||
|
|
6bacf94a62 | ||
|
|
336cd60920 | ||
|
|
76c9b66db4 | ||
|
|
0c5ca28a14 | ||
|
|
db63bb4495 | ||
|
|
34afb54c21 | ||
|
|
69888e148e | ||
|
|
98a55c0613 | ||
|
|
5425e9aee3 | ||
|
|
7fef5f5654 | ||
|
|
fc94e846a6 | ||
|
|
7d7bbf15bf | ||
|
|
8a545b98ec | ||
|
|
ecdb60b44e | ||
|
|
2eea85b786 | ||
|
|
87fd0e6f29 | ||
|
|
ea191afd9d | ||
|
|
89b624308e | ||
|
|
facdf0ca9c | ||
|
|
98484d54c0 | ||
|
|
ea31ca5ee8 | ||
|
|
6b5b9b3d62 | ||
|
|
975dab6d1d | ||
|
|
eaa7adc88c | ||
|
|
f76b014a52 | ||
|
|
8676a1b4ef | ||
|
|
e1eaa2097e | ||
|
|
6f2357c695 | ||
|
|
91427264c3 | ||
|
|
74aa961561 | ||
|
|
aa47e11471 | ||
|
|
89d69a5d5a | ||
|
|
3bbe1e9c0c | ||
|
|
6377631ae7 | ||
|
|
3562ac1438 | ||
|
|
e152785de9 | ||
|
|
dd259f1852 | ||
|
|
5001cea3a3 | ||
|
|
a4d586b24e | ||
|
|
46f927fc1b | ||
|
|
7419f992e7 | ||
|
|
b83e7e6c5c | ||
|
|
5f463d5f6b | ||
|
|
2e301c2919 | ||
|
|
9526d42ec5 | ||
|
|
a566479ddb | ||
|
|
1bba0f6bb2 | ||
|
|
232d42881b | ||
|
|
abeaf76fe9 | ||
|
|
03d4584562 | ||
|
|
f2f5226ebb | ||
|
|
660860b92d | ||
|
|
c0a1a8b47c | ||
|
|
bd82e81e26 | ||
|
|
0a94df592c | ||
|
|
66506ea1ce | ||
|
|
4a4292a0dc | ||
|
|
7bff4db483 | ||
|
|
9208da8a50 | ||
|
|
70fcd93ca7 | ||
|
|
9ba9bd4415 | ||
|
|
480ce6f522 | ||
|
|
f1254fd5d4 | ||
|
|
10ebcff48e | ||
|
|
6ee227675a | ||
|
|
89059abe15 | ||
|
|
4503223a4e | ||
|
|
07c31a90f3 | ||
|
|
bbcb9af01f | ||
|
|
1cd415a3ae | ||
|
|
c344e75701 | ||
|
|
0305e4cf8a | ||
|
|
bc86b0345f | ||
|
|
8b0ce30dfc | ||
|
|
4b983300fe | ||
|
|
8829ebba6c | ||
|
|
11b90d2113 | ||
|
|
9d8d4c09c6 | ||
|
|
c90d5bb67c | ||
|
|
7263d9f03e | ||
|
|
d5e77e9bb2 | ||
|
|
1ecd5250fc | ||
|
|
44af5e04e4 | ||
|
|
4582a4fd95 | ||
|
|
2d513277f2 | ||
|
|
7934974d92 | ||
|
|
4dce35b1e6 | ||
|
|
e5f5f96771 | ||
|
|
d4a0076aba | ||
|
|
cd9cd84c5b | ||
|
|
93eca799dd | ||
|
|
34f090662a | ||
|
|
1a1d54387c | ||
|
|
9575f70f38 | ||
|
|
b4e9ed7d18 | ||
|
|
3d4e2a275c | ||
|
|
b526718846 | ||
|
|
a4883cfa15 | ||
|
|
a41f179785 | ||
|
|
bef628212e | ||
|
|
ef3030abe5 | ||
|
|
754ad20eff | ||
|
|
647175cf12 | ||
|
|
5f0a440f0a | ||
|
|
d68544038c | ||
|
|
df36b0eb7e | ||
|
|
4f4748b8df | ||
|
|
028a896303 | ||
|
|
578083df3e | ||
|
|
c5e1823f15 | ||
|
|
5f396d6311 | ||
|
|
5c64c2ff42 | ||
|
|
2dcb91b284 | ||
|
|
d708e7f682 | ||
|
|
a8a4ef82cd | ||
|
|
1286f1c968 | ||
|
|
9368a93279 | ||
|
|
143aaa2d28 | ||
|
|
b8dcdece38 | ||
|
|
be7f4c5da7 | ||
|
|
890807b8d7 | ||
|
|
8e1687e7b3 | ||
|
|
d8510ead43 | ||
|
|
c74db4b81c | ||
|
|
4ee9b4524d | ||
|
|
28cf351878 | ||
|
|
c5e2ec5e00 | ||
|
|
fe3ebc4c84 | ||
|
|
6688f9a5ef | ||
|
|
3167ae21b0 | ||
|
|
bc92586323 | ||
|
|
c40a463549 | ||
|
|
87a85fff08 | ||
|
|
b68381db58 | ||
|
|
25c1884961 | ||
|
|
9980df2c67 | ||
|
|
ed09c1171b | ||
|
|
c473b10667 | ||
|
|
c15e53e9c0 | ||
|
|
e9d3278fc5 | ||
|
|
b683c07d55 | ||
|
|
681f055b16 | ||
|
|
f4cb4c1756 | ||
|
|
1cc67bbbe8 | ||
|
|
0df0450107 | ||
|
|
cb324ca723 | ||
|
|
442a0c48e7 | ||
|
|
d97acacae6 | ||
|
|
3643d6b5d5 | ||
|
|
2edd64470b | ||
|
|
c42e2fe02d | ||
|
|
12c67b5db4 | ||
|
|
a943cc09fe | ||
|
|
1ceda52f59 | ||
|
|
04ee419951 | ||
|
|
f687728c3a | ||
|
|
bde5d27a20 | ||
|
|
07a1651fa2 | ||
|
|
32b47bee2c | ||
|
|
fbf75ea3b9 | ||
|
|
a157aba74f | ||
|
|
e45e5df377 | ||
|
|
85c7bfa160 | ||
|
|
8182f97c15 | ||
|
|
eba824f5d0 | ||
|
|
40456ebaae | ||
|
|
99983798a4 | ||
|
|
93ed032015 | ||
|
|
9359f5b296 | ||
|
|
3b467c19cb | ||
|
|
470a6f0ab2 | ||
|
|
fe8a0c1a6b | ||
|
|
f0d098d0ef | ||
|
|
f17df1f16d | ||
|
|
b1f8f9830b | ||
|
|
e78ccc6bec | ||
|
|
b54892a783 | ||
|
|
16c37a0f3d | ||
|
|
141fb78237 | ||
|
|
eb31b9a4d6 | ||
|
|
f10d9e1332 | ||
|
|
6d63521622 | ||
|
|
e1aa066489 | ||
|
|
c78ec12e99 | ||
|
|
3fa4e2f58d | ||
|
|
c64aaade70 | ||
|
|
e8d8b290a6 | ||
|
|
456d9e79e6 | ||
|
|
3095e14247 | ||
|
|
a332d68704 | ||
|
|
84ca992e91 | ||
|
|
f91f3796a8 | ||
|
|
22250ae552 | ||
|
|
8a95b5b5b0 | ||
|
|
7506619f4c | ||
|
|
577d9ddf65 | ||
|
|
43c3bdf7c5 | ||
|
|
8ba142eb45 | ||
|
|
0fc4e01b1e | ||
|
|
f83ebbcd3a | ||
|
|
77ec4b5cad | ||
|
|
9a687976bc | ||
|
|
5a796a86d7 | ||
|
|
71d4221af2 | ||
|
|
526ba37435 | ||
|
|
f3c080f8a4 | ||
|
|
09a0cf07e4 | ||
|
|
4a3bf46c30 | ||
|
|
30dfe12910 | ||
|
|
ae2b5dfd3e | ||
|
|
cb0f968467 | ||
|
|
e8e3db6888 | ||
|
|
012ade5000 | ||
|
|
5350078543 | ||
|
|
404715e02d | ||
|
|
31dde394eb | ||
|
|
8ff2627e8e | ||
|
|
f79ad91a9a | ||
|
|
ff6a79bca3 | ||
|
|
e4d6092939 | ||
|
|
9d998d27c5 | ||
|
|
d6aca6fa00 | ||
|
|
7c34c45983 | ||
|
|
dd15472da7 | ||
|
|
b03712a30e | ||
|
|
d025ba2793 | ||
|
|
e5e09c9b51 | ||
|
|
5b8d1df349 | ||
|
|
fa092c0162 | ||
|
|
08c1359a27 | ||
|
|
dba355eccd | ||
|
|
2ad927b677 | ||
|
|
315f672254 | ||
|
|
7a51407f6d | ||
|
|
783c2b6b03 | ||
|
|
a64e1b2aa6 | ||
|
|
440516e95f | ||
|
|
31f6d13cd8 | ||
|
|
dc6108575c | ||
|
|
6c7316408b | ||
|
|
9aecc69461 | ||
|
|
949be436a6 | ||
|
|
cb91891f22 | ||
|
|
8795f0c8c4 | ||
|
|
fbb5bb2f05 | ||
|
|
ba309fe6e5 | ||
|
|
fee5f959fd | ||
|
|
f9a5f4955c | ||
|
|
325b362727 | ||
|
|
75065f29f7 | ||
|
|
ed874fe3ea | ||
|
|
502e6b0ce5 | ||
|
|
516380f979 | ||
|
|
6885761f87 | ||
|
|
a4762fe65c | ||
|
|
bee407ea34 | ||
|
|
db71673722 | ||
|
|
9ecbbf09cc | ||
|
|
b6b14f4957 | ||
|
|
6e0d6dcac5 | ||
|
|
47a0ebdc91 | ||
|
|
f3a61007a7 | ||
|
|
4a56d6bf1c | ||
|
|
517d4dc6f5 | ||
|
|
722f1c4430 | ||
|
|
f4d1b87f73 | ||
|
|
f64f875806 | ||
|
|
7ae09fa1fe | ||
|
|
8a29dfc3fa | ||
|
|
1015188c4e | ||
|
|
f0bc2a3645 | ||
|
|
82f46464f3 | ||
|
|
d336d920e8 | ||
|
|
2f61dd1c41 | ||
|
|
10ffd5c1ab | ||
|
|
7e99be12b0 | ||
|
|
d37a790b57 | ||
|
|
7ea8509dfe | ||
|
|
783c0c7c7b | ||
|
|
68b0775e4b | ||
|
|
682334d844 | ||
|
|
75981491a7 | ||
|
|
7cc805b203 | ||
|
|
8cdd3a0abb | ||
|
|
571c630d93 | ||
|
|
fa1021df59 | ||
|
|
9acbb2203c | ||
|
|
c770bcbf96 | ||
|
|
caace05ba6 | ||
|
|
c65dc44f20 | ||
|
|
3ea624e1db | ||
|
|
c9c58074fa | ||
|
|
aa687afd37 | ||
|
|
8cb69c1482 | ||
|
|
a68326490d | ||
|
|
ab763c38d9 | ||
|
|
970557660e | ||
|
|
fa8548fe34 | ||
|
|
ac88c1a8f1 | ||
|
|
f2893097a7 | ||
|
|
c0cba7b376 | ||
|
|
87d1058de3 | ||
|
|
85e65da492 | ||
|
|
ce97fa87e7 | ||
|
|
10ffdb2766 | ||
|
|
fec49e5609 | ||
|
|
28fdd992c9 | ||
|
|
048d3c8386 | ||
|
|
50e3d6ff37 | ||
|
|
37b80f0ce3 | ||
|
|
7d37b02cff | ||
|
|
c6556b8442 | ||
|
|
5685c376cb | ||
|
|
2ce64e1bf5 | ||
|
|
7d03a41e3e | ||
|
|
35b68db847 | ||
|
|
0b21fce94e | ||
|
|
abaf36a2de | ||
|
|
26440d94f1 | ||
|
|
205b61e4cf | ||
|
|
fc5fc5bbee | ||
|
|
c4171a01bd | ||
|
|
32669cb07f | ||
|
|
7018c381ee | ||
|
|
b02677ee21 | ||
|
|
63edc60753 | ||
|
|
065d01bcf6 | ||
|
|
42b15e8bbe | ||
|
|
e8195b78ba | ||
|
|
1d7d7cf9a0 | ||
|
|
979575c311 | ||
|
|
be12739342 | ||
|
|
7f7acd8bde | ||
|
|
f5e2899275 | ||
|
|
bee34a3222 | ||
|
|
5b00cb1e64 | ||
|
|
6bb9de5a96 | ||
|
|
b977050caf | ||
|
|
3f63732c31 | ||
|
|
211660eb3d | ||
|
|
0c709f431f | ||
|
|
9062bf14b6 | ||
|
|
47ebb6ae6c | ||
|
|
b1e3f88704 | ||
|
|
bc439cc47f | ||
|
|
1bba5d5c94 | ||
|
|
d159d49700 | ||
|
|
7ef7ef03dd | ||
|
|
808b758cd7 | ||
|
|
ff6d66b96e | ||
|
|
da82b14307 | ||
|
|
7b5e18d94b | ||
|
|
72974c85c8 | ||
|
|
28627a81dc | ||
|
|
bbfe6b66ef | ||
|
|
bce0e3ebf6 | ||
|
|
bf46c241d0 | ||
|
|
287e32aaed | ||
|
|
aa11a5deb8 | ||
|
|
194d63acd8 | ||
|
|
46d640cd86 | ||
|
|
51783a45e6 | ||
|
|
2679c58892 | ||
|
|
2a5af37075 | ||
|
|
e529d3ecc9 | ||
|
|
e8f9ecc7d9 | ||
|
|
aa3723d2bd | ||
|
|
bbbda44218 | ||
|
|
f99aea5cb1 | ||
|
|
65c003eef8 | ||
|
|
959843ee9c | ||
|
|
c16632d99a | ||
|
|
3d066ea1b8 | ||
|
|
e163730118 | ||
|
|
3c8838af08 | ||
|
|
ac5394a1dc | ||
|
|
2e74d91ddc | ||
|
|
2d82c4ada4 | ||
|
|
03f0ca965e | ||
|
|
a527dcd95b | ||
|
|
de29abb05c | ||
|
|
cb7efcb188 | ||
|
|
bf4f22b203 | ||
|
|
7f3a467a66 | ||
|
|
72ef621f9d | ||
|
|
73452f758c | ||
|
|
049e1b2679 | ||
|
|
4631123231 | ||
|
|
c86bcb4dd6 | ||
|
|
a6280661ee | ||
|
|
ca7709a284 | ||
|
|
384c06f2e9 | ||
|
|
774c11781d | ||
|
|
7a692898e4 | ||
|
|
2f1971ea8f | ||
|
|
ce13de7d6c | ||
|
|
d51ad77ab4 | ||
|
|
a9b289626e | ||
|
|
8a542f2ce8 | ||
|
|
14a2c9d48f | ||
|
|
37fef7e4f8 | ||
|
|
b83ab85fd9 | ||
|
|
d424e1e9ff | ||
|
|
aaa52bd767 | ||
|
|
56254e728c | ||
|
|
284159aadc | ||
|
|
29593f0161 | ||
|
|
deca217544 | ||
|
|
c09212de81 | ||
|
|
db8d93d308 | ||
|
|
4c96106666 | ||
|
|
8e849ea6f8 | ||
|
|
82d80d2ead | ||
|
|
a5da55d0f7 | ||
|
|
702e6c8080 | ||
|
|
46e957ab7e | ||
|
|
c27f8a5c1e | ||
|
|
8e835f2f6b | ||
|
|
35e8a027ad | ||
|
|
94642f9066 | ||
|
|
2dd5de4373 | ||
|
|
793e80490c | ||
|
|
727a1f4ddd | ||
|
|
6a752a56ff | ||
|
|
32466e3804 | ||
|
|
a530503c0c | ||
|
|
7ba4af7e2e | ||
|
|
c9c05ad2a8 | ||
|
|
ab1df3a1d0 | ||
|
|
56a60772a4 | ||
|
|
63e6731207 | ||
|
|
8b53ded53a | ||
|
|
d5075d706c | ||
|
|
03927b0a68 | ||
|
|
0d88b8012b | ||
|
|
a583c21136 | ||
|
|
b8ec63cf8c | ||
|
|
4b9afdf53a | ||
|
|
788d1650a2 | ||
|
|
8f58886a21 | ||
|
|
94b3bb2391 | ||
|
|
c8f5fb4d03 | ||
|
|
070a21a9eb | ||
|
|
5698ff9c4c | ||
|
|
47b562b032 | ||
|
|
69234db848 | ||
|
|
ebc132ea65 | ||
|
|
0899eeddc0 | ||
|
|
cf8ff2cf86 | ||
|
|
ee9dc789af | ||
|
|
570598f556 | ||
|
|
e8c3546433 | ||
|
|
1062776762 | ||
|
|
584379b502 | ||
|
|
87e1c45c05 | ||
|
|
9447afe49c | ||
|
|
fc5b1ae3e2 | ||
|
|
13735d0475 | ||
|
|
6b3a783ce9 | ||
|
|
3b66bba92e | ||
|
|
a2e01f8a53 | ||
|
|
34da9a9655 | ||
|
|
df8d73ae43 | ||
|
|
aa3a93b6a0 | ||
|
|
17bfa35f77 | ||
|
|
59797a5c9a | ||
|
|
61fe2923e4 | ||
|
|
50b9eca34c | ||
|
|
f5684eba90 | ||
|
|
f32510e10a | ||
|
|
4fb0eeda37 | ||
|
|
b1aeae6772 | ||
|
|
5a6bd38d22 | ||
|
|
97da8e2f2e | ||
|
|
10be150503 | ||
|
|
36aa248556 | ||
|
|
183c22cc84 | ||
|
|
63f4cf3d07 | ||
|
|
eeeae12639 | ||
|
|
0d854c6ea6 | ||
|
|
1e1c4d159b | ||
|
|
4dc9f6948d | ||
|
|
c06e739c9b | ||
|
|
061720bcf0 | ||
|
|
11585327bf | ||
|
|
2793eeb10a | ||
|
|
8fb093b272 | ||
|
|
c90c008f65 | ||
|
|
3d1a7f173c | ||
|
|
ba078f3ff5 | ||
|
|
6d54401d7c | ||
|
|
c9a0897208 | ||
|
|
6a1049bfb7 | ||
|
|
5995ab3f4c | ||
|
|
a4112ebed2 | ||
|
|
289cae4213 | ||
|
|
eaac21cda1 | ||
|
|
3b9b827ebf | ||
|
|
c908beade2 | ||
|
|
abcf030181 | ||
|
|
22a16da09e | ||
|
|
0e31da5e51 | ||
|
|
61e6a03d70 | ||
|
|
3f2119556f | ||
|
|
77493d0d09 | ||
|
|
340c73cbdf | ||
|
|
ea7f4447b2 | ||
|
|
19f3c75a8d | ||
|
|
25ba08abcf | ||
|
|
26be0c7c82 | ||
|
|
b7c5e3b5d5 | ||
|
|
701653a6bd | ||
|
|
2c099c7f0e | ||
|
|
fba53117d8 | ||
|
|
e1bf53d90a | ||
|
|
ecc82739d8 | ||
|
|
d16afa9692 | ||
|
|
9f3ce09e88 | ||
|
|
cbfb1edb79 | ||
|
|
b6c336bf72 | ||
|
|
403e34506e | ||
|
|
83db868542 | ||
|
|
1b6e673b50 | ||
|
|
a0144f093f | ||
|
|
a5d84bf8a9 | ||
|
|
84bb740e62 | ||
|
|
d37482ada1 | ||
|
|
75fc8202ab | ||
|
|
24aff15752 | ||
|
|
338b9928f0 | ||
|
|
b9607b4b8e | ||
|
|
586f241074 | ||
|
|
e298987d9e | ||
|
|
71cc4b5bf2 | ||
|
|
4fdd9feddc | ||
|
|
caf7da1053 | ||
|
|
7d04ba0fc3 | ||
|
|
d98d091c43 | ||
|
|
3ad196c4c7 | ||
|
|
562f320198 | ||
|
|
3e5581e094 | ||
|
|
c4721e1020 | ||
|
|
728f2670f3 | ||
|
|
8dd157d2eb | ||
|
|
2d40d69fa2 | ||
|
|
f2f0d69bce | ||
|
|
812f5045b0 | ||
|
|
9a8e7b11e5 | ||
|
|
e213e695c8 | ||
|
|
e24eea313c | ||
|
|
a3286ebac3 | ||
|
|
95ae23a32c | ||
|
|
d240f3242c | ||
|
|
814f60a512 | ||
|
|
fac6229e43 | ||
|
|
c528d739c8 | ||
|
|
c664be52d7 | ||
|
|
4ac4f44ba7 | ||
|
|
174430e3b5 | ||
|
|
762b21f809 | ||
|
|
9340bf385e | ||
|
|
9f5be52a97 | ||
|
|
9dc5a4fce3 | ||
|
|
fda3cd5fe7 | ||
|
|
6b8469e9a3 | ||
|
|
7dbbe5a7d8 | ||
|
|
2d6fdeb7ad | ||
|
|
4d3a01a5fe | ||
|
|
8cc6756815 | ||
|
|
5967ab75b1 | ||
|
|
69c954760a | ||
|
|
40a4c3ccbd | ||
|
|
aacb9d9570 | ||
|
|
9b6c229b71 | ||
|
|
1da5be2871 | ||
|
|
66dafca61a | ||
|
|
1f22b5b083 | ||
|
|
5be0b7a731 | ||
|
|
b64b5d9103 | ||
|
|
953d78da9e | ||
|
|
ce9e0981a2 | ||
|
|
76e1114a1f | ||
|
|
cfc80b491f | ||
|
|
43ed05d3c2 | ||
|
|
4cf5ce871f | ||
|
|
91ec08df4e | ||
|
|
c79363ef63 | ||
|
|
cc6672198a | ||
|
|
17cdf7c79d | ||
|
|
725f939f35 | ||
|
|
e2df00bb2e | ||
|
|
a9a33c6179 | ||
|
|
8e7eb87a2d | ||
|
|
217004e7a5 | ||
|
|
4d10848984 | ||
|
|
da2c04f681 | ||
|
|
8deb327b3b | ||
|
|
642b01bf0d | ||
|
|
9fd78b1eb1 | ||
|
|
66c09fc44c | ||
|
|
2cb5e1a6c2 | ||
|
|
02ac638bd4 | ||
|
|
323f74c43a | ||
|
|
1e56d17d39 | ||
|
|
16af8e082b | ||
|
|
9215a54c23 | ||
|
|
fab34d3dbb | ||
|
|
03d7330af5 | ||
|
|
346b0c9d68 | ||
|
|
c29359e7a8 | ||
|
|
4b903931bc | ||
|
|
4e0929e71a | ||
|
|
1bad097a13 | ||
|
|
331065eec6 | ||
|
|
f51ba499d5 | ||
|
|
f62ccc2d48 | ||
|
|
cf485aa62e | ||
|
|
6b16a48568 | ||
|
|
ff7cf503ae | ||
|
|
2412a0d502 | ||
|
|
b1612bb1ed | ||
|
|
b8a205f755 | ||
|
|
eab08ea78c | ||
|
|
d7653769b4 | ||
|
|
c72d9695da | ||
|
|
0493f00a7a | ||
|
|
ff757ddc88 | ||
|
|
c4c495948a | ||
|
|
986ee6bac3 | ||
|
|
6ab7e79987 | ||
|
|
c6e35876fa | ||
|
|
eb31accf20 | ||
|
|
ea1ba0f09b | ||
|
|
10911f5b64 | ||
|
|
0eab8e9322 | ||
|
|
fb2602716e | ||
|
|
be68906ae9 | ||
|
|
c53d6d80ba | ||
|
|
1362177352 | ||
|
|
28ab1230e2 | ||
|
|
0784934520 | ||
|
|
79fbf9d47f | ||
|
|
dabdc8e4c5 | ||
|
|
466ad192b0 | ||
|
|
ac59d9e1b6 | ||
|
|
d44245e1e9 | ||
|
|
c50105493a | ||
|
|
2768a62f92 | ||
|
|
5841d0d87d | ||
|
|
2a796051bf | ||
|
|
50286fd173 | ||
|
|
44f0bad2a6 | ||
|
|
611b9c4fd1 | ||
|
|
3f50776062 | ||
|
|
c70d2ad6fa | ||
|
|
9dd0bd604c | ||
|
|
0565519509 | ||
|
|
c282d95be1 | ||
|
|
766286b8bc | ||
|
|
f405c62f1e | ||
|
|
93fbd7b3ba | ||
|
|
ae5cea7f36 | ||
|
|
8b7b6cfbc5 | ||
|
|
f6e988d6fd | ||
|
|
f88f68f248 | ||
|
|
14f2b24b16 | ||
|
|
f2dde98e2f | ||
|
|
90d8ec0e81 | ||
|
|
14cdb531c8 | ||
|
|
3a50320f79 | ||
|
|
597b5e6cfb | ||
|
|
2cd056cfb3 | ||
|
|
be6aab4c40 | ||
|
|
d030df925f | ||
|
|
50756eb94a | ||
|
|
21b3576b66 | ||
|
|
2e5226356b | ||
|
|
21b76d3d2b | ||
|
|
2d252e6459 | ||
|
|
43be363542 | ||
|
|
8cb3e3418a | ||
|
|
cd47ddd539 | ||
|
|
2be1c10522 | ||
|
|
7f26670173 | ||
|
|
d838ce85c3 | ||
|
|
6350f5e6e8 | ||
|
|
10f3690ede | ||
|
|
06daa8bb0e | ||
|
|
34a90f442e | ||
|
|
afe81dcdbe | ||
|
|
24d616672b | ||
|
|
9cfc61cd45 | ||
|
|
487df84b90 | ||
|
|
614c1306f6 | ||
|
|
07dca9bd16 | ||
|
|
1ebcbd5b0e | ||
|
|
32644ddada | ||
|
|
cf3bab996e | ||
|
|
926ffe2581 | ||
|
|
fff3587d99 | ||
|
|
866cf940da | ||
|
|
7868e1527e | ||
|
|
556bfb752a | ||
|
|
a3b08654b4 | ||
|
|
4cf4436169 | ||
|
|
e2acc55819 | ||
|
|
6b29d6b8dc | ||
|
|
b668c4c302 | ||
|
|
646778227a | ||
|
|
a973630cb4 | ||
|
|
4e7375c09c | ||
|
|
881d0652e7 | ||
|
|
0c46993baa | ||
|
|
09b15f4940 | ||
|
|
ebf7be56bb | ||
|
|
727068cc4b | ||
|
|
6f77c6f3f4 | ||
|
|
c5e3e17eae | ||
|
|
effdb70417 | ||
|
|
e28f910c88 | ||
|
|
c84468dbed | ||
|
|
4b9e39ac64 | ||
|
|
6b0c05ee7c | ||
|
|
5c6ec70126 | ||
|
|
2757ef94c9 | ||
|
|
9ba7120011 | ||
|
|
124f9ec44e | ||
|
|
0d229175cd | ||
|
|
10638b6e40 | ||
|
|
134baad56d | ||
|
|
9a5984d750 | ||
|
|
073f42e64a | ||
|
|
096927beed | ||
|
|
4bc76995d1 | ||
|
|
9f41151156 | ||
|
|
6b3bd755b0 | ||
|
|
7e580e6a0b | ||
|
|
047c8eda22 | ||
|
|
f22e5c209c | ||
|
|
8cc3a08871 | ||
|
|
35f6c6cb98 | ||
|
|
814b174f25 | ||
|
|
5fbaf0bc7d | ||
|
|
ba772ab481 | ||
|
|
0a4888a18f | ||
|
|
fedbf2cc44 | ||
|
|
0f68bbac8e | ||
|
|
13e965096b | ||
|
|
92961bb7bf | ||
|
|
340686ba06 | ||
|
|
d8906f508c | ||
|
|
dde53ea4ba | ||
|
|
225ed5b662 | ||
|
|
02857cf2b5 | ||
|
|
118a771980 | ||
|
|
359123564f | ||
|
|
49d2878938 | ||
|
|
f08ea4a9a3 | ||
|
|
f2bc71bc2a | ||
|
|
2b1e40c6c6 | ||
|
|
105c2deeb3 | ||
|
|
c3dbbc9144 | ||
|
|
ca55a9a8a6 | ||
|
|
7ea5af448e | ||
|
|
2f6898142e | ||
|
|
02e0b8cc32 | ||
|
|
b962a4c69b | ||
|
|
ed3e83df67 | ||
|
|
b07bff61f0 | ||
|
|
a7c955055c | ||
|
|
13f33a9d19 | ||
|
|
be3fa6091d | ||
|
|
8ffddf06e4 | ||
|
|
9b7f583b2b | ||
|
|
9fe4f3adea | ||
|
|
74d9f89c09 | ||
|
|
63c36e917e | ||
|
|
184c6ee252 | ||
|
|
1c024afc1b | ||
|
|
51519361e2 | ||
|
|
bd092295a4 | ||
|
|
153c275d74 | ||
|
|
db0dfa1bf1 | ||
|
|
debd13d8c3 | ||
|
|
4b8466e5e5 | ||
|
|
9d9793e1af | ||
|
|
46fafebade | ||
|
|
1dae3d951a | ||
|
|
fb213a1efd | ||
|
|
93deb37c94 | ||
|
|
004a93a841 | ||
|
|
da5be9f01d | ||
|
|
344d0ae3ec | ||
|
|
3639c86adf | ||
|
|
4fc80fd366 | ||
|
|
336ab2d82a | ||
|
|
74a7e67002 | ||
|
|
f76c04b7a6 | ||
|
|
8130487b18 | ||
|
|
83790a5a73 | ||
|
|
1b35f68de9 | ||
|
|
3e912c6198 | ||
|
|
f995595202 | ||
|
|
6264569ca0 | ||
|
|
e868d427dd | ||
|
|
b9cbdb2dc4 | ||
|
|
7ae563867c | ||
|
|
f2f760bda4 | ||
|
|
ed561ad86b | ||
|
|
675861c323 | ||
|
|
ba330a42d6 | ||
|
|
2a9727c6b7 | ||
|
|
5be147e8cc | ||
|
|
eb96edbd31 | ||
|
|
14c85fa975 | ||
|
|
b0e3339370 | ||
|
|
70e502e55d | ||
|
|
ff38a3bbfe | ||
|
|
b5723a6c18 | ||
|
|
89012cd73b | ||
|
|
756e86662b | ||
|
|
27ca3b4b01 | ||
|
|
a5be4c9d0e | ||
|
|
07cc547bab | ||
|
|
f672af9706 | ||
|
|
58b058ab3a | ||
|
|
28c2ca8bf8 | ||
|
|
d7a06dc7a9 | ||
|
|
8970e6a48a | ||
|
|
b8eef181b9 | ||
|
|
fb94d6ae2b | ||
|
|
fa68e392c8 | ||
|
|
9eaa51442f | ||
|
|
68482d712b | ||
|
|
09fc767bb0 | ||
|
|
ea7e6615f2 | ||
|
|
a183ca8661 | ||
|
|
05939a2bbc | ||
|
|
543a372435 | ||
|
|
e795de5562 | ||
|
|
ae6877ce2f | ||
|
|
a0f3e81b11 | ||
|
|
88f52c4902 | ||
|
|
bf8db7725f | ||
|
|
f4d8c3304a | ||
|
|
44556b7f5e | ||
|
|
2e1e95d483 | ||
|
|
ccc24337be | ||
|
|
b15b38868d | ||
|
|
8feca6874a | ||
|
|
ecd3a49d48 | ||
|
|
6de7cd5063 | ||
|
|
f6d7f7d984 | ||
|
|
d5d501875e | ||
|
|
88561c22d3 | ||
|
|
b786576bcb | ||
|
|
21b5f2c96a | ||
|
|
d8f24b442b | ||
|
|
a1c81a63dd | ||
|
|
4d2b535b04 | ||
|
|
3cfbc05bf9 | ||
|
|
895820f14c | ||
|
|
37fc21f3cf | ||
|
|
5e068c3af5 | ||
|
|
e2c192d254 | ||
|
|
e481ed37ce | ||
|
|
4d7c089b09 | ||
|
|
a4dc67cba0 | ||
|
|
03973cc6d4 | ||
|
|
66c301c031 | ||
|
|
e4edc59689 | ||
|
|
f2d9d38c6f | ||
|
|
667ea43b3c | ||
|
|
f3856819fe | ||
|
|
d6bfe7810a | ||
|
|
7a52ae18f1 | ||
|
|
444539b826 | ||
|
|
c8d6425123 | ||
|
|
e50c35d38c | ||
|
|
aa764fbd1c | ||
|
|
2628426084 | ||
|
|
aa6bc8042a | ||
|
|
26a6c9e932 | ||
|
|
0f9376e959 | ||
|
|
ace3e86546 | ||
|
|
d79c6b8f06 | ||
|
|
6538a2e673 | ||
|
|
153d883aeb | ||
|
|
689432f627 | ||
|
|
cd237219e4 | ||
|
|
8589493581 | ||
|
|
ca2e148ad7 | ||
|
|
f7ca44cad8 | ||
|
|
1b2ac38a50 | ||
|
|
f62d25fa5f | ||
|
|
025eec1782 | ||
|
|
846ff46b2e | ||
|
|
f9718bccb9 | ||
|
|
f66f4ffee6 | ||
|
|
a47417ff49 | ||
|
|
c9836cf0f7 | ||
|
|
289b679e3c | ||
|
|
23e019ec83 | ||
|
|
eeffcea69e | ||
|
|
ae10793d0f | ||
|
|
a062bca431 | ||
|
|
6a453bcc8a | ||
|
|
5a2c4919c6 | ||
|
|
09a80ed654 | ||
|
|
72e954b78f | ||
|
|
a1c27aed6a | ||
|
|
0b3a719a95 | ||
|
|
6c9b4a8c5d | ||
|
|
d9babda1b8 | ||
|
|
ea8e1be294 | ||
|
|
44eccd85fd | ||
|
|
a62720b9d8 | ||
|
|
1a9422c3f9 | ||
|
|
5e52b3609c | ||
|
|
8622385e88 | ||
|
|
d0ffaab339 | ||
|
|
347157b999 | ||
|
|
a9f3235fd3 | ||
|
|
4098a5c08e | ||
|
|
dba7a2ee4f | ||
|
|
a5f49550b3 | ||
|
|
5c9a69e0e8 | ||
|
|
2bf32fb3fa | ||
|
|
0de1e2c6fc | ||
|
|
61868d97c4 | ||
|
|
c994c11d8c | ||
|
|
5ad10955be | ||
|
|
95f100f378 | ||
|
|
3d6c93cd6b | ||
|
|
fc25da37c5 | ||
|
|
896bb2187e | ||
|
|
99398bf0da | ||
|
|
827a54435d | ||
|
|
3c9459e489 | ||
|
|
9291f5c9c6 | ||
|
|
0ab5f993c7 | ||
|
|
4f8db487e7 | ||
|
|
0e1765e045 | ||
|
|
ebc411bbbd | ||
|
|
a76d8f0f9f | ||
|
|
f245feb0b0 | ||
|
|
43a90d7b98 | ||
|
|
2e1a9a8df9 | ||
|
|
57bb0da1d6 | ||
|
|
0d2df22074 | ||
|
|
c7173d5e1c | ||
|
|
789eb48698 | ||
|
|
e686fad546 | ||
|
|
4e4f9b6f8b | ||
|
|
f2292fd618 | ||
|
|
7035ead9e7 | ||
|
|
f01f6e94d1 | ||
|
|
f10064ce39 | ||
|
|
b68f06ca83 | ||
|
|
2ce61402bb | ||
|
|
70e9d85a75 | ||
|
|
a461f462d2 | ||
|
|
50ff0d251a | ||
|
|
f6103d3841 | ||
|
|
cb68d19bed | ||
|
|
89d2505a7c | ||
|
|
9ddfc750e5 | ||
|
|
3b80de1747 | ||
|
|
90ea714e48 | ||
|
|
f9e4182624 | ||
|
|
0291cc2ef4 | ||
|
|
caf2e469a6 | ||
|
|
45da2843ee | ||
|
|
8353f928a1 | ||
|
|
9c1a6d042e | ||
|
|
448b25a8b2 | ||
|
|
4c2d4009da | ||
|
|
67f1e07508 | ||
|
|
c49fdf1233 | ||
|
|
7c835bae20 | ||
|
|
ae81cc2644 | ||
|
|
3907b4101a | ||
|
|
aa5ea0e3a1 | ||
|
|
d21043802e | ||
|
|
995bdb3f9e | ||
|
|
8363b4fda7 | ||
|
|
23979f4ce6 | ||
|
|
28b5f39b84 | ||
|
|
47ce2398a4 | ||
|
|
0a83d8e6a0 | ||
|
|
aa215f2a5a | ||
|
|
b03a6a5327 | ||
|
|
ca36a6fe41 | ||
|
|
bd6285c8b1 | ||
|
|
00cfdc7d92 | ||
|
|
5e2dc14dd5 | ||
|
|
c5f2890cbe | ||
|
|
36aaca997a | ||
|
|
e9f7c61113 | ||
|
|
2373b94d3e | ||
|
|
f131e31949 | ||
|
|
8fd55a210a | ||
|
|
678650beaf | ||
|
|
e09386be44 | ||
|
|
75db2867dc | ||
|
|
80e37df012 | ||
|
|
1f404bb622 | ||
|
|
54078087e5 | ||
|
|
23b8df1c36 | ||
|
|
65395516b0 | ||
|
|
849308e28d | ||
|
|
4d98a64000 | ||
|
|
0c8fdfca7d | ||
|
|
fd928e8d12 | ||
|
|
2a1fe99a29 | ||
|
|
4fa4ba6301 | ||
|
|
48b3959cfb | ||
|
|
9bbff744e9 | ||
|
|
19b0c266f9 | ||
|
|
fead940d10 | ||
|
|
687e17ac52 | ||
|
|
b1c85dcb74 | ||
|
|
a15aad9f9c | ||
|
|
06a1a8690d | ||
|
|
42b9b6426a | ||
|
|
332f0118a2 | ||
|
|
6ed709d6e6 | ||
|
|
7a461c1684 | ||
|
|
7cf171671d | ||
|
|
ebee94fb11 | ||
|
|
61e8becd38 | ||
|
|
a78caa2976 | ||
|
|
c54f7c81c4 | ||
|
|
85840872ab | ||
|
|
d582c30f6e | ||
|
|
392f5f914a | ||
|
|
799d25925a | ||
|
|
4431d50635 | ||
|
|
e120e9a78e | ||
|
|
b6e379d14e | ||
|
|
9a86034162 | ||
|
|
8456c8b47b | ||
|
|
bb656ce44b | ||
|
|
3c2a3898e1 | ||
|
|
c265bd6c4d | ||
|
|
aff65083cc | ||
|
|
aff8cd478c | ||
|
|
bce2a63772 | ||
|
|
3f9d2601b4 | ||
|
|
04bfd52fba | ||
|
|
87dd890eb0 | ||
|
|
a5c0b48b57 | ||
|
|
5d38693b4d | ||
|
|
a4773d259d | ||
|
|
f9b6b1bf76 | ||
|
|
ef106f3232 | ||
|
|
c0b0df34d2 | ||
|
|
d15cc7cc47 | ||
|
|
6336d38a3e | ||
|
|
6a9d2ba653 | ||
|
|
34a8d4a57d | ||
|
|
ffc666eaaa | ||
|
|
c45aab7cef | ||
|
|
eefff148e9 | ||
|
|
05f7578928 | ||
|
|
2ebb2d8f0e | ||
|
|
afe2935c9d | ||
|
|
380c7b7720 | ||
|
|
8657226594 | ||
|
|
41da48f5ff | ||
|
|
405aa906c5 | ||
|
|
1c507a47d2 | ||
|
|
f48a7df80f | ||
|
|
5f73f09836 | ||
|
|
f63dd75f08 | ||
|
|
cc55335a8d | ||
|
|
b5875f3a0a | ||
|
|
cb8333a48f | ||
|
|
f412f4ca88 | ||
|
|
941f30d1ea | ||
|
|
97afa502c5 | ||
|
|
9ae9ea18e1 | ||
|
|
0bf2abaa4c | ||
|
|
924f281536 | ||
|
|
1fc5dacd87 | ||
|
|
5c877de2c2 | ||
|
|
751b95d4af | ||
|
|
e0d5ba9915 | ||
|
|
b8a6946661 | ||
|
|
e5fac08d1d | ||
|
|
df5b7c7d0d | ||
|
|
27649f7d4c | ||
|
|
350dea6228 | ||
|
|
aef6b7712c | ||
|
|
642bcfcdea | ||
|
|
e625d8aabc | ||
|
|
5888ecbdcd | ||
|
|
e2a76056b8 | ||
|
|
a98498eb06 | ||
|
|
8366c8d2a7 | ||
|
|
ed8d441a02 | ||
|
|
f1fb265119 | ||
|
|
6c628094ce | ||
|
|
a60c52e2f0 | ||
|
|
ac2e1709f8 | ||
|
|
db88183a23 | ||
|
|
c7d55ad858 | ||
|
|
06a4e6c323 | ||
|
|
d1de89f387 | ||
|
|
bbba01da92 | ||
|
|
25dbf62274 | ||
|
|
ed6851863b | ||
|
|
ba924e295e | ||
|
|
0828065a62 | ||
|
|
68c789dceb | ||
|
|
6424084502 | ||
|
|
4abea18afe | ||
|
|
0a3c4f131e | ||
|
|
f5e1077e20 | ||
|
|
44d1c3fd2f | ||
|
|
e345161763 | ||
|
|
64d7c87591 | ||
|
|
1fae3baaa3 | ||
|
|
38103aaac5 | ||
|
|
cc25b22f11 | ||
|
|
e6dbeda18e | ||
|
|
8437d45866 | ||
|
|
0bb89de821 | ||
|
|
905cad56d8 | ||
|
|
65eeb70eb3 | ||
|
|
266744f640 | ||
|
|
23d6739580 | ||
|
|
5c9970c786 | ||
|
|
3eae716a2d | ||
|
|
c57b13d922 | ||
|
|
17fb419fb1 | ||
|
|
598d0e216a | ||
|
|
7bbe926232 | ||
|
|
2e848a7c9a | ||
|
|
437225b43e | ||
|
|
d39229713f | ||
|
|
93911be1b9 | ||
|
|
b74055478c | ||
|
|
8614c4db73 | ||
|
|
215d39fc54 | ||
|
|
c4e5a130ee | ||
|
|
630072b574 | ||
|
|
5261a3e845 | ||
|
|
0096a91a57 | ||
|
|
56699a9f89 | ||
|
|
31ff1372ae | ||
|
|
3afb1922bb | ||
|
|
83c0a8b047 | ||
|
|
6699bd47b5 | ||
|
|
34223b8d4f | ||
|
|
5befe1f019 | ||
|
|
87f86e72f4 | ||
|
|
53b7eba31a | ||
|
|
12c12a8ad1 | ||
|
|
897cc7d355 | ||
|
|
2e5c56205c | ||
|
|
bc5ff37e37 | ||
|
|
20341a381f | ||
|
|
926b945846 | ||
|
|
aa877a73ba | ||
|
|
b28208d1bf | ||
|
|
9bd97383bd | ||
|
|
522c7b2f9d | ||
|
|
1833c0acbc | ||
|
|
c5644ee3f9 | ||
|
|
447566fe14 | ||
|
|
9692c34f6c | ||
|
|
37c450f1e1 | ||
|
|
a003e396c5 | ||
|
|
996f61efe1 | ||
|
|
40cdcf8b06 | ||
|
|
5947364846 | ||
|
|
9470107bba | ||
|
|
54b945511b | ||
|
|
acfaa0041e | ||
|
|
aeed2dbc3e | ||
|
|
0c6befe8a5 | ||
|
|
bdcb26edae | ||
|
|
e091667b42 | ||
|
|
d35b14f4cc | ||
|
|
87996c6811 | ||
|
|
a880c733c8 | ||
|
|
ca10dfeb5f | ||
|
|
91f55a637b | ||
|
|
8ae43cfd14 | ||
|
|
83d9513c4a | ||
|
|
1c76d43e44 | ||
|
|
1036ce0fa5 | ||
|
|
3dbab68f17 | ||
|
|
5896cebeaa | ||
|
|
fbe629154d | ||
|
|
364136213b | ||
|
|
136b663cef | ||
|
|
803f11bebb | ||
|
|
7c8036807a | ||
|
|
84ccca0e98 | ||
|
|
74efdb95e8 | ||
|
|
10e45ac493 | ||
|
|
60befdb36e | ||
|
|
59f99ea9bb | ||
|
|
1a894abcff | ||
|
|
4934fc8809 | ||
|
|
18cc6a184f | ||
|
|
0a08765d73 | ||
|
|
355c7437ed | ||
|
|
3c55c2d777 | ||
|
|
94806ad0b3 | ||
|
|
6840259734 | ||
|
|
a1fc48f2a6 | ||
|
|
400e3d21f9 | ||
|
|
8f3daad502 | ||
|
|
b0395933de | ||
|
|
f8f2ab9cba | ||
|
|
ae5f5375da | ||
|
|
ab5f1e712b | ||
|
|
4532ca97fa | ||
|
|
5a9ef57f78 | ||
|
|
8791f382b3 | ||
|
|
abdef67ccc | ||
|
|
33494c4f4b | ||
|
|
daad975f5d | ||
|
|
18c00f0a4b | ||
|
|
e7f46b4fbe | ||
|
|
74827cd8cf | ||
|
|
5ffe1893cd | ||
|
|
f24618e8df | ||
|
|
f843d34234 | ||
|
|
23c7340afe | ||
|
|
bf3615fb32 |
2
.dir-locals.el
Normal file
@@ -0,0 +1,2 @@
|
||||
((c++-mode . ((indent-tabs-mode . t)))
|
||||
(c-mode . ((mode . c++))))
|
||||
35
.gitignore
vendored
@@ -1,16 +1,21 @@
|
||||
# i2pd
|
||||
obj/*.o
|
||||
*.o
|
||||
router.info
|
||||
router.keys
|
||||
i2p
|
||||
libi2pd.so
|
||||
netDb
|
||||
/i2pd
|
||||
/libi2pd.a
|
||||
/libi2pdclient.a
|
||||
*.exe
|
||||
|
||||
|
||||
# Autotools
|
||||
autom4te.cache
|
||||
.deps
|
||||
stamp-h1
|
||||
Makefile
|
||||
#Makefile
|
||||
config.h
|
||||
config.h.in~
|
||||
config.log
|
||||
@@ -233,3 +238,29 @@ pip-log.txt
|
||||
|
||||
# Sphinx
|
||||
docs/_build
|
||||
/androidIdea/
|
||||
|
||||
# Doxygen
|
||||
docs/generated
|
||||
|
||||
# emacs files
|
||||
*~
|
||||
*\#*
|
||||
|
||||
# gdb files
|
||||
.gdb_history
|
||||
|
||||
# cmake makefile
|
||||
build/Makefile
|
||||
|
||||
# debian stuff
|
||||
.pc/
|
||||
|
||||
# qt
|
||||
|
||||
qt/i2pd_qt/*.ui.autosave
|
||||
qt/i2pd_qt/*.ui.bk*
|
||||
qt/i2pd_qt/*.ui_*
|
||||
|
||||
#unknown android stuff
|
||||
android/libs/
|
||||
|
||||
67
.travis.yml
@@ -2,30 +2,53 @@ language: cpp
|
||||
cache:
|
||||
apt: true
|
||||
os:
|
||||
- linux
|
||||
sudo: required
|
||||
- linux
|
||||
#- osx
|
||||
dist: trusty
|
||||
sudo: required
|
||||
compiler:
|
||||
- g++
|
||||
- clang++
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j 2"
|
||||
matrix:
|
||||
- BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
|
||||
- BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
|
||||
- BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
|
||||
- BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
|
||||
- os: osx
|
||||
env: BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
env: BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
|
||||
- os: linux
|
||||
compiler: clang++
|
||||
env: BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- cmake
|
||||
- g++
|
||||
- clang
|
||||
- libboost-chrono-dev
|
||||
- libboost-date-time-dev
|
||||
- libboost-filesystem-dev
|
||||
- libboost-program-options-dev
|
||||
- libboost-regex-dev
|
||||
- libboost-system-dev
|
||||
- libboost-thread-dev
|
||||
- libminiupnpc-dev
|
||||
- libssl-dev
|
||||
compiler:
|
||||
- gcc
|
||||
env:
|
||||
matrix:
|
||||
- BUILD_TYPE=Release UPNP=ON
|
||||
- BUILD_TYPE=Release UPNP=OFF
|
||||
- build-essential
|
||||
- cmake
|
||||
- g++
|
||||
- clang
|
||||
- libboost-chrono-dev
|
||||
- libboost-date-time-dev
|
||||
- libboost-filesystem-dev
|
||||
- libboost-program-options-dev
|
||||
- libboost-system-dev
|
||||
- libboost-thread-dev
|
||||
- libminiupnpc-dev
|
||||
- libssl-dev
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libressl miniupnpc ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew outdated boost || brew upgrade boost ; fi
|
||||
script:
|
||||
- cd build && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_UPNP=${UPNP} && make
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "cmake" ]]; then cd build && cmake -DCMAKE_BUILD_TYPE=Release -DWITH_UPNP=${UPNP} && make ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "make" ]]; then make USE_UPNP=${MAKE_UPNP} ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make HOMEBREW=1 USE_UPNP=${MAKE_UPNP} ; fi
|
||||
|
||||
582
AddressBook.cpp
@@ -1,582 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "Base.h"
|
||||
#include "util.h"
|
||||
#include "Identity.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "NetDb.h"
|
||||
#include "ClientContext.h"
|
||||
#include "AddressBook.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
// TODO: this is actually proxy class
|
||||
class AddressBookFilesystemStorage: public AddressBookStorage
|
||||
{
|
||||
private:
|
||||
i2p::fs::HashedStorage storage;
|
||||
std::string indexPath;
|
||||
|
||||
public:
|
||||
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") {};
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const;
|
||||
void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
||||
void RemoveAddress (const i2p::data::IdentHash& ident);
|
||||
|
||||
bool Init ();
|
||||
int Load (std::map<std::string, i2p::data::IdentHash>& addresses);
|
||||
int Save (const std::map<std::string, i2p::data::IdentHash>& addresses);
|
||||
};
|
||||
|
||||
bool AddressBookFilesystemStorage::Init()
|
||||
{
|
||||
storage.SetPlace(i2p::fs::GetDataDir());
|
||||
indexPath = storage.GetRoot() + i2p::fs::dirSep + "addresses.csv";
|
||||
return storage.Init(i2p::data::GetBase32SubstitutionTable(), 32);
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
|
||||
{
|
||||
std::string filename = storage.Path(ident.ToBase32());
|
||||
std::ifstream f(filename, std::ifstream::binary);
|
||||
if (!f.is_open ()) {
|
||||
LogPrint(eLogDebug, "Addressbook: Requested, but not found: ", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
f.seekg (0,std::ios::end);
|
||||
size_t len = f.tellg ();
|
||||
if (len < i2p::data::DEFAULT_IDENTITY_SIZE) {
|
||||
LogPrint (eLogError, "Addresbook: File ", filename, " is too short: ", len);
|
||||
return nullptr;
|
||||
}
|
||||
f.seekg(0, std::ios::beg);
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
f.read((char *)buf, len);
|
||||
auto address = std::make_shared<i2p::data::IdentityEx>(buf, len);
|
||||
delete[] buf;
|
||||
return address;
|
||||
}
|
||||
|
||||
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||
{
|
||||
std::string path = storage.Path( address->GetIdentHash().ToBase32() );
|
||||
std::ofstream f (path, std::ofstream::binary | std::ofstream::out);
|
||||
if (!f.is_open ()) {
|
||||
LogPrint (eLogError, "Addresbook: can't open file ", path);
|
||||
return;
|
||||
}
|
||||
size_t len = address->GetFullLen ();
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
address->ToBuffer (buf, len);
|
||||
f.write ((char *)buf, len);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
storage.Remove( ident.ToBase32() );
|
||||
}
|
||||
|
||||
int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses)
|
||||
{
|
||||
int num = 0;
|
||||
std::string s;
|
||||
std::ifstream f (indexPath, std::ifstream::in); // in text mode
|
||||
|
||||
if (f.is_open ()) {
|
||||
LogPrint(eLogInfo, "Addressbook: using index file ", indexPath);
|
||||
} else {
|
||||
LogPrint(eLogWarning, "Addressbook: Can't open ", indexPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addresses.clear ();
|
||||
while (!f.eof ()) {
|
||||
getline(f, s);
|
||||
if (!s.length())
|
||||
continue; // skip empty line
|
||||
|
||||
std::size_t pos = s.find(',');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string name = s.substr(0, pos++);
|
||||
std::string addr = s.substr(pos);
|
||||
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (addr);
|
||||
addresses[name] = ident;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded from storage");
|
||||
return num;
|
||||
}
|
||||
|
||||
int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
|
||||
{
|
||||
if (addresses.size() == 0) {
|
||||
LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
std::ofstream f (indexPath, std::ofstream::out); // in text mode
|
||||
|
||||
if (!f.is_open ()) {
|
||||
LogPrint (eLogWarning, "Addressbook: Can't open ", indexPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto it: addresses) {
|
||||
f << it.first << "," << it.second.ToBase32 () << std::endl;
|
||||
num++;
|
||||
}
|
||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
||||
return num;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false),
|
||||
m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AddressBook::~AddressBook ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void AddressBook::Start ()
|
||||
{
|
||||
m_Storage->Init();
|
||||
LoadHosts (); /* try storage, then hosts.txt, then download */
|
||||
StartSubscriptions ();
|
||||
}
|
||||
|
||||
void AddressBook::Stop ()
|
||||
{
|
||||
StopSubscriptions ();
|
||||
if (m_SubscriptionsUpdateTimer)
|
||||
{
|
||||
delete m_SubscriptionsUpdateTimer;
|
||||
m_SubscriptionsUpdateTimer = nullptr;
|
||||
}
|
||||
if (m_IsDownloading)
|
||||
{
|
||||
LogPrint (eLogInfo, "Addresbook: subscriptions is downloading, abort");
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
if (!m_IsDownloading)
|
||||
{
|
||||
LogPrint (eLogInfo, "Addresbook: subscriptions download complete");
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for (std::chrono::seconds (1)); // wait for 1 seconds
|
||||
}
|
||||
LogPrint (eLogError, "Addresbook: subscription download timeout");
|
||||
m_IsDownloading = false;
|
||||
}
|
||||
if (m_Storage)
|
||||
{
|
||||
m_Storage->Save (m_Addresses);
|
||||
delete m_Storage;
|
||||
m_Storage = nullptr;
|
||||
}
|
||||
m_DefaultSubscription = nullptr;
|
||||
for (auto it: m_Subscriptions)
|
||||
delete it;
|
||||
m_Subscriptions.clear ();
|
||||
}
|
||||
|
||||
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto pos = address.find(".b32.i2p");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
Base32ToByteStream (address.c_str(), pos, ident, 32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = address.find (".i2p");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto identHash = FindAddress (address);
|
||||
if (identHash)
|
||||
{
|
||||
ident = *identHash;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if not .b32 we assume full base64 address
|
||||
i2p::data::IdentityEx dest;
|
||||
if (!dest.FromBase64 (address))
|
||||
return false;
|
||||
ident = dest.GetIdentHash ();
|
||||
return true;
|
||||
}
|
||||
|
||||
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
|
||||
{
|
||||
auto it = m_Addresses.find (address);
|
||||
if (it != m_Addresses.end ())
|
||||
return &it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AddressBook::InsertAddress (const std::string& address, const std::string& base64)
|
||||
{
|
||||
auto ident = std::make_shared<i2p::data::IdentityEx>();
|
||||
ident->FromBase64 (base64);
|
||||
m_Storage->AddAddress (ident);
|
||||
m_Addresses[address] = ident->GetIdentHash ();
|
||||
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ()));
|
||||
}
|
||||
|
||||
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||
{
|
||||
m_Storage->AddAddress (address);
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetAddress (const std::string& address)
|
||||
{
|
||||
i2p::data::IdentHash ident;
|
||||
if (!GetIdentHash (address, ident)) return nullptr;
|
||||
return m_Storage->GetAddress (ident);
|
||||
}
|
||||
|
||||
void AddressBook::LoadHosts ()
|
||||
{
|
||||
if (m_Storage->Load (m_Addresses) > 0)
|
||||
{
|
||||
m_IsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// then try hosts.txt
|
||||
std::ifstream f (i2p::fs::DataDirPath("hosts.txt"), std::ifstream::in); // in text mode
|
||||
if (f.is_open ())
|
||||
{
|
||||
LoadHostsFromStream (f);
|
||||
m_IsLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBook::LoadHostsFromStream (std::istream& f)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_AddressBookMutex);
|
||||
int numAddresses = 0;
|
||||
std::string s;
|
||||
while (!f.eof ())
|
||||
{
|
||||
getline(f, s);
|
||||
|
||||
if (!s.length())
|
||||
continue; // skip empty line
|
||||
|
||||
size_t pos = s.find('=');
|
||||
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string name = s.substr(0, pos++);
|
||||
std::string addr = s.substr(pos);
|
||||
|
||||
auto ident = std::make_shared<i2p::data::IdentityEx> ();
|
||||
if (ident->FromBase64(addr))
|
||||
{
|
||||
m_Addresses[name] = ident->GetIdentHash ();
|
||||
m_Storage->AddAddress (ident);
|
||||
numAddresses++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Addresbook: malformed address ", addr, " for ", name);
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Addresbook: ", numAddresses, " addresses processed");
|
||||
if (numAddresses > 0)
|
||||
{
|
||||
m_IsLoaded = true;
|
||||
m_Storage->Save (m_Addresses);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBook::LoadSubscriptions ()
|
||||
{
|
||||
if (!m_Subscriptions.size ())
|
||||
{
|
||||
std::ifstream f (i2p::fs::DataDirPath ("subscriptions.txt"), std::ifstream::in); // in text mode
|
||||
if (f.is_open ())
|
||||
{
|
||||
std::string s;
|
||||
while (!f.eof ())
|
||||
{
|
||||
getline(f, s);
|
||||
if (!s.length()) continue; // skip empty line
|
||||
m_Subscriptions.push_back (new AddressBookSubscription (*this, s));
|
||||
}
|
||||
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Addresbook: subscriptions.txt not found in datadir");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Addressbook: subscriptions already loaded");
|
||||
}
|
||||
|
||||
void AddressBook::DownloadComplete (bool success)
|
||||
{
|
||||
m_IsDownloading = false;
|
||||
if (success && m_DefaultSubscription)
|
||||
{
|
||||
m_DefaultSubscription.reset (nullptr);
|
||||
m_IsLoaded = true;
|
||||
}
|
||||
if (m_SubscriptionsUpdateTimer)
|
||||
{
|
||||
m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(
|
||||
success ? CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT : CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT));
|
||||
m_SubscriptionsUpdateTimer->async_wait (std::bind (&AddressBook::HandleSubscriptionsUpdateTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBook::StartSubscriptions ()
|
||||
{
|
||||
LoadSubscriptions ();
|
||||
if (m_IsLoaded && m_Subscriptions.empty ()) return;
|
||||
|
||||
auto dest = i2p::client::context.GetSharedLocalDestination ();
|
||||
if (dest)
|
||||
{
|
||||
m_SubscriptionsUpdateTimer = new boost::asio::deadline_timer (dest->GetService ());
|
||||
m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT));
|
||||
m_SubscriptionsUpdateTimer->async_wait (std::bind (&AddressBook::HandleSubscriptionsUpdateTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Addresbook: can't start subscriptions: missing shared local destination");
|
||||
}
|
||||
|
||||
void AddressBook::StopSubscriptions ()
|
||||
{
|
||||
if (m_SubscriptionsUpdateTimer)
|
||||
m_SubscriptionsUpdateTimer->cancel ();
|
||||
}
|
||||
|
||||
void AddressBook::HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto dest = i2p::client::context.GetSharedLocalDestination ();
|
||||
if (!dest) {
|
||||
LogPrint(eLogWarning, "Addressbook: missing local destination, skip subscription update");
|
||||
return;
|
||||
}
|
||||
if (!m_IsDownloading && dest->IsReady ())
|
||||
{
|
||||
if (!m_IsLoaded)
|
||||
{
|
||||
// download it from http://i2p-projekt.i2p/hosts.txt
|
||||
LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription.");
|
||||
if (!m_DefaultSubscription)
|
||||
m_DefaultSubscription.reset (new AddressBookSubscription (*this, DEFAULT_SUBSCRIPTION_ADDRESS));
|
||||
m_IsDownloading = true;
|
||||
m_DefaultSubscription->CheckSubscription ();
|
||||
}
|
||||
else if (!m_Subscriptions.empty ())
|
||||
{
|
||||
// pick random subscription
|
||||
auto ind = rand () % m_Subscriptions.size();
|
||||
m_IsDownloading = true;
|
||||
m_Subscriptions[ind]->CheckSubscription ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// try it again later
|
||||
m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(INITIAL_SUBSCRIPTION_RETRY_TIMEOUT));
|
||||
m_SubscriptionsUpdateTimer->async_wait (std::bind (&AddressBook::HandleSubscriptionsUpdateTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link):
|
||||
m_Book (book), m_Link (link)
|
||||
{
|
||||
}
|
||||
|
||||
void AddressBookSubscription::CheckSubscription ()
|
||||
{
|
||||
std::thread load_hosts(&AddressBookSubscription::Request, this);
|
||||
load_hosts.detach(); // TODO: use join
|
||||
}
|
||||
|
||||
void AddressBookSubscription::Request ()
|
||||
{
|
||||
// must be run in separate thread
|
||||
LogPrint (eLogInfo, "Addresbook: Downloading hosts database from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||
bool success = false;
|
||||
i2p::util::http::url u (m_Link);
|
||||
i2p::data::IdentHash ident;
|
||||
if (m_Book.GetIdentHash (u.host_, ident))
|
||||
{
|
||||
std::condition_variable newDataReceived;
|
||||
std::mutex newDataReceivedMutex;
|
||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident);
|
||||
if (!leaseSet)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
||||
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (ident,
|
||||
[&newDataReceived, &leaseSet](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||
{
|
||||
leaseSet = ls;
|
||||
newDataReceived.notify_all ();
|
||||
});
|
||||
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
|
||||
{
|
||||
LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
|
||||
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident);
|
||||
}
|
||||
}
|
||||
if (leaseSet)
|
||||
{
|
||||
std::stringstream request, response;
|
||||
// standard header
|
||||
request << "GET " << u.path_ << " HTTP/1.1\r\n"
|
||||
<< "Host: " << u.host_ << "\r\n"
|
||||
<< "Accept: */*\r\n"
|
||||
<< "User-Agent: Wget/1.11.4\r\n"
|
||||
//<< "Accept-Encoding: gzip\r\n"
|
||||
<< "X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n"
|
||||
<< "Connection: close\r\n";
|
||||
if (m_Etag.length () > 0) // etag
|
||||
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
|
||||
if (m_LastModified.length () > 0) // if-modfief-since
|
||||
request << i2p::util::http::IF_MODIFIED_SINCE << ": " << m_LastModified << "\r\n";
|
||||
request << "\r\n"; // end of header
|
||||
auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, u.port_);
|
||||
stream->Send ((uint8_t *)request.str ().c_str (), request.str ().length ());
|
||||
|
||||
uint8_t buf[4096];
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
stream->AsyncReceive (boost::asio::buffer (buf, 4096),
|
||||
[&](const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (bytes_transferred)
|
||||
response.write ((char *)buf, bytes_transferred);
|
||||
if (ecode == boost::asio::error::timed_out || !stream->IsOpen ())
|
||||
end = true;
|
||||
newDataReceived.notify_all ();
|
||||
},
|
||||
30); // wait for 30 seconds
|
||||
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
||||
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
|
||||
LogPrint (eLogError, "Addresbook: subscriptions request timeout expired");
|
||||
}
|
||||
// process remaining buffer
|
||||
while (size_t len = stream->ReadSome (buf, 4096))
|
||||
response.write ((char *)buf, len);
|
||||
|
||||
// parse response
|
||||
std::string version;
|
||||
response >> version; // HTTP version
|
||||
int status = 0;
|
||||
response >> status; // status
|
||||
if (status == 200) // OK
|
||||
{
|
||||
bool isChunked = false, isGzip = false;
|
||||
std::string header, statusMessage;
|
||||
std::getline (response, statusMessage);
|
||||
// read until new line meaning end of header
|
||||
while (!response.eof () && header != "\r")
|
||||
{
|
||||
std::getline (response, header);
|
||||
auto colon = header.find (':');
|
||||
if (colon != std::string::npos)
|
||||
{
|
||||
std::string field = header.substr (0, colon);
|
||||
boost::to_lower (field); // field are not case-sensitive
|
||||
colon++;
|
||||
header.resize (header.length () - 1); // delete \r
|
||||
if (field == i2p::util::http::ETAG)
|
||||
m_Etag = header.substr (colon + 1);
|
||||
else if (field == i2p::util::http::LAST_MODIFIED)
|
||||
m_LastModified = header.substr (colon + 1);
|
||||
else if (field == i2p::util::http::TRANSFER_ENCODING)
|
||||
isChunked = !header.compare (colon + 1, std::string::npos, "chunked");
|
||||
else if (field == i2p::util::http::CONTENT_ENCODING)
|
||||
isGzip = !header.compare (colon + 1, std::string::npos, "gzip") ||
|
||||
!header.compare (colon + 1, std::string::npos, "x-i2p-gzip");
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||
if (!response.eof ())
|
||||
{
|
||||
success = true;
|
||||
if (!isChunked)
|
||||
success = ProcessResponse (response, isGzip);
|
||||
else
|
||||
{
|
||||
// merge chunks
|
||||
std::stringstream merged;
|
||||
i2p::util::http::MergeChunkedResponse (response, merged);
|
||||
success = ProcessResponse (merged, isGzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (status == 304)
|
||||
{
|
||||
success = true;
|
||||
LogPrint (eLogInfo, "Addressbook: no updates from ", m_Link);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Adressbook: HTTP response ", status);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Addressbook: address ", u.host_, " not found");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Addressbook: Can't resolve ", u.host_);
|
||||
|
||||
if (!success)
|
||||
LogPrint (eLogError, "Addressbook: download hosts.txt from ", m_Link, " failed");
|
||||
|
||||
m_Book.DownloadComplete (success);
|
||||
}
|
||||
|
||||
bool AddressBookSubscription::ProcessResponse (std::stringstream& s, bool isGzip)
|
||||
{
|
||||
if (isGzip)
|
||||
{
|
||||
std::stringstream uncompressed;
|
||||
i2p::data::GzipInflator inflator;
|
||||
inflator.Inflate (s, uncompressed);
|
||||
if (!uncompressed.fail ())
|
||||
m_Book.LoadHostsFromStream (uncompressed);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_Book.LoadHostsFromStream (s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
134
Base.h
@@ -1,134 +0,0 @@
|
||||
#ifndef BASE_H__
|
||||
#define BASE_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <zlib.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
|
||||
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
||||
const char * GetBase32SubstitutionTable ();
|
||||
const char * GetBase64SubstitutionTable ();
|
||||
|
||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
||||
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||
|
||||
/**
|
||||
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
||||
*/
|
||||
size_t Base64EncodingBufferSize(const size_t input_size);
|
||||
|
||||
template<int sz>
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
|
||||
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
|
||||
Tag (const Tag<sz>& ) = default;
|
||||
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
|
||||
Tag (Tag<sz>&& ) = default;
|
||||
#endif
|
||||
Tag () = default;
|
||||
|
||||
Tag<sz>& operator= (const Tag<sz>& ) = default;
|
||||
#ifndef _WIN32
|
||||
Tag<sz>& operator= (Tag<sz>&& ) = default;
|
||||
#endif
|
||||
|
||||
uint8_t * operator()() { return m_Buf; };
|
||||
const uint8_t * operator()() const { return m_Buf; };
|
||||
|
||||
operator uint8_t * () { return m_Buf; };
|
||||
operator const uint8_t * () const { return m_Buf; };
|
||||
|
||||
const uint64_t * GetLL () const { return ll; };
|
||||
|
||||
bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
|
||||
bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; };
|
||||
|
||||
bool IsZero () const
|
||||
{
|
||||
for (int i = 0; i < sz/8; i++)
|
||||
if (ll[i]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ToBase64 () const
|
||||
{
|
||||
char str[sz*2];
|
||||
int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2);
|
||||
str[l] = 0;
|
||||
return std::string (str);
|
||||
}
|
||||
|
||||
std::string ToBase32 () const
|
||||
{
|
||||
char str[sz*2];
|
||||
int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2);
|
||||
str[l] = 0;
|
||||
return std::string (str);
|
||||
}
|
||||
|
||||
void FromBase32 (const std::string& s)
|
||||
{
|
||||
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||
}
|
||||
|
||||
void FromBase64 (const std::string& s)
|
||||
{
|
||||
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
union // 8 bytes alignment
|
||||
{
|
||||
uint8_t m_Buf[sz];
|
||||
uint64_t ll[sz/8];
|
||||
};
|
||||
};
|
||||
|
||||
const size_t GZIP_CHUNK_SIZE = 16384;
|
||||
class GzipInflator
|
||||
{
|
||||
public:
|
||||
|
||||
GzipInflator ();
|
||||
~GzipInflator ();
|
||||
|
||||
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
||||
bool Inflate (const uint8_t * in, size_t inLen, std::ostream& s);
|
||||
// return true when finshed or error, s failbit will be set in case of error
|
||||
void Inflate (std::istream& in, std::ostream& out);
|
||||
|
||||
private:
|
||||
|
||||
z_stream m_Inflator;
|
||||
bool m_IsDirty;
|
||||
};
|
||||
|
||||
class GzipDeflator
|
||||
{
|
||||
public:
|
||||
|
||||
GzipDeflator ();
|
||||
~GzipDeflator ();
|
||||
|
||||
void SetCompressionLevel (int level);
|
||||
size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
||||
|
||||
private:
|
||||
|
||||
z_stream m_Deflator;
|
||||
bool m_IsDirty;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
299
ChangeLog
Normal file
@@ -0,0 +1,299 @@
|
||||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.21.0] - 2018-10-04
|
||||
### Added
|
||||
- EdDSA, x25519 and SipHash from openssl 1.1.1
|
||||
- NTCP2 ipv6 incoming connections
|
||||
- Show total number of destination's outgoing tags in the web console
|
||||
### Changed
|
||||
- Android build with openssl 1.1.1/boost 1.64
|
||||
- Bandwidth classes 'P' and 'X' don't add 'O' anymore
|
||||
### Fixed
|
||||
- Update own RouterInfo if no SSU
|
||||
- Recognize 'P' and 'X' routers as high bandwidth without 'O'
|
||||
- NTCP address doesn't disappear if NTCP2 enabled
|
||||
- Android with api 26+
|
||||
|
||||
## [2.20.0] - 2018-08-23
|
||||
### Added
|
||||
- Full implementation of NTCP2
|
||||
- Assets for android
|
||||
### Changed
|
||||
- armeabi-v7a and x86 in one apk for android
|
||||
- NTCP2 is enabled by default
|
||||
- Show lease's expiration time in readable format in the web console
|
||||
### Fixed
|
||||
- Correct names for transports in the web console
|
||||
|
||||
## [2.19.0] - 2018-06-26
|
||||
### Added
|
||||
- ECIES support for RouterInfo
|
||||
- HTTP outproxy authorization
|
||||
- AVX/AESNI runtime detection
|
||||
- Initial implementation of NTCP2
|
||||
- I2CP session reconfigure
|
||||
- I2CP method ClientServicesInfo
|
||||
- Datagrams to websocks
|
||||
### Changed
|
||||
- RouterInfo uses EdDSA signature by default
|
||||
- Remove stream bans
|
||||
- Android build system changed to gradle
|
||||
- Multiple changes in QT GUI
|
||||
- Dockerfile
|
||||
### Fixed
|
||||
- zero tunnelID issue
|
||||
- tunnels reload
|
||||
- headers in webconsole
|
||||
- XSS in webconsole from SAM session name
|
||||
- build for gcc 8
|
||||
- cmake build scripts
|
||||
- systemd service files
|
||||
- some netbsd issues
|
||||
|
||||
## [2.18.0] - 2018-01-30
|
||||
### Added
|
||||
- Show tunnel nicknames for I2CP destination in WebUI
|
||||
- Re-create HTTP and SOCKS proxy by tunnel reload
|
||||
- Graceful shutdown as soon as no more transit tunnels
|
||||
### Changed
|
||||
- Regenerate shared local destination by tunnel reload
|
||||
- Use transient local destination by default if not specified
|
||||
- Return correct code if pid file can't be created
|
||||
- Timing and number of attempts for adressbook requests
|
||||
- Certificates list
|
||||
### Fixed
|
||||
- Malformed addressbook subsctiption request
|
||||
- Build with boost 1.66
|
||||
- Few race conditions for SAM
|
||||
- Check LeaseSet's signature before update
|
||||
|
||||
## [2.17.0] - 2017-12-04
|
||||
### Added
|
||||
- Reseed through HTTP and SOCKS proxy
|
||||
- Show status of client services through web console
|
||||
- Change log level through web connsole
|
||||
- transient keys for tunnels
|
||||
- i2p.streaming.initialAckDelay parameter
|
||||
- CRYPTO_TYPE for SAM destination
|
||||
- signature and crypto type for newkeys BOB command
|
||||
### Changed
|
||||
- Correct publication of ECIES destinations
|
||||
- Disable RSA signatures completely
|
||||
### Fixed
|
||||
- CVE-2017-17066
|
||||
- Possible buffer overflow for RSA-4096
|
||||
- Shutdown from web console for Windows
|
||||
- Web console page layout
|
||||
## [2.16.0] - 2017-11-13
|
||||
### Added
|
||||
- https and "Connect" method for HTTP proxy
|
||||
- outproxy for HTTP proxy
|
||||
- initial support of ECIES crypto
|
||||
- NTCP soft and hard descriptors limits
|
||||
- Support full timestamps in logs
|
||||
### Changed
|
||||
- Faster implementation of GOST R 34.11 hash
|
||||
- Reject routers with RSA signtures
|
||||
- Reload config and shudown from Windows GUI
|
||||
- Update tunnels address(destination) without restart
|
||||
### Fixed
|
||||
- BOB crashes if destination is not set
|
||||
- Correct SAM tunnel name
|
||||
- QT GUI issues
|
||||
|
||||
## [2.15.0] - 2017-08-17
|
||||
### Added
|
||||
- QT GUI
|
||||
- Ability to add and remove I2P tunnels without restart
|
||||
- Ability to disable SOCKS outproxy option
|
||||
### Changed
|
||||
- Strip-out Accept-* hedaers in HTTP proxy
|
||||
- Don't run peer test if nat=false
|
||||
- Separate output of NTCP and SSU sessions in Transports tab
|
||||
### Fixed
|
||||
- Handle lines with comments in hosts.txt file for address book
|
||||
- Run router with empty netdb for testnet
|
||||
- Skip expired introducers by iexp
|
||||
|
||||
## [2.14.0] - 2017-06-01
|
||||
### Added
|
||||
- Transit traffic bandwidth limitation
|
||||
- NTCP connections through HTTP and SOCKS proxies
|
||||
- Ability to disable address helper for HTTP proxy
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- Minimal required version is 4.0 for Android
|
||||
### Fixed
|
||||
- Ignore comments in addressbook feed
|
||||
|
||||
## [2.13.0] - 2017-04-06
|
||||
### Added
|
||||
- Persist local destination's tags
|
||||
- GOST signature types 9 and 10
|
||||
- Exploratory tunnels configuration
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- Inactive NTCP sockets get closed faster
|
||||
- Some EdDSA speed up
|
||||
### Fixed
|
||||
- Multiple acceptors for SAM
|
||||
- Follow on data after STREAM CREATE for SAM
|
||||
- Memory leaks
|
||||
|
||||
## [2.12.0] - 2017-02-14
|
||||
### Added
|
||||
- Additional HTTP and SOCKS proxy tunnels
|
||||
- Reseed from ZIP archive
|
||||
- Some stats in a main window for Windows version
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- MTU of 1488 for ipv6
|
||||
- Android and Mac OS X versions use OpenSSL 1.1
|
||||
- New logo for Android
|
||||
### Fixed
|
||||
- Multiple memory leaks
|
||||
- Incomptibility of some EdDSA private keys with Java
|
||||
- Clock skew for Windows XP
|
||||
- Occasional crashes with I2PSnark
|
||||
|
||||
## [2.11.0] - 2016-12-18
|
||||
### Added
|
||||
- Websockets support
|
||||
- Reseed through a floodfill
|
||||
- Tunnel configuration for HTTP and SOCKS proxy
|
||||
- Zero-hops tunnels for destinations
|
||||
- Multiple acceptors for SAM
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- DHT uses AVX if applicable
|
||||
- New logo
|
||||
- LeaseSet lookups
|
||||
### Fixed
|
||||
- HTTP Proxy connection reset for Windows
|
||||
- Crash upon SAM session termination
|
||||
- Can't connect to a destination for a longer time after restart
|
||||
- Mass packet loss for UDP tunnels
|
||||
|
||||
## [2.10.2] - 2016-12-04
|
||||
### Fixed
|
||||
- Fixes UPnP discovery bug, producing excessive CPU usage
|
||||
- Fixes sudden SSU thread stop for Windows.
|
||||
|
||||
## [2.10.1] - 2016-11-07
|
||||
### Fixed
|
||||
- Fixed some performance issues for Windows and Android
|
||||
|
||||
## [2.10.0] - 2016-10-17
|
||||
### Added
|
||||
- Datagram i2p tunnels
|
||||
- Unique local addresses for server tunnels
|
||||
- Configurable list of reseed servers and initial addressbook
|
||||
- Configurable netid
|
||||
- Initial iOS support
|
||||
|
||||
### Changed
|
||||
- Reduced file descriptors usage
|
||||
- Strict reseed checks enabled by default
|
||||
|
||||
## Fixed
|
||||
- Multiple fixes in I2CP and BOB implementations
|
||||
|
||||
## [2.9.0] - 2016-08-12
|
||||
### Changed
|
||||
- Proxy refactoring & speedup
|
||||
- Transmission-I2P support
|
||||
- Graceful shutdown for Windows
|
||||
- Android without QT
|
||||
- Reduced number of timers in SSU
|
||||
- ipv6 peer test support
|
||||
- Reseed from SU3 file
|
||||
|
||||
## [2.8.0] - 2016-06-20
|
||||
### Added
|
||||
- Basic Android support
|
||||
- I2CP implementation
|
||||
- 'doxygen' target
|
||||
|
||||
### Changed
|
||||
- I2PControl refactoring & fixes (proper jsonrpc responses on errors)
|
||||
- boost::regex no more needed
|
||||
|
||||
### Fixed
|
||||
- initscripts: added openrc one, in sysv-ish make I2PD_PORT optional
|
||||
- properly close NTCP sessions (memleak)
|
||||
|
||||
## [2.7.0] - 2016-05-18
|
||||
### Added
|
||||
- Precomputed El-Gamal/DH tables
|
||||
- Configurable limit of transit tunnels
|
||||
|
||||
### Changed
|
||||
- Speed-up of asymmetric crypto for non-x64 platforms
|
||||
- Refactoring of web-console
|
||||
|
||||
## [2.6.0] - 2016-03-31
|
||||
### Added
|
||||
- Graceful shutdown on SIGINT
|
||||
- Numeric bandwidth limits (was: by router class)
|
||||
- Jumpservices in web-console
|
||||
- Logging to syslog
|
||||
- Tray icon for windows application
|
||||
|
||||
### Changed
|
||||
- Logs refactoring
|
||||
- Improved statistics in web-console
|
||||
|
||||
### Deprecated:
|
||||
- Renamed main/tunnels config files (will use old, if found, but emits warning)
|
||||
|
||||
## [2.5.1] - 2016-03-10
|
||||
### Fixed
|
||||
- Doesn't create ~/.i2pd dir if missing
|
||||
|
||||
## [2.5.0] - 2016-03-04
|
||||
### Added
|
||||
- IRC server tunnels
|
||||
- SOCKS outproxy support
|
||||
- Support for gzipped addressbook updates
|
||||
- Support for router families
|
||||
|
||||
### Changed
|
||||
- Shared RTT/RTO between streams
|
||||
- Filesystem work refactoring
|
||||
|
||||
## [2.4.0] - 2016-02-03
|
||||
### Added
|
||||
- X-I2P-* headers for server http-tunnels
|
||||
- I2CP options for I2P tunnels
|
||||
- Show I2P tunnels in webconsole
|
||||
|
||||
### Changed
|
||||
- Refactoring of cmdline/config parsing
|
||||
|
||||
## [2.3.0] - 2016-01-12
|
||||
### Added
|
||||
- Support for new router bandwidth class codes (P and X)
|
||||
- I2PControl supports external webui
|
||||
- Added --pidfile and --notransit parameters
|
||||
- Ability to specify signature type for i2p tunnel
|
||||
|
||||
### Changed
|
||||
- Fixed multiple floodfill-related bugs
|
||||
- New webconsole layout
|
||||
|
||||
## [2.2.0] - 2015-12-22
|
||||
### Added
|
||||
- Ability to connect to router without ip via introducer
|
||||
|
||||
### Changed
|
||||
- Persist temporary encryption keys for local destinations
|
||||
- Performance improvements for EdDSA
|
||||
- New addressbook structure
|
||||
|
||||
## [2.1.0] - 2015-11-12
|
||||
### Added
|
||||
- Implementation of EdDSA
|
||||
|
||||
### Changed
|
||||
- EdDSA is default signature type for new RouterInfos
|
||||
@@ -1,380 +0,0 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include "Config.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "Identity.h"
|
||||
#include "ClientContext.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
ClientContext context;
|
||||
|
||||
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
||||
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
||||
m_BOBCommandChannel (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ClientContext::~ClientContext ()
|
||||
{
|
||||
delete m_HttpProxy;
|
||||
delete m_SocksProxy;
|
||||
delete m_SamBridge;
|
||||
delete m_BOBCommandChannel;
|
||||
}
|
||||
|
||||
void ClientContext::Start ()
|
||||
{
|
||||
if (!m_SharedLocalDestination)
|
||||
{
|
||||
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
||||
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
|
||||
m_SharedLocalDestination->Start ();
|
||||
}
|
||||
|
||||
m_AddressBook.Start ();
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination;
|
||||
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
|
||||
if (httproxy) {
|
||||
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
|
||||
std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr);
|
||||
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
|
||||
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
|
||||
if (httpProxyKeys.length () > 0)
|
||||
{
|
||||
i2p::data::PrivateKeys keys;
|
||||
LoadPrivateKeys (keys, httpProxyKeys);
|
||||
localDestination = CreateNewLocalDestination (keys, false);
|
||||
}
|
||||
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination);
|
||||
m_HttpProxy->Start();
|
||||
}
|
||||
|
||||
bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
|
||||
if (socksproxy) {
|
||||
std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
|
||||
std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
|
||||
uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort);
|
||||
std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr);
|
||||
uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort);
|
||||
LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort);
|
||||
if (socksProxyKeys.length () > 0)
|
||||
{
|
||||
i2p::data::PrivateKeys keys;
|
||||
LoadPrivateKeys (keys, socksProxyKeys);
|
||||
localDestination = CreateNewLocalDestination (keys, false);
|
||||
}
|
||||
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination);
|
||||
m_SocksProxy->Start();
|
||||
}
|
||||
|
||||
// I2P tunnels
|
||||
ReadTunnels ();
|
||||
|
||||
// SAM
|
||||
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
||||
if (sam) {
|
||||
std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
|
||||
uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
|
||||
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
|
||||
m_SamBridge = new SAMBridge (samAddr, samPort);
|
||||
m_SamBridge->Start ();
|
||||
}
|
||||
|
||||
// BOB
|
||||
bool bob; i2p::config::GetOption("bob.enabled", bob);
|
||||
if (bob) {
|
||||
std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr);
|
||||
uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort);
|
||||
LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort);
|
||||
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
|
||||
m_BOBCommandChannel->Start ();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::Stop ()
|
||||
{
|
||||
if (m_HttpProxy)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
|
||||
m_HttpProxy->Stop();
|
||||
delete m_HttpProxy;
|
||||
m_HttpProxy = nullptr;
|
||||
}
|
||||
|
||||
if (m_SocksProxy)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
|
||||
m_SocksProxy->Stop();
|
||||
delete m_SocksProxy;
|
||||
m_SocksProxy = nullptr;
|
||||
}
|
||||
|
||||
for (auto& it: m_ClientTunnels)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first);
|
||||
it.second->Stop ();
|
||||
}
|
||||
m_ClientTunnels.clear ();
|
||||
|
||||
for (auto& it: m_ServerTunnels)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2P server tunnel");
|
||||
it.second->Stop ();
|
||||
}
|
||||
m_ServerTunnels.clear ();
|
||||
|
||||
if (m_SamBridge)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping SAM bridge");
|
||||
m_SamBridge->Stop ();
|
||||
delete m_SamBridge;
|
||||
m_SamBridge = nullptr;
|
||||
}
|
||||
|
||||
if (m_BOBCommandChannel)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping BOB command channel");
|
||||
m_BOBCommandChannel->Stop ();
|
||||
delete m_BOBCommandChannel;
|
||||
m_BOBCommandChannel = nullptr;
|
||||
}
|
||||
|
||||
LogPrint(eLogInfo, "Clients: stopping AddressBook");
|
||||
m_AddressBook.Stop ();
|
||||
for (auto it: m_Destinations)
|
||||
it.second->Stop ();
|
||||
m_Destinations.clear ();
|
||||
m_SharedLocalDestination = nullptr;
|
||||
}
|
||||
|
||||
void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
|
||||
{
|
||||
std::string fullPath = i2p::fs::DataDirPath (filename);
|
||||
std::ifstream s(fullPath, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0, std::ios::end);
|
||||
size_t len = s.tellg();
|
||||
s.seekg (0, std::ios::beg);
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
s.read ((char *)buf, len);
|
||||
keys.FromBuffer (buf, len);
|
||||
delete[] buf;
|
||||
LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType);
|
||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
size_t len = keys.GetFullLen ();
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
len = keys.ToBuffer (buf, len);
|
||||
f.write ((char *)buf, len);
|
||||
delete[] buf;
|
||||
|
||||
LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
||||
const std::map<std::string, std::string> * params)
|
||||
{
|
||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
||||
{
|
||||
if (!destination) return;
|
||||
auto it = m_Destinations.find (destination->GetIdentHash ());
|
||||
if (it != m_Destinations.end ())
|
||||
{
|
||||
auto d = it->second;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations.erase (it);
|
||||
}
|
||||
d->Stop ();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||
const std::map<std::string, std::string> * params)
|
||||
{
|
||||
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
|
||||
if (it != m_Destinations.end ())
|
||||
{
|
||||
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||
if (!it->second->IsRunning ())
|
||||
{
|
||||
it->second->Start ();
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||
{
|
||||
auto it = m_Destinations.find (destination);
|
||||
if (it != m_Destinations.end ())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Section, typename Type>
|
||||
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
||||
{
|
||||
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
|
||||
}
|
||||
|
||||
template<typename Section>
|
||||
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
|
||||
{
|
||||
options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH);
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH);
|
||||
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
|
||||
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
||||
}
|
||||
|
||||
void ClientContext::ReadTunnels ()
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
std::string tunConf; i2p::config::GetOption("tunconf", tunConf);
|
||||
if (tunConf == "")
|
||||
tunConf = i2p::fs::DataDirPath ("tunnels.cfg");
|
||||
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_ini (tunConf, pt);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
|
||||
return;
|
||||
}
|
||||
|
||||
int numClientTunnels = 0, numServerTunnels = 0;
|
||||
for (auto& section: pt)
|
||||
{
|
||||
std::string name = section.first;
|
||||
try
|
||||
{
|
||||
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
|
||||
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT)
|
||||
{
|
||||
// mandatory params
|
||||
std::string dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
|
||||
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
||||
// optional params
|
||||
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
||||
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
|
||||
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
// I2CP
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
if (keys.length () > 0)
|
||||
{
|
||||
i2p::data::PrivateKeys k;
|
||||
LoadPrivateKeys (k, keys, sigType);
|
||||
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
||||
if (!localDestination)
|
||||
localDestination = CreateNewLocalDestination (k, false, &options);
|
||||
}
|
||||
auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
|
||||
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
|
||||
clientTunnel->Start ();
|
||||
else
|
||||
LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists");
|
||||
numClientTunnels++;
|
||||
}
|
||||
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_IRC)
|
||||
{
|
||||
// mandatory params
|
||||
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
|
||||
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
|
||||
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS);
|
||||
// optional params
|
||||
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
||||
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
||||
std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
|
||||
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
||||
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
// I2CP
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
i2p::data::PrivateKeys k;
|
||||
LoadPrivateKeys (k, keys, sigType);
|
||||
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
||||
if (!localDestination)
|
||||
localDestination = CreateNewLocalDestination (k, true, &options);
|
||||
|
||||
I2PServerTunnel * serverTunnel;
|
||||
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
||||
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
|
||||
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
|
||||
serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip);
|
||||
else // regular server tunnel by default
|
||||
serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip);
|
||||
|
||||
if (accessList.length () > 0)
|
||||
{
|
||||
std::set<i2p::data::IdentHash> idents;
|
||||
size_t pos = 0, comma;
|
||||
do
|
||||
{
|
||||
comma = accessList.find (',', pos);
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
||||
idents.insert (ident);
|
||||
pos = comma + 1;
|
||||
}
|
||||
while (comma != std::string::npos);
|
||||
serverTunnel->SetAccessList (idents);
|
||||
}
|
||||
if (m_ServerTunnels.insert (std::make_pair (
|
||||
std::make_tuple (localDestination->GetIdentHash (), inPort),
|
||||
std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
|
||||
serverTunnel->Start ();
|
||||
else
|
||||
LogPrint (eLogError, "Clients: I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
|
||||
numServerTunnels++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created");
|
||||
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
#ifndef CLIENT_CONTEXT_H__
|
||||
#define CLIENT_CONTEXT_H__
|
||||
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include "Destination.h"
|
||||
#include "HTTPProxy.h"
|
||||
#include "SOCKS.h"
|
||||
#include "I2PTunnel.h"
|
||||
#include "SAM.h"
|
||||
#include "BOB.h"
|
||||
#include "AddressBook.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
const char I2P_TUNNELS_SECTION_TYPE[] = "type";
|
||||
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
|
||||
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
|
||||
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
|
||||
const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc";
|
||||
const char I2P_CLIENT_TUNNEL_PORT[] = "port";
|
||||
const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
|
||||
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||
const char I2P_SERVER_TUNNEL_GZIP[] = "gzip";
|
||||
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
||||
|
||||
class ClientContext
|
||||
{
|
||||
public:
|
||||
|
||||
ClientContext ();
|
||||
~ClientContext ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
|
||||
const std::map<std::string, std::string> * params = nullptr); // transient
|
||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||
const std::map<std::string, std::string> * params = nullptr);
|
||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
void LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
|
||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
||||
|
||||
private:
|
||||
|
||||
void ReadTunnels ();
|
||||
template<typename Section, typename Type>
|
||||
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const;
|
||||
template<typename Section>
|
||||
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const;
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_DestinationsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations;
|
||||
std::shared_ptr<ClientDestination> m_SharedLocalDestination;
|
||||
|
||||
AddressBook m_AddressBook;
|
||||
|
||||
i2p::proxy::HTTPProxy * m_HttpProxy;
|
||||
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
||||
std::map<int, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // port->tunnel
|
||||
std::map<std::tuple<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
|
||||
SAMBridge * m_SamBridge;
|
||||
BOBCommandChannel * m_BOBCommandChannel;
|
||||
|
||||
public:
|
||||
// for HTTP
|
||||
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
||||
const decltype(m_ClientTunnels)& GetClientTunnels () const { return m_ClientTunnels; };
|
||||
const decltype(m_ServerTunnels)& GetServerTunnels () const { return m_ServerTunnels; };
|
||||
};
|
||||
|
||||
extern ClientContext context;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
244
Config.cpp
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include "Config.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace boost::program_options;
|
||||
|
||||
namespace i2p {
|
||||
namespace config {
|
||||
options_description m_OptionsDesc;
|
||||
variables_map m_Options;
|
||||
|
||||
/* list of renamed options */
|
||||
std::map<std::string, std::string> remapped_options = {
|
||||
{ "tunnelscfg", "tunconf" },
|
||||
{ "v6", "ipv6" },
|
||||
{ "httpaddress", "http.address" },
|
||||
{ "httpport", "http.port" },
|
||||
{ "httpproxyaddress", "httpproxy.address" },
|
||||
{ "httpproxyport", "httpproxy.port" },
|
||||
{ "socksproxyaddress", "socksproxy.address" },
|
||||
{ "socksproxyport", "socksproxy.port" },
|
||||
{ "samaddress", "sam.address" },
|
||||
{ "samport", "sam.port" },
|
||||
{ "bobaddress", "bob.address" },
|
||||
{ "bobport", "bob.port" },
|
||||
{ "i2pcontroladdress", "i2pcontrol.address" },
|
||||
{ "i2pcontroladdress", "i2pcontrol.port" },
|
||||
{ "proxykeys", "httpproxy.keys" },
|
||||
};
|
||||
/* list of options, that loose their argument and become simple switch */
|
||||
std::set<std::string> boolean_options = {
|
||||
"daemon", "floodfill", "notransit", "service", "ipv6"
|
||||
};
|
||||
|
||||
/* this function is a solid piece of shit, remove it after 2.6.0 */
|
||||
std::pair<std::string, std::string> old_syntax_parser(const std::string& s) {
|
||||
std::string name = "";
|
||||
std::string value = "";
|
||||
std::size_t pos = 0;
|
||||
/* shortcuts -- -h */
|
||||
if (s.length() == 2 && s.at(0) == '-' && s.at(1) != '-')
|
||||
return make_pair(s.substr(1), "");
|
||||
/* old-style -- -log, /log, etc */
|
||||
if (s.at(0) == '/' || (s.at(0) == '-' && s.at(1) != '-')) {
|
||||
if ((pos = s.find_first_of("= ")) != std::string::npos) {
|
||||
name = s.substr(1, pos - 1);
|
||||
value = s.substr(pos + 1);
|
||||
} else {
|
||||
name = s.substr(1, pos);
|
||||
value = "";
|
||||
}
|
||||
if (boolean_options.count(name) > 0 && value != "")
|
||||
std::cerr << "args: don't give an argument to switch option: " << s << std::endl;
|
||||
if (m_OptionsDesc.find_nothrow(name, false)) {
|
||||
std::cerr << "args: option " << s << " style is DEPRECATED, use --" << name << " instead" << std::endl;
|
||||
return std::make_pair(name, value);
|
||||
}
|
||||
if (remapped_options.count(name) > 0) {
|
||||
name = remapped_options[name];
|
||||
std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl;
|
||||
return std::make_pair(name, value);
|
||||
} /* else */
|
||||
}
|
||||
/* long options -- --help */
|
||||
if (s.substr(0, 2) == "--") {
|
||||
if ((pos = s.find_first_of("= ")) != std::string::npos) {
|
||||
name = s.substr(2, pos - 2);
|
||||
value = s.substr(pos + 1);
|
||||
} else {
|
||||
name = s.substr(2, pos);
|
||||
value = "";
|
||||
}
|
||||
if (boolean_options.count(name) > 0 && value != "") {
|
||||
std::cerr << "args: don't give an argument to switch option: " << s << std::endl;
|
||||
value = "";
|
||||
}
|
||||
if (m_OptionsDesc.find_nothrow(name, false))
|
||||
return std::make_pair(name, value);
|
||||
if (remapped_options.count(name) > 0) {
|
||||
name = remapped_options[name];
|
||||
std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl;
|
||||
return std::make_pair(name, value);
|
||||
} /* else */
|
||||
}
|
||||
std::cerr << "args: unknown option -- " << s << std::endl;
|
||||
return std::make_pair("", "");
|
||||
}
|
||||
|
||||
void Init() {
|
||||
options_description general("General options");
|
||||
general.add_options()
|
||||
("help", "Show this message")
|
||||
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)")
|
||||
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)")
|
||||
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
|
||||
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)")
|
||||
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
|
||||
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
|
||||
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
|
||||
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
|
||||
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
|
||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
|
||||
("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start")
|
||||
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'")
|
||||
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup")
|
||||
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
|
||||
("bandwidth", value<char>()->default_value('-'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited")
|
||||
#ifdef _WIN32
|
||||
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
||||
#endif
|
||||
;
|
||||
|
||||
options_description httpserver("HTTP Server options");
|
||||
httpserver.add_options()
|
||||
("http.enabled", value<bool>()->default_value(true), "Enable or disable webconsole")
|
||||
("http.address", value<std::string>()->default_value("127.0.0.1"), "Webconsole listen address")
|
||||
("http.port", value<uint16_t>()->default_value(7070), "Webconsole listen port")
|
||||
;
|
||||
|
||||
options_description httpproxy("HTTP Proxy options");
|
||||
httpproxy.add_options()
|
||||
("httpproxy.enabled", value<bool>()->default_value(true), "Enable or disable HTTP Proxy")
|
||||
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
|
||||
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
|
||||
("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys")
|
||||
;
|
||||
|
||||
options_description socksproxy("SOCKS Proxy options");
|
||||
socksproxy.add_options()
|
||||
("socksproxy.enabled", value<bool>()->default_value(true), "Enable or disable SOCKS Proxy")
|
||||
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address")
|
||||
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
|
||||
("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys")
|
||||
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
|
||||
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
|
||||
;
|
||||
|
||||
options_description sam("SAM bridge options");
|
||||
sam.add_options()
|
||||
("sam.enabled", value<bool>()->default_value(false), "Enable or disable SAM Application bridge")
|
||||
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
|
||||
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
|
||||
;
|
||||
|
||||
options_description bob("BOB options");
|
||||
bob.add_options()
|
||||
("bob.enabled", value<bool>()->default_value(false), "Enable or disable BOB command channel")
|
||||
("bob.address", value<std::string>()->default_value("127.0.0.1"), "BOB listen address")
|
||||
("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port")
|
||||
;
|
||||
|
||||
options_description i2pcontrol("I2PControl options");
|
||||
i2pcontrol.add_options()
|
||||
("i2pcontrol.enabled", value<bool>()->default_value(false), "Enable or disable I2P Control Protocol")
|
||||
("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address")
|
||||
("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port")
|
||||
("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password")
|
||||
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"), "I2PCP connection cerificate")
|
||||
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key")
|
||||
;
|
||||
|
||||
m_OptionsDesc
|
||||
.add(general)
|
||||
.add(httpserver)
|
||||
.add(httpproxy)
|
||||
.add(socksproxy)
|
||||
.add(sam)
|
||||
.add(bob)
|
||||
.add(i2pcontrol)
|
||||
;
|
||||
}
|
||||
|
||||
void ParseCmdline(int argc, char* argv[]) {
|
||||
try {
|
||||
auto style = boost::program_options::command_line_style::unix_style
|
||||
| boost::program_options::command_line_style::allow_long_disguise;
|
||||
style &= ~ boost::program_options::command_line_style::allow_guessing;
|
||||
store(parse_command_line(argc, argv, m_OptionsDesc, style, old_syntax_parser), m_Options);
|
||||
} catch (boost::program_options::error& e) {
|
||||
std::cerr << "args: " << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (m_Options.count("help") || m_Options.count("h")) {
|
||||
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
|
||||
std::cout << m_OptionsDesc;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseConfig(const std::string& path) {
|
||||
if (path == "") return;
|
||||
|
||||
std::ifstream config(path, std::ios::in);
|
||||
|
||||
if (!config.is_open())
|
||||
{
|
||||
std::cerr << "missing/unreadable config file: " << path << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options);
|
||||
}
|
||||
catch (boost::program_options::error& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
};
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
notify(m_Options);
|
||||
}
|
||||
|
||||
bool IsDefault(const char *name) {
|
||||
if (!m_Options.count(name))
|
||||
throw "try to check non-existent option";
|
||||
|
||||
if (m_Options[name].defaulted())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} // namespace config
|
||||
} // namespace i2p
|
||||
714
Crypto.cpp
@@ -1,714 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "TunnelBase.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include "Log.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
const uint8_t elgp_[256]=
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
const int elgg_ = 2;
|
||||
|
||||
const uint8_t dsap_[128]=
|
||||
{
|
||||
0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c,
|
||||
0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15,
|
||||
0xfc, 0xad, 0xae, 0x31, 0xa0, 0xad, 0x18, 0xfa, 0xb3, 0xf0, 0x1b, 0x00, 0xa3, 0x58, 0xde, 0x23,
|
||||
0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c,
|
||||
0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8,
|
||||
0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c,
|
||||
0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11,
|
||||
0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93
|
||||
};
|
||||
|
||||
const uint8_t dsaq_[20]=
|
||||
{
|
||||
0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d,
|
||||
0x68, 0x40, 0x46, 0xb7
|
||||
};
|
||||
|
||||
const uint8_t dsag_[128]=
|
||||
{
|
||||
0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0,
|
||||
0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81,
|
||||
0x07, 0x5f, 0xf9, 0x08, 0x2e, 0xd3, 0x23, 0x53, 0xd4, 0x37, 0x4d, 0x73, 0x01, 0xcd, 0xa1, 0xd2,
|
||||
0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52,
|
||||
0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc,
|
||||
0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a,
|
||||
0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c,
|
||||
0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82
|
||||
};
|
||||
|
||||
const int rsae_ = 65537;
|
||||
|
||||
struct CryptoConstants
|
||||
{
|
||||
// DH/ElGamal
|
||||
BIGNUM * elgp;
|
||||
BIGNUM * elgg;
|
||||
|
||||
// DSA
|
||||
BIGNUM * dsap;
|
||||
BIGNUM * dsaq;
|
||||
BIGNUM * dsag;
|
||||
|
||||
// RSA
|
||||
BIGNUM * rsae;
|
||||
|
||||
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
|
||||
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
|
||||
{
|
||||
elgp = BN_new ();
|
||||
BN_bin2bn (elgp_, 256, elgp);
|
||||
elgg = BN_new ();
|
||||
BN_set_word (elgg, elgg_);
|
||||
dsap = BN_new ();
|
||||
BN_bin2bn (dsap_, 128, dsap);
|
||||
dsaq = BN_new ();
|
||||
BN_bin2bn (dsaq_, 20, dsaq);
|
||||
dsag = BN_new ();
|
||||
BN_bin2bn (dsag_, 128, dsag);
|
||||
rsae = BN_new ();
|
||||
BN_set_word (rsae, rsae_);
|
||||
}
|
||||
|
||||
~CryptoConstants ()
|
||||
{
|
||||
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
||||
}
|
||||
};
|
||||
|
||||
static const CryptoConstants& GetCryptoConstants ()
|
||||
{
|
||||
static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_);
|
||||
return cryptoConstants;
|
||||
}
|
||||
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len)
|
||||
{
|
||||
int offset = len - BN_num_bytes (bn);
|
||||
if (offset < 0) return false;
|
||||
BN_bn2bin (bn, buf + offset);
|
||||
memset (buf, 0, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// RSA
|
||||
#define rsae GetCryptoConstants ().rsae
|
||||
const BIGNUM * GetRSAE ()
|
||||
{
|
||||
return rsae;
|
||||
}
|
||||
|
||||
// DSA
|
||||
#define dsap GetCryptoConstants ().dsap
|
||||
#define dsaq GetCryptoConstants ().dsaq
|
||||
#define dsag GetCryptoConstants ().dsag
|
||||
DSA * CreateDSA ()
|
||||
{
|
||||
DSA * dsa = DSA_new ();
|
||||
dsa->p = BN_dup (dsap);
|
||||
dsa->q = BN_dup (dsaq);
|
||||
dsa->g = BN_dup (dsag);
|
||||
dsa->priv_key = NULL;
|
||||
dsa->pub_key = NULL;
|
||||
return dsa;
|
||||
}
|
||||
|
||||
// DH/ElGamal
|
||||
#define elgp GetCryptoConstants ().elgp
|
||||
#define elgg GetCryptoConstants ().elgg
|
||||
|
||||
// DH
|
||||
|
||||
DHKeys::DHKeys (): m_IsUpdated (true)
|
||||
{
|
||||
m_DH = DH_new ();
|
||||
m_DH->p = BN_dup (elgp);
|
||||
m_DH->g = BN_dup (elgg);
|
||||
m_DH->priv_key = NULL;
|
||||
m_DH->pub_key = NULL;
|
||||
}
|
||||
|
||||
DHKeys::~DHKeys ()
|
||||
{
|
||||
DH_free (m_DH);
|
||||
}
|
||||
|
||||
void DHKeys::GenerateKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
if (m_DH->priv_key) { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; };
|
||||
if (m_DH->pub_key) { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; };
|
||||
DH_generate_key (m_DH);
|
||||
if (priv) bn2buf (m_DH->priv_key, priv, 256);
|
||||
if (pub) bn2buf (m_DH->pub_key, pub, 256);
|
||||
m_IsUpdated = true;
|
||||
}
|
||||
|
||||
const uint8_t * DHKeys::GetPublicKey ()
|
||||
{
|
||||
if (m_IsUpdated)
|
||||
{
|
||||
bn2buf (m_DH->pub_key, m_PublicKey, 256);
|
||||
BN_free (m_DH->pub_key); m_DH->pub_key = NULL;
|
||||
m_IsUpdated= false;
|
||||
}
|
||||
return m_PublicKey;
|
||||
}
|
||||
|
||||
void DHKeys::Agree (const uint8_t * pub, uint8_t * shared)
|
||||
{
|
||||
BIGNUM * pk = BN_bin2bn (pub, 256, NULL);
|
||||
DH_compute_key (shared, pk, m_DH);
|
||||
BN_free (pk);
|
||||
}
|
||||
|
||||
// ElGamal
|
||||
|
||||
ElGamalEncryption::ElGamalEncryption (const uint8_t * key)
|
||||
{
|
||||
ctx = BN_CTX_new ();
|
||||
// select random k
|
||||
BIGNUM * k = BN_new ();
|
||||
BN_rand_range (k, elgp);
|
||||
if (BN_is_zero (k)) BN_one (k);
|
||||
// caulculate a
|
||||
a = BN_new ();
|
||||
BN_mod_exp (a, elgg, k, elgp, ctx);
|
||||
BIGNUM * y = BN_new ();
|
||||
BN_bin2bn (key, 256, y);
|
||||
// calculate b1
|
||||
b1 = BN_new ();
|
||||
BN_mod_exp (b1, y, k, elgp, ctx);
|
||||
BN_free (y);
|
||||
BN_free (k);
|
||||
}
|
||||
|
||||
ElGamalEncryption::~ElGamalEncryption ()
|
||||
{
|
||||
BN_CTX_free (ctx);
|
||||
BN_free (a);
|
||||
BN_free (b1);
|
||||
}
|
||||
|
||||
void ElGamalEncryption::Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding) const
|
||||
{
|
||||
// create m
|
||||
uint8_t m[255];
|
||||
m[0] = 0xFF;
|
||||
memcpy (m+33, data, len);
|
||||
SHA256 (m+33, 222, m+1);
|
||||
// calculate b = b1*m mod p
|
||||
BIGNUM * b = BN_new ();
|
||||
BN_bin2bn (m, 255, b);
|
||||
BN_mod_mul (b, b1, b, elgp, ctx);
|
||||
// copy a and b
|
||||
if (zeroPadding)
|
||||
{
|
||||
encrypted[0] = 0;
|
||||
bn2buf (a, encrypted + 1, 256);
|
||||
encrypted[257] = 0;
|
||||
bn2buf (b, encrypted + 258, 256);
|
||||
}
|
||||
else
|
||||
{
|
||||
bn2buf (a, encrypted, 256);
|
||||
bn2buf (b, encrypted + 256, 256);
|
||||
}
|
||||
BN_free (b);
|
||||
}
|
||||
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
|
||||
uint8_t * data, bool zeroPadding)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * x = BN_new (), * a = BN_new (), * b = BN_new ();
|
||||
BN_bin2bn (key, 256, x);
|
||||
BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1
|
||||
BN_bin2bn (zeroPadding ? encrypted + 1 : encrypted, 256, a);
|
||||
BN_bin2bn (zeroPadding ? encrypted + 258 : encrypted + 256, 256, b);
|
||||
// m = b*(a^x mod p) mod p
|
||||
BN_mod_exp (x, a, x, elgp, ctx);
|
||||
BN_mod_mul (b, b, x, elgp, ctx);
|
||||
uint8_t m[255];
|
||||
bn2buf (b, m, 255);
|
||||
BN_free (x); BN_free (a); BN_free (b);
|
||||
BN_CTX_free (ctx);
|
||||
uint8_t hash[32];
|
||||
SHA256 (m + 33, 222, hash);
|
||||
if (memcmp (m + 1, hash, 32))
|
||||
{
|
||||
LogPrint (eLogError, "ElGamal decrypt hash doesn't match");
|
||||
return false;
|
||||
}
|
||||
memcpy (data, m + 33, 222);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
||||
RAND_bytes (priv, 256);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * p = BN_new ();
|
||||
BN_bin2bn (priv, 256, p);
|
||||
BN_mod_exp (p, elgg, p, elgp, ctx);
|
||||
bn2buf (p, pub, 256);
|
||||
BN_free (p);
|
||||
BN_CTX_free (ctx);
|
||||
#else
|
||||
DHKeys dh;
|
||||
dh.GenerateKeys (priv, pub);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// HMAC
|
||||
const uint64_t IPAD = 0x3636363636363636;
|
||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
||||
|
||||
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
||||
// key is 32 bytes
|
||||
// digest is 16 bytes
|
||||
// block size is 64 bytes
|
||||
{
|
||||
uint64_t buf[256];
|
||||
// ikeypad
|
||||
buf[0] = key.GetLL ()[0] ^ IPAD;
|
||||
buf[1] = key.GetLL ()[1] ^ IPAD;
|
||||
buf[2] = key.GetLL ()[2] ^ IPAD;
|
||||
buf[3] = key.GetLL ()[3] ^ IPAD;
|
||||
buf[4] = IPAD;
|
||||
buf[5] = IPAD;
|
||||
buf[6] = IPAD;
|
||||
buf[7] = IPAD;
|
||||
// concatenate with msg
|
||||
memcpy (buf + 8, msg, len);
|
||||
// calculate first hash
|
||||
uint8_t hash[16]; // MD5
|
||||
MD5((uint8_t *)buf, len + 64, hash);
|
||||
|
||||
// okeypad
|
||||
buf[0] = key.GetLL ()[0] ^ OPAD;
|
||||
buf[1] = key.GetLL ()[1] ^ OPAD;
|
||||
buf[2] = key.GetLL ()[2] ^ OPAD;
|
||||
buf[3] = key.GetLL ()[3] ^ OPAD;
|
||||
buf[4] = OPAD;
|
||||
buf[5] = OPAD;
|
||||
buf[6] = OPAD;
|
||||
buf[7] = OPAD;
|
||||
// copy first hash after okeypad
|
||||
memcpy (buf + 8, hash, 16);
|
||||
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||
memset (buf + 10, 0, 16);
|
||||
|
||||
// calculate digest
|
||||
MD5((uint8_t *)buf, 96, digest);
|
||||
}
|
||||
|
||||
// AES
|
||||
#ifdef AESNI
|
||||
|
||||
#define KeyExpansion256(round0,round1) \
|
||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||
"movaps %%xmm1, %%xmm4 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm1 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm1 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm1 \n" \
|
||||
"pxor %%xmm2, %%xmm1 \n" \
|
||||
"movaps %%xmm1, "#round0"(%[sched]) \n" \
|
||||
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
|
||||
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
|
||||
"movaps %%xmm3, %%xmm4 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm3 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm3 \n" \
|
||||
"pslldq $4, %%xmm4 \n" \
|
||||
"pxor %%xmm4, %%xmm3 \n" \
|
||||
"pxor %%xmm2, %%xmm3 \n" \
|
||||
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
||||
|
||||
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[key]), %%xmm1 \n"
|
||||
"movups 16(%[key]), %%xmm3 \n"
|
||||
"movaps %%xmm1, (%[sched]) \n"
|
||||
"movaps %%xmm3, 16(%[sched]) \n"
|
||||
"aeskeygenassist $1, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(32,48)
|
||||
"aeskeygenassist $2, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(64,80)
|
||||
"aeskeygenassist $4, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(96,112)
|
||||
"aeskeygenassist $8, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(128,144)
|
||||
"aeskeygenassist $16, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(160,176)
|
||||
"aeskeygenassist $32, %%xmm3, %%xmm2 \n"
|
||||
KeyExpansion256(192,208)
|
||||
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
|
||||
// key expansion final
|
||||
"pshufd $0xff, %%xmm2, %%xmm2 \n"
|
||||
"movaps %%xmm1, %%xmm4 \n"
|
||||
"pslldq $4, %%xmm4 \n"
|
||||
"pxor %%xmm4, %%xmm1 \n"
|
||||
"pslldq $4, %%xmm4 \n"
|
||||
"pxor %%xmm4, %%xmm1 \n"
|
||||
"pslldq $4, %%xmm4 \n"
|
||||
"pxor %%xmm4, %%xmm1 \n"
|
||||
"pxor %%xmm2, %%xmm1 \n"
|
||||
"movups %%xmm1, 224(%[sched]) \n"
|
||||
: // output
|
||||
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
|
||||
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
|
||||
);
|
||||
}
|
||||
|
||||
#define EncryptAES256(sched) \
|
||||
"pxor (%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 16(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 32(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 48(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 64(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 80(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 96(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 112(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 128(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 144(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 160(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 176(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 192(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 208(%["#sched"]), %%xmm0 \n" \
|
||||
"aesenclast 224(%["#sched"]), %%xmm0 \n"
|
||||
|
||||
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#define DecryptAES256(sched) \
|
||||
"pxor 224(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 208(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 192(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 176(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 160(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 144(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 128(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 112(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 96(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 80(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 64(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 48(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 32(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 16(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdeclast (%["#sched"]), %%xmm0 \n"
|
||||
|
||||
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#define CallAESIMC(offset) \
|
||||
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
||||
"aesimc %%xmm0, %%xmm0 \n" \
|
||||
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
||||
|
||||
void ECBDecryptionAESNI::SetKey (const AESKey& key)
|
||||
{
|
||||
ExpandKey (key); // expand encryption key first
|
||||
// then invert it using aesimc
|
||||
__asm__
|
||||
(
|
||||
CallAESIMC(16)
|
||||
CallAESIMC(32)
|
||||
CallAESIMC(48)
|
||||
CallAESIMC(64)
|
||||
CallAESIMC(80)
|
||||
CallAESIMC(96)
|
||||
CallAESIMC(112)
|
||||
CallAESIMC(128)
|
||||
CallAESIMC(144)
|
||||
CallAESIMC(160)
|
||||
CallAESIMC(176)
|
||||
CallAESIMC(192)
|
||||
CallAESIMC(208)
|
||||
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
#else
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
m_LastBlock ^= in[i];
|
||||
m_ECBEncryption.Encrypt (&m_LastBlock, &m_LastBlock);
|
||||
out[i] = m_LastBlock;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
||||
{
|
||||
// len/16
|
||||
int numBlocks = len >> 4;
|
||||
if (numBlocks > 0)
|
||||
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||
}
|
||||
|
||||
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
#else
|
||||
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
#else
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
ChipherBlock tmp = in[i];
|
||||
m_ECBDecryption.Decrypt (in + i, out + i);
|
||||
out[i] ^= m_IV;
|
||||
m_IV = tmp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
|
||||
{
|
||||
int numBlocks = len >> 4;
|
||||
if (numBlocks > 0)
|
||||
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||
}
|
||||
|
||||
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
:
|
||||
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
#else
|
||||
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
// encrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
EncryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// encrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched_l)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
#else
|
||||
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||
m_LayerEncryption.SetIV (out);
|
||||
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||
#endif
|
||||
}
|
||||
|
||||
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef AESNI
|
||||
__asm__
|
||||
(
|
||||
// decrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
DecryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// decrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched_l)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
#else
|
||||
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||
m_LayerDecryption.SetIV (out);
|
||||
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||
#endif
|
||||
}
|
||||
|
||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
||||
{
|
||||
if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ())
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
m_OpenSSLMutexes[type]->lock ();
|
||||
else
|
||||
m_OpenSSLMutexes[type]->unlock ();
|
||||
}
|
||||
}*/
|
||||
|
||||
void InitCrypto ()
|
||||
{
|
||||
SSL_library_init ();
|
||||
/* auto numLocks = CRYPTO_num_locks();
|
||||
for (int i = 0; i < numLocks; i++)
|
||||
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
||||
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
|
||||
}
|
||||
|
||||
void TerminateCrypto ()
|
||||
{
|
||||
/* CRYPTO_set_locking_callback (nullptr);
|
||||
m_OpenSSLMutexes.clear ();*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
281
Crypto.h
@@ -1,281 +0,0 @@
|
||||
#ifndef CRYPTO_H__
|
||||
#define CRYPTO_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "Base.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||
|
||||
// DSA
|
||||
DSA * CreateDSA ();
|
||||
|
||||
// RSA
|
||||
const BIGNUM * GetRSAE ();
|
||||
|
||||
// DH
|
||||
class DHKeys
|
||||
{
|
||||
public:
|
||||
|
||||
DHKeys ();
|
||||
~DHKeys ();
|
||||
|
||||
void GenerateKeys (uint8_t * priv = nullptr, uint8_t * pub = nullptr);
|
||||
const uint8_t * GetPublicKey ();
|
||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||
|
||||
private:
|
||||
|
||||
DH * m_DH;
|
||||
uint8_t m_PublicKey[256];
|
||||
bool m_IsUpdated;
|
||||
};
|
||||
|
||||
// ElGamal
|
||||
class ElGamalEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
ElGamalEncryption (const uint8_t * key);
|
||||
~ElGamalEncryption ();
|
||||
|
||||
void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const;
|
||||
|
||||
private:
|
||||
|
||||
BN_CTX * ctx;
|
||||
BIGNUM * a, * b1;
|
||||
};
|
||||
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, bool zeroPadding = false);
|
||||
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
|
||||
|
||||
// HMAC
|
||||
typedef i2p::data::Tag<32> MACKey;
|
||||
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
|
||||
|
||||
// AES
|
||||
struct ChipherBlock
|
||||
{
|
||||
uint8_t buf[16];
|
||||
|
||||
void operator^=(const ChipherBlock& other) // XOR
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__SSE__) // for Intel x84 or with SSE
|
||||
__asm__
|
||||
(
|
||||
"movups (%[buf]), %%xmm0 \n"
|
||||
"movups (%[other]), %%xmm1 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[buf]) \n"
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
#else
|
||||
// TODO: implement it better
|
||||
for (int i = 0; i < 16; i++)
|
||||
buf[i] ^= other.buf[i];
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
typedef i2p::data::Tag<32> AESKey;
|
||||
|
||||
template<size_t sz>
|
||||
class AESAlignedBuffer // 16 bytes alignment
|
||||
{
|
||||
public:
|
||||
|
||||
AESAlignedBuffer ()
|
||||
{
|
||||
m_Buf = m_UnalignedBuffer;
|
||||
uint8_t rem = ((size_t)m_Buf) & 0x0f;
|
||||
if (rem)
|
||||
m_Buf += (16 - rem);
|
||||
}
|
||||
|
||||
operator uint8_t * () { return m_Buf; };
|
||||
operator const uint8_t * () const { return m_Buf; };
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
|
||||
uint8_t * m_Buf;
|
||||
};
|
||||
|
||||
|
||||
#ifdef AESNI
|
||||
class ECBCryptoAESNI
|
||||
{
|
||||
public:
|
||||
|
||||
uint8_t * GetKeySchedule () { return m_KeySchedule; };
|
||||
|
||||
protected:
|
||||
|
||||
void ExpandKey (const AESKey& key);
|
||||
|
||||
private:
|
||||
|
||||
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
|
||||
};
|
||||
|
||||
class ECBEncryptionAESNI: public ECBCryptoAESNI
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key) { ExpandKey (key); };
|
||||
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||
};
|
||||
|
||||
class ECBDecryptionAESNI: public ECBCryptoAESNI
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key);
|
||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||
};
|
||||
|
||||
typedef ECBEncryptionAESNI ECBEncryption;
|
||||
typedef ECBDecryptionAESNI ECBDecryption;
|
||||
|
||||
#else // use openssl
|
||||
|
||||
class ECBEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
AES_set_encrypt_key (key, 256, &m_Key);
|
||||
}
|
||||
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
AES_encrypt (in->buf, out->buf, &m_Key);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
AES_KEY m_Key;
|
||||
};
|
||||
|
||||
class ECBDecryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
AES_set_decrypt_key (key, 256, &m_Key);
|
||||
}
|
||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
AES_decrypt (in->buf, out->buf, &m_Key);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
AES_KEY m_Key;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
class CBCEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
CBCEncryption () { memset (m_LastBlock.buf, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
||||
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
|
||||
|
||||
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||
void Encrypt (const uint8_t * in, uint8_t * out); // one block
|
||||
|
||||
private:
|
||||
|
||||
ChipherBlock m_LastBlock;
|
||||
|
||||
ECBEncryption m_ECBEncryption;
|
||||
};
|
||||
|
||||
class CBCDecryption
|
||||
{
|
||||
public:
|
||||
|
||||
CBCDecryption () { memset (m_IV.buf, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
||||
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
|
||||
|
||||
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||
void Decrypt (const uint8_t * in, uint8_t * out); // one block
|
||||
|
||||
private:
|
||||
|
||||
ChipherBlock m_IV;
|
||||
ECBDecryption m_ECBDecryption;
|
||||
};
|
||||
|
||||
class TunnelEncryption // with double IV encryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
m_LayerEncryption.SetKey (layerKey);
|
||||
m_IVEncryption.SetKey (ivKey);
|
||||
}
|
||||
|
||||
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||
|
||||
private:
|
||||
|
||||
ECBEncryption m_IVEncryption;
|
||||
#ifdef AESNI
|
||||
ECBEncryption m_LayerEncryption;
|
||||
#else
|
||||
CBCEncryption m_LayerEncryption;
|
||||
#endif
|
||||
};
|
||||
|
||||
class TunnelDecryption // with double IV encryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
m_LayerDecryption.SetKey (layerKey);
|
||||
m_IVDecryption.SetKey (ivKey);
|
||||
}
|
||||
|
||||
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||
|
||||
private:
|
||||
|
||||
ECBDecryption m_IVDecryption;
|
||||
#ifdef AESNI
|
||||
ECBDecryption m_LayerDecryption;
|
||||
#else
|
||||
CBCDecryption m_LayerDecryption;
|
||||
#endif
|
||||
};
|
||||
|
||||
void InitCrypto ();
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
#include <inttypes.h>
|
||||
#include "CryptoConst.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
const uint8_t elgp_[256]=
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
const uint8_t dsap_[128]=
|
||||
{
|
||||
0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c,
|
||||
0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15,
|
||||
0xfc, 0xad, 0xae, 0x31, 0xa0, 0xad, 0x18, 0xfa, 0xb3, 0xf0, 0x1b, 0x00, 0xa3, 0x58, 0xde, 0x23,
|
||||
0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c,
|
||||
0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8,
|
||||
0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c,
|
||||
0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11,
|
||||
0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93
|
||||
};
|
||||
|
||||
const uint8_t dsaq_[20]=
|
||||
{
|
||||
0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d,
|
||||
0x68, 0x40, 0x46, 0xb7
|
||||
};
|
||||
|
||||
const uint8_t dsag_[128]=
|
||||
{
|
||||
0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0,
|
||||
0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81,
|
||||
0x07, 0x5f, 0xf9, 0x08, 0x2e, 0xd3, 0x23, 0x53, 0xd4, 0x37, 0x4d, 0x73, 0x01, 0xcd, 0xa1, 0xd2,
|
||||
0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52,
|
||||
0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc,
|
||||
0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a,
|
||||
0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c,
|
||||
0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82
|
||||
};
|
||||
|
||||
const CryptoConstants& GetCryptoConstants ()
|
||||
{
|
||||
static CryptoConstants cryptoConstants =
|
||||
{
|
||||
{elgp_, 256}, // elgp
|
||||
{2}, // elgg
|
||||
{dsap_, 128}, // dsap
|
||||
{dsaq_, 20}, // dsaq
|
||||
{dsag_, 128} // dsag
|
||||
};
|
||||
return cryptoConstants;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef CRYPTO_CONST_H__
|
||||
#define CRYPTO_CONST_H__
|
||||
|
||||
#include <cryptopp/integer.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
struct CryptoConstants
|
||||
{
|
||||
// DH/ElGamal
|
||||
const CryptoPP::Integer elgp;
|
||||
const CryptoPP::Integer elgg;
|
||||
|
||||
// DSA
|
||||
const CryptoPP::Integer dsap;
|
||||
const CryptoPP::Integer dsaq;
|
||||
const CryptoPP::Integer dsag;
|
||||
};
|
||||
|
||||
const CryptoConstants& GetCryptoConstants ();
|
||||
|
||||
// DH/ElGamal
|
||||
#define elgp GetCryptoConstants ().elgp
|
||||
#define elgg GetCryptoConstants ().elgg
|
||||
|
||||
// DSA
|
||||
#define dsap GetCryptoConstants ().dsap
|
||||
#define dsaq GetCryptoConstants ().dsaq
|
||||
#define dsag GetCryptoConstants ().dsag
|
||||
|
||||
// RSA
|
||||
const int rsae = 65537;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
239
Daemon.cpp
@@ -1,239 +0,0 @@
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "FS.h"
|
||||
#include "Base.h"
|
||||
#include "version.h"
|
||||
#include "Transports.h"
|
||||
#include "NTCPSession.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Tunnel.h"
|
||||
#include "NetDb.h"
|
||||
#include "Garlic.h"
|
||||
#include "Streaming.h"
|
||||
#include "Destination.h"
|
||||
#include "HTTPServer.h"
|
||||
#include "I2PControl.h"
|
||||
#include "ClientContext.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include "UPnP.h"
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
class Daemon_Singleton::Daemon_Singleton_Private
|
||||
{
|
||||
public:
|
||||
Daemon_Singleton_Private() {};
|
||||
~Daemon_Singleton_Private() {};
|
||||
|
||||
std::unique_ptr<i2p::util::HTTPServer> httpServer;
|
||||
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
||||
|
||||
#ifdef USE_UPNP
|
||||
i2p::transport::UPnP m_UPnP;
|
||||
#endif
|
||||
};
|
||||
|
||||
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
|
||||
Daemon_Singleton::~Daemon_Singleton() {
|
||||
delete &d;
|
||||
};
|
||||
|
||||
bool Daemon_Singleton::IsService () const
|
||||
{
|
||||
bool service = false;
|
||||
#ifndef _WIN32
|
||||
i2p::config::GetOption("service", service);
|
||||
#endif
|
||||
return service;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::init(int argc, char* argv[])
|
||||
{
|
||||
i2p::config::Init();
|
||||
i2p::config::ParseCmdline(argc, argv);
|
||||
|
||||
std::string config; i2p::config::GetOption("conf", config);
|
||||
std::string datadir; i2p::config::GetOption("datadir", datadir);
|
||||
i2p::fs::DetectDataDir(datadir, IsService());
|
||||
i2p::fs::Init();
|
||||
|
||||
datadir = i2p::fs::GetDataDir();
|
||||
if (config == "")
|
||||
{
|
||||
config = i2p::fs::DataDirPath("i2p.conf");
|
||||
// use i2p.cong only if exists
|
||||
if (!i2p::fs::Exists (config)) config = ""; /* reset */
|
||||
}
|
||||
|
||||
i2p::config::ParseConfig(config);
|
||||
i2p::config::Finalize();
|
||||
|
||||
i2p::crypto::InitCrypto ();
|
||||
i2p::context.Init ();
|
||||
|
||||
i2p::config::GetOption("daemon", isDaemon);
|
||||
|
||||
// TODO: move log init here
|
||||
|
||||
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
|
||||
LogPrint(eLogDebug, "FS: main config file: ", config);
|
||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (!i2p::config::IsDefault("port"))
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
||||
i2p::context.UpdatePort (port);
|
||||
}
|
||||
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!i2p::config::IsDefault("host"))
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host);
|
||||
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
|
||||
}
|
||||
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool transit; i2p::config::GetOption("notransit", transit);
|
||||
i2p::context.SetSupportsV6 (ipv6);
|
||||
i2p::context.SetAcceptsTunnels (!transit);
|
||||
|
||||
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
|
||||
char bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
|
||||
|
||||
if (isFloodfill)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: router will be floodfill");
|
||||
i2p::context.SetFloodfill (true);
|
||||
}
|
||||
else
|
||||
i2p::context.SetFloodfill (false);
|
||||
if (bandwidth != '-')
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth);
|
||||
if (bandwidth > 'O')
|
||||
i2p::context.SetExtraBandwidth ();
|
||||
else if (bandwidth > 'L')
|
||||
i2p::context.SetHighBandwidth ();
|
||||
else
|
||||
i2p::context.SetLowBandwidth ();
|
||||
}
|
||||
else if (isFloodfill)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
|
||||
i2p::context.SetExtraBandwidth ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'");
|
||||
i2p::context.SetLowBandwidth ();
|
||||
}
|
||||
|
||||
std::string family; i2p::config::GetOption("family", family);
|
||||
i2p::context.SetFamily (family);
|
||||
if (family.length () > 0)
|
||||
LogPrint(eLogInfo, "Daemon: family set to ", family);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::start()
|
||||
{
|
||||
std::string logs = ""; i2p::config::GetOption("log", logs);
|
||||
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
|
||||
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
|
||||
|
||||
if (isDaemon && (logs == "" || logs == "stdout"))
|
||||
logs = "file";
|
||||
|
||||
if (logs == "file") {
|
||||
if (logfile == "")
|
||||
logfile = i2p::fs::DataDirPath("i2pd.log");
|
||||
StartLog (logfile);
|
||||
} else {
|
||||
// use stdout
|
||||
StartLog ("");
|
||||
}
|
||||
SetLogLevel(loglevel);
|
||||
|
||||
bool http; i2p::config::GetOption("http.enabled", http);
|
||||
if (http) {
|
||||
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
|
||||
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(httpAddr, httpPort));
|
||||
d.httpServer->Start();
|
||||
}
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting NetDB");
|
||||
i2p::data::netdb.Start();
|
||||
|
||||
#ifdef USE_UPNP
|
||||
LogPrint(eLogInfo, "Daemon: starting UPnP");
|
||||
d.m_UPnP.Start ();
|
||||
#endif
|
||||
LogPrint(eLogInfo, "Daemon: starting Transports");
|
||||
i2p::transport::transports.Start();
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Tunnels");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Client");
|
||||
i2p::client::context.Start ();
|
||||
|
||||
// I2P Control Protocol
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
if (i2pcontrol) {
|
||||
std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
|
||||
uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
|
||||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
|
||||
d.m_I2PControlService->Start ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::stop()
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: stopping Client");
|
||||
i2p::client::context.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: stopping Tunnels");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
#ifdef USE_UPNP
|
||||
LogPrint(eLogInfo, "Daemon: stopping UPnP");
|
||||
d.m_UPnP.Stop ();
|
||||
#endif
|
||||
LogPrint(eLogInfo, "Daemon: stopping Transports");
|
||||
i2p::transport::transports.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: stopping NetDB");
|
||||
i2p::data::netdb.Stop();
|
||||
if (d.httpServer) {
|
||||
LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
|
||||
d.httpServer->Stop();
|
||||
d.httpServer = nullptr;
|
||||
}
|
||||
if (d.m_I2PControlService)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: stopping I2PControl");
|
||||
d.m_I2PControlService->Stop ();
|
||||
d.m_I2PControlService = nullptr;
|
||||
}
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
StopLog ();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Daemon.h
@@ -1,79 +0,0 @@
|
||||
#ifndef DAEMON_H__
|
||||
#define DAEMON_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define Daemon i2p::util::DaemonWin32::Instance()
|
||||
#else
|
||||
#define Daemon i2p::util::DaemonLinux::Instance()
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
class Daemon_Singleton_Private;
|
||||
class Daemon_Singleton
|
||||
{
|
||||
public:
|
||||
virtual bool init(int argc, char* argv[]);
|
||||
virtual bool start();
|
||||
virtual bool stop();
|
||||
virtual void run () {};
|
||||
|
||||
bool isLogging;
|
||||
bool isDaemon;
|
||||
|
||||
bool running;
|
||||
|
||||
protected:
|
||||
Daemon_Singleton();
|
||||
virtual ~Daemon_Singleton();
|
||||
|
||||
bool IsService () const;
|
||||
|
||||
// d-pointer for httpServer, httpProxy, etc.
|
||||
class Daemon_Singleton_Private;
|
||||
Daemon_Singleton_Private &d;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
class DaemonWin32 : public Daemon_Singleton
|
||||
{
|
||||
public:
|
||||
static DaemonWin32& Instance()
|
||||
{
|
||||
static DaemonWin32 instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool init(int argc, char* argv[]);
|
||||
bool start();
|
||||
bool stop();
|
||||
void run ();
|
||||
};
|
||||
#else
|
||||
class DaemonLinux : public Daemon_Singleton
|
||||
{
|
||||
public:
|
||||
static DaemonLinux& Instance()
|
||||
{
|
||||
static DaemonLinux instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool start();
|
||||
bool stop();
|
||||
; void run ();
|
||||
|
||||
private:
|
||||
std::string pidfile;
|
||||
int pidFH;
|
||||
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DAEMON_H__
|
||||
133
DaemonLinux.cpp
@@ -1,133 +0,0 @@
|
||||
#include "Daemon.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
|
||||
void handle_signal(int sig)
|
||||
{
|
||||
switch (sig)
|
||||
{
|
||||
case SIGHUP:
|
||||
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
|
||||
ReopenLogFile ();
|
||||
break;
|
||||
case SIGABRT:
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
Daemon.running = 0; // Exit loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
bool DaemonLinux::start()
|
||||
{
|
||||
if (isDaemon == 1)
|
||||
{
|
||||
pid_t pid;
|
||||
pid = fork();
|
||||
if (pid > 0) // parent
|
||||
::exit (EXIT_SUCCESS);
|
||||
|
||||
if (pid < 0) // error
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// child
|
||||
umask(S_IWGRP | S_IRWXO); // 0027
|
||||
int sid = setsid();
|
||||
if (sid < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not create process group.");
|
||||
return false;
|
||||
}
|
||||
std::string d = i2p::fs::GetDataDir();
|
||||
if (chdir(d.c_str()) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// close stdin/stdout/stderr descriptors
|
||||
::close (0);
|
||||
::open ("/dev/null", O_RDWR);
|
||||
::close (1);
|
||||
::open ("/dev/null", O_RDWR);
|
||||
::close (2);
|
||||
::open ("/dev/null", O_RDWR);
|
||||
}
|
||||
|
||||
// Pidfile
|
||||
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
|
||||
std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
|
||||
if (pidfile == "") {
|
||||
pidfile = i2p::fs::DataDirPath("i2pd.pid");
|
||||
}
|
||||
if (pidfile != "") {
|
||||
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
||||
if (pidFH < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
char pid[10];
|
||||
sprintf(pid, "%d\n", getpid());
|
||||
ftruncate(pidFH, 0);
|
||||
if (write(pidFH, pid, strlen(pid)) < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Signal handler
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = handle_signal;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGHUP, &sa, 0);
|
||||
sigaction(SIGABRT, &sa, 0);
|
||||
sigaction(SIGTERM, &sa, 0);
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
|
||||
return Daemon_Singleton::start();
|
||||
}
|
||||
|
||||
bool DaemonLinux::stop()
|
||||
{
|
||||
i2p::fs::Remove(pidfile);
|
||||
|
||||
return Daemon_Singleton::stop();
|
||||
}
|
||||
|
||||
void DaemonLinux::run ()
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "Config.h"
|
||||
#include "Daemon.h"
|
||||
#include "util.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "Win32/Win32App.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
bool DaemonWin32::init(int argc, char* argv[])
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
SetConsoleCP(1251);
|
||||
SetConsoleOutputCP(1251);
|
||||
setlocale(LC_ALL, "Russian");
|
||||
return Daemon_Singleton::init(argc, argv);
|
||||
}
|
||||
|
||||
bool DaemonWin32::start()
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
SetConsoleCP(1251);
|
||||
SetConsoleOutputCP(1251);
|
||||
setlocale(LC_ALL, "Russian");
|
||||
if (!i2p::win32::StartWin32App ()) return false;
|
||||
|
||||
// override log
|
||||
i2p::config::SetOption("log", std::string ("file"));
|
||||
bool ret = Daemon_Singleton::start();
|
||||
if (ret && IsLogToFile ())
|
||||
{
|
||||
// TODO: find out where this garbage to console comes from
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
|
||||
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DaemonWin32::stop()
|
||||
{
|
||||
i2p::win32::StopWin32App ();
|
||||
return Daemon_Singleton::stop();
|
||||
}
|
||||
|
||||
void DaemonWin32::run ()
|
||||
{
|
||||
i2p::win32::RunWin32App ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
144
Datagram.cpp
@@ -1,144 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "Log.h"
|
||||
#include "TunnelBase.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Destination.h"
|
||||
#include "Datagram.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace datagram
|
||||
{
|
||||
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
|
||||
m_Owner (owner), m_Receiver (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DatagramDestination::~DatagramDestination ()
|
||||
{
|
||||
}
|
||||
|
||||
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
uint8_t buf[MAX_DATAGRAM_SIZE];
|
||||
auto identityLen = m_Owner->GetIdentity ()->ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
||||
uint8_t * signature = buf + identityLen;
|
||||
auto signatureLen = m_Owner->GetIdentity ()->GetSignatureLen ();
|
||||
uint8_t * buf1 = signature + signatureLen;
|
||||
size_t headerLen = identityLen + signatureLen;
|
||||
|
||||
memcpy (buf1, payload, len);
|
||||
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
SHA256(buf1, len, hash);
|
||||
m_Owner->Sign (hash, 32, signature);
|
||||
}
|
||||
else
|
||||
m_Owner->Sign (buf1, len, signature);
|
||||
|
||||
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
||||
auto remote = m_Owner->FindLeaseSet (ident);
|
||||
if (remote)
|
||||
m_Owner->GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote));
|
||||
else
|
||||
m_Owner->RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (remote)
|
||||
SendMsg (msg, remote);
|
||||
}
|
||||
|
||||
void DatagramDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
|
||||
{
|
||||
auto outboundTunnel = m_Owner->GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||
auto leases = remote->GetNonExpiredLeases ();
|
||||
if (!leases.empty () && outboundTunnel)
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
uint32_t i = rand () % leases.size ();
|
||||
auto garlic = m_Owner->WrapMessage (remote, msg, true);
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
leases[i]->tunnelGateway, leases[i]->tunnelID,
|
||||
garlic
|
||||
});
|
||||
outboundTunnel->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outboundTunnel)
|
||||
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
|
||||
else
|
||||
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::data::IdentityEx identity;
|
||||
size_t identityLen = identity.FromBuffer (buf, len);
|
||||
const uint8_t * signature = buf + identityLen;
|
||||
size_t headerLen = identityLen + identity.GetSignatureLen ();
|
||||
|
||||
bool verified = false;
|
||||
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
SHA256(buf + headerLen, len - headerLen, hash);
|
||||
verified = identity.Verify (hash, 32, signature);
|
||||
}
|
||||
else
|
||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||
|
||||
if (verified)
|
||||
{
|
||||
auto it = m_ReceiversByPorts.find (toPort);
|
||||
if (it != m_ReceiversByPorts.end ())
|
||||
it->second (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||
else if (m_Receiver != nullptr)
|
||||
m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||
else
|
||||
LogPrint (eLogWarning, "Receiver for datagram is not set");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
// unzip it
|
||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||
size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
||||
if (uncompressedLen)
|
||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
auto msg = NewI2NPMessage ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
buf += 4; // reserve for length
|
||||
size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
|
||||
if (size)
|
||||
{
|
||||
htobe32buf (msg->GetPayload (), size); // length
|
||||
htobe16buf (buf + 4, fromPort); // source port
|
||||
htobe16buf (buf + 6, toPort); // destination port
|
||||
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
|
||||
msg->len += size + 4;
|
||||
msg->FillI2NPMessageHeader (eI2NPData);
|
||||
}
|
||||
else
|
||||
msg = nullptr;
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
Datagram.h
@@ -1,61 +0,0 @@
|
||||
#ifndef DATAGRAM_H__
|
||||
#define DATAGRAM_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include "Base.h"
|
||||
#include "Identity.h"
|
||||
#include "LeaseSet.h"
|
||||
#include "I2NPProtocol.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
class ClientDestination;
|
||||
}
|
||||
namespace datagram
|
||||
{
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
class DatagramDestination
|
||||
{
|
||||
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
||||
|
||||
public:
|
||||
|
||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
||||
~DatagramDestination ();
|
||||
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
void ResetReceiver () { m_Receiver = nullptr; };
|
||||
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port) { m_ReceiversByPorts[port] = receiver; };
|
||||
void ResetReceiver (uint16_t port) { m_ReceiversByPorts.erase (port); };
|
||||
|
||||
private:
|
||||
|
||||
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
void SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||
Receiver m_Receiver; // default
|
||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
i2p::data::GzipDeflator m_Deflator;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
784
Destination.cpp
@@ -1,784 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "Log.h"
|
||||
#include "FS.h"
|
||||
#include "Crypto.h"
|
||||
#include "Timestamp.h"
|
||||
#include "NetDb.h"
|
||||
#include "Destination.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||
const std::map<std::string, std::string> * params):
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
|
||||
m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0),
|
||||
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service),
|
||||
m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service)
|
||||
{
|
||||
if (m_IsPublic)
|
||||
PersistTemporaryKeys ();
|
||||
else
|
||||
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
|
||||
int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
|
||||
int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
||||
int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
|
||||
int numTags = DEFAULT_TAGS_TO_SEND;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
|
||||
if (params)
|
||||
{
|
||||
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
|
||||
if (it != params->end ())
|
||||
{
|
||||
int len = boost::lexical_cast<int>(it->second);
|
||||
if (len > 0)
|
||||
{
|
||||
inboundTunnelLen = len;
|
||||
LogPrint (eLogInfo, "Destination: Inbound tunnel length set to ", len);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
|
||||
if (it != params->end ())
|
||||
{
|
||||
int len = boost::lexical_cast<int>(it->second);
|
||||
if (len > 0)
|
||||
{
|
||||
outboundTunnelLen = len;
|
||||
LogPrint (eLogInfo, "Destination: Outbound tunnel length set to ", len);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
|
||||
if (it != params->end ())
|
||||
{
|
||||
int quantity = boost::lexical_cast<int>(it->second);
|
||||
if (quantity > 0)
|
||||
{
|
||||
inboundTunnelsQuantity = quantity;
|
||||
LogPrint (eLogInfo, "Destination: Inbound tunnels quantity set to ", quantity);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
|
||||
if (it != params->end ())
|
||||
{
|
||||
int quantity = boost::lexical_cast<int>(it->second);
|
||||
if (quantity > 0)
|
||||
{
|
||||
outboundTunnelsQuantity = quantity;
|
||||
LogPrint (eLogInfo, "Destination: Outbound tunnels quantity set to ", quantity);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_TAGS_TO_SEND);
|
||||
if (it != params->end ())
|
||||
{
|
||||
int tagsToSend = boost::lexical_cast<int>(it->second);
|
||||
if (tagsToSend > 0)
|
||||
{
|
||||
numTags = tagsToSend;
|
||||
LogPrint (eLogInfo, "Destination: Tags to send set to ", tagsToSend);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
|
||||
if (it != params->end ())
|
||||
{
|
||||
explicitPeers = std::make_shared<std::vector<i2p::data::IdentHash> >();
|
||||
std::stringstream ss(it->second);
|
||||
std::string b64;
|
||||
while (std::getline (ss, b64, ','))
|
||||
{
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase64 (b64);
|
||||
explicitPeers->push_back (ident);
|
||||
}
|
||||
LogPrint (eLogInfo, "Destination: Explicit peers set to ", it->second);
|
||||
}
|
||||
}
|
||||
SetNumTags (numTags);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
|
||||
if (explicitPeers)
|
||||
m_Pool->SetExplicitPeers (explicitPeers);
|
||||
if (m_IsPublic)
|
||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||
}
|
||||
|
||||
ClientDestination::~ClientDestination ()
|
||||
{
|
||||
if (m_IsRunning)
|
||||
Stop ();
|
||||
for (auto it: m_LeaseSetRequests)
|
||||
if (it.second->requestComplete) it.second->requestComplete (nullptr);
|
||||
m_LeaseSetRequests.clear ();
|
||||
if (m_Pool)
|
||||
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
||||
if (m_DatagramDestination)
|
||||
delete m_DatagramDestination;
|
||||
}
|
||||
|
||||
void ClientDestination::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::Start ()
|
||||
{
|
||||
if (!m_IsRunning)
|
||||
{
|
||||
m_IsRunning = true;
|
||||
m_Pool->SetLocalDestination (shared_from_this ());
|
||||
m_Pool->SetActive (true);
|
||||
m_Thread = new std::thread (std::bind (&ClientDestination::Run, shared_from_this ()));
|
||||
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this ()); // TODO:
|
||||
m_StreamingDestination->Start ();
|
||||
for (auto it: m_StreamingDestinationsByPorts)
|
||||
it.second->Start ();
|
||||
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
||||
m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::Stop ()
|
||||
{
|
||||
if (m_IsRunning)
|
||||
{
|
||||
m_CleanupTimer.cancel ();
|
||||
m_PublishConfirmationTimer.cancel ();
|
||||
m_PublishVerificationTimer.cancel ();
|
||||
m_IsRunning = false;
|
||||
m_StreamingDestination->Stop ();
|
||||
m_StreamingDestination = nullptr;
|
||||
for (auto it: m_StreamingDestinationsByPorts)
|
||||
it.second->Stop ();
|
||||
if (m_DatagramDestination)
|
||||
{
|
||||
auto d = m_DatagramDestination;
|
||||
m_DatagramDestination = nullptr;
|
||||
delete d;
|
||||
}
|
||||
if (m_Pool)
|
||||
{
|
||||
m_Pool->SetLocalDestination (nullptr);
|
||||
i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
|
||||
}
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::LeaseSet> ClientDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto it = m_RemoteLeaseSets.find (ident);
|
||||
if (it != m_RemoteLeaseSets.end ())
|
||||
{
|
||||
if (!it->second->IsExpired ())
|
||||
return it->second;
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: remote LeaseSet expired");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ls = i2p::data::netdb.FindLeaseSet (ident);
|
||||
if (ls && !ls->IsExpired ())
|
||||
{
|
||||
ls->PopulateLeases (); // since we don't store them in netdb
|
||||
m_RemoteLeaseSets[ident] = ls;
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::LeaseSet> ClientDestination::GetLeaseSet ()
|
||||
{
|
||||
if (!m_Pool) return nullptr;
|
||||
if (!m_LeaseSet)
|
||||
UpdateLeaseSet ();
|
||||
return m_LeaseSet;
|
||||
}
|
||||
|
||||
void ClientDestination::UpdateLeaseSet ()
|
||||
{
|
||||
m_LeaseSet.reset (new i2p::data::LeaseSet (m_Pool));
|
||||
}
|
||||
|
||||
bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t k[32], t[32];
|
||||
} data;
|
||||
memcpy (data.k, key, 32);
|
||||
memcpy (data.t, tag, 32);
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s,data](void)
|
||||
{
|
||||
s->AddSessionKey (data.k, data.t);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, shared_from_this (), msg));
|
||||
}
|
||||
|
||||
void ClientDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, shared_from_this (), msg));
|
||||
}
|
||||
|
||||
void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
{
|
||||
uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET];
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPData:
|
||||
HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
// we assume tunnel tests non-encrypted
|
||||
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
|
||||
break;
|
||||
case eI2NPDatabaseStore:
|
||||
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
||||
break;
|
||||
case eI2NPDatabaseSearchReply:
|
||||
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
||||
break;
|
||||
default:
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
|
||||
size_t offset = DATABASE_STORE_HEADER_SIZE;
|
||||
if (replyToken)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
|
||||
offset += 36;
|
||||
}
|
||||
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
||||
if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet
|
||||
{
|
||||
LogPrint (eLogDebug, "Remote LeaseSet");
|
||||
auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
if (it != m_RemoteLeaseSets.end ())
|
||||
{
|
||||
leaseSet = it->second;
|
||||
if (leaseSet->IsNewer (buf + offset, len - offset))
|
||||
{
|
||||
leaseSet->Update (buf + offset, len - offset);
|
||||
if (leaseSet->IsValid ())
|
||||
LogPrint (eLogDebug, "Remote LeaseSet updated");
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "Remote LeaseSet update failed");
|
||||
m_RemoteLeaseSets.erase (it);
|
||||
leaseSet = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "Remote LeaseSet is older. Not updated");
|
||||
}
|
||||
else
|
||||
{
|
||||
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset);
|
||||
if (leaseSet->IsValid ())
|
||||
{
|
||||
if (leaseSet->GetIdentHash () != GetIdentHash ())
|
||||
{
|
||||
LogPrint (eLogDebug, "New remote LeaseSet added");
|
||||
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "Own remote LeaseSet dropped");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "New remote LeaseSet failed");
|
||||
leaseSet = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
|
||||
|
||||
auto it1 = m_LeaseSetRequests.find (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
if (it1 != m_LeaseSetRequests.end ())
|
||||
{
|
||||
it1->second->requestTimeoutTimer.cancel ();
|
||||
if (it1->second->requestComplete) it1->second->requestComplete (leaseSet);
|
||||
m_LeaseSetRequests.erase (it1);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::data::IdentHash key (buf);
|
||||
int num = buf[32]; // num
|
||||
LogPrint (eLogDebug, "Destination: DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
|
||||
auto it = m_LeaseSetRequests.find (key);
|
||||
if (it != m_LeaseSetRequests.end ())
|
||||
{
|
||||
auto request = it->second;
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
i2p::data::IdentHash peerHash (buf + 33 + i*32);
|
||||
auto floodfill = i2p::data::netdb.FindRouter (peerHash);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", peerHash.ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
|
||||
i2p::data::netdb.RequestDestination (peerHash);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
LogPrint (eLogError, "Destination: Suggested floodfills are not presented in netDb");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
if (!found)
|
||||
{
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||
if (msgID == m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed");
|
||||
m_ExcludedFloodfills.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
// schedule verification
|
||||
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
|
||||
m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
|
||||
}
|
||||
|
||||
void ClientDestination::SetLeaseSetUpdated ()
|
||||
{
|
||||
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
|
||||
UpdateLeaseSet ();
|
||||
if (m_IsPublic)
|
||||
{
|
||||
m_PublishVerificationTimer.cancel ();
|
||||
Publish ();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::Publish ()
|
||||
{
|
||||
if (!m_LeaseSet || !m_Pool)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
|
||||
return;
|
||||
}
|
||||
if (m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet is pending");
|
||||
return;
|
||||
}
|
||||
auto outbound = m_Pool->GetNextOutboundTunnel ();
|
||||
if (!outbound)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
|
||||
return;
|
||||
}
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
if (!floodfill)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
m_ExcludedFloodfills.clear ();
|
||||
return;
|
||||
}
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken));
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
|
||||
}
|
||||
|
||||
void ClientDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
|
||||
m_PublishReplyToken = 0;
|
||||
Publish ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
RequestLeaseSet (GetIdentHash (),
|
||||
// "this" added due to bug in gcc 4.7-4.8
|
||||
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
||||
{
|
||||
if (leaseSet)
|
||||
{
|
||||
if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet)
|
||||
{
|
||||
// we got latest LeasetSet
|
||||
LogPrint (eLogDebug, "Destination: published LeaseSet verified");
|
||||
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
|
||||
s->m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet");
|
||||
// we have to publish again
|
||||
s->Publish ();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
buf += 4;
|
||||
// we assume I2CP payload
|
||||
uint16_t fromPort = bufbe16toh (buf + 4), // source
|
||||
toPort = bufbe16toh (buf + 6); // destination
|
||||
switch (buf[9])
|
||||
{
|
||||
case PROTOCOL_TYPE_STREAMING:
|
||||
{
|
||||
// streaming protocol
|
||||
auto dest = GetStreamingDestination (toPort);
|
||||
if (dest)
|
||||
dest->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing streaming destination");
|
||||
}
|
||||
break;
|
||||
case PROTOCOL_TYPE_DATAGRAM:
|
||||
// datagram protocol
|
||||
if (m_DatagramDestination)
|
||||
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing datagram destination");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
|
||||
return;
|
||||
}
|
||||
auto leaseSet = FindLeaseSet (dest);
|
||||
if (leaseSet)
|
||||
streamRequestComplete(CreateStream (leaseSet, port));
|
||||
else
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
RequestDestination (dest,
|
||||
[s, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if (ls)
|
||||
streamRequestComplete(s->CreateStream (ls, port));
|
||||
else
|
||||
streamRequestComplete (nullptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
auto it = m_StreamingDestinationsByPorts.find (port);
|
||||
if (it != m_StreamingDestinationsByPorts.end ())
|
||||
return it->second;
|
||||
}
|
||||
// if port is zero or not found, use default destination
|
||||
return m_StreamingDestination;
|
||||
}
|
||||
|
||||
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
m_StreamingDestination->SetAcceptor (acceptor);
|
||||
}
|
||||
|
||||
void ClientDestination::StopAcceptingStreams ()
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
m_StreamingDestination->ResetAcceptor ();
|
||||
}
|
||||
|
||||
bool ClientDestination::IsAcceptingStreams () const
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->IsAcceptorSet ();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
|
||||
{
|
||||
auto dest = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this (), port, gzip);
|
||||
if (port)
|
||||
m_StreamingDestinationsByPorts[port] = dest;
|
||||
else // update default
|
||||
m_StreamingDestination = dest;
|
||||
return dest;
|
||||
}
|
||||
|
||||
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination ()
|
||||
{
|
||||
if (!m_DatagramDestination)
|
||||
m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ());
|
||||
return m_DatagramDestination;
|
||||
}
|
||||
|
||||
bool ClientDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
|
||||
{
|
||||
if (!m_Pool || !IsReady ())
|
||||
{
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
return false;
|
||||
}
|
||||
m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([dest, s](void)
|
||||
{
|
||||
auto it = s->m_LeaseSetRequests.find (dest);
|
||||
if (it != s->m_LeaseSetRequests.end ())
|
||||
{
|
||||
auto requestComplete = it->second->requestComplete;
|
||||
s->m_LeaseSetRequests.erase (it);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ClientDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
|
||||
{
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
auto request = std::make_shared<LeaseSetRequest> (m_Service);
|
||||
request->requestComplete = requestComplete;
|
||||
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> >(dest,request));
|
||||
if (ret.second) // inserted
|
||||
{
|
||||
if (!SendLeaseSetRequest (dest, floodfill, request))
|
||||
{
|
||||
// request failed
|
||||
m_LeaseSetRequests.erase (dest);
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
else // duplicate
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
|
||||
// TODO: queue up requests
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found");
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
|
||||
request->replyTunnel = m_Pool->GetNextInboundTunnel ();
|
||||
if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
|
||||
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
|
||||
request->outboundTunnel = m_Pool->GetNextOutboundTunnel ();
|
||||
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
|
||||
|
||||
if (request->replyTunnel && request->outboundTunnel)
|
||||
{
|
||||
request->excluded.insert (nextFloodfill->GetIdentHash ());
|
||||
request->requestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
request->requestTimeoutTimer.cancel ();
|
||||
|
||||
uint8_t replyKey[32], replyTag[32];
|
||||
RAND_bytes (replyKey, 32); // random session key
|
||||
RAND_bytes (replyTag, 32); // random session tag
|
||||
AddSessionKey (replyKey, replyTag);
|
||||
|
||||
auto msg = WrapMessage (nextFloodfill,
|
||||
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded,
|
||||
request->replyTunnel, replyKey, replyTag));
|
||||
request->outboundTunnel->SendTunnelDataMsg (
|
||||
{
|
||||
i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
nextFloodfill->GetIdentHash (), 0, msg
|
||||
}
|
||||
});
|
||||
request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT));
|
||||
request->requestTimeoutTimer.async_wait (std::bind (&ClientDestination::HandleRequestTimoutTimer,
|
||||
shared_from_this (), std::placeholders::_1, dest));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto it = m_LeaseSetRequests.find (dest);
|
||||
if (it != m_LeaseSetRequests.end ())
|
||||
{
|
||||
bool done = false;
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
|
||||
{
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
// reset tunnels, because one them might fail
|
||||
it->second->outboundTunnel = nullptr;
|
||||
it->second->replyTunnel = nullptr;
|
||||
done = !SendLeaseSetRequest (dest, floodfill, it->second);
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (done)
|
||||
{
|
||||
auto requestComplete = it->second->requestComplete;
|
||||
m_LeaseSetRequests.erase (it);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
CleanupExpiredTags ();
|
||||
CleanupRemoteLeaseSets ();
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
||||
m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CleanupRemoteLeaseSets ()
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it = m_RemoteLeaseSets.begin (); it != m_RemoteLeaseSets.end ();)
|
||||
{
|
||||
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
it = m_RemoteLeaseSets.erase (it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::PersistTemporaryKeys ()
|
||||
{
|
||||
std::string ident = GetIdentHash().ToBase32();
|
||||
std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat"));
|
||||
std::ifstream f(path, std::ifstream::binary);
|
||||
|
||||
if (f) {
|
||||
f.read ((char *)m_EncryptionPublicKey, 256);
|
||||
f.read ((char *)m_EncryptionPrivateKey, 256);
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
|
||||
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
|
||||
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
||||
if (f1) {
|
||||
f1.write ((char *)m_EncryptionPublicKey, 256);
|
||||
f1.write ((char *)m_EncryptionPrivateKey, 256);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
321
HTTPProxy.cpp
@@ -1,321 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include "HTTPProxy.h"
|
||||
#include "util.h"
|
||||
#include "Identity.h"
|
||||
#include "Streaming.h"
|
||||
#include "Destination.h"
|
||||
#include "ClientContext.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "I2PTunnel.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace proxy
|
||||
{
|
||||
static const size_t http_buffer_size = 8192;
|
||||
class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPProxyHandler>
|
||||
{
|
||||
private:
|
||||
enum state
|
||||
{
|
||||
GET_METHOD,
|
||||
GET_HOSTNAME,
|
||||
GET_HTTPV,
|
||||
GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed
|
||||
DONE
|
||||
};
|
||||
|
||||
void EnterState(state nstate);
|
||||
bool HandleData(uint8_t *http_buff, std::size_t len);
|
||||
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
||||
void Terminate();
|
||||
void AsyncSockRead();
|
||||
void HTTPRequestFailed(/*std::string message*/);
|
||||
void ExtractRequest();
|
||||
bool ValidateHTTPRequest();
|
||||
void HandleJumpServices();
|
||||
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
|
||||
void SentHTTPFailed(const boost::system::error_code & ecode);
|
||||
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
uint8_t m_http_buff[http_buffer_size];
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
|
||||
std::string m_request; //Data left to be sent
|
||||
std::string m_url; //URL
|
||||
std::string m_method; //Method
|
||||
std::string m_version; //HTTP version
|
||||
std::string m_address; //Address
|
||||
std::string m_path; //Path
|
||||
int m_port; //Port
|
||||
state m_state;//Parsing state
|
||||
|
||||
public:
|
||||
|
||||
HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
|
||||
I2PServiceHandler(parent), m_sock(sock)
|
||||
{ EnterState(GET_METHOD); }
|
||||
~HTTPProxyHandler() { Terminate(); }
|
||||
void Handle () { AsyncSockRead(); }
|
||||
};
|
||||
|
||||
void HTTPProxyHandler::AsyncSockRead()
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: async sock read");
|
||||
if(m_sock) {
|
||||
m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
|
||||
std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
} else {
|
||||
LogPrint(eLogError, "HTTPProxy: no socket for read");
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::Terminate() {
|
||||
if (Kill()) return;
|
||||
if (m_sock)
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: close sock");
|
||||
m_sock->close();
|
||||
m_sock = nullptr;
|
||||
}
|
||||
Done(shared_from_this());
|
||||
}
|
||||
|
||||
/* All hope is lost beyond this point */
|
||||
//TODO: handle this apropriately
|
||||
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
|
||||
{
|
||||
static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n";
|
||||
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
|
||||
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate)
|
||||
{
|
||||
m_state = nstate;
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::ExtractRequest()
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
|
||||
std::string server="";
|
||||
std::string port="80";
|
||||
boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
|
||||
boost::smatch m;
|
||||
std::string path;
|
||||
if(boost::regex_search(m_url, m, rHTTP, boost::match_extra))
|
||||
{
|
||||
server=m[1].str();
|
||||
if (m[2].str() != "") port=m[3].str();
|
||||
path=m[4].str();
|
||||
}
|
||||
LogPrint(eLogDebug, "HTTPProxy: server: ", server, ", port: ", port, ", path: ", path);
|
||||
m_address = server;
|
||||
m_port = boost::lexical_cast<int>(port);
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
bool HTTPProxyHandler::ValidateHTTPRequest()
|
||||
{
|
||||
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
|
||||
{
|
||||
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
|
||||
HTTPRequestFailed(); //TODO: send right stuff
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::HandleJumpServices()
|
||||
{
|
||||
static const char * helpermark1 = "?i2paddresshelper=";
|
||||
static const char * helpermark2 = "&i2paddresshelper=";
|
||||
size_t addressHelperPos1 = m_path.rfind (helpermark1);
|
||||
size_t addressHelperPos2 = m_path.rfind (helpermark2);
|
||||
size_t addressHelperPos;
|
||||
if (addressHelperPos1 == std::string::npos)
|
||||
{
|
||||
if (addressHelperPos2 == std::string::npos)
|
||||
return; //Not a jump service
|
||||
else
|
||||
addressHelperPos = addressHelperPos2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addressHelperPos2 == std::string::npos)
|
||||
addressHelperPos = addressHelperPos1;
|
||||
else if ( addressHelperPos1 > addressHelperPos2 )
|
||||
addressHelperPos = addressHelperPos1;
|
||||
else
|
||||
addressHelperPos = addressHelperPos2;
|
||||
}
|
||||
auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
|
||||
base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
|
||||
LogPrint (eLogInfo, "HTTPProxy: jump service for ", m_address, ", inserting to address book");
|
||||
//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
|
||||
//TODO: we could redirect the user again to avoid dirtiness in the browser
|
||||
i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
|
||||
m_path.erase(addressHelperPos);
|
||||
}
|
||||
|
||||
bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
|
||||
{
|
||||
ExtractRequest(); //TODO: parse earlier
|
||||
if (!ValidateHTTPRequest()) return false;
|
||||
HandleJumpServices();
|
||||
m_request = m_method;
|
||||
m_request.push_back(' ');
|
||||
m_request += m_path;
|
||||
m_request.push_back(' ');
|
||||
m_request += m_version;
|
||||
m_request.push_back('\r');
|
||||
m_request.push_back('\n');
|
||||
m_request.append("Connection: close\r\n");
|
||||
// TODO: temporary shortcut. Must be implemented properly
|
||||
uint8_t * eol = nullptr;
|
||||
bool isEndOfHeader = false;
|
||||
while (!isEndOfHeader && len && (eol = (uint8_t *)memchr (http_buff, '\r', len)))
|
||||
{
|
||||
if (eol)
|
||||
{
|
||||
*eol = 0; eol++;
|
||||
if (strncmp ((const char *)http_buff, "Referer", 7)) // strip out referer
|
||||
{
|
||||
if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent
|
||||
m_request.append("User-Agent: MYOB/6.66 (AN/ON)");
|
||||
else
|
||||
m_request.append ((const char *)http_buff);
|
||||
m_request.append ("\r\n");
|
||||
}
|
||||
isEndOfHeader = !http_buff[0];
|
||||
auto l = eol - http_buff;
|
||||
http_buff = eol;
|
||||
len -= l;
|
||||
if (len > 0) // \r
|
||||
{
|
||||
http_buff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_request.append(reinterpret_cast<const char *>(http_buff),len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len)
|
||||
{
|
||||
while (len > 0)
|
||||
{
|
||||
//TODO: fallback to finding HOst: header if needed
|
||||
switch (m_state)
|
||||
{
|
||||
case GET_METHOD:
|
||||
switch (*http_buff)
|
||||
{
|
||||
case ' ': EnterState(GET_HOSTNAME); break;
|
||||
default: m_method.push_back(*http_buff); break;
|
||||
}
|
||||
break;
|
||||
case GET_HOSTNAME:
|
||||
switch (*http_buff)
|
||||
{
|
||||
case ' ': EnterState(GET_HTTPV); break;
|
||||
default: m_url.push_back(*http_buff); break;
|
||||
}
|
||||
break;
|
||||
case GET_HTTPV:
|
||||
switch (*http_buff)
|
||||
{
|
||||
case '\r': EnterState(GET_HTTPVNL); break;
|
||||
default: m_version.push_back(*http_buff); break;
|
||||
}
|
||||
break;
|
||||
case GET_HTTPVNL:
|
||||
switch (*http_buff)
|
||||
{
|
||||
case '\n': EnterState(DONE); break;
|
||||
default:
|
||||
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
|
||||
HTTPRequestFailed(); //TODO: add correct code
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
|
||||
HTTPRequestFailed(); //TODO: add correct code 500
|
||||
return false;
|
||||
}
|
||||
http_buff++;
|
||||
len--;
|
||||
if (m_state == DONE)
|
||||
return CreateHTTPRequest(http_buff,len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
|
||||
if(ecode)
|
||||
{
|
||||
LogPrint(eLogWarning, "HTTPProxy: sock recv got error: ", ecode);
|
||||
Terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (HandleData(m_http_buff, len))
|
||||
{
|
||||
if (m_state == DONE)
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
|
||||
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete,
|
||||
shared_from_this(), std::placeholders::_1), m_address, m_port);
|
||||
}
|
||||
else
|
||||
AsyncSockRead();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode)
|
||||
{
|
||||
if (ecode)
|
||||
LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
|
||||
Terminate();
|
||||
}
|
||||
|
||||
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
if (Kill()) return;
|
||||
LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection");
|
||||
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
|
||||
GetOwner()->AddHandler (connection);
|
||||
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
|
||||
Done(shared_from_this());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
|
||||
HTTPRequestFailed(); // TODO: Send correct error message host unreachable
|
||||
}
|
||||
}
|
||||
|
||||
HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
||||
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
{
|
||||
return std::make_shared<HTTPProxyHandler> (this, socket);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
32
HTTPProxy.h
@@ -1,32 +0,0 @@
|
||||
#ifndef HTTP_PROXY_H__
|
||||
#define HTTP_PROXY_H__
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <boost/asio.hpp>
|
||||
#include <mutex>
|
||||
#include "I2PService.h"
|
||||
#include "Destination.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace proxy
|
||||
{
|
||||
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
|
||||
{
|
||||
public:
|
||||
|
||||
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||
~HTTPProxyServer() {};
|
||||
|
||||
protected:
|
||||
// Implements TCPIPAcceptor
|
||||
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||
const char* GetName() { return "HTTP Proxy"; }
|
||||
};
|
||||
|
||||
typedef HTTPProxyServer HTTPProxy;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
948
HTTPServer.cpp
@@ -1,948 +0,0 @@
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include "Base.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "Tunnel.h"
|
||||
#include "TransitTunnel.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Streaming.h"
|
||||
#include "Destination.h"
|
||||
#include "RouterContext.h"
|
||||
#include "ClientContext.h"
|
||||
#include "HTTPServer.h"
|
||||
|
||||
// For image and info
|
||||
#include "version.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
const std::string HTTPConnection::itoopieImage =
|
||||
"<img alt=\"ICToopie Icon\" src=\"data:image/png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXM"
|
||||
"AAA3XAAAN1wFCKJt4AAAAB3RJTUUH3ggRChYFXVBoSgAAIABJREFUeNrtnXl8VOX1/9/PvXcmewiQBB"
|
||||
"J2CKsKihQXkCJuiD8VKyptXejXaikWbe1C1dqi0lpr7UvrgihV64ZCXaqCUBEUQVBAAZUl7EtYEkLIP"
|
||||
"pmZ+zy/P+6dySx3JgESkpAcX/MiznLvc8/5POc55zznnAfaqFWTaIXPnAt0AzoBqYAB1AAVwAFgF3Ck"
|
||||
"DQCnBvUHxgEXAMOBLsfw22+BT4ElwGKgrE1ftAwaBswEygFlv+QJvALX2AH8BchrY3HzpF8A+xtA4PU"
|
||||
"BwxZgUhvLmwf9AfA1suBjgaEK+GWbDdA0dAswC0iwhVEvSk5A9smFThmIjFSUroPHC0cr0HYexNxTiH"
|
||||
"aMfBFAiT2e99sA0PiUBXwMnFEfwZ/ZB3n1eTDmTDh3IMKdgoYZoi8CXBCABhioA/uRn3+H+OgreGcFq"
|
||||
"vAoWj15udQ2Oj1tAGgcmgS8WJfgczsif3sd3D4OkZyCZnqPQUWEkKaBlgDbd2PO+gDx5H/B462TZwq4"
|
||||
"zPYc2gDQgPQmcH084Z/eE/nkHYjRw9H8VQ17c02A5ka99j/kb59DHDgSl3cC+BswrQ0AJ04GsB4YFEv"
|
||||
"47VJQr/8eNW4kuv8kKF8jEfXSfOSUf6JVe+PydhEwtg0Ax0/Jtv+dHesLU65EPn0Xmt/XJM+ibn0M8+"
|
||||
"XF6HH4+xVwdhsAjp0Sgb1AB6dxCoH67B+oEaeh+80mVE8GLP0a8+LfI6R05KcA1gFntQHg2GgX0N3pg"
|
||||
"87tkd/NRktPbj7jr/SghkxG7j7k6DEI23O5uLkxWWumwl8WS/i9OmPueQ3RnIQPkJKI2PUq+jkDgs5l"
|
||||
"pGdwEfDPNgDUTQ9hbd5EUfds5PZ/owvRPIHr98Oqp9EvHBITBFOBa9qWgNg0FFjrZO1npKIOvgm61my"
|
||||
"1Vq1d4IbhP0euzo9pE3TAih62ASCCioH2TrNn72vQuUPzF34QBDoqdyLywBHHMa+zwd62BITQX+yZEU"
|
||||
"X/uR+V04TCN9ygFOaafNTbyzHnLsNc9g3S60ca7hjLgYlY9yxajNjFWcBNbRqgltKBUidmTRiFnPcnd"
|
||||
"L9DwEUI0JNgz17k5xuRBYfRvX7I6YD8/mBEr+5o/uoTEHwC6vn3UE+9h9qwwxmAw/oh/3or4qJhaE5j"
|
||||
"fGcF5vUzHH/rtV3dNgBgxfdvcfL1a+YjhIgep6Ej/zYX+eg8tMOlzs/RLQv52M/gujHo/pr6D0bXYG0"
|
||||
"+5iX3II5W1I9Hlw/HnP8Qhimjtce432N+uDoKBAJ4AJje2gHQDjjqNPtn34265ZJwxmkarMnHvOi3iA"
|
||||
"pP/cY/5izkx4/UL2CkaTBvGf6Jfw6L7gXus/aCCy4YcujQoZL8/HzdXrKC4x7UHfXdbLTI+1TXINPHO"
|
||||
"/JbNLUMmoMNMN1J+DkdkLdeGc4cXYO3l+M/ZypaiPAFsHvMmDFFl1122ZoxY8Zsyc7OLgxl7JKv0YZM"
|
||||
"RhquugezJh8zQvjmpEmT9hUWFuYrpc5etmyZsWXLliylVOLs2bPXCyFKA/fauAcxfjr+SLsgORHtjz+"
|
||||
"OuYl1F62c/Dhk3My5F7/vQ1Toa8XjmIHPhRAK2L1w4cIDSimPiqCCgoJdI0aM2EtIptAtl+BTH4VfM/"
|
||||
"SlPkalJ9feIyEhQa5fv36Nik/Fffv2LbHHIwH5v4ejx24uQkLttUNe+1uz8K/CIZUrIxVTLUWGMXAhM"
|
||||
"tFdK/y8vLzNSimzDuGo++67b37oPdY8HS2cwOuZqWECqtm0adNaVT86AhQEftuvK361NAIAC1G/uc4R"
|
||||
"AAo4s7UuAT9xUv+/uQ5l1tSqcE3A/f9GeWwru127dnu2bt3auz7jnzFjxriJEyeuEkIIgDufRjm5boY"
|
||||
"bZn4QHIuYPn367gEDBtTXV2+/atWqI4GlIH8f2uYdhFkCUsG06x1/q2jCBNOmNgKVEwDK/otKctcK10"
|
||||
"hEuS5G+U3LaNq5c2dhz549s4/hPj4hxFEgE6BoHmSkhj+7pmHqlwXvWaaUcmFtR9ebMjMzNxcXF/cHm"
|
||||
"DEJNe2GcIAabjhnCuaXW6KAexCrYKVVaQDH2TW8PzItNXxcK9cjbeGTnZ295xiFD+CaMmWKPwD4uZ9G"
|
||||
"g+7bnbX3vP766w8fq/ABpk2bFrTqV26ytorDjB0v3Oi8H5hje0OtCgCOrJh4ocWoUFqxsXac11xzzXG"
|
||||
"Nefz48cGrLvsWZUSkcBwuq00RHTNmzHFlGFx55ZU5gb93HUQ6cffakTG17oWtDQDnO6n/K8+JUs1s3x"
|
||||
"9cT8WgQYNkHdfdiVUVFEaDBw/2Bf7eVgCROTyGXntfl8t1XBmFOTk5e4O+vxflJOrcXLTUxKjdQgWc0"
|
||||
"9oAcKZT5C+vdzjbBODzhwfqnC722Wef7cnMzNwthOglhEjMzMxct2HDhj1BARtG8CpHK6OF0yWz9u/8"
|
||||
"/PxOAEoppJSlU6ZM2dipU6cCIcSXEyZM2KaUKncaQ3l5eXrQHkhHd/T8vTDydEctcEZrA0CPyDfOykP"
|
||||
"hD2eOlJCdEXxPff7551FFmgsWLDg4atSorsXFxd3t2WQUFxcPGTJkSJeFCxceBti2bVtwoyk1CREpnD"
|
||||
"7dEQGj9IknnvABFBcXl+u6rs+cOXNQYWFhLvC9t956K0/TtIMQvee/fPny4FUHdEcqf/RDmyYM6VN/m"
|
||||
"+hUBUCa05uDutuhkgjdOLRvSFRvyZLIHcODV1xxRaxqHu3yyy/XgKqXXnopKI7enR3EZyLGnGnBwuPx"
|
||||
"dP/666935+Xl7QNSIpYqJYToO3Xq1PWRN3vooYeqA98dOwzNdFislILeOTENwVYDAEeXp1uWNUOi7IJ"
|
||||
"za4VbVFTUafXq1RtCZr+POFnDQIfbb7/962effbZdQDgjT7eyd8IsdB9MqQ09q6FDh3rKysoGOvquSq"
|
||||
"mnnnoqzGpftGjRVxs3buwf+MrE0bFd7JwOxLJjcloLABz3/TukoTktmwkuxPgRwVmohg8fHtQg+/btK"
|
||||
"60r1vD888+PCHXrbr7YWTjXjkHLzggKp59SKl5BUW9gD8CKFSu2jh07tm8AYPdMRCkVGwDtU2Omkbca"
|
||||
"ACThLGhHhvtNeGZqqLEoemVnZx+srKwsGjhwYHo9A04A/L9zUZkZzs/t98D8GfUPjuXn538+ZsyYb0e"
|
||||
"OHNkXq9sInTKQf/kpuowDHU3EvEdGawGA476cz4zN/OwMtNl3WxaCUkoVFRV1Sk1NTZg5c+aeY4k8vv"
|
||||
"w7hN8f+wvD+qH9YzL1iQPI/v37T1y6dOnpAYClJKK+eQ7N74v/Q1PGXAJcrQUAjiyqjJO9oxTcOg7jr"
|
||||
"7eGCSdtzpw5I6ln7eeqf0JaUvwZ7jfhVxMwnrmTuuINQa8By1CVB96AjLS6NUhI0CkKG60FAJVOb+4p"
|
||||
"wtTjjMjvg2k3YCx6GJmUEK3eY1G3LGT+i6hhfev3vH4f/OwK9J2voEYPiS+UIX2Q707HXDsLPSkBrT7"
|
||||
"rx/7imOOoONmCMJoIAMWOAChEF5qThx0+Q8eciV71PuqRNzGffg+xtyiaoalJyAuHwE8vR1w1yioaPZ"
|
||||
"YScSmhayba0sfQjpYhF3yJ2rwXUVqJmdkO47QeyEuGItLSrHzF+qacCQFbC1Ax3NZDJ1sQTbUbmGxrg"
|
||||
"TCZdEzHPPweRn0TOYUAPQHwYe4uRPj8kJwAudmAjoYv2t07YYYJazk67hnngot+g1yyzjE9zDjZy0BT"
|
||||
"bgc7bgXXLEBqIqab1OLJSIbkSzCrvVFayw+4W4sNAFbxZxR9/DWnNB04gHQQPlhl5LQmAKx3evO9ldY"
|
||||
"O4KlK76+KaYqsbG0AWO20BL35CWiJp6bwDRe8sTTmUvxxawOAIytKKtBWf4N5KgLA40EuXR+T5/NbGw"
|
||||
"A+j/XB0/+1agBONZr5flxtqFobAMBqohRF//4IzedvGoY0mvpPRP15Tkz1/3JTjaupAfCvWK7oA68it"
|
||||
"VOol/m8j5HFZTHd7tlNNa7mwOJYcT9VMx+haS2/pb2RiOr8A9ShEsdnWYjVXbRVagCAR2IAUdz+BKbR"
|
||||
"wkNCQsATc5ExhC+AGU06vmbAowSs3rqOa/6GWaiB3WmxJmGlB5lxTUxeb8U61ILWrAFqgEdjgfHSe1C"
|
||||
"Gq2UK30hAjbsvpvAF8KumHmNzmVnTsGLhUXTwCNqND+NvaSDQNXj4VczPN8bUspuABU0+zmbEs93EaK"
|
||||
"H2zU60HlmYZ+WhqRbiHK74DnnTIzEnmMCqjDrU1ONsbhb2GuLkxy97DHX+ac0fBNv2Yw68NW73D59t+"
|
||||
"zQ5NTfjamw8UI76NWLtVqRoxo7hzoP4T7utztYvbqyDrZp+qWpm/KvCSrUeH+sLsz9EDO+PHNANTTYj"
|
||||
"TaAJWL8D84zb0eKlhIfQ97CaSnzVBoBwWgecS5zj2V5fitAE8sJhCGk2/TJmuOHVxcjL7zvm84ausgG"
|
||||
"/rs0GAObOhQ8+QLz8Msp2D+Pa/qMGIz/8M8JtNGETSRfqhzMw3/jkuCeTAO4B/tpmBAJCMFIpXsc63r"
|
||||
"VOJa8J1CvTUD+67OScFhI665evx3/FH9DKqsL4qM7nbDqSIQ9QqK3hm/rwWQBPY5192GoB4BaCuUpxN"
|
||||
"cexNTq0L2r5P8DVyNrAcMGuA6jJT6AWrQnn37WMlT/kKg2UkCh0NHR01vKt+ojP1CrW1XXO0HvA1a0R"
|
||||
"AFcC79ZzPMECzsgPrj4P+e4DDX+CSKAl7RfrMR94BSK7fmbTUT3Ar0QmGULGwK6Ojh+/eoV31XyWiDj"
|
||||
"PtpwY7fJPVQC8BfxACOKWYuaQLccx2ncOZ/o6kam2sUu7h0dTvCFFRmf0Qm6Y7dxXONCvxzTrl9ZtGJ"
|
||||
"anvnkr5pyl8NwCKyoZ7beOkrfzQ91H/fLPNTQKOCin8VdR41wgJbDyA88/1QEwGPiEOgoiu5Erf8r1n"
|
||||
"rMY5K+mJmy8bzI/4W0WBlOp774W+eht4YWZhhtmvYf8cDVKSkSfXNSg7ojeOaiMVLT0ZJQmrPMAj1bC"
|
||||
"7kPIrQVoq7cgF64BUzovKSkkq3uYrAaSp/uPI4Otkmp1O/fidwaOAOZhHZN3SgLgfuDBgBp3KrZIJkl"
|
||||
"N4UbPBXzP54kQfIDms9T9Mm8HI2oFc1DZIZW/moCH30D+4aWGe84cstRVXMJYRmlefCd0rU1sM6fzRL"
|
||||
"xw8R3AM41q05xkwacDn2L1BwqKPEL4YjyXem7mB14fPmIJX0Own0NB5o0dhszNQg+tzFWg/vDSiQ+6P"
|
||||
"e3UBQzjIkbQk66ahxpOVPgAQxio96OXmc9OJxAo2zN4HauZdosHwDXA20RUBIXO/q50lvcztaoD7ZSv"
|
||||
"DgYnkKDW8m1w/HeOR0SWZb++JLwGbzTnmns5oO2hAB9+R2AlkyS70ln0opsaSB8xmAGiI+21GrwoFB5"
|
||||
"qGowhXnxcw2XiEZ6N9RUFPAXc2JIB4Lbdm8siLfcQ4Ysfc7XnOsZ5a/Ai6+EF7qZAL6E0cCKHuvz88A"
|
||||
"JNw4B5n9UCII8e8lf8n2EiMdCRSFVOpfTiFQJBAm6VTpoukbqJiR8TZY+jIYUeSd9jcF3L049bMgBGA"
|
||||
"EvsiJ5ygncG6eoh7q7sRKaswVtvS/o9/ucOXHPCBSj8EZE4F+r9lbWz/xauFQFB2tpFuHHp7pBgYxXV"
|
||||
"nGwy0EV72vlLKNXrMJg3NMb9tUYE1hu2T+uKYeKIUWqY/wUeqcimo1THEPvREHzE58HrTr4SEen7L15"
|
||||
"VO/s7k6UGM6BZppVJJNl0rCuMvKElaYAJwNxYwZoA/VbdVnkeQ81o/1nV6Zx8wJKg8NOTURcNR4SWlB"
|
||||
"s6vLAo1Pi4tFHV+ImQAlzxxfBhS/IC/g3cHE/wncmSM/h1VRop6niEn0Sieo/FQd//l9egTE+EJtNRc"
|
||||
"2oLz9TFjBD+ZlptJoA4QSQBvNqY929ItTizLuFfxAjfs8yoSCNF1RWW0NAQCAo4qCXgVoHzIrexWy/m"
|
||||
"aFBl3j0hOkPovyHG32jORaKaLOCVSALVeKQ7Rum/hkYhxfH6Ec1pCRqgHzA5nvCvZaz3x4yvqcErnFW"
|
||||
"hItA9TUPjOV5P/IgVLstZEGoU3/MNYZD5DouCxt+lZyPbpYX7/oYBL1rHs+gAlzASWWe/p8aY2YJt7J"
|
||||
"YzeFJU4RG96Sb/zr1a5GzX0JTtzcRS/6olAOD78f1AF5OY4KmiWsRaCQPCr6BK/IoHU8qoDNn0UXzKl"
|
||||
"65P+TLMoPzNhGjfH5D/XWmpiySS1Bn016rxnHQAHKRI3sujwefdwV7xPkvkWEaFCXtP7CODBPBcY4+z"
|
||||
"oZaA5+NFq3T0uDo4FOJT+VOo8IO92CLzANuloi45L9pgeGtZ7VoymnOaxPhLJIFHmBX1/qesUu4Ip2g"
|
||||
"jW+PN8HdbCgAgTkJnNR7xBesNZ+FLBAINwYv8J6EKjwgLFMW42S+uQpkR5wYaBrywqPYnFzAM1QRFxl"
|
||||
"vZJQs4GMWLQooJPftaR+drNsYa4OsnY6wNCYAvgHtjgeBv4tmk6Li+InASvBu3WslaV9jMV+ERw9DWM"
|
||||
"VOvRkQaf6YfteDL4DOp0+jXJMbfmhhueyQYXRis5CvRVOq/MQJBD2PFrsMPfRDgVT5xFw+mxArzSqRI"
|
||||
"I1XhgCClrGtI25Yb0A3ZKSt67M8tqLX2hjMkZry/MUlHZyf7HD9zYYQ9/Vd8J2NMGA/WplmLA4C1jMP"
|
||||
"fIx9MAUcpE1P5U6qJiSL02RVevNzFT6rDIgKiFkChdONF0Y0ZjUR44t3ae57DmcJsAt9fR6OcCkfg+U"
|
||||
"JOw9DR+JgVsS7zwskab2OFR39rxwQEhG/3HqZETOa+1AqqRKTW60GuvIfJ1YrwXUKlwq8xfkT0rFm3G"
|
||||
"XPL3tr3z2+CAzgkUr3CO3IHex0/r6Raq8KjAEykWs6aWNb/yy0dAACvAGdBtBleQZW4nftSN7FN1yNS"
|
||||
"6Rdbvn/Y+h+6lAC8+jGyqgYZ6B1gGPDQa7UXGckw5cI4qeq/iCPyRu7mbRaJeJ7HS8yTblx8yCexwp5"
|
||||
"+2546aZHIBiUFbGCwGMIGFfSKrAcaDCgNEbrdKy5hpHcyP/J48XMXD6QWUiycMoSc3ptwAfLBW6wzhT"
|
||||
"In1D7L37mHbuSeTACom7hbefE5tX+NMnrGcaFawRpKKXca4zzghhYLgOD6Hf32UwLuUIE0sJDvJuKmM"
|
||||
"1nmLgr0+gg/8v9Tk5CV1bWnjbzPbGIHnRo+4vcOi8w5vB+qTcsmZVDR1UXKp5Uc+ayKHKxDMlQ95HEX"
|
||||
"8M8WuQTMJe52zi90xA9DPw58twYvuynQNa3W4g8FqF1rJ2JpglDhA5RSftKcfxcGK1gbVhiyrS/mUzl"
|
||||
"0mZZJxv960rtyIPLGduyq54Q7cjKXrgYFwAgeZ26Mh7yXnoYf9YaAoQJEQPjBYI/t5gUEnKzhfzKHzS"
|
||||
"t7oeZ2Y98vO7K/h5viyMJLJx37AUuUOEn5rjp6WDh3eBKHurnoEBiTX4GElOe70PPlLmyvBwgOt0gAf"
|
||||
"AK8wi/FDaDmhrw/i1xm00esQ8kXEDxiFUL2Ddh0gRkf+i8gHu7EnkkZDDg9Ee3yVLo+lE3u9jwyN+Wx"
|
||||
"9/I0CoK/dxjLG7wvKqk6KVogAmji0lQSvA539iuY0I4+d3TgmzpAcLBFAmA01llw07GS2QOa4Gfs51v"
|
||||
"2iwXsls+QIbrSTaym1zYXYriyNUGE8EFAoog+W7BaQVcX3d7uRtdNeRR1dVEYg5ni1/xZSRq/lYSIsK"
|
||||
"U6GbHz2kwFT+YwECiLc8k9LQ4AS4EPQNwMarptC1xvT843gMeplgB3YfIj9sov0LTpZH/lFlo7oCBU+"
|
||||
"EKgBKhfH8SbJJz3cf0WELJ29aP9be2d1eoRSsXPuFcVU6Ias9XgTvbJiLHFTe8yFUaqFiNQ0FJtgPsB"
|
||||
"RY9gHlhoOcvEoFrOEjdRpv5Cd93Axz5d4+IJsqJHD/KASiHANgeEUlCp6DpsJ4UaURGjIFVJ3E/m0Gd"
|
||||
"GNt85gaCMCjGFP/Im800dXWkNpPAEgkQS1Lfkq9/zSJgDtNWLHg9ufiitkPSOiaeTTKIhZr+HjqKAYv"
|
||||
"XTGN+5kgzxfxxVW+ijJZPAdo6I6jFKZp93iKLDaLNmcbEQLITa+kBbKwig9I4O+G/MgGGJVBjCPnNYw"
|
||||
"EEfe5ZXoS2qQH+9FFUl4x68qC5mBOczlNPoRwJuzY9JfcPFOjoJuNjJPrmElfyPzwKuZlixaprGgbKB"
|
||||
"5FZE6C6XgKMmBefuIHGXz/ngTKz0r5tbFAAA3gHtGpCRLuB0+/U4XfTVpMvz2MFWMrTNJJs3vbJTlJa"
|
||||
"h3XGHJQEhKFSKzIALGOYOKstWsOko1rk6qdQ2WjrmtT6T9rIX3UQvutGJTNWJTC2NFBJJUAKBDz8VVI"
|
||||
"rDlMj9HBJb2ckGtigPNYHQZTndkPTAoJCj5NMl4Nnel8XWGdlk+hUFm2vouaSSqldL8a6uJjcOz4WtP"
|
||||
"OfRUmgW8G8QHzJAADzChVHfeYw8A+AfZGiv0V+MI1sD+N3vLH1805AgQ2YLgRTWul/7r9VLuKlfgWqm"
|
||||
"EvpRwpWUcCc1/ALFFBQ/Zq/9eeT3Q1/1ucdJpxNKCfsZMJfB2uVsMDeBWMnSsIe4mk5iMO3Mn5OijaC"
|
||||
"repAj2gIKzUsvRf/7v5A/vxS9x3pLA2ga+UohlLKqdYMbQfFiqvG0mosictERwC4U0LGelxAYlNIZHT"
|
||||
"DRqKELKXTFSy7J+ElAEd7WsiNdSeMA5XQ+Xo1kz6eTTie0BCwgV4xjv3qZwdzMhmBk7zqgEz3FU+xSk"
|
||||
"8gWP6VQ/RGrRChAd16A/s/PLOHfMQV95rPcISVPaAIlVVDgIiLCHP85UijhdLycQRIppAeXdwMvGyhm"
|
||||
"KZmouKAXdOMw15KGP6SPX31ySqup4UU7sh0+VlHP8adgdUlrORpgHPvVJ8BoOwNGBE3Z03Czhz/QWXx"
|
||||
"qFWKJj6nNzX7sJsQXr1hsnTYNo8SDlJJUzT40Mij8qzmAi1QOotjHUUpIohQFpNm3KyWLJLpSzun4aU"
|
||||
"+P4MwMTRb14mYAOfSljH/hxU/HGI8kGUcy3uNo4phEAj+nmq8o5BAmAkEqCWThZxUGVTH7IAis+r+qF"
|
||||
"qcBAjQfxBUhCJ8IooLBKoES8RZ7w5B/xyC0nhmoHpeiCtpBUhJi8mSUYTBL+cVtZuhEuRZBp5CRavYr"
|
||||
"dE5Jju2oRZMynicZ6eCvp1PCJDpwoodNaiGawwCeZDvK0fUTWI2yf9dUdtwJO8ZzgSsi1NsboJLYpv0"
|
||||
"nQvgPno22dyOqqBi1Efjr47D4BWsM0i8GmPG0pLIF7QO89svHsZ+zqZPO2BgRxA54G6SEQIYsG5Y6i3"
|
||||
"XE/RtNKfwGAYBTD5Nr6KLNo0q+ZP//tN7wu3SE2o4amoc6+n2YPh2uGop+9W0BnqlBUbPDy+5Geeq+5"
|
||||
"JLqcH5xSj3X+2PncCz137WpPbkGzwi6jjOEQZW6DvgJML0DHDyI0HOgSqCOjIO1WxFTf4Lr7AtRN90W"
|
||||
"nMOZUVngnkaK4fqAc0iI0AKCdNo3+L0q2E3shpcjTzkAzOMbBTkqGM0YiOjTGfHwFtTi3jBnPaJfGVp"
|
||||
"7N77Jd1rzzdDEwGCMNSzWGzNiduLUz8Ho6tgIVSRVIaDSHTeKup5SALBAsLE2GrgC9ccdlqAPZSB67E"
|
||||
"XMWYt5ur3lcUMvhKlUXiD6F7bqF1HdaPs4brIhYonJaoQOEV5Sgi5gF6yMuHA6+5QDQPDJIh6tfwGs2"
|
||||
"YGcPhqu3w6fPoo41AuhFJmOFziA0WjtrCXQJWLvwN0oRYQq5C+N9ChLt+8pC4C1ayE3t/b/P95sPfz0"
|
||||
"T+BWgbjvPUR5KZLo42Ks0Gg57fFQ0iiDU4BOedh7+2PGB04k0lITtDUUGon4IxzZLqcsAAD2xyh+XeN"
|
||||
"DLP8MuXYtAEVhnnqot7++Eas7wqOCimWUNnjLjEi7xkVCRFQw7ZQGQCxav8FeC28HYEuYpx66ibKaZF"
|
||||
"z17B51rCGw0ohedKV0Ib+Bc/IOBw1LgUGNXa4sGjoY1+IAEGIkQWgihAjODs1eDJJZFzeF6vhIx0MZq"
|
||||
"VE6YSGJeBvIGHRhssIOBen4cJFIDUaEBiht3QB4KfjXUlsEwlacHpKosVVzCnoDLwV7KMHauCECfCm8"
|
||||
"SPkJc0YDlnGASjIAQXYwLhCph3a0bgDU0pwwdahIJBMdDRNFEkspaDBlqQFrHXoXdgFSUZhk8zrF6Mf"
|
||||
"ZD1YDNnOIr+kKKFLxkYKLcnwOu5Gr2wBg0b+i1PFhBN0QgORbulLaQD1ziznM7qDraYbxIweNZHwcoS"
|
||||
"MfUnbMRqEBrGIbi+kEKNz46GTnJRwOb5Nr0xdtAKh1/cJBUI2BH0V7u5Z8Dj70E8ycEVQx116HXUhyQ"
|
||||
"7Zt/HiQQC4GBpJtdGQ1+49B81TxNkWsIc/WYT664wI0SvDhj2oV9kJTM725nRmUjXWapgpzC/uisxMT"
|
||||
"PwbZ7OaH9Dgu5awo5jUSKSMZ8NMHHZBstwHREUmGHXoyMdll8+cHFNOZrLjTaC+FfEA6pp0QkoGfLFx"
|
||||
"IwIdkDypiwgmgE1DYlAxvbsfGVWIdFnVWGHtr8JGDzlEklbSngqP0JbHeO3cGUEARr5OMh2QAeqAF/y"
|
||||
"ulxj7ixyTN5omGhgs/lRhsQqMPB0iinQMHJYso5nOysGoC/HRB0Q6XvYUt7YBzpPDvp5G7gLZEDRAAZ"
|
||||
"U0UwzrjRaFxyF6VsyjiCjTS6Ri2/05YGOko24EVlFFK96Bm6YYXt531I4B9gMcWVx4ayr63AA7hpxwd"
|
||||
"8HIhRxlMeyRuNLx8w2E+IR1JKtauv4+sEDXvR7Eb6SD8X2CdBUAbAJzpOmqLjWupD4rDVFMa3GARJLC"
|
||||
"fXAyS8JBCd2oopgwfJeiU0t6e/9Z33fjJBfQQ004g2YZJID0uG5O0kM814ACSimCF8mEySeEwEiuDAF"
|
||||
"z46IwgwW4CJIBKajgQteYLrJPS/9ZcGN2MT+HlQ6wzBmopGS9dSKAUH4WIei5hVgQuE500jChNcRBJO"
|
||||
"aEF6X76YKAIL1IvwUsxRths1jDJQpJur/UBQB3G5Kij/yBsO6eouTDZaMYAqHJ4x025zfAUFEe/Nz35"
|
||||
"AAABiUlEQVTwUoHAjJppVk5vMpJ0dNwkhC0TGlCJj8OANyIeoDA4iEnnkJZe1sEGbtojqcCHHz8JGCT"
|
||||
"jQqIH+13VYHIAiT8uX4cAi9s0QHxKBKqDccGIM4VIwkMSbhLwY+BGpxrwIzAwcKHZwgv9XQ1evAiq0C"
|
||||
"hH2QEZFZMvafjojIGsg0cC6+yXIkyqo1LCnWgHcc5Fbn0AOA34zjEqeEM9x69C/lVYuwuh28surGNr6"
|
||||
"pOfH6kffWQCabijMv1N/FQgKMVPTdQOX11jfgbrRLBWTgMdATia+pVSncyyMB8JmCQiSUQFtdOJXfMn"
|
||||
"bRrAmcqD1vWpTQLoBexqykE0t3N0noCoLdpTlRQnsSFkS9AABlbCtqL1kKDVJ4TU0sWtzAISWAdptmk"
|
||||
"Am9phNX9QTcwD1cg8K8HqBLYO+FEbAMIpF3gc+AGNv1G1GPgSqzYgkKeTBmTar2ygg22TGHZgqgBYb/"
|
||||
"+mHGvzKrRS0R/yqsZq++6BRshpPMUDQcfzHFrIsqZHhWqasAtHc6b/D3cbSAuGcmWdAAAAAElFTkSuQmCC\" />";
|
||||
|
||||
const std::string HTTPConnection::itoopieFavicon =
|
||||
"data:image/png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv"
|
||||
"8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4wOGVynO"
|
||||
"EAAAIzSURBVDhPjZNdSFNhGMf3nm3n7OzMs+8JtfJGzdlgoPtoWBrkqc1OsLTMKEY3eZOQbbS6aBVYO"
|
||||
"oO8CKSLXEulQtZNahAM9Cq6lS533UUaeDEEKcN/79x7kbQT/eDhfPB7/u/7Poej08JqtXoEQbhoMpmG"
|
||||
"ZFn2stf/h8nEZ4aHue1SiWBlhSCV4n41NBifBINBjina8DyfzOUIVlcJtrYINjcJ3rw1oFAg4HnjHaZ"
|
||||
"p4/Ppv8zPH0G5XKZNPZibO4lKpYJ8vgOqqv+uKMq/d9Hfz/0sFr3w+/3IZt2YnbWhszOAxUUv0mkCs9"
|
||||
"ncyNT6hEL6dYBgY4Ngd5eger+zU7sODHA/mpubzUytj9FofLa0VGv4s9bWCCTJUGSaNvSzXT3stuHDM"
|
||||
"rc3xEqF4N2CERciURyyHfgqSZKPqfuxUMyC+OKcL4YHyl28nDFAPdqDZMcQ7tPnSfURUt0jMBgMH1nL"
|
||||
"fkRRDPvcLds3otfhbRTwasaE8b6He43VSrT3QW3tBT3iPdbyN3T7Ibsor988H8OxtiaMx2sB1aBbCRW"
|
||||
"R1hbQhbqYXh+6QkaJn8DZyzF09x6HeiaOTC6NK9cSsFqkb3aH3cLU+tCAx9l8FoXPBUy9n8LgyCCmS9"
|
||||
"MYez0Gm9P2iWna0GOcDp8KY2JhAsnbSQS6Ahh9OgrlklINeM40bWhAkBd4SLIEh8cBURLhOeiBIArVA"
|
||||
"U4yTRvJItk5PRehQVFaYfpbt9PBtTmdziaXyyUzjaHT/QZBQuKHAA0UxAAAAABJRU5ErkJggg==";
|
||||
|
||||
const char HTTP_COMMAND_TUNNELS[] = "tunnels";
|
||||
const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels";
|
||||
const char HTTP_COMMAND_TRANSPORTS[] = "transports";
|
||||
const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels";
|
||||
const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels";
|
||||
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
||||
const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations";
|
||||
const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination";
|
||||
const char HTTP_PARAM_BASE32_ADDRESS[] = "b32";
|
||||
const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions";
|
||||
const char HTTP_COMMAND_SAM_SESSION[] = "sam_session";
|
||||
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
||||
const char HTTP_COMMAND_I2P_TUNNELS[] = "i2p_tunnels";
|
||||
|
||||
namespace misc_strings
|
||||
{
|
||||
|
||||
const char name_value_separator[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
|
||||
} // namespace misc_strings
|
||||
|
||||
std::vector<boost::asio::const_buffer> HTTPConnection::reply::to_buffers(int status)
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
if (headers.size () > 0)
|
||||
{
|
||||
status_string = "HTTP/1.1 ";
|
||||
status_string += std::to_string (status);
|
||||
status_string += " ";
|
||||
switch (status)
|
||||
{
|
||||
case 105: status_string += "Name Not Resolved"; break;
|
||||
case 200: status_string += "OK"; break;
|
||||
case 400: status_string += "Bad Request"; break;
|
||||
case 404: status_string += "Not Found"; break;
|
||||
case 408: status_string += "Request Timeout"; break;
|
||||
case 500: status_string += "Internal Server Error"; break;
|
||||
case 502: status_string += "Bad Gateway"; break;
|
||||
case 503: status_string += "Not Implemented"; break;
|
||||
case 504: status_string += "Gateway Timeout"; break;
|
||||
default: status_string += "WTF";
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(status_string, status_string.size()));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
|
||||
for (std::size_t i = 0; i < headers.size(); ++i)
|
||||
{
|
||||
header& h = headers[i];
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
void HTTPConnection::Terminate ()
|
||||
{
|
||||
if (!m_Stream) return;
|
||||
m_Stream->Close ();
|
||||
m_Stream = nullptr;
|
||||
m_Socket->close ();
|
||||
}
|
||||
|
||||
void HTTPConnection::Receive ()
|
||||
{
|
||||
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE),
|
||||
std::bind(&HTTPConnection::HandleReceive, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
if (!m_Stream) // new request
|
||||
{
|
||||
m_Buffer[bytes_transferred] = 0;
|
||||
m_BufferLen = bytes_transferred;
|
||||
RunRequest();
|
||||
}
|
||||
else // follow-on
|
||||
m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred);
|
||||
Receive ();
|
||||
}
|
||||
else if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
|
||||
void HTTPConnection::RunRequest ()
|
||||
{
|
||||
auto address = ExtractAddress ();
|
||||
if (address.length () > 1 && address[1] != '?') // not just '/' or '/?'
|
||||
{
|
||||
std::string uri ("/"), b32;
|
||||
size_t pos = address.find ('/', 1);
|
||||
if (pos == std::string::npos)
|
||||
b32 = address.substr (1); // excluding leading '/' to end of line
|
||||
else
|
||||
{
|
||||
b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/'
|
||||
uri = address.substr (pos); // rest of line
|
||||
}
|
||||
|
||||
HandleDestinationRequest (b32, uri);
|
||||
}
|
||||
else
|
||||
HandleRequest (address);
|
||||
}
|
||||
|
||||
std::string HTTPConnection::ExtractAddress ()
|
||||
{
|
||||
char * get = strstr (m_Buffer, "GET");
|
||||
if (get)
|
||||
{
|
||||
char * http = strstr (get, "HTTP");
|
||||
if (http)
|
||||
return std::string (get + 4, http - get - 5);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void HTTPConnection::ExtractParams (const std::string& str, std::map<std::string, std::string>& params)
|
||||
{
|
||||
if (str[0] != '&') return;
|
||||
size_t pos = 1, end;
|
||||
do
|
||||
{
|
||||
end = str.find ('&', pos);
|
||||
std::string param = str.substr (pos, end - pos);
|
||||
LogPrint (eLogDebug, "HTTPServer: extracted parameters: ", param);
|
||||
size_t e = param.find ('=');
|
||||
if (e != std::string::npos)
|
||||
params[param.substr(0, e)] = param.substr(e+1);
|
||||
pos = end + 1;
|
||||
}
|
||||
while (end != std::string::npos);
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
boost::system::error_code ignored_ec;
|
||||
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleWrite (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode || (m_Stream && !m_Stream->IsOpen ()))
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else // data keeps coming
|
||||
AsyncStreamReceive ();
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleRequest (const std::string& address)
|
||||
{
|
||||
std::stringstream s;
|
||||
// Html5 head start
|
||||
s << "<!DOCTYPE html>\r\n<html lang=\"en\">"; // TODO: Add support for locale.
|
||||
s << "<head>\r\n<meta charset=\"utf-8\">\r\n"; // TODO: Find something to parse html/template system. This is horrible.
|
||||
s << "<link rel='shortcut icon' href='" + itoopieFavicon + "'>\r\n";
|
||||
s << "<title>Purple I2P " << VERSION " Webconsole</title>\r\n";
|
||||
s << "<style>\r\n";
|
||||
s << "body {font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456;}";
|
||||
s << "a {text-decoration: none; color: #894C84;}";
|
||||
s << "a:hover {color: #FAFAFA; background: #894C84;}";
|
||||
s << ".header {font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84;}";
|
||||
s << ".wrapper {margin: 0 auto; padding: 1em; max-width: 60em;}";
|
||||
s << ".left {float: left; position: absolute;}";
|
||||
s << ".right {font-size: 1em; margin-left: 13em; float: left; max-width: 46em; overflow: auto;}";
|
||||
s << ".established_tunnel {color: #56b734;}";
|
||||
s << ".expiring_tunnel {color: #d3ae3f;}";
|
||||
s << ".failed_tunnel {color: #d33f3f;}";
|
||||
s << ".another_tunnel {color: #434343;}";
|
||||
s << "caption {font-size: 1.5em; text-align: center; color: #894C84;}";
|
||||
s << "table {width: 100%; border-collapse: collapse; text-align: center;}";
|
||||
s << "</style>\r\n</head>\r\n<body>\r\n";
|
||||
s << "<div class=header><b>i2pd </b>webconsole</div>";
|
||||
s << "<div class=wrapper>";
|
||||
s << "<div class=left>\r\n";
|
||||
s << "<a href=/>Main page</a><br>\r\n<br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATIONS << ">Local destinations</a><br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_TUNNELS << ">Tunnels</a><br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_TRANSIT_TUNNELS << ">Transit tunnels</a><br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_TRANSPORTS << ">Transports</a><br>\r\n<br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_I2P_TUNNELS << ">I2P tunnels</a><br>\r\n";
|
||||
if (i2p::client::context.GetSAMBridge ())
|
||||
s << "<a href=/?" << HTTP_COMMAND_SAM_SESSIONS << ">SAM sessions</a><br>\r\n<br>\r\n";
|
||||
if (i2p::context.AcceptsTunnels ())
|
||||
s << "<a href=/?" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a><br>\r\n<br>\r\n";
|
||||
else
|
||||
s << "<a href=/?" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a><br>\r\n<br>\r\n";
|
||||
s << "<a href=/?" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a><br>\r\n<br>\r\n";
|
||||
s << "</div><div class=right>";
|
||||
if (address.length () > 1)
|
||||
HandleCommand (address.substr (2), s);
|
||||
else
|
||||
FillContent (s);
|
||||
s << "</div></div>\r\n</body>\r\n</html>";
|
||||
SendReply (s.str ());
|
||||
}
|
||||
|
||||
void HTTPConnection::FillContent (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Uptime:</b> " << boost::posix_time::to_simple_string (
|
||||
boost::posix_time::time_duration (boost::posix_time::seconds (
|
||||
i2p::context.GetUptime ()))) << "<br>\r\n";
|
||||
s << "<b>Status:</b> ";
|
||||
switch (i2p::context.GetStatus ())
|
||||
{
|
||||
case eRouterStatusOK: s << "OK"; break;
|
||||
case eRouterStatusTesting: s << "Testing"; break;
|
||||
case eRouterStatusFirewalled: s << "Firewalled"; break;
|
||||
default: s << "Unknown";
|
||||
}
|
||||
s << "<br>\r\n";
|
||||
s << "<b>Tunnel creation success rate:</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
|
||||
s << "<b>Received:</b> " << i2p::transport::transports.GetTotalReceivedBytes ()/1000 << "K";
|
||||
s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)<br>\r\n";
|
||||
s << "<b>Sent:</b> " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K";
|
||||
s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)<br>\r\n";
|
||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n";
|
||||
s << "<b>Our external address:</b>" << "<br>\r\n" ;
|
||||
for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
||||
{
|
||||
switch (address.transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
if (address.host.is_v6 ())
|
||||
s << "NTCP6 ";
|
||||
else
|
||||
s << "NTCP ";
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
if (address.host.is_v6 ())
|
||||
s << "SSU6 ";
|
||||
else
|
||||
s << "SSU ";
|
||||
break;
|
||||
default:
|
||||
s << "Unknown ";
|
||||
}
|
||||
s << address.host.to_string() << ":" << address.port << "<br>\r\n";
|
||||
}
|
||||
s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
||||
|
||||
size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels();
|
||||
clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels();
|
||||
size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels();
|
||||
|
||||
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
||||
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s)
|
||||
{
|
||||
size_t paramsPos = command.find('&');
|
||||
std::string cmd = command.substr (0, paramsPos);
|
||||
if (cmd == HTTP_COMMAND_TRANSPORTS)
|
||||
ShowTransports (s);
|
||||
else if (cmd == HTTP_COMMAND_TUNNELS)
|
||||
ShowTunnels (s);
|
||||
else if (cmd == HTTP_COMMAND_TRANSIT_TUNNELS)
|
||||
ShowTransitTunnels (s);
|
||||
else if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS)
|
||||
StartAcceptingTunnels (s);
|
||||
else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS)
|
||||
StopAcceptingTunnels (s);
|
||||
else if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
|
||||
RunPeerTest (s);
|
||||
else if (cmd == HTTP_COMMAND_LOCAL_DESTINATIONS)
|
||||
ShowLocalDestinations (s);
|
||||
else if (cmd == HTTP_COMMAND_LOCAL_DESTINATION)
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (command.substr (paramsPos), params);
|
||||
auto b32 = params[HTTP_PARAM_BASE32_ADDRESS];
|
||||
ShowLocalDestination (b32, s);
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_SAM_SESSIONS)
|
||||
ShowSAMSessions (s);
|
||||
else if (cmd == HTTP_COMMAND_SAM_SESSION)
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (command.substr (paramsPos), params);
|
||||
auto id = params[HTTP_PARAM_SAM_SESSION_ID];
|
||||
ShowSAMSession (id, s);
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_I2P_TUNNELS)
|
||||
ShowI2PTunnels (s);
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowLocalDestinations (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Local Destinations:</b><br>\r\n<br>\r\n";
|
||||
for (auto& it: i2p::client::context.GetDestinations ())
|
||||
{
|
||||
auto ident = it.second->GetIdentHash ();;
|
||||
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
|
||||
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s)
|
||||
{
|
||||
s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (b32);
|
||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||
if (dest)
|
||||
{
|
||||
s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"1\" wrap=\"off\">";
|
||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||
s << "<b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i><br>\r\n";
|
||||
auto pool = dest->GetTunnelPool ();
|
||||
if (pool)
|
||||
{
|
||||
s << "<b>Tunnels:</b><br>\r\n";
|
||||
for (auto it: pool->GetOutboundTunnels ())
|
||||
{
|
||||
it->Print (s);
|
||||
auto state = it->GetState ();
|
||||
if (state == i2p::tunnel::eTunnelStateFailed)
|
||||
s << " " << "Failed";
|
||||
else if (state == i2p::tunnel::eTunnelStateExpiring)
|
||||
s << " " << "Exp";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
for (auto it: pool->GetInboundTunnels ())
|
||||
{
|
||||
it->Print (s);
|
||||
auto state = it->GetState ();
|
||||
if (state == i2p::tunnel::eTunnelStateFailed)
|
||||
s << " " << "Failed";
|
||||
else if (state == i2p::tunnel::eTunnelStateExpiring)
|
||||
s << " " << "Exp";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
s << "<b>Tags</b><br>Incoming: " << dest->GetNumIncomingTags () << "<br>Outgoing:<br>" << std::endl;
|
||||
for (auto it: dest->GetSessions ())
|
||||
{
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " ";
|
||||
s << it.second->GetNumOutgoingTags () << "<br>" << std::endl;
|
||||
}
|
||||
s << "<br>" << std::endl;
|
||||
// s << "<br>\r\n<b>Streams:</b><br>\r\n";
|
||||
// for (auto it: dest->GetStreamingDestination ()->GetStreams ())
|
||||
// {
|
||||
// s << it.first << "->" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << " ";
|
||||
// s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
// s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]";
|
||||
// s << "[buf:" << it.second->GetSendBufferSize () << "]";
|
||||
// s << "[RTT:" << it.second->GetRTT () << "]";
|
||||
// s << "[Window:" << it.second->GetWindowSize () << "]";
|
||||
// s << "[Status:" << (int)it.second->GetStatus () << "]";
|
||||
// s << "<br>\r\n"<< std::endl;
|
||||
// }
|
||||
s << "<br>\r\n<table><caption>Streams</caption><tr>";
|
||||
s << "<th>StreamID</th>";
|
||||
s << "<th>Destination</th>";
|
||||
s << "<th>Sent</th>";
|
||||
s << "<th>Received</th>";
|
||||
s << "<th>Out</th>";
|
||||
s << "<th>In</th>";
|
||||
s << "<th>Buf</th>";
|
||||
s << "<th>RTT</th>";
|
||||
s << "<th>Window</th>";
|
||||
s << "<th>Status</th>";
|
||||
s << "</tr>";
|
||||
|
||||
for (auto it: dest->GetStreamingDestination ()->GetStreams ())
|
||||
{
|
||||
s << "<tr>";
|
||||
s << "<td>" << it.first << "</td>";
|
||||
s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << "</td>";
|
||||
s << "<td>" << it.second->GetNumSentBytes () << "</td>";
|
||||
s << "<td>" << it.second->GetNumReceivedBytes () << "</td>";
|
||||
s << "<td>" << it.second->GetSendQueueSize () << "</td>";
|
||||
s << "<td>" << it.second->GetReceiveQueueSize () << "</td>";
|
||||
s << "<td>" << it.second->GetSendBufferSize () << "</td>";
|
||||
s << "<td>" << it.second->GetRTT () << "</td>";
|
||||
s << "<td>" << it.second->GetWindowSize () << "</td>";
|
||||
s << "<td>" << (int)it.second->GetStatus () << "</td>";
|
||||
s << "</tr><br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Tunnels:</b><br>\r\n<br>\r\n";
|
||||
s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n";
|
||||
for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ())
|
||||
{
|
||||
it->Print (s);
|
||||
auto state = it->GetState ();
|
||||
if (state == i2p::tunnel::eTunnelStateFailed)
|
||||
s << "<span class=failed_tunnel> " << "Failed</span>";
|
||||
else if (state == i2p::tunnel::eTunnelStateExpiring)
|
||||
s << "<span class=expiring_tunnel> " << "Exp</span>";
|
||||
s << " " << (int)it->GetNumSentBytes () << "<br>\r\n";
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ())
|
||||
{
|
||||
it->Print (s);
|
||||
auto state = it->GetState ();
|
||||
if (state == i2p::tunnel::eTunnelStateFailed)
|
||||
s << "<span class=failed_tunnel> " << "Failed</span>";
|
||||
else if (state == i2p::tunnel::eTunnelStateExpiring)
|
||||
s << "<span class=expiring_tunnel> " << "Exp</span>";
|
||||
s << " " << (int)it->GetNumReceivedBytes () << "<br>\r\n";
|
||||
s << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowTransitTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
||||
for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||
{
|
||||
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
||||
s << it->GetTunnelID () << " ⇒ ";
|
||||
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
||||
s << " ⇒ " << it->GetTunnelID ();
|
||||
else
|
||||
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
||||
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowTransports (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Transports:</b><br>\r\n<br>\r\n";
|
||||
auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
|
||||
if (ntcpServer)
|
||||
{
|
||||
s << "<b>NTCP</b><br>\r\n";
|
||||
for (auto it: ntcpServer->GetNTCPSessions ())
|
||||
{
|
||||
if (it.second && it.second->IsEstablished ())
|
||||
{
|
||||
// incoming connection doesn't have remote RI
|
||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
|
||||
if (!it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto ssuServer = i2p::transport::transports.GetSSUServer ();
|
||||
if (ssuServer)
|
||||
{
|
||||
s << "<br>\r\n<b>SSU</b><br>\r\n";
|
||||
for (auto it: ssuServer->GetSessions ())
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
if (!it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
s << "<br>\r\n<b>SSU6</b><br>\r\n";
|
||||
for (auto it: ssuServer->GetSessionsV6 ())
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
if (!it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowSAMSessions (std::stringstream& s)
|
||||
{
|
||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
||||
auto sam = i2p::client::context.GetSAMBridge ();
|
||||
if (sam)
|
||||
{
|
||||
for (auto& it: sam->GetSessions ())
|
||||
{
|
||||
s << "<a href=/?" << HTTP_COMMAND_SAM_SESSION;
|
||||
s << "&" << HTTP_PARAM_SAM_SESSION_ID << "=" << it.first << ">";
|
||||
s << it.first << "</a><br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowSAMSession (const std::string& id, std::stringstream& s)
|
||||
{
|
||||
s << "<b>SAM Session:</b><br>\r\n<br>\r\n";
|
||||
auto sam = i2p::client::context.GetSAMBridge ();
|
||||
if (sam)
|
||||
{
|
||||
auto session = sam->FindSession (id);
|
||||
if (session)
|
||||
{
|
||||
auto& ident = session->localDestination->GetIdentHash();
|
||||
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
|
||||
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
|
||||
s << "<b>Streams:</b><br>\r\n";
|
||||
for (auto it: session->sockets)
|
||||
{
|
||||
switch (it->GetSocketType ())
|
||||
{
|
||||
case i2p::client::eSAMSocketTypeSession:
|
||||
s << "session";
|
||||
break;
|
||||
case i2p::client::eSAMSocketTypeStream:
|
||||
s << "stream";
|
||||
break;
|
||||
case i2p::client::eSAMSocketTypeAcceptor:
|
||||
s << "acceptor";
|
||||
break;
|
||||
default:
|
||||
s << "unknown";
|
||||
}
|
||||
s << " [" << it->GetSocket ().remote_endpoint() << "]";
|
||||
s << "<br>\r\n" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::ShowI2PTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
|
||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||
{
|
||||
s << it.second->GetName () << " ⇐ ";
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
|
||||
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</a><br>\r\n"<< std::endl;
|
||||
}
|
||||
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
|
||||
for (auto& it: i2p::client::context.GetServerTunnels ())
|
||||
{
|
||||
s << it.second->GetName () << " ⇒ ";
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
|
||||
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << ":" << it.second->GetLocalPort ();
|
||||
s << "</a><br>\r\n"<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::StopAcceptingTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Stop Accepting Tunnels:</b><br>\r\n<br>\r\n";
|
||||
i2p::context.SetAcceptsTunnels (false);
|
||||
s << "Accepting tunnels stopped" << std::endl;
|
||||
}
|
||||
|
||||
void HTTPConnection::StartAcceptingTunnels (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Start Accepting Tunnels:</b><br>\r\n<br>\r\n";
|
||||
i2p::context.SetAcceptsTunnels (true);
|
||||
s << "Accepting tunnels started" << std::endl;
|
||||
}
|
||||
|
||||
void HTTPConnection::RunPeerTest (std::stringstream& s)
|
||||
{
|
||||
s << "<b>Run Peer Test:</b><br>\r\n<br>\r\n";
|
||||
i2p::transport::transports.PeerTest ();
|
||||
s << "Peer test is running" << std::endl;
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
|
||||
{
|
||||
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n\r\n";
|
||||
LogPrint(eLogInfo, "HTTPServer: client request: ", request);
|
||||
SendToAddress (address, 80, request.c_str (), request.size ());
|
||||
}
|
||||
|
||||
void HTTPConnection::SendToAddress (const std::string& address, int port, const char * buf, size_t len)
|
||||
{
|
||||
i2p::data::IdentHash destination;
|
||||
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
|
||||
{
|
||||
LogPrint (eLogWarning, "HTTPServer: Unknown address ", address);
|
||||
SendReply ("<html>" + itoopieImage + "<br>\r\nUnknown address " + address + "</html>", 404);
|
||||
return;
|
||||
}
|
||||
|
||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
|
||||
if (leaseSet && !leaseSet->IsExpired ())
|
||||
SendToDestination (leaseSet, port, buf, len);
|
||||
else
|
||||
{
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination);
|
||||
m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT));
|
||||
m_Timer.async_wait (std::bind (&HTTPConnection::HandleDestinationRequestTimeout,
|
||||
shared_from_this (), std::placeholders::_1, destination, port, m_Buffer, m_BufferLen));
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
||||
i2p::data::IdentHash destination, int port, const char * buf, size_t len)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
|
||||
if (leaseSet && !leaseSet->IsExpired ())
|
||||
SendToDestination (leaseSet, port, buf, len);
|
||||
else
|
||||
// still no LeaseSet
|
||||
SendReply (leaseSet ? "<html>" + itoopieImage + "<br>\r\nLeases expired</html>" : "<html>" + itoopieImage + "LeaseSet not found</html>", 504);
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::SendToDestination (std::shared_ptr<const i2p::data::LeaseSet> remote, int port, const char * buf, size_t len)
|
||||
{
|
||||
if (!m_Stream)
|
||||
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (remote, port);
|
||||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Send ((uint8_t *)buf, len);
|
||||
AsyncStreamReceive ();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::AsyncStreamReceive ()
|
||||
{
|
||||
if (m_Stream)
|
||||
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192),
|
||||
std::bind (&HTTPConnection::HandleStreamReceive, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
45); // 45 seconds timeout
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
|
||||
std::bind (&HTTPConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ecode == boost::asio::error::timed_out)
|
||||
SendReply ("<html>" + itoopieImage + "<br>\r\nNot responding</html>", 504);
|
||||
else if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::SendReply (const std::string& content, int status)
|
||||
{
|
||||
m_Reply.content = content;
|
||||
m_Reply.headers.resize(3);
|
||||
// we need the date header to be complaint with http 1.1
|
||||
std::time_t time_now = std::time(nullptr);
|
||||
char time_buff[128];
|
||||
if (std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)))
|
||||
{
|
||||
m_Reply.headers[0].name = "Date";
|
||||
m_Reply.headers[0].value = std::string(time_buff);
|
||||
m_Reply.headers[1].name = "Content-Length";
|
||||
m_Reply.headers[1].value = boost::lexical_cast<std::string>(m_Reply.content.size());
|
||||
m_Reply.headers[2].name = "Content-Type";
|
||||
m_Reply.headers[2].value = "text/html";
|
||||
}
|
||||
|
||||
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
|
||||
std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
HTTPServer::HTTPServer (const std::string& address, int port):
|
||||
m_Thread (nullptr), m_Work (m_Service),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port))
|
||||
{
|
||||
}
|
||||
|
||||
HTTPServer::~HTTPServer ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void HTTPServer::Start ()
|
||||
{
|
||||
m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this)));
|
||||
m_Acceptor.listen ();
|
||||
Accept ();
|
||||
}
|
||||
|
||||
void HTTPServer::Stop ()
|
||||
{
|
||||
m_Acceptor.close();
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::Run ()
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
|
||||
void HTTPServer::Accept ()
|
||||
{
|
||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
|
||||
m_Acceptor.async_accept (*newSocket, boost::bind (&HTTPServer::HandleAccept, this,
|
||||
boost::asio::placeholders::error, newSocket));
|
||||
}
|
||||
|
||||
void HTTPServer::HandleAccept(const boost::system::error_code& ecode,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
CreateConnection(newSocket);
|
||||
Accept ();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
|
||||
{
|
||||
auto conn = std::make_shared<HTTPConnection> (newSocket);
|
||||
conn->Receive ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
138
HTTPServer.h
@@ -1,138 +0,0 @@
|
||||
#ifndef HTTP_SERVER_H__
|
||||
#define HTTP_SERVER_H__
|
||||
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include "LeaseSet.h"
|
||||
#include "Streaming.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||
{
|
||||
protected:
|
||||
|
||||
struct header
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct request
|
||||
{
|
||||
std::string method;
|
||||
std::string uri;
|
||||
std::string host;
|
||||
int port;
|
||||
int http_version_major;
|
||||
int http_version_minor;
|
||||
std::vector<header> headers;
|
||||
};
|
||||
|
||||
struct reply
|
||||
{
|
||||
std::vector<header> headers;
|
||||
std::string status_string, content;
|
||||
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||
m_Socket (socket), m_Timer (socket->get_io_service ()),
|
||||
m_Stream (nullptr), m_BufferLen (0) {};
|
||||
void Receive ();
|
||||
|
||||
private:
|
||||
|
||||
void Terminate ();
|
||||
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void AsyncStreamReceive ();
|
||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleWriteReply(const boost::system::error_code& ecode);
|
||||
void HandleWrite (const boost::system::error_code& ecode);
|
||||
void SendReply (const std::string& content, int status = 200);
|
||||
|
||||
void HandleRequest (const std::string& address);
|
||||
void HandleCommand (const std::string& command, std::stringstream& s);
|
||||
void ShowTransports (std::stringstream& s);
|
||||
void ShowTunnels (std::stringstream& s);
|
||||
void ShowTransitTunnels (std::stringstream& s);
|
||||
void ShowLocalDestinations (std::stringstream& s);
|
||||
void ShowLocalDestination (const std::string& b32, std::stringstream& s);
|
||||
void ShowSAMSessions (std::stringstream& s);
|
||||
void ShowSAMSession (const std::string& id, std::stringstream& s);
|
||||
void ShowI2PTunnels (std::stringstream& s);
|
||||
void StartAcceptingTunnels (std::stringstream& s);
|
||||
void StopAcceptingTunnels (std::stringstream& s);
|
||||
void RunPeerTest (std::stringstream& s);
|
||||
void FillContent (std::stringstream& s);
|
||||
std::string ExtractAddress ();
|
||||
void ExtractParams (const std::string& str, std::map<std::string, std::string>& params);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
||||
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
|
||||
size_t m_BufferLen;
|
||||
request m_Request;
|
||||
reply m_Reply;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void RunRequest ();
|
||||
void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
||||
void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
|
||||
void HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
||||
i2p::data::IdentHash destination, int port, const char * buf, size_t len);
|
||||
void SendToDestination (std::shared_ptr<const i2p::data::LeaseSet> remote, int port, const char * buf, size_t len);
|
||||
|
||||
public:
|
||||
|
||||
static const std::string itoopieImage;
|
||||
static const std::string itoopieFavicon;
|
||||
};
|
||||
|
||||
class HTTPServer
|
||||
{
|
||||
public:
|
||||
|
||||
HTTPServer (const std::string& address, int port);
|
||||
virtual ~HTTPServer ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
private:
|
||||
|
||||
void Run ();
|
||||
void Accept ();
|
||||
void HandleAccept(const boost::system::error_code& ecode,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
|
||||
protected:
|
||||
virtual void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
211
I2PService.cpp
@@ -1,211 +0,0 @@
|
||||
#include "Destination.h"
|
||||
#include "Identity.h"
|
||||
#include "ClientContext.h"
|
||||
#include "I2PService.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
static const i2p::data::SigningKeyType I2P_SERVICE_DEFAULT_KEY_TYPE = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
||||
|
||||
I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
|
||||
m_LocalDestination (localDestination ? localDestination :
|
||||
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE))
|
||||
{
|
||||
}
|
||||
|
||||
I2PService::I2PService (i2p::data::SigningKeyType kt):
|
||||
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt))
|
||||
{
|
||||
}
|
||||
|
||||
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
||||
assert(streamRequestComplete);
|
||||
i2p::data::IdentHash identHash;
|
||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash))
|
||||
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PService: Remote destination ", dest, " not found");
|
||||
streamRequestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) {}
|
||||
|
||||
TCPIPPipe::~TCPIPPipe()
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
|
||||
void TCPIPPipe::Start()
|
||||
{
|
||||
AsyncReceiveUpstream();
|
||||
AsyncReceiveDownstream();
|
||||
}
|
||||
|
||||
void TCPIPPipe::Terminate()
|
||||
{
|
||||
if(Kill()) return;
|
||||
Done(shared_from_this());
|
||||
if (m_up) {
|
||||
if (m_up->is_open()) {
|
||||
m_up->close();
|
||||
}
|
||||
m_up = nullptr;
|
||||
}
|
||||
if (m_down) {
|
||||
if (m_down->is_open()) {
|
||||
m_down->close();
|
||||
}
|
||||
m_down = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::AsyncReceiveUpstream()
|
||||
{
|
||||
if (m_up) {
|
||||
m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, TCP_IP_PIPE_BUFFER_SIZE),
|
||||
std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
} else {
|
||||
LogPrint(eLogError, "TCPIPPipe: no upstream socket for read");
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::AsyncReceiveDownstream()
|
||||
{
|
||||
if (m_down) {
|
||||
m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, TCP_IP_PIPE_BUFFER_SIZE),
|
||||
std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
} else {
|
||||
LogPrint(eLogError, "TCPIPPipe: no downstream socket for read");
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::UpstreamWrite(const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_up) {
|
||||
LogPrint(eLogDebug, "TCPIPPipe: write upstream ", (int)len);
|
||||
boost::asio::async_write(*m_up, boost::asio::buffer(buf, len),
|
||||
boost::asio::transfer_all(),
|
||||
std::bind(&TCPIPPipe::HandleUpstreamWrite,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)
|
||||
);
|
||||
} else {
|
||||
LogPrint(eLogError, "tcpip pipe upstream socket null");
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::DownstreamWrite(const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_down) {
|
||||
LogPrint(eLogDebug, "TCPIPPipe: write downstream ", (int)len);
|
||||
boost::asio::async_write(*m_down, boost::asio::buffer(buf, len),
|
||||
boost::asio::transfer_all(),
|
||||
std::bind(&TCPIPPipe::HandleDownstreamWrite,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)
|
||||
);
|
||||
} else {
|
||||
LogPrint(eLogError, "tcpip pipe downstream socket null");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
|
||||
{
|
||||
LogPrint(eLogDebug, "TCPIPPipe downstream got ", (int) bytes_transfered);
|
||||
if (ecode) {
|
||||
LogPrint(eLogError, "TCPIPPipe Downstream read error:" , ecode.message());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate();
|
||||
} else {
|
||||
if (bytes_transfered > 0 ) {
|
||||
memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered);
|
||||
UpstreamWrite(m_upstream_buf, bytes_transfered);
|
||||
}
|
||||
AsyncReceiveDownstream();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) {
|
||||
if (ecode) {
|
||||
LogPrint(eLogError, "TCPIPPipe Downstream write error:" , ecode.message());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
|
||||
if (ecode) {
|
||||
LogPrint(eLogError, "TCPIPPipe Upstream write error:" , ecode.message());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
|
||||
{
|
||||
LogPrint(eLogDebug, "TCPIPPipe upstream got ", (int) bytes_transfered);
|
||||
if (ecode) {
|
||||
LogPrint(eLogError, "TCPIPPipe Upstream read error:" , ecode.message());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate();
|
||||
} else {
|
||||
if (bytes_transfered > 0 ) {
|
||||
memcpy(m_upstream_buf, m_upstream_to_down_buf, bytes_transfered);
|
||||
DownstreamWrite(m_upstream_buf, bytes_transfered);
|
||||
}
|
||||
AsyncReceiveUpstream();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPIPAcceptor::Start ()
|
||||
{
|
||||
m_Acceptor.listen ();
|
||||
Accept ();
|
||||
}
|
||||
|
||||
void TCPIPAcceptor::Stop ()
|
||||
{
|
||||
m_Acceptor.close();
|
||||
m_Timer.cancel ();
|
||||
ClearHandlers();
|
||||
}
|
||||
|
||||
void TCPIPAcceptor::Accept ()
|
||||
{
|
||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
|
||||
m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
|
||||
std::placeholders::_1, newSocket));
|
||||
}
|
||||
|
||||
void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted");
|
||||
auto handler = CreateHandler(socket);
|
||||
if (handler)
|
||||
{
|
||||
AddHandler(handler);
|
||||
handler->Handle();
|
||||
}
|
||||
else
|
||||
socket->close();
|
||||
Accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
503
I2PTunnel.cpp
@@ -1,503 +0,0 @@
|
||||
#include <cassert>
|
||||
#include "Base.h"
|
||||
#include "Log.h"
|
||||
#include "Destination.h"
|
||||
#include "ClientContext.h"
|
||||
#include "I2PTunnel.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
|
||||
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
|
||||
m_IsQuiet (true)
|
||||
{
|
||||
m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port);
|
||||
}
|
||||
|
||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
|
||||
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
||||
m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true)
|
||||
{
|
||||
}
|
||||
|
||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
|
||||
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
||||
m_RemoteEndpoint (target), m_IsQuiet (quiet)
|
||||
{
|
||||
}
|
||||
|
||||
I2PTunnelConnection::~I2PTunnelConnection ()
|
||||
{
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
|
||||
{
|
||||
if (m_Stream)
|
||||
{
|
||||
if (msg)
|
||||
m_Stream->Send (msg, len); // connect and send
|
||||
else
|
||||
m_Stream->Send (m_Buffer, 0); // connect
|
||||
}
|
||||
StreamReceive ();
|
||||
Receive ();
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::Connect ()
|
||||
{
|
||||
if (m_Socket)
|
||||
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::Terminate ()
|
||||
{
|
||||
if (Kill()) return;
|
||||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Close ();
|
||||
m_Stream.reset ();
|
||||
}
|
||||
m_Socket->close ();
|
||||
Done(shared_from_this ());
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::Receive ()
|
||||
{
|
||||
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
|
||||
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Stream)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Stream->AsyncSend (m_Buffer, bytes_transferred,
|
||||
[s](const boost::system::error_code& ecode)
|
||||
{
|
||||
if (!ecode)
|
||||
s->Receive ();
|
||||
else
|
||||
s->Terminate ();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: write error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
StreamReceive ();
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::StreamReceive ()
|
||||
{
|
||||
if (m_Stream)
|
||||
{
|
||||
if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew ||
|
||||
m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular
|
||||
{
|
||||
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
|
||||
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
I2P_TUNNEL_CONNECTION_MAX_IDLE);
|
||||
}
|
||||
else // closed by peer
|
||||
{
|
||||
// get remaning data
|
||||
auto len = m_Stream->ReadSome (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE);
|
||||
if (len > 0) // still some data
|
||||
Write (m_StreamBuffer, len);
|
||||
else // no more data
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: stream read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (bytes_transferred > 0)
|
||||
Write (m_StreamBuffer, bytes_transferred); // postpone termination
|
||||
else
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
Write (m_StreamBuffer, bytes_transferred);
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
|
||||
{
|
||||
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
|
||||
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: connect error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "I2PTunnel: connected");
|
||||
if (m_IsQuiet)
|
||||
StreamReceive ();
|
||||
else
|
||||
{
|
||||
// send destination first like received from I2P
|
||||
std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 ();
|
||||
dest += "\n";
|
||||
memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
|
||||
HandleStreamReceive (boost::system::error_code (), dest.size ());
|
||||
}
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
|
||||
I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
|
||||
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ())
|
||||
{
|
||||
}
|
||||
|
||||
void I2PTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_HeaderSent)
|
||||
I2PTunnelConnection::Write (buf, len);
|
||||
else
|
||||
{
|
||||
m_InHeader.clear ();
|
||||
m_InHeader.write ((const char *)buf, len);
|
||||
std::string line;
|
||||
bool endOfHeader = false;
|
||||
while (!endOfHeader)
|
||||
{
|
||||
std::getline(m_InHeader, line);
|
||||
if (!m_InHeader.fail ())
|
||||
{
|
||||
if (line == "\r") endOfHeader = true;
|
||||
else
|
||||
{
|
||||
if (line.find ("Host:") != std::string::npos)
|
||||
m_OutHeader << "Host: " << m_Host << "\r\n";
|
||||
else
|
||||
m_OutHeader << line << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// add X-I2P fields
|
||||
if (m_From)
|
||||
{
|
||||
m_OutHeader << X_I2P_DEST_B32 << ": " << context.GetAddressBook ().ToAddress(m_From->GetIdentHash ()) << "\r\n";
|
||||
m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n";
|
||||
m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n";
|
||||
}
|
||||
|
||||
if (endOfHeader)
|
||||
{
|
||||
m_OutHeader << "\r\n"; // end of header
|
||||
m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
|
||||
m_HeaderSent = true;
|
||||
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass):
|
||||
I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()),
|
||||
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
|
||||
{
|
||||
}
|
||||
|
||||
void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_NeedsWebIrc) {
|
||||
m_NeedsWebIrc = false;
|
||||
m_OutPacket.str ("");
|
||||
m_OutPacket << "WEBIRC " << this->m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n";
|
||||
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
|
||||
}
|
||||
|
||||
std::string line;
|
||||
m_OutPacket.str ("");
|
||||
m_InPacket.clear ();
|
||||
m_InPacket.write ((const char *)buf, len);
|
||||
|
||||
while (!m_InPacket.eof () && !m_InPacket.fail ())
|
||||
{
|
||||
std::getline (m_InPacket, line);
|
||||
if (line.length () == 0 && m_InPacket.eof ()) {
|
||||
m_InPacket.str ("");
|
||||
}
|
||||
auto pos = line.find ("USER");
|
||||
if (pos != std::string::npos && pos == 0)
|
||||
{
|
||||
pos = line.find (" ");
|
||||
pos++;
|
||||
pos = line.find (" ", pos);
|
||||
pos++;
|
||||
auto nextpos = line.find (" ", pos);
|
||||
m_OutPacket << line.substr (0, pos);
|
||||
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
|
||||
m_OutPacket << line.substr (nextpos) << '\n';
|
||||
} else {
|
||||
m_OutPacket << line << '\n';
|
||||
}
|
||||
}
|
||||
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
|
||||
}
|
||||
|
||||
|
||||
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
|
||||
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
|
||||
{
|
||||
public:
|
||||
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
|
||||
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||
I2PServiceHandler(parent), m_DestinationIdentHash(destination),
|
||||
m_DestinationPort (destinationPort), m_Socket(socket) {};
|
||||
void Handle();
|
||||
void Terminate();
|
||||
private:
|
||||
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
i2p::data::IdentHash m_DestinationIdentHash;
|
||||
int m_DestinationPort;
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||
};
|
||||
|
||||
void I2PClientTunnelHandler::Handle()
|
||||
{
|
||||
GetOwner()->GetLocalDestination ()->CreateStream (
|
||||
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
|
||||
m_DestinationIdentHash, m_DestinationPort);
|
||||
}
|
||||
|
||||
void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
if (Kill()) return;
|
||||
LogPrint (eLogDebug, "I2PTunnel: new connection");
|
||||
auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
|
||||
GetOwner()->AddHandler (connection);
|
||||
connection->I2PConnect ();
|
||||
Done(shared_from_this());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void I2PClientTunnelHandler::Terminate()
|
||||
{
|
||||
if (Kill()) return;
|
||||
if (m_Socket)
|
||||
{
|
||||
m_Socket->close();
|
||||
m_Socket = nullptr;
|
||||
}
|
||||
Done(shared_from_this());
|
||||
}
|
||||
|
||||
I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
|
||||
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
||||
TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
|
||||
m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
|
||||
{
|
||||
}
|
||||
|
||||
void I2PClientTunnel::Start ()
|
||||
{
|
||||
TCPIPAcceptor::Start ();
|
||||
GetIdentHash();
|
||||
}
|
||||
|
||||
void I2PClientTunnel::Stop ()
|
||||
{
|
||||
TCPIPAcceptor::Stop();
|
||||
auto *originalIdentHash = m_DestinationIdentHash;
|
||||
m_DestinationIdentHash = nullptr;
|
||||
delete originalIdentHash;
|
||||
}
|
||||
|
||||
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
|
||||
const i2p::data::IdentHash * I2PClientTunnel::GetIdentHash ()
|
||||
{
|
||||
if (!m_DestinationIdentHash)
|
||||
{
|
||||
i2p::data::IdentHash identHash;
|
||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
||||
else
|
||||
LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
|
||||
}
|
||||
return m_DestinationIdentHash;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
{
|
||||
const i2p::data::IdentHash *identHash = GetIdentHash();
|
||||
if (identHash)
|
||||
return std::make_shared<I2PClientTunnelHandler>(this, *identHash, m_DestinationPort, socket);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
|
||||
int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
|
||||
I2PService (localDestination), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
|
||||
{
|
||||
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip);
|
||||
}
|
||||
|
||||
void I2PServerTunnel::Start ()
|
||||
{
|
||||
m_Endpoint.port (m_Port);
|
||||
boost::system::error_code ec;
|
||||
auto addr = boost::asio::ip::address::from_string (m_Address, ec);
|
||||
if (!ec)
|
||||
{
|
||||
m_Endpoint.address (addr);
|
||||
Accept ();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
|
||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""),
|
||||
std::bind (&I2PServerTunnel::HandleResolve, this,
|
||||
std::placeholders::_1, std::placeholders::_2, resolver));
|
||||
}
|
||||
}
|
||||
|
||||
void I2PServerTunnel::Stop ()
|
||||
{
|
||||
ClearHandlers ();
|
||||
}
|
||||
|
||||
void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
auto addr = (*it).endpoint ().address ();
|
||||
LogPrint (eLogInfo, "I2PTunnel: server tunnel ", (*it).host_name (), " has been resolved to ", addr);
|
||||
m_Endpoint.address (addr);
|
||||
Accept ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ());
|
||||
}
|
||||
|
||||
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
|
||||
{
|
||||
m_AccessList = accessList;
|
||||
m_IsAccessList = true;
|
||||
}
|
||||
|
||||
void I2PServerTunnel::Accept ()
|
||||
{
|
||||
if (m_PortDestination)
|
||||
m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
|
||||
auto localDestination = GetLocalDestination ();
|
||||
if (localDestination)
|
||||
{
|
||||
if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet
|
||||
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PTunnel: Local destination not set for server tunnel");
|
||||
}
|
||||
|
||||
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
if (m_IsAccessList)
|
||||
{
|
||||
if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ()))
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PTunnel: Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
|
||||
stream->Close ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CreateI2PConnection (stream);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
|
||||
AddHandler (conn);
|
||||
conn->Connect ();
|
||||
}
|
||||
|
||||
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
|
||||
int port, std::shared_ptr<ClientDestination> localDestination,
|
||||
const std::string& host, int inport, bool gzip):
|
||||
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
|
||||
m_Host (host.length () > 0 ? host : address)
|
||||
{
|
||||
}
|
||||
|
||||
void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream,
|
||||
std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
|
||||
AddHandler (conn);
|
||||
conn->Connect ();
|
||||
}
|
||||
|
||||
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
|
||||
int port, std::shared_ptr<ClientDestination> localDestination,
|
||||
const std::string& webircpass, int inport, bool gzip):
|
||||
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
|
||||
m_WebircPass (webircpass)
|
||||
{
|
||||
}
|
||||
|
||||
void I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
auto conn = std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), this->m_WebircPass);
|
||||
AddHandler (conn);
|
||||
conn->Connect ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
208
I2PTunnel.h
@@ -1,208 +0,0 @@
|
||||
#ifndef I2PTUNNEL_H__
|
||||
#define I2PTUNNEL_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "Destination.h"
|
||||
#include "Streaming.h"
|
||||
#include "I2PService.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||
// for HTTP tunnels
|
||||
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
|
||||
const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
|
||||
const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
|
||||
|
||||
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
|
||||
{
|
||||
public:
|
||||
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
|
||||
~I2PTunnelConnection ();
|
||||
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
||||
void Connect ();
|
||||
|
||||
protected:
|
||||
|
||||
void Terminate ();
|
||||
|
||||
void Receive ();
|
||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
|
||||
void HandleWrite (const boost::system::error_code& ecode);
|
||||
|
||||
void StreamReceive ();
|
||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleConnect (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE];
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
||||
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
|
||||
bool m_IsQuiet; // don't send destination
|
||||
};
|
||||
|
||||
class I2PTunnelConnectionHTTP: public I2PTunnelConnection
|
||||
{
|
||||
public:
|
||||
|
||||
I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
|
||||
|
||||
protected:
|
||||
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_Host;
|
||||
std::stringstream m_InHeader, m_OutHeader;
|
||||
bool m_HeaderSent;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_From;
|
||||
};
|
||||
|
||||
class I2PTunnelConnectionIRC: public I2PTunnelConnection
|
||||
{
|
||||
public:
|
||||
|
||||
I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
|
||||
|
||||
protected:
|
||||
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_From;
|
||||
std::stringstream m_OutPacket, m_InPacket;
|
||||
bool m_NeedsWebIrc;
|
||||
std::string m_WebircPass;
|
||||
};
|
||||
|
||||
|
||||
class I2PClientTunnel: public TCPIPAcceptor
|
||||
{
|
||||
protected:
|
||||
|
||||
// Implements TCPIPAcceptor
|
||||
std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||
|
||||
public:
|
||||
|
||||
I2PClientTunnel (const std::string& name, const std::string& destination,
|
||||
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
||||
~I2PClientTunnel () {}
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
|
||||
private:
|
||||
|
||||
const i2p::data::IdentHash * GetIdentHash ();
|
||||
|
||||
private:
|
||||
|
||||
std::string m_Name, m_Destination;
|
||||
const i2p::data::IdentHash * m_DestinationIdentHash;
|
||||
int m_DestinationPort;
|
||||
};
|
||||
|
||||
class I2PServerTunnel: public I2PService
|
||||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnel (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
|
||||
|
||||
const std::string& GetAddress() const { return m_Address; }
|
||||
int GetPort () const { return m_Port; };
|
||||
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
|
||||
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
|
||||
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
|
||||
private:
|
||||
|
||||
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||
|
||||
void Accept ();
|
||||
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
virtual void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_Name, m_Address;
|
||||
int m_Port;
|
||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
||||
std::set<i2p::data::IdentHash> m_AccessList;
|
||||
bool m_IsAccessList;
|
||||
};
|
||||
|
||||
class I2PServerTunnelHTTP: public I2PServerTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, const std::string& host,
|
||||
int inport = 0, bool gzip = true);
|
||||
|
||||
private:
|
||||
|
||||
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_Host;
|
||||
};
|
||||
|
||||
class I2PServerTunnelIRC: public I2PServerTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass,
|
||||
int inport = 0, bool gzip = true);
|
||||
|
||||
private:
|
||||
|
||||
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_WebircPass;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
248
LeaseSet.cpp
@@ -1,248 +0,0 @@
|
||||
#include <string.h>
|
||||
#include "I2PEndian.h"
|
||||
#include "Crypto.h"
|
||||
#include "Log.h"
|
||||
#include "Timestamp.h"
|
||||
#include "NetDb.h"
|
||||
#include "TunnelPool.h"
|
||||
#include "LeaseSet.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
|
||||
LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
|
||||
m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0)
|
||||
{
|
||||
m_Buffer = new uint8_t[len];
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
ReadFromBuffer ();
|
||||
}
|
||||
|
||||
LeaseSet::LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool):
|
||||
m_IsValid (true), m_StoreLeases (true), m_ExpirationTime (0)
|
||||
{
|
||||
if (!pool) return;
|
||||
// header
|
||||
auto localDestination = pool->GetLocalDestination ();
|
||||
if (!localDestination)
|
||||
{
|
||||
m_Buffer = nullptr;
|
||||
m_BufferLen = 0;
|
||||
m_IsValid = false;
|
||||
LogPrint (eLogError, "LeaseSet: Destination for local LeaseSet doesn't exist");
|
||||
return;
|
||||
}
|
||||
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
|
||||
m_BufferLen = localDestination->GetIdentity ()->ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE);
|
||||
memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256);
|
||||
m_BufferLen += 256;
|
||||
auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen ();
|
||||
memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
|
||||
m_BufferLen += signingKeyLen;
|
||||
int numTunnels = pool->GetNumInboundTunnels () + 2; // 2 backup tunnels
|
||||
if (numTunnels > 16) numTunnels = 16; // 16 tunnels maximum
|
||||
auto tunnels = pool->GetInboundTunnels (numTunnels);
|
||||
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
|
||||
m_BufferLen++;
|
||||
// leases
|
||||
auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it: tunnels)
|
||||
{
|
||||
memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32);
|
||||
m_BufferLen += 32; // gateway id
|
||||
htobe32buf (m_Buffer + m_BufferLen, it->GetNextTunnelID ());
|
||||
m_BufferLen += 4; // tunnel id
|
||||
uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
||||
ts *= 1000; // in milliseconds
|
||||
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
|
||||
// make sure leaseset is newer than previous, but adding some time to expiration date
|
||||
ts += (currentTime - it->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
|
||||
htobe64buf (m_Buffer + m_BufferLen, ts);
|
||||
m_BufferLen += 8; // end date
|
||||
}
|
||||
// signature
|
||||
localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
|
||||
m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen ();
|
||||
LogPrint (eLogDebug, "LeaseSet: Local LeaseSet of ", tunnels.size (), " leases created");
|
||||
|
||||
ReadFromBuffer ();
|
||||
}
|
||||
|
||||
void LeaseSet::Update (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len > m_BufferLen)
|
||||
{
|
||||
auto oldBuffer = m_Buffer;
|
||||
m_Buffer = new uint8_t[len];
|
||||
delete[] oldBuffer;
|
||||
}
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
ReadFromBuffer (false);
|
||||
}
|
||||
|
||||
void LeaseSet::PopulateLeases ()
|
||||
{
|
||||
m_StoreLeases = true;
|
||||
ReadFromBuffer (false);
|
||||
}
|
||||
|
||||
void LeaseSet::ReadFromBuffer (bool readIdentity)
|
||||
{
|
||||
if (readIdentity || !m_Identity)
|
||||
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
if (size > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", m_BufferLen);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
memcpy (m_EncryptionKey, m_Buffer + size, 256);
|
||||
size += 256; // encryption key
|
||||
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
||||
uint8_t num = m_Buffer[size];
|
||||
size++; // num
|
||||
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
|
||||
if (!num || num > MAX_NUM_LEASES)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// reset existing leases
|
||||
if (m_StoreLeases)
|
||||
for (auto it: m_Leases)
|
||||
it->isUpdated = false;
|
||||
else
|
||||
m_Leases.clear ();
|
||||
|
||||
// process leases
|
||||
m_ExpirationTime = 0;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
const uint8_t * leases = m_Buffer + size;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Lease lease;
|
||||
lease.tunnelGateway = leases;
|
||||
leases += 32; // gateway
|
||||
lease.tunnelID = bufbe32toh (leases);
|
||||
leases += 4; // tunnel ID
|
||||
lease.endDate = bufbe64toh (leases);
|
||||
leases += 8; // end date
|
||||
if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
|
||||
{
|
||||
if (lease.endDate > m_ExpirationTime)
|
||||
m_ExpirationTime = lease.endDate;
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
||||
if (!ret.second) *(*ret.first) = lease; // update existing
|
||||
(*ret.first)->isUpdated = true;
|
||||
// check if lease's gateway is in our netDb
|
||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||
{
|
||||
// if not found request it
|
||||
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
|
||||
netdb.RequestDestination (lease.tunnelGateway);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
|
||||
}
|
||||
if (!m_ExpirationTime)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
|
||||
// delete old leases
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
for (auto it = m_Leases.begin (); it != m_Leases.end ();)
|
||||
{
|
||||
if (!(*it)->isUpdated)
|
||||
{
|
||||
(*it)->endDate = 0; // somebody might still hold it
|
||||
m_Leases.erase (it++);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// verify
|
||||
if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: verification failed");
|
||||
m_IsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
if (!m_Identity) return 0;
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
if (size > len) return 0;
|
||||
size += 256; // encryption key
|
||||
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
||||
if (size > len) return 0;
|
||||
uint8_t num = buf[size];
|
||||
size++; // num
|
||||
if (size + num*44 > len) return 0;
|
||||
uint64_t timestamp= 0 ;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
size += 36; // gateway (32) + tunnelId(4)
|
||||
auto endDate = bufbe64toh (buf + size);
|
||||
size += 8; // end date
|
||||
if (!timestamp || endDate < timestamp)
|
||||
timestamp = endDate;
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
std::vector<std::shared_ptr<const Lease> > leases;
|
||||
for (auto it: m_Leases)
|
||||
{
|
||||
auto endDate = it->endDate;
|
||||
if (withThreshold)
|
||||
endDate += LEASE_ENDDATE_THRESHOLD;
|
||||
else
|
||||
endDate -= LEASE_ENDDATE_THRESHOLD;
|
||||
if (ts < endDate)
|
||||
leases.push_back (it);
|
||||
}
|
||||
return leases;
|
||||
}
|
||||
|
||||
bool LeaseSet::HasExpiredLeases () const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it: m_Leases)
|
||||
if (ts >= it->endDate) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LeaseSet::IsExpired () const
|
||||
{
|
||||
if (IsEmpty ()) return true;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
return ts > m_ExpirationTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
LeaseSet.h
@@ -1,88 +0,0 @@
|
||||
#ifndef LEASE_SET_H__
|
||||
#define LEASE_SET_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
class TunnelPool;
|
||||
}
|
||||
|
||||
namespace data
|
||||
{
|
||||
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
|
||||
struct Lease
|
||||
{
|
||||
IdentHash tunnelGateway;
|
||||
uint32_t tunnelID;
|
||||
uint64_t endDate; // 0 means invalid
|
||||
bool isUpdated; // trasient
|
||||
};
|
||||
|
||||
struct LeaseCmp
|
||||
{
|
||||
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
|
||||
{
|
||||
if (l1->tunnelID != l2->tunnelID)
|
||||
return l1->tunnelID < l2->tunnelID;
|
||||
else
|
||||
return l1->tunnelGateway < l2->tunnelGateway;
|
||||
};
|
||||
};
|
||||
|
||||
const int MAX_LS_BUFFER_SIZE = 3072;
|
||||
const uint8_t MAX_NUM_LEASES = 16;
|
||||
class LeaseSet: public RoutingDestination
|
||||
{
|
||||
public:
|
||||
|
||||
LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true);
|
||||
LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool);
|
||||
~LeaseSet () { delete[] m_Buffer; };
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
void PopulateLeases (); // from buffer
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
bool IsValid () const { return m_IsValid; };
|
||||
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
|
||||
bool HasExpiredLeases () const;
|
||||
bool IsExpired () const;
|
||||
bool IsEmpty () const { return m_Leases.empty (); };
|
||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||
bool operator== (const LeaseSet& other) const
|
||||
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
||||
|
||||
// implements RoutingDestination
|
||||
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
|
||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
||||
bool IsDestination () const { return true; };
|
||||
|
||||
private:
|
||||
|
||||
void ReadFromBuffer (bool readIdentity = true);
|
||||
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time
|
||||
|
||||
private:
|
||||
|
||||
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
|
||||
std::set<std::shared_ptr<Lease>, LeaseCmp> m_Leases;
|
||||
uint64_t m_ExpirationTime; // in milliseconds
|
||||
std::shared_ptr<const IdentityEx> m_Identity;
|
||||
uint8_t m_EncryptionKey[256];
|
||||
uint8_t * m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
86
Log.cpp
@@ -1,86 +0,0 @@
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include "Log.h"
|
||||
|
||||
Log * g_Log = nullptr;
|
||||
|
||||
static const char * g_LogLevelStr[eNumLogLevels] =
|
||||
{
|
||||
"error", // eLogError
|
||||
"warn", // eLogWarning
|
||||
"info", // eLogInfo
|
||||
"debug" // eLogDebug
|
||||
};
|
||||
|
||||
void LogMsg::Process()
|
||||
{
|
||||
auto stream = log ? log->GetLogStream () : nullptr;
|
||||
auto& output = stream ? *stream : std::cout;
|
||||
if (log)
|
||||
output << log->GetTimestamp ();
|
||||
else
|
||||
output << boost::posix_time::second_clock::local_time().time_of_day ();
|
||||
output << "/" << g_LogLevelStr[level] << " - ";
|
||||
output << s.str();
|
||||
}
|
||||
|
||||
const std::string& Log::GetTimestamp ()
|
||||
{
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
|
||||
auto ts = std::chrono::monotonic_clock::now ();
|
||||
#else
|
||||
auto ts = std::chrono::steady_clock::now ();
|
||||
#endif
|
||||
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
|
||||
{
|
||||
m_LastTimestampUpdate = ts;
|
||||
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ());
|
||||
}
|
||||
return m_Timestamp;
|
||||
}
|
||||
|
||||
void Log::Flush ()
|
||||
{
|
||||
if (m_LogStream)
|
||||
m_LogStream->flush();
|
||||
}
|
||||
|
||||
void Log::SetLogFile (const std::string& fullFilePath, bool truncate)
|
||||
{
|
||||
m_FullFilePath = fullFilePath;
|
||||
auto mode = std::ofstream::out | std::ofstream::binary;
|
||||
mode |= truncate ? std::ofstream::trunc : std::ofstream::app;
|
||||
auto logFile = std::make_shared<std::ofstream> (fullFilePath, mode);
|
||||
if (logFile->is_open ())
|
||||
{
|
||||
SetLogStream (logFile);
|
||||
LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::ReopenLogFile ()
|
||||
{
|
||||
if (m_FullFilePath.length () > 0)
|
||||
{
|
||||
SetLogFile (m_FullFilePath, false); // don't truncate
|
||||
LogPrint(eLogInfo, "Log: file ", m_FullFilePath, " reopen");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Log::SetLogLevel (const std::string& level)
|
||||
{
|
||||
if (level == "error") { m_MinLevel = eLogError; }
|
||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||
else if (level == "info") { m_MinLevel = eLogInfo; }
|
||||
else if (level == "debug") { m_MinLevel = eLogDebug; }
|
||||
else {
|
||||
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "Log: min msg level set to ", level);
|
||||
}
|
||||
|
||||
void Log::SetLogStream (std::shared_ptr<std::ostream> logStream)
|
||||
{
|
||||
m_LogStream = logStream;
|
||||
}
|
||||
148
Log.h
@@ -1,148 +0,0 @@
|
||||
#ifndef LOG_H__
|
||||
#define LOG_H__
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include "Queue.h"
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
eLogError = 0,
|
||||
eLogWarning,
|
||||
eLogInfo,
|
||||
eLogDebug,
|
||||
eNumLogLevels
|
||||
};
|
||||
|
||||
class Log;
|
||||
struct LogMsg
|
||||
{
|
||||
std::stringstream s;
|
||||
Log * log;
|
||||
LogLevel level;
|
||||
|
||||
LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
|
||||
|
||||
void Process();
|
||||
};
|
||||
|
||||
class Log: public i2p::util::MsgQueue<LogMsg>
|
||||
{
|
||||
public:
|
||||
|
||||
Log () { SetOnEmpty (std::bind (&Log::Flush, this)); };
|
||||
~Log () {};
|
||||
|
||||
void SetLogFile (const std::string& fullFilePath, bool truncate = true);
|
||||
void ReopenLogFile ();
|
||||
void SetLogLevel (const std::string& level);
|
||||
void SetLogStream (std::shared_ptr<std::ostream> logStream);
|
||||
std::shared_ptr<std::ostream> GetLogStream () const { return m_LogStream; };
|
||||
const std::string& GetTimestamp ();
|
||||
LogLevel GetLogLevel () { return m_MinLevel; };
|
||||
const std::string& GetFullFilePath () const { return m_FullFilePath; };
|
||||
|
||||
private:
|
||||
|
||||
void Flush ();
|
||||
|
||||
private:
|
||||
|
||||
std::string m_FullFilePath; // empty if stream
|
||||
std::shared_ptr<std::ostream> m_LogStream;
|
||||
enum LogLevel m_MinLevel;
|
||||
std::string m_Timestamp;
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) // gcc 4.6
|
||||
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
|
||||
#else
|
||||
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern Log * g_Log;
|
||||
|
||||
inline void StartLog (const std::string& fullFilePath)
|
||||
{
|
||||
if (!g_Log)
|
||||
{
|
||||
auto log = new Log ();
|
||||
if (fullFilePath.length () > 0)
|
||||
log->SetLogFile (fullFilePath);
|
||||
g_Log = log;
|
||||
}
|
||||
}
|
||||
|
||||
inline void StartLog (std::shared_ptr<std::ostream> s)
|
||||
{
|
||||
if (!g_Log)
|
||||
{
|
||||
auto log = new Log ();
|
||||
if (s)
|
||||
log->SetLogStream (s);
|
||||
g_Log = log;
|
||||
}
|
||||
}
|
||||
|
||||
inline void StopLog ()
|
||||
{
|
||||
if (g_Log)
|
||||
{
|
||||
auto log = g_Log;
|
||||
g_Log = nullptr;
|
||||
log->Stop ();
|
||||
delete log;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetLogLevel (const std::string& level)
|
||||
{
|
||||
if (g_Log)
|
||||
g_Log->SetLogLevel(level);
|
||||
}
|
||||
|
||||
inline void ReopenLogFile ()
|
||||
{
|
||||
if (g_Log)
|
||||
g_Log->ReopenLogFile ();
|
||||
}
|
||||
|
||||
inline bool IsLogToFile ()
|
||||
{
|
||||
return g_Log ? !g_Log->GetFullFilePath ().empty () : false;
|
||||
}
|
||||
|
||||
template<typename TValue>
|
||||
void LogPrint (std::stringstream& s, TValue arg)
|
||||
{
|
||||
s << arg;
|
||||
}
|
||||
|
||||
template<typename TValue, typename... TArgs>
|
||||
void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
|
||||
{
|
||||
LogPrint (s, arg);
|
||||
LogPrint (s, args...);
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
void LogPrint (LogLevel level, TArgs... args)
|
||||
{
|
||||
if (g_Log && level > g_Log->GetLogLevel ())
|
||||
return;
|
||||
LogMsg * msg = new LogMsg (g_Log, level);
|
||||
LogPrint (msg->s, args...);
|
||||
msg->s << std::endl;
|
||||
if (g_Log) {
|
||||
g_Log->Put (msg);
|
||||
} else {
|
||||
msg->Process ();
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
228
Makefile
@@ -1,91 +1,137 @@
|
||||
UNAME := $(shell uname -s)
|
||||
SHLIB := libi2pd.so
|
||||
ARLIB := libi2pd.a
|
||||
SHLIB_CLIENT := libi2pdclient.so
|
||||
ARLIB_CLIENT := libi2pdclient.a
|
||||
I2PD := i2pd
|
||||
GREP := fgrep
|
||||
DEPS := obj/make.dep
|
||||
|
||||
include filelist.mk
|
||||
|
||||
USE_AESNI := yes
|
||||
USE_STATIC := no
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
DAEMON_SRC += DaemonLinux.cpp
|
||||
include Makefile.osx
|
||||
else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
|
||||
DAEMON_SRC += DaemonLinux.cpp
|
||||
include Makefile.bsd
|
||||
else ifeq ($(UNAME),Linux)
|
||||
DAEMON_SRC += DaemonLinux.cpp
|
||||
include Makefile.linux
|
||||
else # win32 mingw
|
||||
DAEMON_SRC += DaemonWin32.cpp Win32/Win32App.cpp
|
||||
include Makefile.mingw
|
||||
endif
|
||||
|
||||
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
||||
|
||||
mk_obj_dir:
|
||||
@mkdir -p obj
|
||||
@mkdir -p obj/Win32
|
||||
|
||||
api: mk_obj_dir $(SHLIB) $(ARLIB)
|
||||
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
## For example, when adding 'hardening flags' to the build
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FLAGS to work at build-time.
|
||||
|
||||
deps: mk_obj_dir
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
|
||||
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
|
||||
|
||||
obj/%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
|
||||
|
||||
# '-' is 'ignore if missing' on first run
|
||||
-include $(DEPS)
|
||||
|
||||
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
|
||||
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
|
||||
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS)
|
||||
|
||||
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||
ifneq ($(USE_STATIC),yes)
|
||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
||||
endif
|
||||
|
||||
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
||||
|
||||
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||
ar -r $@ $^
|
||||
|
||||
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||
ar -r $@ $^
|
||||
|
||||
clean:
|
||||
rm -rf obj
|
||||
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||
|
||||
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
|
||||
strip $^
|
||||
|
||||
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
|
||||
dist:
|
||||
git archive --format=tar.gz -9 --worktree-attributes \
|
||||
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
|
||||
|
||||
.PHONY: all
|
||||
.PHONY: clean
|
||||
.PHONY: deps
|
||||
.PHONY: dist
|
||||
.PHONY: api
|
||||
.PHONY: api_client
|
||||
.PHONY: mk_obj_dir
|
||||
SYS := $(shell $(CXX) -dumpmachine)
|
||||
SHLIB := libi2pd.so
|
||||
ARLIB := libi2pd.a
|
||||
SHLIB_CLIENT := libi2pdclient.so
|
||||
ARLIB_CLIENT := libi2pdclient.a
|
||||
I2PD := i2pd
|
||||
GREP := grep
|
||||
DEPS := obj/make.dep
|
||||
|
||||
LIB_SRC_DIR := libi2pd
|
||||
LIB_CLIENT_SRC_DIR := libi2pd_client
|
||||
DAEMON_SRC_DIR := daemon
|
||||
|
||||
include filelist.mk
|
||||
|
||||
USE_AESNI := yes
|
||||
USE_AVX := yes
|
||||
USE_STATIC := no
|
||||
USE_MESHNET := no
|
||||
USE_UPNP := no
|
||||
DEBUG := yes
|
||||
|
||||
ifeq ($(DEBUG),yes)
|
||||
CXX_DEBUG = -g
|
||||
else
|
||||
CXX_DEBUG = -Os
|
||||
LD_DEBUG = -s
|
||||
endif
|
||||
|
||||
ifeq ($(WEBSOCKETS),1)
|
||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
||||
endif
|
||||
|
||||
ifneq (, $(findstring darwin, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
ifeq ($(HOMEBREW),1)
|
||||
include Makefile.homebrew
|
||||
else
|
||||
include Makefile.osx
|
||||
endif
|
||||
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
include Makefile.linux
|
||||
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
include Makefile.bsd
|
||||
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
||||
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp
|
||||
include Makefile.mingw
|
||||
else # not supported
|
||||
$(error Not supported platform)
|
||||
endif
|
||||
|
||||
ifeq ($(USE_MESHNET),yes)
|
||||
NEEDED_CXXFLAGS += -DMESHNET
|
||||
endif
|
||||
|
||||
NEEDED_CXXFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR)
|
||||
|
||||
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
||||
|
||||
mk_obj_dir:
|
||||
@mkdir -p obj
|
||||
@mkdir -p obj/Win32
|
||||
@mkdir -p obj/$(LIB_SRC_DIR)
|
||||
@mkdir -p obj/$(LIB_CLIENT_SRC_DIR)
|
||||
@mkdir -p obj/$(DAEMON_SRC_DIR)
|
||||
|
||||
api: mk_obj_dir $(SHLIB) $(ARLIB)
|
||||
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
## For example, when adding 'hardening flags' to the build
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FLAGS to work at build-time.
|
||||
|
||||
deps: mk_obj_dir
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
|
||||
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
|
||||
|
||||
obj/%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
|
||||
|
||||
# '-' is 'ignore if missing' on first run
|
||||
-include $(DEPS)
|
||||
|
||||
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
|
||||
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||
ifneq ($(USE_STATIC),yes)
|
||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
||||
endif
|
||||
|
||||
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
||||
|
||||
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||
$(AR) -r $@ $^
|
||||
|
||||
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||
$(AR) -r $@ $^
|
||||
|
||||
clean:
|
||||
$(RM) -r obj
|
||||
$(RM) -r docs/generated
|
||||
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||
|
||||
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
|
||||
strip $^
|
||||
|
||||
LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl)
|
||||
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
dist:
|
||||
git archive --format=tar.gz -9 --worktree-attributes \
|
||||
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
|
||||
|
||||
last-dist:
|
||||
git archive --format=tar.gz -9 --worktree-attributes \
|
||||
--prefix=i2pd_$(LATEST_TAG)/ $(BRANCH) -o ../i2pd_$(LATEST_TAG).orig.tar.gz
|
||||
|
||||
doxygen:
|
||||
doxygen -s docs/Doxyfile
|
||||
|
||||
.PHONY: all
|
||||
.PHONY: clean
|
||||
.PHONY: deps
|
||||
.PHONY: doxygen
|
||||
.PHONY: dist
|
||||
.PHONY: last-dist
|
||||
.PHONY: api
|
||||
.PHONY: api_client
|
||||
.PHONY: mk_obj_dir
|
||||
.PHONY: install
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS = -O2
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
|
||||
## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
## For example, when adding 'hardening flags' to the build
|
||||
@@ -8,5 +8,5 @@ CXXFLAGS = -O2
|
||||
## custom FLAGS to work at build-time.
|
||||
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
|
||||
54
Makefile.homebrew
Normal file
@@ -0,0 +1,54 @@
|
||||
# root directory holding homebrew
|
||||
BREWROOT = /usr/local
|
||||
BOOSTROOT = ${BREWROOT}/opt/boost
|
||||
SSLROOT = ${BREWROOT}/opt/openssl@1.1
|
||||
UPNPROOT = ${BREWROOT}/opt/miniupnpc
|
||||
CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
|
||||
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
|
||||
LDFLAGS = ${LD_DEBUG}
|
||||
|
||||
ifndef TRAVIS
|
||||
CXX = clang++
|
||||
endif
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread
|
||||
else
|
||||
LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
INCFLAGS += -I${UPNPROOT}/include
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
|
||||
else
|
||||
LDFLAGS += -L${UPNPROOT}/lib
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
# OSX Notes
|
||||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -maes
|
||||
endif
|
||||
ifeq ($(USE_AVX),1)
|
||||
CXXFLAGS += -mavx
|
||||
endif
|
||||
|
||||
install: all
|
||||
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
|
||||
install -m 755 ${I2PD} ${PREFIX}/bin/
|
||||
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
||||
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
|
||||
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
|
||||
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
||||
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
||||
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
||||
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf
|
||||
@@ -1,13 +1,13 @@
|
||||
# set defaults instead redefine
|
||||
CXXFLAGS ?= -g -Wall
|
||||
INCFLAGS ?=
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
|
||||
LDFLAGS ?= ${LD_DEBUG}
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
## For example, when adding 'hardening flags' to the build
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FLAGS to work at build-time.
|
||||
## custom FDLAGS to work at build-time.
|
||||
|
||||
# detect proper flag for c++11 support by compilers
|
||||
CXXVER := $(shell $(CXX) -dumpversion)
|
||||
@@ -19,42 +19,61 @@ else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
||||
NEEDED_CXXFLAGS += -std=c++0x
|
||||
else ifeq ($(shell expr match ${CXXVER} "5\.[0-9]"),3) # gcc >= 5.0
|
||||
else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
LDLIBS = -latomic
|
||||
else ifeq ($(shell expr match ${CXXVER} "[7-8]"),1) # gcc 7 ubuntu or gcc 8 arch
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
LDLIBS = -latomic
|
||||
else # not supported
|
||||
$(error Compiler too old)
|
||||
$(error Compiler too old)
|
||||
endif
|
||||
|
||||
NEEDED_CXXFLAGS += -fPIC
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LIBDIR := /usr/lib
|
||||
LDLIBS = $(LIBDIR)/libboost_system.a
|
||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||
LDLIBS += $(LIBDIR)/libboost_regex.a
|
||||
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
||||
LDLIBS += $(LIBDIR)/libcrypto.a
|
||||
LDLIBS += $(LIBDIR)/libssl.a
|
||||
LDLIBS += $(LIBDIR)/libz.a
|
||||
LDLIBS += -lpthread -static-libstdc++ -static-libgcc
|
||||
USE_AESNI := no
|
||||
# NOTE: on glibc you will get this warning:
|
||||
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
||||
# the shared libraries from the glibc version used for linking
|
||||
LIBDIR := /usr/lib
|
||||
LDLIBS += $(LIBDIR)/libboost_system.a
|
||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
||||
LDLIBS += $(LIBDIR)/libssl.a
|
||||
LDLIBS += $(LIBDIR)/libcrypto.a
|
||||
LDLIBS += $(LIBDIR)/libz.a
|
||||
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl
|
||||
USE_AESNI := no
|
||||
else
|
||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
endif
|
||||
|
||||
# UPNP Support (miniupnpc 1.5 or 1.6)
|
||||
ifeq ($(USE_UPNP),1)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
# UPNP Support (miniupnpc 1.5 and higher)
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += $(LIBDIR)/libminiupnpc.a
|
||||
else
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(GREP) -c "64")
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
ifeq ($(IS_64),1)
|
||||
#check if AES-NI is supported by CPU
|
||||
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
|
||||
CPU_FLAGS = -maes -DAESNI
|
||||
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
||||
machine := $(shell uname -m)
|
||||
ifeq ($(machine), aarch64)
|
||||
CXXFLAGS += -DARM64AES
|
||||
else
|
||||
CPU_FLAGS += -maes
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),yes)
|
||||
#check if AVX supported by CPU
|
||||
ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0)
|
||||
CPU_FLAGS += -mavx
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1,38 +1,54 @@
|
||||
CXX = g++
|
||||
WINDRES = windres
|
||||
CXXFLAGS = -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
BOOST_SUFFIX = -mt
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
LDFLAGS = -mwindows -Wl,-rpath,/usr/local/lib \
|
||||
-L/usr/local/lib \
|
||||
-L/c/dev/openssl \
|
||||
-L/c/dev/boost/lib
|
||||
LDLIBS = \
|
||||
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
|
||||
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
|
||||
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \
|
||||
-Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \
|
||||
-Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \
|
||||
-Wl,-Bstatic -lssl \
|
||||
-Wl,-Bstatic -lcrypto \
|
||||
-Wl,-Bstatic -lz \
|
||||
-Wl,-Bstatic -lwsock32 \
|
||||
-Wl,-Bstatic -lws2_32 \
|
||||
-Wl,-Bstatic -lgdi32 \
|
||||
-Wl,-Bstatic -liphlpapi \
|
||||
-static-libgcc -static-libstdc++ \
|
||||
-Wl,-Bstatic -lstdc++ \
|
||||
-Wl,-Bstatic -lpthread
|
||||
DAEMON_RC += Win32/Resource.rc
|
||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||
|
||||
ifeq ($(USE_AESNI),1)
|
||||
CPU_FLAGS = -maes -DAESNI
|
||||
else
|
||||
CPU_FLAGS = -msse
|
||||
endif
|
||||
|
||||
obj/%.o : %.rc
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
USE_WIN32_APP=yes
|
||||
CXX = g++
|
||||
WINDRES = windres
|
||||
CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
BOOST_SUFFIX = -mt
|
||||
INCFLAGS = -Idaemon -I.
|
||||
LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++
|
||||
|
||||
# UPNP Support
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
|
||||
LDLIBS = -lminiupnpc
|
||||
endif
|
||||
|
||||
LDLIBS += \
|
||||
-lboost_system$(BOOST_SUFFIX) \
|
||||
-lboost_date_time$(BOOST_SUFFIX) \
|
||||
-lboost_filesystem$(BOOST_SUFFIX) \
|
||||
-lboost_program_options$(BOOST_SUFFIX) \
|
||||
-lssl \
|
||||
-lcrypto \
|
||||
-lz \
|
||||
-lwsock32 \
|
||||
-lws2_32 \
|
||||
-lgdi32 \
|
||||
-liphlpapi \
|
||||
-lstdc++ \
|
||||
-lpthread
|
||||
|
||||
ifeq ($(USE_WIN32_APP), yes)
|
||||
CXXFLAGS += -DWIN32_APP
|
||||
LDFLAGS += -mwindows
|
||||
DAEMON_RC += Win32/Resource.rc
|
||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||
endif
|
||||
|
||||
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
||||
ifeq ($(USE_AESNI),1)
|
||||
CPU_FLAGS += -maes
|
||||
else
|
||||
CPU_FLAGS += -msse
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),1)
|
||||
CPU_FLAGS += -mavx
|
||||
endif
|
||||
|
||||
ifeq ($(USE_ASLR),yes)
|
||||
LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols
|
||||
endif
|
||||
|
||||
obj/%.o : %.rc
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
43
Makefile.osx
@@ -1,25 +1,30 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
|
||||
#CXXFLAGS = -g -O2 -Wall -std=c++11
|
||||
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
||||
INCFLAGS = -I/usr/local/include
|
||||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
|
||||
ifeq ($(USE_UPNP),1)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||
else
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
endif
|
||||
|
||||
# OSX Notes
|
||||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -maes -DAESNI
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += /usr/local/lib/libminiupnpc.a
|
||||
else
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
# Disabled, since it will be the default make rule. I think its better
|
||||
# to define the default rule in Makefile and not Makefile.<ostype> - torkel
|
||||
#install: all
|
||||
# test -d ${PREFIX} || mkdir -p ${PREFIX}/
|
||||
# cp -r i2p ${PREFIX}/
|
||||
ifeq ($(USE_AESNI),1)
|
||||
CXXFLAGS += -maes
|
||||
else
|
||||
CXXFLAGS += -msse
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),1)
|
||||
CXXFLAGS += -mavx
|
||||
endif
|
||||
|
||||
970
NTCPSession.cpp
@@ -1,970 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <zlib.h>
|
||||
#include "I2PEndian.h"
|
||||
#include "Base.h"
|
||||
#include "Log.h"
|
||||
#include "Timestamp.h"
|
||||
#include "Crypto.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.h"
|
||||
#include "NTCPSession.h"
|
||||
|
||||
using namespace i2p::crypto;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
|
||||
TransportSession (in_RemoteRouter), m_Server (server), m_Socket (m_Server.GetService ()),
|
||||
m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false),
|
||||
m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_IsSending (false)
|
||||
{
|
||||
m_Establisher = new Establisher;
|
||||
}
|
||||
|
||||
NTCPSession::~NTCPSession ()
|
||||
{
|
||||
delete m_Establisher;
|
||||
}
|
||||
|
||||
void NTCPSession::CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key)
|
||||
{
|
||||
uint8_t sharedKey[256];
|
||||
m_DHKeysPair->Agree (pubKey, sharedKey);
|
||||
|
||||
uint8_t * aesKey = key;
|
||||
if (sharedKey[0] & 0x80)
|
||||
{
|
||||
aesKey[0] = 0;
|
||||
memcpy (aesKey + 1, sharedKey, 31);
|
||||
}
|
||||
else if (sharedKey[0])
|
||||
memcpy (aesKey, sharedKey, 32);
|
||||
else
|
||||
{
|
||||
// find first non-zero byte
|
||||
uint8_t * nonZero = sharedKey + 1;
|
||||
while (!*nonZero)
|
||||
{
|
||||
nonZero++;
|
||||
if (nonZero - sharedKey > 32)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: First 32 bytes of shared key is all zeros, ignored");
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy (aesKey, nonZero, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::Done ()
|
||||
{
|
||||
m_Server.GetService ().post (std::bind (&NTCPSession::Terminate, shared_from_this ()));
|
||||
}
|
||||
|
||||
void NTCPSession::Terminate ()
|
||||
{
|
||||
if (!m_IsTerminated)
|
||||
{
|
||||
m_IsTerminated = true;
|
||||
m_IsEstablished = false;
|
||||
m_Socket.close ();
|
||||
transports.PeerDisconnected (shared_from_this ());
|
||||
m_Server.RemoveNTCPSession (shared_from_this ());
|
||||
m_SendQueue.clear ();
|
||||
m_NextMessage = nullptr;
|
||||
m_TerminationTimer.cancel ();
|
||||
LogPrint (eLogDebug, "NTCP: session terminated");
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::Connected ()
|
||||
{
|
||||
m_IsEstablished = true;
|
||||
|
||||
delete m_Establisher;
|
||||
m_Establisher = nullptr;
|
||||
|
||||
m_DHKeysPair = nullptr;
|
||||
|
||||
SendTimeSyncMessage ();
|
||||
m_SendQueue.push_back (CreateDatabaseStoreMsg ()); // we tell immediately who we are
|
||||
|
||||
transports.PeerConnected (shared_from_this ());
|
||||
}
|
||||
|
||||
void NTCPSession::ClientLogin ()
|
||||
{
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
// send Phase1
|
||||
const uint8_t * x = m_DHKeysPair->GetPublicKey ();
|
||||
memcpy (m_Establisher->phase1.pubKey, x, 256);
|
||||
SHA256(x, 256, m_Establisher->phase1.HXxorHI);
|
||||
const uint8_t * ident = m_RemoteIdentity->GetIdentHash ();
|
||||
for (int i = 0; i < 32; i++)
|
||||
m_Establisher->phase1.HXxorHI[i] ^= ident[i];
|
||||
|
||||
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase1Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
ScheduleTermination ();
|
||||
}
|
||||
|
||||
void NTCPSession::ServerLogin ()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto ep = m_Socket.remote_endpoint(ec);
|
||||
if (!ec)
|
||||
{
|
||||
m_ConnectedFrom = ep.address ();
|
||||
// receive Phase1
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase1Received, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: couldn't send Phase 1 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase2Received, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: phase 1 read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify ident
|
||||
uint8_t digest[32];
|
||||
SHA256(m_Establisher->phase1.pubKey, 256, digest);
|
||||
const uint8_t * ident = i2p::context.GetIdentHash ();
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: phase 1 error: ident mismatch");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SendPhase2 ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::SendPhase2 ()
|
||||
{
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
const uint8_t * y = m_DHKeysPair->GetPublicKey ();
|
||||
memcpy (m_Establisher->phase2.pubKey, y, 256);
|
||||
uint8_t xy[512];
|
||||
memcpy (xy, m_Establisher->phase1.pubKey, 256);
|
||||
memcpy (xy + 256, y, 256);
|
||||
SHA256(xy, 512, m_Establisher->phase2.encrypted.hxy);
|
||||
uint32_t tsB = htobe32 (i2p::util::GetSecondsSinceEpoch ());
|
||||
memcpy (m_Establisher->phase2.encrypted.timestamp, &tsB, 4);
|
||||
RAND_bytes (m_Establisher->phase2.encrypted.filler, 12);
|
||||
|
||||
i2p::crypto::AESKey aesKey;
|
||||
CreateAESKey (m_Establisher->phase1.pubKey, aesKey);
|
||||
m_Encryption.SetKey (aesKey);
|
||||
m_Encryption.SetIV (y + 240);
|
||||
m_Decryption.SetKey (aesKey);
|
||||
m_Decryption.SetIV (m_Establisher->phase1.HXxorHI + 16);
|
||||
|
||||
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted);
|
||||
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB));
|
||||
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 2 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase3Received, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2, tsB));
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// this RI is not valid
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
m_DHKeysPair = nullptr;
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i2p::crypto::AESKey aesKey;
|
||||
CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
|
||||
m_Decryption.SetKey (aesKey);
|
||||
m_Decryption.SetIV (m_Establisher->phase2.pubKey + 240);
|
||||
m_Encryption.SetKey (aesKey);
|
||||
m_Encryption.SetIV (m_Establisher->phase1.HXxorHI + 16);
|
||||
|
||||
m_Decryption.Decrypt((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted);
|
||||
// verify
|
||||
uint8_t xy[512];
|
||||
memcpy (xy, m_DHKeysPair->GetPublicKey (), 256);
|
||||
memcpy (xy + 256, m_Establisher->phase2.pubKey, 256);
|
||||
uint8_t digest[32];
|
||||
SHA256 (xy, 512, digest);
|
||||
if (memcmp(m_Establisher->phase2.encrypted.hxy, digest, 32))
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Phase 2 process error: incorrect hash");
|
||||
transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
m_DHKeysPair = nullptr;
|
||||
Terminate ();
|
||||
return ;
|
||||
}
|
||||
SendPhase3 ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::SendPhase3 ()
|
||||
{
|
||||
auto keys = i2p::context.GetPrivateKeys ();
|
||||
uint8_t * buf = m_ReceiveBuffer;
|
||||
htobe16buf (buf, keys.GetPublic ()->GetFullLen ());
|
||||
buf += 2;
|
||||
buf += i2p::context.GetIdentity ()->ToBuffer (buf, NTCP_BUFFER_SIZE);
|
||||
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
|
||||
htobuf32(buf,tsA);
|
||||
buf += 4;
|
||||
size_t signatureLen = keys.GetPublic ()->GetSignatureLen ();
|
||||
size_t len = (buf - m_ReceiveBuffer) + signatureLen;
|
||||
size_t paddingSize = len & 0x0F; // %16
|
||||
if (paddingSize > 0)
|
||||
{
|
||||
paddingSize = 16 - paddingSize;
|
||||
// fill padding with random data
|
||||
RAND_bytes(buf, paddingSize);
|
||||
buf += paddingSize;
|
||||
len += paddingSize;
|
||||
}
|
||||
|
||||
SignedData s;
|
||||
s.Insert (m_Establisher->phase1.pubKey, 256); // x
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
|
||||
s.Sign (keys, buf);
|
||||
|
||||
m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
|
||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, len), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase3Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsA));
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 3 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait for phase4
|
||||
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
||||
size_t paddingSize = signatureLen & 0x0F; // %16
|
||||
if (paddingSize > 0) signatureLen += (16 - paddingSize);
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase4Received, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2, tsA));
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Phase 3 read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
|
||||
uint8_t * buf = m_ReceiveBuffer;
|
||||
uint16_t size = bufbe16toh (buf);
|
||||
SetRemoteIdentity (std::make_shared<i2p::data::IdentityEx> (buf + 2, size));
|
||||
if (m_Server.FindNTCPSession (m_RemoteIdentity->GetIdentHash ()))
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: session already exists");
|
||||
Terminate ();
|
||||
}
|
||||
size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity->GetSignatureLen ();
|
||||
size_t paddingLen = expectedSize & 0x0F;
|
||||
if (paddingLen) paddingLen = (16 - paddingLen);
|
||||
if (expectedSize > NTCP_DEFAULT_PHASE3_SIZE)
|
||||
{
|
||||
// we need more bytes for Phase3
|
||||
expectedSize += paddingLen;
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize - NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase3ExtraReceived, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2, tsB, paddingLen));
|
||||
}
|
||||
else
|
||||
HandlePhase3 (tsB, paddingLen);
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Phase 3 extra read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Decryption.Decrypt (m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, bytes_transferred, m_ReceiveBuffer+ NTCP_DEFAULT_PHASE3_SIZE);
|
||||
HandlePhase3 (tsB, paddingLen);
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase3 (uint32_t tsB, size_t paddingLen)
|
||||
{
|
||||
uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity->GetFullLen () + 2 /*size*/;
|
||||
uint32_t tsA = buf32toh(buf);
|
||||
buf += 4;
|
||||
buf += paddingLen;
|
||||
|
||||
// check timestamp
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
uint32_t tsA1 = be32toh (tsA);
|
||||
if (tsA1 < ts - NTCP_CLOCK_SKEW || tsA1 > ts + NTCP_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Phase3 time difference ", ts - tsA1, " exceeds clock skew");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
|
||||
// check signature
|
||||
SignedData s;
|
||||
s.Insert (m_Establisher->phase1.pubKey, 256); // x
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (tsB); // tsB
|
||||
if (!s.Verify (m_RemoteIdentity, buf))
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: signature verification failed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
|
||||
SendPhase4 (tsA, tsB);
|
||||
}
|
||||
|
||||
void NTCPSession::SendPhase4 (uint32_t tsA, uint32_t tsB)
|
||||
{
|
||||
SignedData s;
|
||||
s.Insert (m_Establisher->phase1.pubKey, 256); // x
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (tsB); // tsB
|
||||
auto keys = i2p::context.GetPrivateKeys ();
|
||||
auto signatureLen = keys.GetPublic ()->GetSignatureLen ();
|
||||
s.Sign (keys, m_ReceiveBuffer);
|
||||
size_t paddingSize = signatureLen & 0x0F; // %16
|
||||
if (paddingSize > 0) signatureLen += (16 - paddingSize);
|
||||
m_Encryption.Encrypt (m_ReceiveBuffer, signatureLen, m_ReceiveBuffer);
|
||||
|
||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandlePhase4Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: Couldn't send Phase 4 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Server session from ", m_Socket.remote_endpoint (), " connected");
|
||||
m_Server.AddNTCPSession (shared_from_this ());
|
||||
|
||||
Connected ();
|
||||
m_ReceiveBufferOffset = 0;
|
||||
m_NextMessage = nullptr;
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock");
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// this router doesn't like us
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
|
||||
|
||||
// check timestamp
|
||||
uint32_t tsB = bufbe32toh (m_Establisher->phase2.encrypted.timestamp);
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (tsB < ts - NTCP_CLOCK_SKEW || tsB > ts + NTCP_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Phase4 time difference ", ts - tsB, " exceeds clock skew");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
|
||||
// verify signature
|
||||
SignedData s;
|
||||
s.Insert (m_Establisher->phase1.pubKey, 256); // x
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (i2p::context.GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
|
||||
|
||||
if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Phase 4 process error: signature verification failed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogDebug, "NTCP: session to ", m_Socket.remote_endpoint (), " connected");
|
||||
Connected ();
|
||||
|
||||
m_ReceiveBufferOffset = 0;
|
||||
m_NextMessage = nullptr;
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPSession::Receive ()
|
||||
{
|
||||
m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, NTCP_BUFFER_SIZE - m_ReceiveBufferOffset),
|
||||
std::bind(&NTCPSession::HandleReceived, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (ecode) {
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ());
|
||||
if (!m_NumReceivedBytes)
|
||||
m_Server.Ban (m_ConnectedFrom);
|
||||
//if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NumReceivedBytes += bytes_transferred;
|
||||
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
|
||||
m_ReceiveBufferOffset += bytes_transferred;
|
||||
|
||||
if (m_ReceiveBufferOffset >= 16)
|
||||
{
|
||||
int numReloads = 0;
|
||||
do
|
||||
{
|
||||
uint8_t * nextBlock = m_ReceiveBuffer;
|
||||
while (m_ReceiveBufferOffset >= 16)
|
||||
{
|
||||
if (!DecryptNextBlock (nextBlock)) // 16 bytes
|
||||
{
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
nextBlock += 16;
|
||||
m_ReceiveBufferOffset -= 16;
|
||||
}
|
||||
if (m_ReceiveBufferOffset > 0)
|
||||
memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
|
||||
|
||||
// try to read more
|
||||
if (numReloads < 5)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (moreBytes)
|
||||
{
|
||||
if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset)
|
||||
moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset;
|
||||
moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes));
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ());
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
m_NumReceivedBytes += moreBytes;
|
||||
m_ReceiveBufferOffset += moreBytes;
|
||||
numReloads++;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (m_ReceiveBufferOffset >= 16);
|
||||
m_Handler.Flush ();
|
||||
}
|
||||
|
||||
ScheduleTermination (); // reset termination timer
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
|
||||
bool NTCPSession::DecryptNextBlock (const uint8_t * encrypted) // 16 bytes
|
||||
{
|
||||
if (!m_NextMessage) // new message, header expected
|
||||
{
|
||||
// decrypt header and extract length
|
||||
uint8_t buf[16];
|
||||
m_Decryption.Decrypt (encrypted, buf);
|
||||
uint16_t dataSize = bufbe16toh (buf);
|
||||
if (dataSize)
|
||||
{
|
||||
// new message
|
||||
if (dataSize + 16U > NTCP_MAX_MESSAGE_SIZE - 2) // + 6 + padding
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: data size ", dataSize, " exceeds max size");
|
||||
return false;
|
||||
}
|
||||
auto msg = (dataSize + 16U) <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
m_NextMessage = msg;
|
||||
memcpy (m_NextMessage->buf, buf, 16);
|
||||
m_NextMessageOffset = 16;
|
||||
m_NextMessage->offset = 2; // size field
|
||||
m_NextMessage->len = dataSize + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timestamp
|
||||
LogPrint (eLogDebug, "NTCP: Timestamp");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else // message continues
|
||||
{
|
||||
m_Decryption.Decrypt (encrypted, m_NextMessage->buf + m_NextMessageOffset);
|
||||
m_NextMessageOffset += 16;
|
||||
}
|
||||
|
||||
if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum
|
||||
{
|
||||
// we have a complete I2NP message
|
||||
uint8_t checksum[4];
|
||||
htobe32buf (checksum, adler32 (adler32 (0, Z_NULL, 0), m_NextMessage->buf, m_NextMessageOffset - 4));
|
||||
if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4))
|
||||
{
|
||||
if (!m_NextMessage->IsExpired ())
|
||||
m_Handler.PutNextMessage (m_NextMessage);
|
||||
else
|
||||
LogPrint (eLogInfo, "NTCP: message expired");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "NTCP: Incorrect adler checksum of message, dropped");
|
||||
m_NextMessage = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NTCPSession::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
m_IsSending = true;
|
||||
boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector<std::shared_ptr<I2NPMessage> >{ msg }));
|
||||
}
|
||||
|
||||
boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
uint8_t * sendBuffer;
|
||||
int len;
|
||||
|
||||
if (msg)
|
||||
{
|
||||
// regular I2NP
|
||||
if (msg->offset < 2)
|
||||
LogPrint (eLogError, "NTCP: Malformed I2NP message"); // TODO:
|
||||
sendBuffer = msg->GetBuffer () - 2;
|
||||
len = msg->GetLength ();
|
||||
htobe16buf (sendBuffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
// prepare timestamp
|
||||
sendBuffer = m_TimeSyncBuffer;
|
||||
len = 4;
|
||||
htobuf16(sendBuffer, 0);
|
||||
htobe32buf (sendBuffer + 2, time (0));
|
||||
}
|
||||
int rem = (len + 6) & 0x0F; // %16
|
||||
int padding = 0;
|
||||
if (rem > 0) {
|
||||
padding = 16 - rem;
|
||||
// fill with random padding
|
||||
RAND_bytes(sendBuffer + len + 2, padding);
|
||||
}
|
||||
htobe32buf (sendBuffer + len + 2 + padding, adler32 (adler32 (0, Z_NULL, 0), sendBuffer, len + 2+ padding));
|
||||
|
||||
int l = len + padding + 6;
|
||||
m_Encryption.Encrypt(sendBuffer, l, sendBuffer);
|
||||
return boost::asio::buffer ((const uint8_t *)sendBuffer, l);
|
||||
}
|
||||
|
||||
|
||||
void NTCPSession::Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
||||
{
|
||||
m_IsSending = true;
|
||||
std::vector<boost::asio::const_buffer> bufs;
|
||||
for (auto it: msgs)
|
||||
bufs.push_back (CreateMsgBuffer (it));
|
||||
boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (),
|
||||
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
|
||||
}
|
||||
|
||||
void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||
{
|
||||
(void) msgs;
|
||||
m_IsSending = false;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: Couldn't send msgs: ", ecode.message ());
|
||||
// we shouldn't call Terminate () here, because HandleReceive takes care
|
||||
// TODO: 'delete this' statement in Terminate () must be eliminated later
|
||||
// Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NumSentBytes += bytes_transferred;
|
||||
i2p::transport::transports.UpdateSentBytes (bytes_transferred);
|
||||
if (!m_SendQueue.empty())
|
||||
{
|
||||
Send (m_SendQueue);
|
||||
m_SendQueue.clear ();
|
||||
}
|
||||
else
|
||||
ScheduleTermination (); // reset termination timer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NTCPSession::SendTimeSyncMessage ()
|
||||
{
|
||||
Send (nullptr);
|
||||
}
|
||||
|
||||
|
||||
void NTCPSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
||||
{
|
||||
m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs));
|
||||
}
|
||||
|
||||
void NTCPSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||
{
|
||||
if (m_IsTerminated) return;
|
||||
if (m_IsSending)
|
||||
{
|
||||
for (auto it: msgs)
|
||||
m_SendQueue.push_back (it);
|
||||
}
|
||||
else
|
||||
Send (msgs);
|
||||
}
|
||||
|
||||
void NTCPSession::ScheduleTermination ()
|
||||
{
|
||||
m_TerminationTimer.cancel ();
|
||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT));
|
||||
m_TerminationTimer.async_wait (std::bind (&NTCPSession::HandleTerminationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void NTCPSession::HandleTerminationTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP: No activity for ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||
//Terminate ();
|
||||
m_Socket.close ();// invoke Terminate () from HandleReceive
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------
|
||||
NTCPServer::NTCPServer ():
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
|
||||
m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NTCPServer::~NTCPServer ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void NTCPServer::Start ()
|
||||
{
|
||||
if (!m_IsRunning)
|
||||
{
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&NTCPServer::Run, this));
|
||||
// create acceptors
|
||||
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||
for (auto& address : addresses)
|
||||
{
|
||||
if (address.transportStyle == i2p::data::RouterInfo::eTransportNTCP && address.host.is_v4 ())
|
||||
{
|
||||
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
|
||||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
|
||||
|
||||
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address.port);
|
||||
auto conn = std::make_shared<NTCPSession>(*this);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
|
||||
conn, std::placeholders::_1));
|
||||
|
||||
if (context.SupportsV6 ())
|
||||
{
|
||||
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
|
||||
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port));
|
||||
m_NTCPV6Acceptor->listen ();
|
||||
|
||||
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address.port);
|
||||
auto conn = std::make_shared<NTCPSession> (*this);
|
||||
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6,
|
||||
this, conn, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPServer::Stop ()
|
||||
{
|
||||
m_NTCPSessions.clear ();
|
||||
|
||||
if (m_IsRunning)
|
||||
{
|
||||
m_IsRunning = false;
|
||||
delete m_NTCPAcceptor;
|
||||
m_NTCPAcceptor = nullptr;
|
||||
delete m_NTCPV6Acceptor;
|
||||
m_NTCPV6Acceptor = nullptr;
|
||||
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NTCPServer::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NTCPServer::AddNTCPSession (std::shared_ptr<NTCPSession> session)
|
||||
{
|
||||
if (!session || !session->GetRemoteIdentity ()) return false;
|
||||
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
|
||||
auto it = m_NTCPSessions.find (ident);
|
||||
if (it != m_NTCPSessions.end ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: session to ", ident.ToBase64 (), " already exists");
|
||||
return false;
|
||||
}
|
||||
m_NTCPSessions.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<NTCPSession> >(ident, session));
|
||||
return true;
|
||||
}
|
||||
|
||||
void NTCPServer::RemoveNTCPSession (std::shared_ptr<NTCPSession> session)
|
||||
{
|
||||
if (session && session->GetRemoteIdentity ())
|
||||
m_NTCPSessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
|
||||
}
|
||||
|
||||
std::shared_ptr<NTCPSession> NTCPServer::FindNTCPSession (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto it = m_NTCPSessions.find (ident);
|
||||
if (it != m_NTCPSessions.end ())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NTCPServer::HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
|
||||
auto it = m_BanList.find (ep.address ());
|
||||
if (it != m_BanList.end ())
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts < it->second)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
m_BanList.erase (it);
|
||||
}
|
||||
if (conn)
|
||||
conn->ServerLogin ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
|
||||
}
|
||||
|
||||
|
||||
if (error != boost::asio::error::operation_aborted)
|
||||
{
|
||||
conn = std::make_shared<NTCPSession> (*this);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
|
||||
conn, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPServer::HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
|
||||
auto it = m_BanList.find (ep.address ());
|
||||
if (it != m_BanList.end ())
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts < it->second)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
m_BanList.erase (it);
|
||||
}
|
||||
if (conn)
|
||||
conn->ServerLogin ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
|
||||
}
|
||||
|
||||
if (error != boost::asio::error::operation_aborted)
|
||||
{
|
||||
conn = std::make_shared<NTCPSession> (*this);
|
||||
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this,
|
||||
conn, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPServer::Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port);
|
||||
m_Service.post([=]()
|
||||
{
|
||||
if (this->AddNTCPSession (conn))
|
||||
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
|
||||
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn));
|
||||
});
|
||||
}
|
||||
|
||||
void NTCPServer::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP: Connect error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
conn->Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP: Connected to ", conn->GetSocket ().remote_endpoint ());
|
||||
if (conn->GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
|
||||
context.UpdateNTCPV6Address (conn->GetSocket ().local_endpoint ().address ());
|
||||
conn->ClientLogin ();
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPServer::Ban (const boost::asio::ip::address& addr)
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_BanList[addr] = ts + NTCP_BAN_EXPIRATION_TIMEOUT;
|
||||
LogPrint (eLogWarning, "NTCP: ", addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
111
README.md
@@ -1,41 +1,86 @@
|
||||
i2pd
|
||||
====
|
||||
|
||||
Independent C++ implementation of I2P router
|
||||
[Русская версия](https://github.com/PurpleI2P/i2pd_docs_ru/blob/master/README.md)
|
||||
|
||||
i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client.
|
||||
|
||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer.
|
||||
All communications over I2P are anonymous and end-to-end encrypted, participants
|
||||
don't reveal their real IP addresses.
|
||||
|
||||
I2P client is a software used for building and using anonymous I2P
|
||||
networks. Such networks are commonly used for anonymous peer-to-peer
|
||||
applications (filesharing, cryptocurrencies) and anonymous client-server
|
||||
applications (websites, instant messengers, chat-servers).
|
||||
|
||||
I2P allows people from all around the world to communicate and share information
|
||||
without restrictions.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Distributed anonymous networking framework
|
||||
* End-to-end encrypted communications
|
||||
* Small footprint, simple dependencies, fast performance
|
||||
* Rich set of APIs for developers of secure applications
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Website](http://i2pd.website)
|
||||
* [Documentation](https://i2pd.readthedocs.io/en/latest/)
|
||||
* [Wiki](https://github.com/PurpleI2P/i2pd/wiki)
|
||||
* [Tickets/Issues](https://github.com/PurpleI2P/i2pd/issues)
|
||||
* [Specifications](https://geti2p.net/spec)
|
||||
* [Twitter](https://twitter.com/hashtag/i2pd)
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
The easiest way to install i2pd is by using
|
||||
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
|
||||
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
||||
i2pd from source on your OS.
|
||||
|
||||
|
||||
Build instructions:
|
||||
|
||||
* [unix](https://i2pd.readthedocs.io/en/latest/devs/building/unix/)
|
||||
* [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/)
|
||||
* [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/)
|
||||
* [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/)
|
||||
|
||||
|
||||
**Supported systems:**
|
||||
|
||||
* GNU/Linux x86/x64 - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||
* Mac OS X - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* CentOS / Fedora - [](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
||||
* Docker image - [](https://hub.docker.com/r/meeh/i2pd/builds/)
|
||||
* FreeBSD
|
||||
* Android
|
||||
* iOS
|
||||
|
||||
Using i2pd
|
||||
----------
|
||||
|
||||
See [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/run/) and
|
||||
[example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/i2pd.conf).
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
BTC: 3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d
|
||||
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
|
||||
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
|
||||
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This project is licensed under the BSD 3-clause license, which can be found in the file
|
||||
LICENSE in the root of the project source code.
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
||||
|
||||
Downloads
|
||||
------------
|
||||
|
||||
Official binary releases could be found at:
|
||||
http://i2pd.website/releases/
|
||||
older releases
|
||||
http://download.i2p.io/purplei2p/i2pd/releases/
|
||||
|
||||
Supported OS
|
||||
------------
|
||||
|
||||
* Linux x86/x64 - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||
* Mac OS X
|
||||
* FreeBSD
|
||||
|
||||
More documentation
|
||||
------------------
|
||||
|
||||
* [Building from source / unix](docs/build_notes_unix.md)
|
||||
* [Building from source / windows](docs/build_notes_windows.md)
|
||||
* [Configuring your i2pd](docs/configuration.md)
|
||||
* [Github wiki](https://github.com/PurpleI2P/i2pd/wiki/)
|
||||
LICENSE in the root of the project source code.
|
||||
|
||||
421
Reseed.cpp
@@ -1,421 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "I2PEndian.h"
|
||||
#include "Reseed.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "Identity.h"
|
||||
#include "Crypto.h"
|
||||
#include "NetDb.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
static std::vector<std::string> httpsReseedHostList =
|
||||
{
|
||||
"https://reseed.i2p-projekt.de/", // Only HTTPS
|
||||
//"https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v3) support
|
||||
"https://i2p.mooo.com/netDb/",
|
||||
"https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required
|
||||
"https://us.reseed.i2p2.no:444/",
|
||||
"https://uk.reseed.i2p2.no:444/",
|
||||
"https://www.torontocrypto.org:8443/",
|
||||
"https://i2p-0.manas.ca:8443/"
|
||||
"https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support
|
||||
"https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support
|
||||
"https://download.xxlspeed.com/" // Only HTTPS and SU3 (v3) support
|
||||
};
|
||||
|
||||
Reseeder::Reseeder()
|
||||
{
|
||||
}
|
||||
|
||||
Reseeder::~Reseeder()
|
||||
{
|
||||
}
|
||||
|
||||
int Reseeder::ReseedNowSU3 ()
|
||||
{
|
||||
auto ind = rand () % httpsReseedHostList.size ();
|
||||
std::string& reseedHost = httpsReseedHostList[ind];
|
||||
return ReseedFromSU3 (reseedHost);
|
||||
}
|
||||
|
||||
int Reseeder::ReseedFromSU3 (const std::string& host)
|
||||
{
|
||||
std::string url = host + "i2pseeds.su3";
|
||||
LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", host);
|
||||
std::string su3 = HttpsRequest (url);
|
||||
if (su3.length () > 0)
|
||||
{
|
||||
std::stringstream s(su3);
|
||||
return ProcessSU3Stream (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: SU3 download failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Reseeder::ProcessSU3File (const char * filename)
|
||||
{
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
return ProcessSU3Stream (s);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char SU3_MAGIC_NUMBER[]="I2Psu3";
|
||||
const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
|
||||
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
|
||||
const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
|
||||
int Reseeder::ProcessSU3Stream (std::istream& s)
|
||||
{
|
||||
char magicNumber[7];
|
||||
s.read (magicNumber, 7); // magic number and zero byte 6
|
||||
if (strcmp (magicNumber, SU3_MAGIC_NUMBER))
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // su3 file format version
|
||||
SigningKeyType signatureType;
|
||||
s.read ((char *)&signatureType, 2); // signature type
|
||||
signatureType = be16toh (signatureType);
|
||||
uint16_t signatureLength;
|
||||
s.read ((char *)&signatureLength, 2); // signature length
|
||||
signatureLength = be16toh (signatureLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t versionLength;
|
||||
s.read ((char *)&versionLength, 1); // version length
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t signerIDLength;
|
||||
s.read ((char *)&signerIDLength, 1); // signer ID length
|
||||
uint64_t contentLength;
|
||||
s.read ((char *)&contentLength, 8); // content length
|
||||
contentLength = be64toh (contentLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t fileType;
|
||||
s.read ((char *)&fileType, 1); // file type
|
||||
if (fileType != 0x00) // zip file
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t contentType;
|
||||
s.read ((char *)&contentType, 1); // content type
|
||||
if (contentType != 0x03) // reseed data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (12, std::ios::cur); // unused
|
||||
|
||||
s.seekg (versionLength, std::ios::cur); // skip version
|
||||
char signerID[256];
|
||||
s.read (signerID, signerIDLength); // signerID
|
||||
signerID[signerIDLength] = 0;
|
||||
|
||||
//try to verify signature
|
||||
auto it = m_SigningKeys.find (signerID);
|
||||
if (it != m_SigningKeys.end ())
|
||||
{
|
||||
// TODO: implement all signature types
|
||||
if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096)
|
||||
{
|
||||
size_t pos = s.tellg ();
|
||||
size_t tbsLen = pos + contentLength;
|
||||
uint8_t * tbs = new uint8_t[tbsLen];
|
||||
s.seekg (0, std::ios::beg);
|
||||
s.read ((char *)tbs, tbsLen);
|
||||
uint8_t * signature = new uint8_t[signatureLength];
|
||||
s.read ((char *)signature, signatureLength);
|
||||
// RSA-raw
|
||||
{
|
||||
// calculate digest
|
||||
uint8_t digest[64];
|
||||
SHA512 (tbs, tbsLen, digest);
|
||||
// encrypt signature
|
||||
BN_CTX * bnctx = BN_CTX_new ();
|
||||
BIGNUM * s = BN_new (), * n = BN_new ();
|
||||
BN_bin2bn (signature, signatureLength, s);
|
||||
BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n);
|
||||
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
|
||||
uint8_t * enSigBuf = new uint8_t[signatureLength];
|
||||
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
|
||||
// digest is right aligned
|
||||
// we can't use RSA_verify due wrong padding in SU3
|
||||
if (memcmp (enSigBuf + (signatureLength - 64), digest, 64))
|
||||
LogPrint (eLogWarning, "Reseed: SU3 signature verification failed");
|
||||
delete[] enSigBuf;
|
||||
BN_free (s); BN_free (n);
|
||||
BN_CTX_free (bnctx);
|
||||
}
|
||||
|
||||
delete[] signature;
|
||||
delete[] tbs;
|
||||
s.seekg (pos, std::ios::beg);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
|
||||
|
||||
// handle content
|
||||
int numFiles = 0;
|
||||
size_t contentPos = s.tellg ();
|
||||
while (!s.eof ())
|
||||
{
|
||||
uint32_t signature;
|
||||
s.read ((char *)&signature, 4);
|
||||
signature = le32toh (signature);
|
||||
if (signature == ZIP_HEADER_SIGNATURE)
|
||||
{
|
||||
// next local file
|
||||
s.seekg (2, std::ios::cur); // version
|
||||
uint16_t bitFlag;
|
||||
s.read ((char *)&bitFlag, 2);
|
||||
bitFlag = le16toh (bitFlag);
|
||||
uint16_t compressionMethod;
|
||||
s.read ((char *)&compressionMethod, 2);
|
||||
compressionMethod = le16toh (compressionMethod);
|
||||
s.seekg (4, std::ios::cur); // skip fields we don't care about
|
||||
uint32_t compressedSize, uncompressedSize;
|
||||
uint32_t crc_32;
|
||||
s.read ((char *)&crc_32, 4);
|
||||
crc_32 = le32toh (crc_32);
|
||||
s.read ((char *)&compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize);
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
uint16_t fileNameLength, extraFieldLength;
|
||||
s.read ((char *)&fileNameLength, 2);
|
||||
fileNameLength = le16toh (fileNameLength);
|
||||
if ( fileNameLength > 255 ) {
|
||||
// too big
|
||||
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&extraFieldLength, 2);
|
||||
extraFieldLength = le16toh (extraFieldLength);
|
||||
char localFileName[255];
|
||||
s.read (localFileName, fileNameLength);
|
||||
localFileName[fileNameLength] = 0;
|
||||
s.seekg (extraFieldLength, std::ios::cur);
|
||||
// take care about data desriptor if presented
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
|
||||
{
|
||||
size_t pos = s.tellg ();
|
||||
if (!FindZipDataDescriptor (s))
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&crc_32, 4);
|
||||
crc_32 = le32toh (crc_32);
|
||||
s.read ((char *)&compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
|
||||
// now we know compressed and uncompressed size
|
||||
s.seekg (pos, std::ios::beg); // back to compressed data
|
||||
}
|
||||
|
||||
LogPrint (eLogDebug, "Reseed: Proccessing file ", localFileName, " ", compressedSize, " bytes");
|
||||
if (!compressedSize)
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t * compressed = new uint8_t[compressedSize];
|
||||
s.read ((char *)compressed, compressedSize);
|
||||
if (compressionMethod) // we assume Deflate
|
||||
{
|
||||
z_stream inflator;
|
||||
memset (&inflator, 0, sizeof (inflator));
|
||||
inflateInit2 (&inflator, -MAX_WBITS); // no zlib header
|
||||
uint8_t * uncompressed = new uint8_t[uncompressedSize];
|
||||
inflator.next_in = compressed;
|
||||
inflator.avail_in = compressedSize;
|
||||
inflator.next_out = uncompressed;
|
||||
inflator.avail_out = uncompressedSize;
|
||||
int err;
|
||||
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
|
||||
{
|
||||
uncompressedSize -= inflator.avail_out;
|
||||
if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: CRC32 verification failed");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
|
||||
delete[] uncompressed;
|
||||
inflateEnd (&inflator);
|
||||
}
|
||||
else // no compression
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
delete[] compressed;
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
|
||||
s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
|
||||
LogPrint (eLogWarning, "Reseed: Missing zip central directory header");
|
||||
break; // no more files
|
||||
}
|
||||
size_t end = s.tellg ();
|
||||
if (end - contentPos >= contentLength)
|
||||
break; // we are beyond contentLength
|
||||
}
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
|
||||
bool Reseeder::FindZipDataDescriptor (std::istream& s)
|
||||
{
|
||||
size_t nextInd = 0;
|
||||
while (!s.eof ())
|
||||
{
|
||||
uint8_t nextByte;
|
||||
s.read ((char *)&nextByte, 1);
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
|
||||
{
|
||||
nextInd++;
|
||||
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
nextInd = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Reseeder::LoadCertificate (const std::string& filename)
|
||||
{
|
||||
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
|
||||
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
|
||||
if (ret)
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
X509 * cert = SSL_get_certificate (ssl);
|
||||
// verify
|
||||
if (cert)
|
||||
{
|
||||
// extract issuer name
|
||||
char name[100];
|
||||
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
RSA * key = X509_get_pubkey (cert)->pkey.rsa;
|
||||
PublicKey value;
|
||||
i2p::crypto::bn2buf (key->n, value, 512);
|
||||
m_SigningKeys[name] = value;
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
}
|
||||
|
||||
void Reseeder::LoadCertificates ()
|
||||
{
|
||||
std::string certDir = i2p::fs::DataDirPath("certificates", "reseed");
|
||||
std::vector<std::string> files;
|
||||
int numCertificates = 0;
|
||||
|
||||
if (!i2p::fs::ReadDir(certDir, files)) {
|
||||
LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::string & file : files) {
|
||||
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
|
||||
LogPrint(eLogWarning, "Reseed: ignoring file ", file);
|
||||
continue;
|
||||
}
|
||||
LoadCertificate (file);
|
||||
numCertificates++;
|
||||
}
|
||||
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
|
||||
}
|
||||
|
||||
std::string Reseeder::HttpsRequest (const std::string& address)
|
||||
{
|
||||
i2p::util::http::url u(address);
|
||||
if (u.port_ == 80) u.port_ = 443;
|
||||
|
||||
boost::asio::io_service service;
|
||||
boost::system::error_code ecode;
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (u.host_, std::to_string (u.port_)), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
boost::asio::ssl::context ctx(service, boost::asio::ssl::context::sslv23);
|
||||
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> s(service, ctx);
|
||||
s.lowest_layer().connect (*it, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
s.handshake (boost::asio::ssl::stream_base::client, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "Reseed: Connected to ", u.host_, ":", u.port_);
|
||||
// send request
|
||||
std::stringstream ss;
|
||||
ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_
|
||||
<< "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n";
|
||||
s.write_some (boost::asio::buffer (ss.str ()));
|
||||
// read response
|
||||
std::stringstream rs;
|
||||
char response[1024]; size_t l = 0;
|
||||
do
|
||||
{
|
||||
l = s.read_some (boost::asio::buffer (response, 1024), ecode);
|
||||
if (l) rs.write (response, l);
|
||||
}
|
||||
while (!ecode && l);
|
||||
// process response
|
||||
return i2p::util::http::GetHttpContent (rs);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to ", u.host_, ": ", ecode.message ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Couldn't resolve address ", u.host_, ": ", ecode.message ());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,387 +0,0 @@
|
||||
#include <fstream>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "Config.h"
|
||||
#include "Crypto.h"
|
||||
#include "Timestamp.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "NetDb.h"
|
||||
#include "FS.h"
|
||||
#include "util.h"
|
||||
#include "version.h"
|
||||
#include "Log.h"
|
||||
#include "Family.h"
|
||||
#include "RouterContext.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
RouterContext context;
|
||||
|
||||
RouterContext::RouterContext ():
|
||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||
m_StartupTime (0), m_Status (eRouterStatusOK )
|
||||
{
|
||||
}
|
||||
|
||||
void RouterContext::Init ()
|
||||
{
|
||||
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
||||
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (!Load ())
|
||||
CreateNewRouter ();
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::CreateNewRouter ()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
||||
#else
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1);
|
||||
#endif
|
||||
SaveKeys ();
|
||||
NewRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::NewRouterInfo ()
|
||||
{
|
||||
i2p::data::RouterInfo routerInfo;
|
||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (!port)
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (i2p::config::IsDefault("host"))
|
||||
host = "127.0.0.1"; // replace default address with safe value
|
||||
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
|
||||
routerInfo.AddNTCPAddress (host.c_str(), port);
|
||||
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
||||
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
||||
routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID));
|
||||
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
||||
routerInfo.CreateBuffer (m_Keys);
|
||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||
}
|
||||
|
||||
void RouterContext::UpdateRouterInfo ()
|
||||
{
|
||||
m_RouterInfo.CreateBuffer (m_Keys);
|
||||
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
|
||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
void RouterContext::SetStatus (RouterStatus status)
|
||||
{
|
||||
if (status != m_Status)
|
||||
{
|
||||
m_Status = status;
|
||||
switch (m_Status)
|
||||
{
|
||||
case eRouterStatusOK:
|
||||
SetReachable ();
|
||||
break;
|
||||
case eRouterStatusFirewalled:
|
||||
SetUnreachable ();
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::UpdatePort (int port)
|
||||
{
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (address.port != port)
|
||||
{
|
||||
address.port = port;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
||||
{
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (address.host != host && address.IsCompatible (host))
|
||||
{
|
||||
address.host = host;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
bool RouterContext::AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
|
||||
{
|
||||
bool ret = m_RouterInfo.AddIntroducer (introducer);
|
||||
if (ret)
|
||||
UpdateRouterInfo ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
||||
{
|
||||
if (m_RouterInfo.RemoveIntroducer (e))
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetFloodfill (bool floodfill)
|
||||
{
|
||||
m_IsFloodfill = floodfill;
|
||||
if (floodfill)
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||
else
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||
// we don't publish number of routers and leaseset for non-floodfill
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
|
||||
}
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetFamily (const std::string& family)
|
||||
{
|
||||
std::string signature;
|
||||
if (family.length () > 0)
|
||||
signature = i2p::data::CreateFamilySignature (family, GetIdentHash ());
|
||||
if (signature.length () > 0)
|
||||
{
|
||||
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY, family);
|
||||
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG, signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY);
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetHighBandwidth ()
|
||||
{
|
||||
if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps ((m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth) & ~i2p::data::RouterInfo::eExtraBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetLowBandwidth ()
|
||||
{
|
||||
if (m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth & ~i2p::data::RouterInfo::eExtraBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetExtraBandwidth ()
|
||||
{
|
||||
if (!m_RouterInfo.IsExtraBandwidth () || !m_RouterInfo.IsHighBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eExtraBandwidth | i2p::data::RouterInfo::eHighBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterContext::IsUnreachable () const
|
||||
{
|
||||
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
||||
}
|
||||
|
||||
void RouterContext::SetUnreachable ()
|
||||
{
|
||||
// set caps
|
||||
m_RouterInfo.SetCaps (i2p::data::RouterInfo::eUnreachable | i2p::data::RouterInfo::eSSUTesting); // LU, B
|
||||
// remove NTCP address
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (size_t i = 0; i < addresses.size (); i++)
|
||||
{
|
||||
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||
{
|
||||
addresses.erase (addresses.begin () + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// delete previous introducers
|
||||
for (auto& addr : addresses)
|
||||
addr.introducers.clear ();
|
||||
|
||||
// update
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetReachable ()
|
||||
{
|
||||
// update caps
|
||||
uint8_t caps = m_RouterInfo.GetCaps ();
|
||||
caps &= ~i2p::data::RouterInfo::eUnreachable;
|
||||
caps |= i2p::data::RouterInfo::eReachable;
|
||||
caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||
if (m_IsFloodfill)
|
||||
caps |= i2p::data::RouterInfo::eFloodfill;
|
||||
m_RouterInfo.SetCaps (caps);
|
||||
|
||||
// insert NTCP back
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (size_t i = 0; i < addresses.size (); i++)
|
||||
{
|
||||
if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||
{
|
||||
// insert NTCP address with host/port from SSU
|
||||
m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// delete previous introducers
|
||||
for (auto& addr : addresses)
|
||||
addr.introducers.clear ();
|
||||
|
||||
// update
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetSupportsV6 (bool supportsV6)
|
||||
{
|
||||
if (supportsV6)
|
||||
m_RouterInfo.EnableV6 ();
|
||||
else
|
||||
m_RouterInfo.DisableV6 ();
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host)
|
||||
{
|
||||
bool updated = false, found = false;
|
||||
int port = 0;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
{
|
||||
if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||
{
|
||||
if (addr.host != host)
|
||||
{
|
||||
addr.host = host;
|
||||
updated = true;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
port = addr.port;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// create new address
|
||||
m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port);
|
||||
auto mtu = i2p::util::net::GetMTU (host);
|
||||
if (mtu)
|
||||
{
|
||||
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
||||
if (mtu > 1472) { // TODO: magic constant
|
||||
mtu = 1472;
|
||||
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes");
|
||||
}
|
||||
}
|
||||
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateStats ()
|
||||
{
|
||||
if (m_IsFloodfill)
|
||||
{
|
||||
// update routers and leasesets
|
||||
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
|
||||
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterContext::Load ()
|
||||
{
|
||||
std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||
if (!fk.is_open ()) return false;
|
||||
fk.seekg (0, std::ios::end);
|
||||
size_t len = fk.tellg();
|
||||
fk.seekg (0, std::ios::beg);
|
||||
|
||||
if (len == sizeof (i2p::data::Keys)) // old keys file format
|
||||
{
|
||||
i2p::data::Keys keys;
|
||||
fk.read ((char *)&keys, sizeof (keys));
|
||||
m_Keys = keys;
|
||||
}
|
||||
else // new keys file format
|
||||
{
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
fk.read ((char *)buf, len);
|
||||
m_Keys.FromBuffer (buf, len);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); // TODO
|
||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
|
||||
m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
|
||||
|
||||
// Migration to 0.9.24. TODO: remove later
|
||||
m_RouterInfo.DeleteProperty ("coreVersion");
|
||||
m_RouterInfo.DeleteProperty ("stat_uptime");
|
||||
|
||||
if (IsUnreachable ())
|
||||
SetReachable (); // we assume reachable until we discover firewall through peer tests
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RouterContext::SaveKeys ()
|
||||
{
|
||||
// save in the same format as .dat files
|
||||
std::ofstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ofstream::binary | std::ofstream::out);
|
||||
size_t len = m_Keys.GetFullLen ();
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
m_Keys.ToBuffer (buf, len);
|
||||
fk.write ((char *)buf, len);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> RouterContext::GetTunnelPool () const
|
||||
{
|
||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
}
|
||||
|
||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
{
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
|
||||
}
|
||||
|
||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
|
||||
}
|
||||
|
||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||
}
|
||||
|
||||
uint32_t RouterContext::GetUptime () const
|
||||
{
|
||||
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
|
||||
}
|
||||
}
|
||||
108
RouterContext.h
@@ -1,108 +0,0 @@
|
||||
#ifndef ROUTER_CONTEXT_H__
|
||||
#define ROUTER_CONTEXT_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "Garlic.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
const char ROUTER_INFO[] = "router.info";
|
||||
const char ROUTER_KEYS[] = "router.keys";
|
||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||
|
||||
enum RouterStatus
|
||||
{
|
||||
eRouterStatusOK = 0,
|
||||
eRouterStatusTesting = 1,
|
||||
eRouterStatusFirewalled = 2
|
||||
};
|
||||
|
||||
class RouterContext: public i2p::garlic::GarlicDestination
|
||||
{
|
||||
public:
|
||||
|
||||
RouterContext ();
|
||||
void Init ();
|
||||
|
||||
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
|
||||
{
|
||||
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
|
||||
[](const i2p::data::RouterInfo *) {});
|
||||
}
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
|
||||
{
|
||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||
[](i2p::garlic::GarlicDestination *) {});
|
||||
}
|
||||
|
||||
uint32_t GetUptime () const;
|
||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
RouterStatus GetStatus () const { return m_Status; };
|
||||
void SetStatus (RouterStatus status);
|
||||
|
||||
void UpdatePort (int port); // called from Daemon
|
||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||
bool IsUnreachable () const;
|
||||
void SetUnreachable ();
|
||||
void SetReachable ();
|
||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||
void SetFloodfill (bool floodfill);
|
||||
void SetFamily (const std::string& family);
|
||||
void SetHighBandwidth ();
|
||||
void SetLowBandwidth ();
|
||||
void SetExtraBandwidth ();
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
void SetSupportsV6 (bool supportsV6);
|
||||
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
|
||||
void UpdateStats ();
|
||||
|
||||
// implements LocalDestination
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); };
|
||||
const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetStandardIdentity ().publicKey; };
|
||||
void SetLeaseSetUpdated () {};
|
||||
|
||||
// implements GarlicDestination
|
||||
std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () { return nullptr; };
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||
|
||||
// override GarlicDestination
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
private:
|
||||
|
||||
void CreateNewRouter ();
|
||||
void NewRouterInfo ();
|
||||
void UpdateRouterInfo ();
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::RouterInfo m_RouterInfo;
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
uint64_t m_LastUpdateTime;
|
||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||
uint64_t m_StartupTime; // in seconds since epoch
|
||||
RouterStatus m_Status;
|
||||
std::mutex m_GarlicMutex;
|
||||
};
|
||||
|
||||
extern RouterContext context;
|
||||
}
|
||||
|
||||
#endif
|
||||
729
RouterInfo.cpp
@@ -1,729 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "I2PEndian.h"
|
||||
#include <fstream>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "version.h"
|
||||
#include "Crypto.h"
|
||||
#include "Base.h"
|
||||
#include "Timestamp.h"
|
||||
#include "Log.h"
|
||||
#include "NetDb.h"
|
||||
#include "RouterInfo.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
RouterInfo::RouterInfo (const std::string& fullPath):
|
||||
m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false),
|
||||
m_SupportedTransports (0), m_Caps (0)
|
||||
{
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
ReadFromFile ();
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
||||
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
|
||||
{
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
ReadFromBuffer (true);
|
||||
}
|
||||
|
||||
RouterInfo::~RouterInfo ()
|
||||
{
|
||||
delete[] m_Buffer;
|
||||
}
|
||||
|
||||
void RouterInfo::Update (const uint8_t * buf, int len)
|
||||
{
|
||||
// verify signature since we have indentity already
|
||||
int l = len - m_RouterIdentity->GetSignatureLen ();
|
||||
if (m_RouterIdentity->Verify (buf, l, buf + l))
|
||||
{
|
||||
// clean up
|
||||
m_IsUpdated = true;
|
||||
m_IsUnreachable = false;
|
||||
m_SupportedTransports = 0;
|
||||
m_Caps = 0;
|
||||
m_Addresses.clear ();
|
||||
m_Properties.clear ();
|
||||
// copy buffer
|
||||
if (!m_Buffer)
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
// skip identity
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
// read new RI
|
||||
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
|
||||
ReadFromStream (str);
|
||||
// don't delete buffer until saved to the file
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
|
||||
{
|
||||
m_RouterIdentity = identity;
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
bool RouterInfo::LoadFile ()
|
||||
{
|
||||
std::ifstream s(m_FullPath.c_str (), std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0,std::ios::end);
|
||||
m_BufferLen = s.tellg ();
|
||||
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
LogPrint(eLogError, "RouterInfo: File", m_FullPath, " is malformed");
|
||||
return false;
|
||||
}
|
||||
s.seekg(0, std::ios::beg);
|
||||
if (!m_Buffer)
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
s.read((char *)m_Buffer, m_BufferLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromFile ()
|
||||
{
|
||||
if (LoadFile ())
|
||||
ReadFromBuffer (false);
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromBuffer (bool verifySignature)
|
||||
{
|
||||
m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
if (identityLen >= m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
|
||||
ReadFromStream (str);
|
||||
if (!str)
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: malformed message");
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
if (verifySignature)
|
||||
{
|
||||
// verify signature
|
||||
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
|
||||
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
m_RouterIdentity->DropVerifier ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromStream (std::istream& s)
|
||||
{
|
||||
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
||||
m_Timestamp = be64toh (m_Timestamp);
|
||||
// read addresses
|
||||
uint8_t numAddresses;
|
||||
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
|
||||
bool introducers = false;
|
||||
for (int i = 0; i < numAddresses; i++)
|
||||
{
|
||||
uint8_t supportedTransports = 0;
|
||||
bool isValidAddress = true;
|
||||
Address address;
|
||||
s.read ((char *)&address.cost, sizeof (address.cost));
|
||||
s.read ((char *)&address.date, sizeof (address.date));
|
||||
char transportStyle[5];
|
||||
ReadString (transportStyle, s);
|
||||
if (!strcmp (transportStyle, "NTCP"))
|
||||
address.transportStyle = eTransportNTCP;
|
||||
else if (!strcmp (transportStyle, "SSU"))
|
||||
address.transportStyle = eTransportSSU;
|
||||
else
|
||||
address.transportStyle = eTransportUnknown;
|
||||
address.port = 0;
|
||||
address.mtu = 0;
|
||||
uint16_t size, r = 0;
|
||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
char key[500], value[500];
|
||||
r += ReadString (key, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // =
|
||||
r += ReadString (value, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // ;
|
||||
if (!strcmp (key, "host"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
address.host = boost::asio::ip::address::from_string (value, ecode);
|
||||
if (ecode)
|
||||
{
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
{
|
||||
supportedTransports |= eNTCPV4; // TODO:
|
||||
address.addressString = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
supportedTransports |= eSSUV4; // TODO:
|
||||
address.addressString = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add supported protocol
|
||||
if (address.host.is_v4 ())
|
||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||
else
|
||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "port"))
|
||||
address.port = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "mtu"))
|
||||
address.mtu = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "key"))
|
||||
Base64ToByteStream (value, strlen (value), address.key, 32);
|
||||
else if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
else if (key[0] == 'i')
|
||||
{
|
||||
// introducers
|
||||
introducers = true;
|
||||
size_t l = strlen(key);
|
||||
unsigned char index = key[l-1] - '0'; // TODO:
|
||||
key[l-1] = 0;
|
||||
if (index >= address.introducers.size ())
|
||||
address.introducers.resize (index + 1);
|
||||
Introducer& introducer = address.introducers.at (index);
|
||||
if (!strcmp (key, "ihost"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
|
||||
}
|
||||
else if (!strcmp (key, "iport"))
|
||||
introducer.iPort = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "itag"))
|
||||
introducer.iTag = boost::lexical_cast<uint32_t>(value);
|
||||
else if (!strcmp (key, "ikey"))
|
||||
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
|
||||
}
|
||||
if (!s) return;
|
||||
}
|
||||
if (isValidAddress)
|
||||
{
|
||||
m_Addresses.push_back(address);
|
||||
m_SupportedTransports |= supportedTransports;
|
||||
}
|
||||
}
|
||||
// read peers
|
||||
uint8_t numPeers;
|
||||
s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return;
|
||||
s.seekg (numPeers*32, std::ios_base::cur); // TODO: read peers
|
||||
// read properties
|
||||
uint16_t size, r = 0;
|
||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char key[500], value[500];
|
||||
// TODO: investigate why properties get read as one long string under Windows
|
||||
// length should not be more than 44
|
||||
#else
|
||||
char key[50], value[50];
|
||||
#endif
|
||||
r += ReadString (key, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // =
|
||||
r += ReadString (value, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // ;
|
||||
m_Properties[key] = value;
|
||||
|
||||
// extract caps
|
||||
if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
// check netId
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != I2PD_NET_ID)
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
// family
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
|
||||
{
|
||||
m_Family = value;
|
||||
boost::to_lower (m_Family);
|
||||
}
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY_SIG))
|
||||
{
|
||||
if (!netdb.GetFamilies ().VerifyFamily (m_Family, GetIdentHash (), value))
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: family signature verification failed");
|
||||
m_Family.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!s) return;
|
||||
}
|
||||
|
||||
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
|
||||
SetUnreachable (true);
|
||||
}
|
||||
|
||||
void RouterInfo::ExtractCaps (const char * value)
|
||||
{
|
||||
const char * cap = value;
|
||||
while (*cap)
|
||||
{
|
||||
switch (*cap)
|
||||
{
|
||||
case CAPS_FLAG_FLOODFILL:
|
||||
m_Caps |= Caps::eFloodfill;
|
||||
break;
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH1:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH2:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH3:
|
||||
m_Caps |= Caps::eHighBandwidth;
|
||||
break;
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
||||
m_Caps |= Caps::eExtraBandwidth;
|
||||
break;
|
||||
case CAPS_FLAG_HIDDEN:
|
||||
m_Caps |= Caps::eHidden;
|
||||
break;
|
||||
case CAPS_FLAG_REACHABLE:
|
||||
m_Caps |= Caps::eReachable;
|
||||
break;
|
||||
case CAPS_FLAG_UNREACHABLE:
|
||||
m_Caps |= Caps::eUnreachable;
|
||||
break;
|
||||
case CAPS_FLAG_SSU_TESTING:
|
||||
m_Caps |= Caps::eSSUTesting;
|
||||
break;
|
||||
case CAPS_FLAG_SSU_INTRODUCER:
|
||||
m_Caps |= Caps::eSSUIntroducer;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
cap++;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateCapsProperty ()
|
||||
{
|
||||
std::string caps;
|
||||
if (m_Caps & eFloodfill)
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1;
|
||||
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
|
||||
}
|
||||
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
|
||||
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
|
||||
|
||||
SetProperty ("caps", caps.c_str ());
|
||||
}
|
||||
|
||||
void RouterInfo::WriteToStream (std::ostream& s)
|
||||
{
|
||||
uint64_t ts = htobe64 (m_Timestamp);
|
||||
s.write ((char *)&ts, sizeof (ts));
|
||||
|
||||
// addresses
|
||||
uint8_t numAddresses = m_Addresses.size ();
|
||||
s.write ((char *)&numAddresses, sizeof (numAddresses));
|
||||
for (auto& address : m_Addresses)
|
||||
{
|
||||
s.write ((char *)&address.cost, sizeof (address.cost));
|
||||
s.write ((char *)&address.date, sizeof (address.date));
|
||||
std::stringstream properties;
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
WriteString ("NTCP", s);
|
||||
else if (address.transportStyle == eTransportSSU)
|
||||
{
|
||||
WriteString ("SSU", s);
|
||||
// caps
|
||||
WriteString ("caps", properties);
|
||||
properties << '=';
|
||||
std::string caps;
|
||||
if (IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
|
||||
if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
||||
WriteString (caps, properties);
|
||||
properties << ';';
|
||||
}
|
||||
else
|
||||
WriteString ("", s);
|
||||
|
||||
WriteString ("host", properties);
|
||||
properties << '=';
|
||||
WriteString (address.host.to_string (), properties);
|
||||
properties << ';';
|
||||
if (address.transportStyle == eTransportSSU)
|
||||
{
|
||||
// write introducers if any
|
||||
if (address.introducers.size () > 0)
|
||||
{
|
||||
int i = 0;
|
||||
for (auto introducer: address.introducers)
|
||||
{
|
||||
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
WriteString (introducer.iHost.to_string (), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (auto introducer: address.introducers)
|
||||
{
|
||||
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
char value[64];
|
||||
size_t l = ByteStreamToBase64 (introducer.iKey, 32, value, 64);
|
||||
value[l] = 0;
|
||||
WriteString (value, properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (auto introducer: address.introducers)
|
||||
{
|
||||
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (auto introducer: address.introducers)
|
||||
{
|
||||
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// write intro key
|
||||
WriteString ("key", properties);
|
||||
properties << '=';
|
||||
char value[64];
|
||||
size_t l = ByteStreamToBase64 (address.key, 32, value, 64);
|
||||
value[l] = 0;
|
||||
WriteString (value, properties);
|
||||
properties << ';';
|
||||
// write mtu
|
||||
if (address.mtu)
|
||||
{
|
||||
WriteString ("mtu", properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(address.mtu), properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
WriteString ("port", properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(address.port), properties);
|
||||
properties << ';';
|
||||
|
||||
uint16_t size = htobe16 (properties.str ().size ());
|
||||
s.write ((char *)&size, sizeof (size));
|
||||
s.write (properties.str ().c_str (), properties.str ().size ());
|
||||
}
|
||||
|
||||
// peers
|
||||
uint8_t numPeers = 0;
|
||||
s.write ((char *)&numPeers, sizeof (numPeers));
|
||||
|
||||
// properties
|
||||
std::stringstream properties;
|
||||
for (auto& p : m_Properties)
|
||||
{
|
||||
WriteString (p.first, properties);
|
||||
properties << '=';
|
||||
WriteString (p.second, properties);
|
||||
properties << ';';
|
||||
}
|
||||
uint16_t size = htobe16 (properties.str ().size ());
|
||||
s.write ((char *)&size, sizeof (size));
|
||||
s.write (properties.str ().c_str (), properties.str ().size ());
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
if (!m_RouterIdentity) return false;
|
||||
size_t size = m_RouterIdentity->GetFullLen ();
|
||||
if (size + 8 > len) return false;
|
||||
return bufbe64toh (buf + size) > m_Timestamp;
|
||||
}
|
||||
|
||||
const uint8_t * RouterInfo::LoadBuffer ()
|
||||
{
|
||||
if (!m_Buffer)
|
||||
{
|
||||
if (LoadFile ())
|
||||
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
|
||||
}
|
||||
return m_Buffer;
|
||||
}
|
||||
|
||||
void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
|
||||
{
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
|
||||
std::stringstream s;
|
||||
uint8_t ident[1024];
|
||||
auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
|
||||
s.write ((char *)ident, identLen);
|
||||
WriteToStream (s);
|
||||
m_BufferLen = s.str ().size ();
|
||||
if (!m_Buffer)
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
memcpy (m_Buffer, s.str ().c_str (), m_BufferLen);
|
||||
// signature
|
||||
privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
|
||||
m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen ();
|
||||
}
|
||||
|
||||
void RouterInfo::SaveToFile (const std::string& fullPath)
|
||||
{
|
||||
m_FullPath = fullPath;
|
||||
if (m_Buffer)
|
||||
{
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
if (f.is_open ())
|
||||
f.write ((char *)m_Buffer, m_BufferLen);
|
||||
else
|
||||
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||
}
|
||||
|
||||
size_t RouterInfo::ReadString (char * str, std::istream& s)
|
||||
{
|
||||
uint8_t len;
|
||||
s.read ((char *)&len, 1);
|
||||
s.read (str, len);
|
||||
str[len] = 0;
|
||||
return len+1;
|
||||
}
|
||||
|
||||
void RouterInfo::WriteString (const std::string& str, std::ostream& s)
|
||||
{
|
||||
uint8_t len = str.size ();
|
||||
s.write ((char *)&len, 1);
|
||||
s.write (str.c_str (), len);
|
||||
}
|
||||
|
||||
void RouterInfo::AddNTCPAddress (const char * host, int port)
|
||||
{
|
||||
Address addr;
|
||||
addr.host = boost::asio::ip::address::from_string (host);
|
||||
addr.port = port;
|
||||
addr.transportStyle = eTransportNTCP;
|
||||
addr.cost = 2;
|
||||
addr.date = 0;
|
||||
addr.mtu = 0;
|
||||
for (auto it: m_Addresses) // don't insert same address twice
|
||||
if (it == addr) return;
|
||||
m_Addresses.push_back(addr);
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4;
|
||||
}
|
||||
|
||||
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
|
||||
{
|
||||
Address addr;
|
||||
addr.host = boost::asio::ip::address::from_string (host);
|
||||
addr.port = port;
|
||||
addr.transportStyle = eTransportSSU;
|
||||
addr.cost = 10; // NTCP should have priority over SSU
|
||||
addr.date = 0;
|
||||
addr.mtu = mtu;
|
||||
memcpy (addr.key, key, 32);
|
||||
for (auto it: m_Addresses) // don't insert same address twice
|
||||
if (it == addr) return;
|
||||
m_Addresses.push_back(addr);
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eSSUV6 : eSSUV4;
|
||||
m_Caps |= eSSUTesting;
|
||||
m_Caps |= eSSUIntroducer;
|
||||
}
|
||||
|
||||
bool RouterInfo::AddIntroducer (const Introducer& introducer)
|
||||
{
|
||||
for (auto& addr : m_Addresses)
|
||||
{
|
||||
if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ())
|
||||
{
|
||||
for (auto intro: addr.introducers)
|
||||
if (intro.iTag == introducer.iTag) return false; // already presented
|
||||
addr.introducers.push_back (introducer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
||||
{
|
||||
for (auto& addr : m_Addresses)
|
||||
{
|
||||
if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ())
|
||||
{
|
||||
for (std::vector<Introducer>::iterator it = addr.introducers.begin (); it != addr.introducers.end (); it++)
|
||||
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
|
||||
{
|
||||
addr.introducers.erase (it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RouterInfo::SetCaps (uint8_t caps)
|
||||
{
|
||||
m_Caps = caps;
|
||||
UpdateCapsProperty ();
|
||||
}
|
||||
|
||||
void RouterInfo::SetCaps (const char * caps)
|
||||
{
|
||||
SetProperty ("caps", caps);
|
||||
m_Caps = 0;
|
||||
ExtractCaps (caps);
|
||||
}
|
||||
|
||||
void RouterInfo::SetProperty (const std::string& key, const std::string& value)
|
||||
{
|
||||
m_Properties[key] = value;
|
||||
}
|
||||
|
||||
void RouterInfo::DeleteProperty (const std::string& key)
|
||||
{
|
||||
m_Properties.erase (key);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNTCP (bool v4only) const
|
||||
{
|
||||
if (v4only)
|
||||
return m_SupportedTransports & eNTCPV4;
|
||||
else
|
||||
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU (bool v4only) const
|
||||
{
|
||||
if (v4only)
|
||||
return m_SupportedTransports & eSSUV4;
|
||||
else
|
||||
return m_SupportedTransports & (eSSUV4 | eSSUV6);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsV6 () const
|
||||
{
|
||||
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
|
||||
}
|
||||
|
||||
void RouterInfo::EnableV6 ()
|
||||
{
|
||||
if (!IsV6 ())
|
||||
m_SupportedTransports |= eNTCPV6 | eSSUV6;
|
||||
}
|
||||
|
||||
void RouterInfo::DisableV6 ()
|
||||
{
|
||||
if (IsV6 ())
|
||||
{
|
||||
// NTCP
|
||||
m_SupportedTransports &= ~eNTCPV6;
|
||||
for (size_t i = 0; i < m_Addresses.size (); i++)
|
||||
{
|
||||
if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP &&
|
||||
m_Addresses[i].host.is_v6 ())
|
||||
{
|
||||
m_Addresses.erase (m_Addresses.begin () + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SSU
|
||||
m_SupportedTransports &= ~eSSUV6;
|
||||
for (size_t i = 0; i < m_Addresses.size (); i++)
|
||||
{
|
||||
if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU &&
|
||||
m_Addresses[i].host.is_v6 ())
|
||||
{
|
||||
m_Addresses.erase (m_Addresses.begin () + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::UsesIntroducer () const
|
||||
{
|
||||
return m_Caps & Caps::eUnreachable; // non-reachable
|
||||
}
|
||||
|
||||
const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const
|
||||
{
|
||||
return GetAddress (eTransportNTCP, v4only);
|
||||
}
|
||||
|
||||
const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const
|
||||
{
|
||||
return GetAddress (eTransportSSU, v4only);
|
||||
}
|
||||
|
||||
const RouterInfo::Address * RouterInfo::GetSSUV6Address () const
|
||||
{
|
||||
return GetAddress (eTransportSSU, false, true);
|
||||
}
|
||||
|
||||
const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
|
||||
{
|
||||
for (auto& address : m_Addresses)
|
||||
{
|
||||
if (address.transportStyle == s)
|
||||
{
|
||||
if ((!v4only || address.host.is_v4 ()) && (!v6only || address.host.is_v6 ()))
|
||||
return &address;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
|
||||
{
|
||||
if (!m_Profile)
|
||||
m_Profile = GetRouterProfile (GetIdentHash ());
|
||||
return m_Profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
486
Signature.cpp
@@ -1,486 +0,0 @@
|
||||
#include <memory>
|
||||
#include "Log.h"
|
||||
#include "Signature.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
class Ed25519
|
||||
{
|
||||
public:
|
||||
|
||||
Ed25519 ()
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * tmp = BN_new ();
|
||||
|
||||
q = BN_new ();
|
||||
// 2^255-19
|
||||
BN_set_bit (q, 255); // 2^255
|
||||
BN_sub_word (q, 19);
|
||||
|
||||
l = BN_new ();
|
||||
// 2^252 + 27742317777372353535851937790883648493
|
||||
BN_set_bit (l, 252);
|
||||
two_252_2 = BN_dup (l);
|
||||
BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
|
||||
BN_add (l, l, tmp);
|
||||
BN_sub_word (two_252_2, 2); // 2^252 - 2
|
||||
|
||||
// -121665*inv(121666)
|
||||
d = BN_new ();
|
||||
BN_set_word (tmp, 121666);
|
||||
BN_mod_inverse (tmp, tmp, q, ctx);
|
||||
BN_set_word (d, 121665);
|
||||
BN_set_negative (d, 1);
|
||||
BN_mul (d, d, tmp, ctx);
|
||||
|
||||
// 2^((q-1)/4)
|
||||
I = BN_new ();
|
||||
BN_free (tmp);
|
||||
tmp = BN_dup (q);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_div_word (tmp, 4);
|
||||
BN_set_word (I, 2);
|
||||
BN_mod_exp (I, I, tmp, q, ctx);
|
||||
BN_free (tmp);
|
||||
|
||||
// 4*inv(5)
|
||||
BIGNUM * By = BN_new ();
|
||||
BN_set_word (By, 5);
|
||||
BN_mod_inverse (By, By, q, ctx);
|
||||
BN_mul_word (By, 4);
|
||||
BIGNUM * Bx = RecoverX (By, ctx);
|
||||
BN_mod (Bx, Bx, q, ctx); // % q
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
|
||||
// precalculate Bi256 table
|
||||
Bi256Carry = { Bx, By }; // B
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
Bi256[i][0] = Bi256Carry; // first point
|
||||
for (int j = 1; j < 128; j++)
|
||||
Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B
|
||||
Bi256Carry = Bi256[i][127];
|
||||
for (int j = 0; j < 128; j++) // add first point 128 more times
|
||||
Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx);
|
||||
}
|
||||
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
|
||||
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
|
||||
Bi256Carry (other.Bi256Carry)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int j = 0; j < 128; j++)
|
||||
Bi256[i][j] = other.Bi256[i][j];
|
||||
}
|
||||
|
||||
~Ed25519 ()
|
||||
{
|
||||
BN_free (q);
|
||||
BN_free (l);
|
||||
BN_free (d);
|
||||
BN_free (I);
|
||||
BN_free (two_252_2);
|
||||
}
|
||||
|
||||
|
||||
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const
|
||||
{
|
||||
return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian
|
||||
}
|
||||
|
||||
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const
|
||||
{
|
||||
return DecodePoint (buf, ctx);
|
||||
}
|
||||
|
||||
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const
|
||||
{
|
||||
EncodePoint (Normalize (publicKey, ctx), buf);
|
||||
}
|
||||
|
||||
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// signature 0..31 - R, 32..63 - S
|
||||
// B*S = R + PK*h => R = B*S - PK*h
|
||||
// we don't decode R, but encode (B*S - PK*h)
|
||||
auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
|
||||
BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0
|
||||
auto PKh = Mul (publicKey, h, ctx); // PK*h
|
||||
uint8_t diff[32];
|
||||
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
|
||||
bool passed = !memcmp (signature, diff, 32); // R
|
||||
BN_free (h);
|
||||
BN_CTX_free (ctx);
|
||||
if (!passed)
|
||||
LogPrint (eLogError, "25519 signature verification failed");
|
||||
return passed;
|
||||
}
|
||||
|
||||
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
|
||||
uint8_t * signature) const
|
||||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
// calculate r
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
uint8_t digest[64];
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
|
||||
// calculate R
|
||||
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
|
||||
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors
|
||||
// calculate S
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
|
||||
BN_mod_mul (h, h, a, l, bnCtx); // %l
|
||||
BN_mod_add (h, h, r, l, bnCtx); // %l
|
||||
memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
|
||||
EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
|
||||
BN_free (r); BN_free (h); BN_free (a);
|
||||
BN_CTX_free (bnCtx);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
|
||||
{
|
||||
// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
|
||||
// y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2)
|
||||
// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
|
||||
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
|
||||
BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
|
||||
|
||||
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
|
||||
BIGNUM * t1 = p1.t, * t2 = p2.t;
|
||||
if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); }
|
||||
if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); }
|
||||
BN_mul (t3, t1, t2, ctx);
|
||||
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
|
||||
if (!p1.t) BN_free (t1);
|
||||
if (!p2.t) BN_free (t2);
|
||||
|
||||
if (p1.z)
|
||||
{
|
||||
if (p2.z)
|
||||
BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2
|
||||
else
|
||||
BN_copy (z3, p1.z); // D = z1
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p2.z)
|
||||
BN_copy (z3, p2.z); // D = z2
|
||||
else
|
||||
BN_one (z3); // D = 1
|
||||
}
|
||||
|
||||
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
|
||||
BN_add (E, p1.x, p1.y);
|
||||
BN_add (F, p2.x, p2.y);
|
||||
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub (E, E, x3);
|
||||
BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
|
||||
BN_sub (F, z3, t3); // F = D - C
|
||||
BN_add (G, z3, t3); // G = D + C
|
||||
BN_add (H, y3, x3); // H = B + A
|
||||
|
||||
BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
|
||||
BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
|
||||
BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G
|
||||
BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H
|
||||
|
||||
BN_free (E); BN_free (F); BN_free (G); BN_free (H);
|
||||
|
||||
return EDDSAPoint {x3, y3, z3, t3};
|
||||
}
|
||||
|
||||
EDDSAPoint Double (const EDDSAPoint& p, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * x2 = BN_new (), * y2 = BN_new (), * z2 = BN_new (), * t2 = BN_new ();
|
||||
|
||||
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
|
||||
if (p.t)
|
||||
BN_sqr (t2, p.t, ctx); // t2 = t^2
|
||||
else
|
||||
{
|
||||
BN_mul (t2, p.x, p.y, ctx); // t = x*y
|
||||
BN_sqr (t2, t2, ctx); // t2 = t^2
|
||||
}
|
||||
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
|
||||
if (p.z)
|
||||
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
|
||||
else
|
||||
BN_one (z2); // z2 = 1
|
||||
|
||||
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
|
||||
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
|
||||
BN_mul (E, p.x, p.y, ctx);
|
||||
BN_lshift1 (E, E); // E =2*x*y
|
||||
BN_sub (F, z2, t2); // F = D - C
|
||||
BN_add (G, z2, t2); // G = D + C
|
||||
BN_add (H, y2, x2); // H = B + A
|
||||
|
||||
BN_mod_mul (x2, E, F, q, ctx); // x2 = E*F
|
||||
BN_mod_mul (y2, G, H, q, ctx); // y2 = G*H
|
||||
BN_mod_mul (z2, F, G, q, ctx); // z2 = F*G
|
||||
BN_mod_mul (t2, E, H, q, ctx); // t2 = E*H
|
||||
|
||||
BN_free (E); BN_free (F); BN_free (G); BN_free (H);
|
||||
|
||||
return EDDSAPoint {x2, y2, z2, t2};
|
||||
}
|
||||
|
||||
EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * zero = BN_new (), * one = BN_new ();
|
||||
BN_zero (zero); BN_one (one);
|
||||
EDDSAPoint res {zero, one};
|
||||
if (!BN_is_zero (e))
|
||||
{
|
||||
int bitCount = BN_num_bits (e);
|
||||
for (int i = bitCount - 1; i >= 0; i--)
|
||||
{
|
||||
res = Double (res, ctx);
|
||||
if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
|
||||
{
|
||||
BIGNUM * zero = BN_new (), * one = BN_new ();
|
||||
BN_zero (zero); BN_one (one);
|
||||
EDDSAPoint res {zero, one};
|
||||
bool carry = false;
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
uint8_t x = e[i];
|
||||
if (carry)
|
||||
{
|
||||
if (x < 255)
|
||||
{
|
||||
x++;
|
||||
carry = false;
|
||||
}
|
||||
else
|
||||
x = 0;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
if (x <= 128)
|
||||
res = Sum (res, Bi256[i][x-1], ctx);
|
||||
else
|
||||
{
|
||||
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
|
||||
carry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (carry) res = Sum (res, Bi256Carry, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const
|
||||
{
|
||||
if (p.z)
|
||||
{
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
BN_mod_inverse (y, p.z, q, ctx);
|
||||
BN_mod_mul (x, p.x, y, q, ctx); // x = x/z
|
||||
BN_mod_mul (y, p.y, y, q, ctx); // y = y/z
|
||||
return EDDSAPoint{x, y};
|
||||
}
|
||||
else
|
||||
return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)};
|
||||
}
|
||||
|
||||
bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * x2 = BN_new ();
|
||||
BN_sqr (x2, p.x, ctx); // x^2
|
||||
BIGNUM * y2 = BN_new ();
|
||||
BN_sqr (y2, p.y, ctx); // y^2
|
||||
// y^2 - x^2 - 1 - d*x^2*y^2
|
||||
BIGNUM * tmp = BN_new ();
|
||||
BN_mul (tmp, d, x2, ctx);
|
||||
BN_mul (tmp, tmp, y2, ctx);
|
||||
BN_sub (tmp, y2, tmp);
|
||||
BN_sub (tmp, tmp, x2);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_mod (tmp, tmp, q, ctx); // % q
|
||||
bool ret = BN_is_zero (tmp);
|
||||
BN_free (x2);
|
||||
BN_free (y2);
|
||||
BN_free (tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * y2 = BN_new ();
|
||||
BN_sqr (y2, y, ctx); // y^2
|
||||
// xx = (y^2 -1)*inv(d*y^2 +1)
|
||||
BIGNUM * xx = BN_new ();
|
||||
BN_mul (xx, d, y2, ctx);
|
||||
BN_add_word (xx, 1);
|
||||
BN_mod_inverse (xx, xx, q, ctx);
|
||||
BN_sub_word (y2, 1);
|
||||
BN_mul (xx, y2, xx, ctx);
|
||||
// x = srqt(xx) = xx^(2^252-2)
|
||||
BIGNUM * x = BN_new ();
|
||||
BN_mod_exp (x, xx, two_252_2, q, ctx);
|
||||
// check (x^2 -xx) % q
|
||||
BN_sqr (y2, x, ctx);
|
||||
BN_mod_sub (y2, y2, xx, q, ctx);
|
||||
if (!BN_is_zero (y2))
|
||||
BN_mod_mul (x, x, I, q, ctx);
|
||||
if (BN_is_odd (x))
|
||||
BN_sub (x, q, x);
|
||||
BN_free (y2);
|
||||
BN_free (xx);
|
||||
return x;
|
||||
}
|
||||
|
||||
EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const
|
||||
{
|
||||
// buf is 32 bytes Little Endian, convert it to Big Endian
|
||||
uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes
|
||||
{
|
||||
buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i];
|
||||
buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i];
|
||||
}
|
||||
bool isHighestBitSet = buf1[0] & 0x80;
|
||||
if (isHighestBitSet)
|
||||
buf1[0] &= 0x7f; // clear highest bit
|
||||
BIGNUM * y = BN_new ();
|
||||
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
|
||||
auto x = RecoverX (y, ctx);
|
||||
if (BN_is_bit_set (x, 0) != isHighestBitSet)
|
||||
BN_sub (x, q, x); // x = q - x
|
||||
BIGNUM * z = BN_new (), * t = BN_new ();
|
||||
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
|
||||
EDDSAPoint p {x, y, z, t};
|
||||
if (!IsOnCurve (p, ctx))
|
||||
LogPrint (eLogError, "Decoded point is not on 25519");
|
||||
return p;
|
||||
}
|
||||
|
||||
void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const
|
||||
{
|
||||
EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
if (BN_is_bit_set (p.x, 0)) // highest bit
|
||||
buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
|
||||
}
|
||||
|
||||
template<int len>
|
||||
BIGNUM * DecodeBN (const uint8_t * buf) const
|
||||
{
|
||||
// buf is Little Endian convert it to Big Endian
|
||||
uint8_t buf1[len];
|
||||
for (size_t i = 0; i < len/2; i++) // invert bytes
|
||||
{
|
||||
buf1[i] = buf[len -1 - i];
|
||||
buf1[len -1 - i] = buf[i];
|
||||
}
|
||||
BIGNUM * res = BN_new ();
|
||||
BN_bin2bn (buf1, len, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const
|
||||
{
|
||||
bn2buf (bn, buf, len);
|
||||
// To Little Endian
|
||||
for (size_t i = 0; i < len/2; i++) // invert bytes
|
||||
{
|
||||
uint8_t tmp = buf[i];
|
||||
buf[i] = buf[len -1 - i];
|
||||
buf[len -1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
// transient values
|
||||
BIGNUM * two_252_2; // 2^252-2
|
||||
EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes
|
||||
// if j > 128 we use 256 - j and carry 1 to next byte
|
||||
// Bi256[0][0] = B, base point
|
||||
EDDSAPoint Bi256Carry; // Bi256[32][0]
|
||||
};
|
||||
|
||||
static std::unique_ptr<Ed25519> g_Ed25519;
|
||||
std::unique_ptr<Ed25519>& GetEd25519 ()
|
||||
{
|
||||
if (!g_Ed25519)
|
||||
g_Ed25519.reset (new Ed25519());
|
||||
|
||||
return g_Ed25519;
|
||||
}
|
||||
|
||||
|
||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
|
||||
{
|
||||
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[64];
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
|
||||
}
|
||||
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
// expand key
|
||||
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
|
||||
m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x1F; // drop first 3 bits
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
|
||||
// generate and encode public key
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
586
Transports.cpp
@@ -1,586 +0,0 @@
|
||||
#include <openssl/dh.h>
|
||||
#include "Log.h"
|
||||
#include "Crypto.h"
|
||||
#include "RouterContext.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "NetDb.h"
|
||||
#include "Transports.h"
|
||||
|
||||
using namespace i2p::data;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
DHKeysPairSupplier::DHKeysPairSupplier (int size):
|
||||
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DHKeysPairSupplier::~DHKeysPairSupplier ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::Start ()
|
||||
{
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&DHKeysPairSupplier::Run, this));
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::Stop ()
|
||||
{
|
||||
m_IsRunning = false;
|
||||
m_Acquired.notify_one ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
int num;
|
||||
while ((num = m_QueueSize - m_Queue.size ()) > 0)
|
||||
CreateDHKeysPairs (num);
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
m_Acquired.wait (l); // wait for element gets aquired
|
||||
}
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::CreateDHKeysPairs (int num)
|
||||
{
|
||||
if (num > 0)
|
||||
{
|
||||
i2p::crypto::DHKeys dh;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
|
||||
pair->GenerateKeys ();
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
m_Queue.push (pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::DHKeys> DHKeysPairSupplier::Acquire ()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
if (!m_Queue.empty ())
|
||||
{
|
||||
auto pair = m_Queue.front ();
|
||||
m_Queue.pop ();
|
||||
m_Acquired.notify_one ();
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
// queue is empty, create new
|
||||
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
|
||||
pair->GenerateKeys ();
|
||||
return pair;
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::Return (std::shared_ptr<i2p::crypto::DHKeys> pair)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
m_Queue.push (pair);
|
||||
}
|
||||
|
||||
Transports transports;
|
||||
|
||||
Transports::Transports ():
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service),
|
||||
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
|
||||
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_InBandwidth (0), m_OutBandwidth (0),
|
||||
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
|
||||
{
|
||||
}
|
||||
|
||||
Transports::~Transports ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void Transports::Start ()
|
||||
{
|
||||
m_DHKeysPairSupplier.Start ();
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||
// create acceptors
|
||||
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||
for (auto& address : addresses)
|
||||
{
|
||||
if (!m_NTCPServer)
|
||||
{
|
||||
m_NTCPServer = new NTCPServer ();
|
||||
m_NTCPServer->Start ();
|
||||
}
|
||||
|
||||
if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ())
|
||||
{
|
||||
if (!m_SSUServer)
|
||||
{
|
||||
m_SSUServer = new SSUServer (address.port);
|
||||
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address.port);
|
||||
m_SSUServer->Start ();
|
||||
DetectExternalIP ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Transports: SSU server already exists");
|
||||
}
|
||||
}
|
||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void Transports::Stop ()
|
||||
{
|
||||
m_PeerCleanupTimer.cancel ();
|
||||
m_Peers.clear ();
|
||||
if (m_SSUServer)
|
||||
{
|
||||
m_SSUServer->Stop ();
|
||||
delete m_SSUServer;
|
||||
m_SSUServer = nullptr;
|
||||
}
|
||||
if (m_NTCPServer)
|
||||
{
|
||||
m_NTCPServer->Stop ();
|
||||
delete m_NTCPServer;
|
||||
m_NTCPServer = nullptr;
|
||||
}
|
||||
|
||||
m_DHKeysPairSupplier.Stop ();
|
||||
m_IsRunning = false;
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Transports: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::UpdateBandwidth ()
|
||||
{
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (m_LastBandwidthUpdateTime > 0)
|
||||
{
|
||||
auto delta = ts - m_LastBandwidthUpdateTime;
|
||||
if (delta > 0)
|
||||
{
|
||||
m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
|
||||
m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
|
||||
}
|
||||
}
|
||||
m_LastBandwidthUpdateTime = ts;
|
||||
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
|
||||
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
|
||||
}
|
||||
|
||||
bool Transports::IsBandwidthExceeded () const
|
||||
{
|
||||
if (i2p::context.GetRouterInfo ().IsExtraBandwidth ()) return false;
|
||||
auto bw = std::max (m_InBandwidth, m_OutBandwidth);
|
||||
return bw > (i2p::context.GetRouterInfo ().IsHighBandwidth () ? HIGH_BANDWIDTH_LIMIT : LOW_BANDWIDTH_LIMIT);
|
||||
}
|
||||
|
||||
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
|
||||
}
|
||||
|
||||
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||
{
|
||||
m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
||||
}
|
||||
|
||||
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
|
||||
{
|
||||
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
|
||||
{
|
||||
// we send it to ourself
|
||||
for (auto it: msgs)
|
||||
i2p::HandleI2NPMessage (it);
|
||||
return;
|
||||
}
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it == m_Peers.end ())
|
||||
{
|
||||
bool connected = false;
|
||||
try
|
||||
{
|
||||
auto r = netdb.FindRouter (ident);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
||||
i2p::util::GetSecondsSinceEpoch (), {} })).first;
|
||||
}
|
||||
connected = ConnectToPeer (ident, it->second);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
|
||||
}
|
||||
if (!connected) return;
|
||||
}
|
||||
if (!it->second.sessions.empty ())
|
||||
it->second.sessions.front ()->SendI2NPMessages (msgs);
|
||||
else
|
||||
{
|
||||
for (auto it1: msgs)
|
||||
it->second.delayedMessages.push_back (it1);
|
||||
}
|
||||
}
|
||||
|
||||
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
||||
{
|
||||
if (peer.router) // we have RI already
|
||||
{
|
||||
if (!peer.numAttempts) // NTCP
|
||||
{
|
||||
peer.numAttempts++;
|
||||
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
||||
if (address)
|
||||
{
|
||||
#if BOOST_VERSION >= 104900
|
||||
if (!address->host.is_unspecified ()) // we have address now
|
||||
#else
|
||||
boost::system::error_code ecode;
|
||||
address->host.to_string (ecode);
|
||||
if (!ecode)
|
||||
#endif
|
||||
{
|
||||
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
|
||||
{
|
||||
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
||||
m_NTCPServer->Connect (address->host, address->port, s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else // we don't have address
|
||||
{
|
||||
if (address->addressString.length () > 0) // trying to resolve
|
||||
{
|
||||
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString);
|
||||
NTCPResolve (address->addressString, ident);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
|
||||
}
|
||||
if (peer.numAttempts == 1)// SSU
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
|
||||
{
|
||||
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
|
||||
#if BOOST_VERSION >= 104900
|
||||
if (!address->host.is_unspecified ()) // we have address now
|
||||
#else
|
||||
boost::system::error_code ecode;
|
||||
address->host.to_string (ecode);
|
||||
if (!ecode)
|
||||
#endif
|
||||
{
|
||||
m_SSUServer->CreateSession (peer.router, address->host, address->port);
|
||||
return true;
|
||||
}
|
||||
else // we don't have address
|
||||
{
|
||||
if (address->addressString.length () > 0) // trying to resolve
|
||||
{
|
||||
LogPrint (eLogDebug, "Transports: Resolving SSU ", address->addressString);
|
||||
SSUResolve (address->addressString, ident);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Transports: No NTCP or SSU addresses available");
|
||||
peer.Done ();
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (ident);
|
||||
return false;
|
||||
}
|
||||
else // otherwise request RI
|
||||
{
|
||||
LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested");
|
||||
i2p::data::netdb.RequestDestination (ident, std::bind (
|
||||
&Transports::RequestComplete, this, std::placeholders::_1, ident));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||
{
|
||||
m_Service.post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
||||
}
|
||||
|
||||
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
|
||||
{
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
if (r)
|
||||
{
|
||||
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, Trying to connect");
|
||||
it->second.router = r;
|
||||
ConnectToPeer (ident, it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Transports: RouterInfo not found, Failed to send messages");
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
|
||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
|
||||
std::bind (&Transports::HandleNTCPResolve, this,
|
||||
std::placeholders::_1, std::placeholders::_2, ident, resolver));
|
||||
}
|
||||
|
||||
void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||
{
|
||||
auto it1 = m_Peers.find (ident);
|
||||
if (it1 != m_Peers.end ())
|
||||
{
|
||||
auto& peer = it1->second;
|
||||
if (!ecode && peer.router)
|
||||
{
|
||||
auto address = (*it).endpoint ().address ();
|
||||
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
|
||||
auto addr = peer.router->GetNTCPAddress ();
|
||||
if (addr)
|
||||
{
|
||||
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
|
||||
m_NTCPServer->Connect (address, addr->port, s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ());
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (it1);
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
|
||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
|
||||
std::bind (&Transports::HandleSSUResolve, this,
|
||||
std::placeholders::_1, std::placeholders::_2, ident, resolver));
|
||||
}
|
||||
|
||||
void Transports::HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||
{
|
||||
auto it1 = m_Peers.find (ident);
|
||||
if (it1 != m_Peers.end ())
|
||||
{
|
||||
auto& peer = it1->second;
|
||||
if (!ecode && peer.router)
|
||||
{
|
||||
auto address = (*it).endpoint ().address ();
|
||||
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
|
||||
auto addr = peer.router->GetSSUAddress (!context.SupportsV6 ());;
|
||||
if (addr)
|
||||
{
|
||||
m_SSUServer->CreateSession (peer.router, address, addr->port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ());
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (it1);
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
|
||||
{
|
||||
if (!router) return;
|
||||
m_Service.post (std::bind (&Transports::PostCloseSession, this, router));
|
||||
}
|
||||
|
||||
void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
|
||||
{
|
||||
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
|
||||
if (ssuSession) // try SSU first
|
||||
{
|
||||
m_SSUServer->DeleteSession (ssuSession);
|
||||
LogPrint (eLogDebug, "Transports: SSU session closed");
|
||||
}
|
||||
// TODO: delete NTCP
|
||||
}
|
||||
|
||||
void Transports::DetectExternalIP ()
|
||||
{
|
||||
if (m_SSUServer)
|
||||
{
|
||||
i2p::context.SetStatus (eRouterStatusTesting);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
||||
if (router && router->IsSSU (!context.SupportsV6 ()))
|
||||
m_SSUServer->CreateSession (router, true); // peer test
|
||||
else
|
||||
{
|
||||
// if not peer test capable routers found pick any
|
||||
router = i2p::data::netdb.GetRandomRouter ();
|
||||
if (router && router->IsSSU ())
|
||||
m_SSUServer->CreateSession (router); // no peer test
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available");
|
||||
}
|
||||
|
||||
void Transports::PeerTest ()
|
||||
{
|
||||
if (m_SSUServer)
|
||||
{
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
||||
if (router && router->IsSSU (!context.SupportsV6 ()))
|
||||
{
|
||||
if (!statusChanged)
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatus (eRouterStatusTesting); // first time only
|
||||
}
|
||||
m_SSUServer->CreateSession (router, true); // peer test
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::DHKeys> Transports::GetNextDHKeysPair ()
|
||||
{
|
||||
return m_DHKeysPairSupplier.Acquire ();
|
||||
}
|
||||
|
||||
void Transports::ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair)
|
||||
{
|
||||
m_DHKeysPairSupplier.Return (pair);
|
||||
}
|
||||
|
||||
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
|
||||
{
|
||||
m_Service.post([session, this]()
|
||||
{
|
||||
auto remoteIdentity = session->GetRemoteIdentity ();
|
||||
if (!remoteIdentity) return;
|
||||
auto ident = remoteIdentity->GetIdentHash ();
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
it->second.sessions.push_back (session);
|
||||
session->SendI2NPMessages (it->second.delayedMessages);
|
||||
it->second.delayedMessages.clear ();
|
||||
}
|
||||
else // incoming connection
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
|
||||
{
|
||||
m_Service.post([session, this]()
|
||||
{
|
||||
auto remoteIdentity = session->GetRemoteIdentity ();
|
||||
if (!remoteIdentity) return;
|
||||
auto ident = remoteIdentity->GetIdentHash ();
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
it->second.sessions.remove (session);
|
||||
if (it->second.sessions.empty ()) // TODO: why?
|
||||
{
|
||||
if (it->second.delayedMessages.size () > 0)
|
||||
ConnectToPeer (ident, it->second);
|
||||
else
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
auto it = m_Peers.find (ident);
|
||||
return it != m_Peers.end ();
|
||||
}
|
||||
|
||||
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
||||
{
|
||||
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
||||
{
|
||||
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
it = m_Peers.erase (it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
UpdateBandwidth (); // TODO: use separate timer(s) for it
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test
|
||||
DetectExternalIP ();
|
||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
|
||||
{
|
||||
if (!m_Peers.size ()) return nullptr;
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
auto it = m_Peers.begin ();
|
||||
std::advance (it, rand () % m_Peers.size ());
|
||||
return it != m_Peers.end () ? it->second.router : nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
247
UPnP.cpp
@@ -1,247 +0,0 @@
|
||||
#ifdef USE_UPNP
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define dlsym GetProcAddress
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "RouterContext.h"
|
||||
#include "UPnP.h"
|
||||
#include "NetDb.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <miniupnpc/miniupnpc.h>
|
||||
#include <miniupnpc/upnpcommands.h>
|
||||
|
||||
// These are per-process and are safe to reuse for all threads
|
||||
#ifndef UPNPDISCOVER_SUCCESS
|
||||
/* miniupnpc 1.5 */
|
||||
UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int);
|
||||
int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *,
|
||||
const char *, const char *, const char *, const char *);
|
||||
#else
|
||||
/* miniupnpc 1.6 */
|
||||
UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int, int, int *);
|
||||
int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *,
|
||||
const char *, const char *, const char *, const char *, const char *);
|
||||
#endif
|
||||
int (*UPNP_GetValidIGDFunc) (struct UPNPDev *, struct UPNPUrls *, struct IGDdatas *, char *, int);
|
||||
int (*UPNP_GetExternalIPAddressFunc) (const char *, const char *, char *);
|
||||
int (*UPNP_DeletePortMappingFunc) (const char *, const char *, const char *, const char *, const char *);
|
||||
void (*freeUPNPDevlistFunc) (struct UPNPDev *);
|
||||
void (*FreeUPNPUrlsFunc) (struct UPNPUrls *);
|
||||
|
||||
// Nice approach http://stackoverflow.com/a/21517513/673826
|
||||
template<class M, typename F>
|
||||
F GetKnownProcAddressImpl(M hmod, const char *name, F) {
|
||||
auto proc = reinterpret_cast<F>(dlsym(hmod, name));
|
||||
if (!proc) {
|
||||
LogPrint(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?");
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func);
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false)
|
||||
{
|
||||
}
|
||||
|
||||
void UPnP::Stop ()
|
||||
{
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UPnP::Start()
|
||||
{
|
||||
if (!m_IsModuleLoaded) {
|
||||
#ifdef MAC_OSX
|
||||
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
|
||||
#elif _WIN32
|
||||
m_Module = LoadLibrary ("miniupnpc.dll"); // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip
|
||||
#else
|
||||
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
|
||||
#endif
|
||||
if (m_Module == NULL)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover);
|
||||
UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD);
|
||||
UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress);
|
||||
UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping);
|
||||
UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping);
|
||||
freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist);
|
||||
FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls);
|
||||
if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc &&
|
||||
UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc)
|
||||
m_IsModuleLoaded = true;
|
||||
}
|
||||
}
|
||||
m_Thread = new std::thread (std::bind (&UPnP::Run, this));
|
||||
}
|
||||
|
||||
UPnP::~UPnP ()
|
||||
{
|
||||
}
|
||||
|
||||
void UPnP::Run ()
|
||||
{
|
||||
for (auto& address : context.GetRouterInfo ().GetAddresses ())
|
||||
{
|
||||
if (!address.host.is_v6 ())
|
||||
{
|
||||
Discover ();
|
||||
if (address.transportStyle == data::RouterInfo::eTransportSSU )
|
||||
{
|
||||
TryPortMapping (I2P_UPNP_UDP, address.port);
|
||||
}
|
||||
else if (address.transportStyle == data::RouterInfo::eTransportNTCP )
|
||||
{
|
||||
TryPortMapping (I2P_UPNP_TCP, address.port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UPnP::Discover ()
|
||||
{
|
||||
#ifndef UPNPDISCOVER_SUCCESS
|
||||
/* miniupnpc 1.5 */
|
||||
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0);
|
||||
#else
|
||||
/* miniupnpc 1.6 */
|
||||
int nerror = 0;
|
||||
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
|
||||
#endif
|
||||
|
||||
int r;
|
||||
r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||
if (r == 1)
|
||||
{
|
||||
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||
if(r != UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_externalIPAddress[0])
|
||||
{
|
||||
LogPrint (eLogInfo, "UPnP: ExternalIPAddress = ", m_externalIPAddress);
|
||||
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: GetExternalIPAddress failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UPnP::TryPortMapping (int type, int port)
|
||||
{
|
||||
std::string strType, strPort (std::to_string (port));
|
||||
switch (type)
|
||||
{
|
||||
case I2P_UPNP_TCP:
|
||||
strType = "TCP";
|
||||
break;
|
||||
case I2P_UPNP_UDP:
|
||||
default:
|
||||
strType = "UDP";
|
||||
}
|
||||
int r;
|
||||
std::string strDesc = "I2Pd";
|
||||
try {
|
||||
for (;;) {
|
||||
#ifndef UPNPDISCOVER_SUCCESS
|
||||
/* miniupnpc 1.5 */
|
||||
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
|
||||
#else
|
||||
/* miniupnpc 1.6 */
|
||||
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
|
||||
#endif
|
||||
if (r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11
|
||||
//boost::this_thread::sleep_for(); // pre c++11
|
||||
//sleep(20*60); // non-portable
|
||||
}
|
||||
}
|
||||
catch (boost::thread_interrupted)
|
||||
{
|
||||
CloseMapping(type, port);
|
||||
Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void UPnP::CloseMapping (int type, int port)
|
||||
{
|
||||
std::string strType, strPort (std::to_string (port));
|
||||
switch (type)
|
||||
{
|
||||
case I2P_UPNP_TCP:
|
||||
strType = "TCP";
|
||||
break;
|
||||
case I2P_UPNP_UDP:
|
||||
default:
|
||||
strType = "UDP";
|
||||
}
|
||||
int r = 0;
|
||||
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
|
||||
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
|
||||
}
|
||||
|
||||
void UPnP::Close ()
|
||||
{
|
||||
freeUPNPDevlistFunc (m_Devlist);
|
||||
m_Devlist = 0;
|
||||
FreeUPNPUrlsFunc (&m_upnpUrls);
|
||||
#ifndef _WIN32
|
||||
dlclose (m_Module);
|
||||
#else
|
||||
FreeLibrary (m_Module);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
63
UPnP.h
@@ -1,63 +0,0 @@
|
||||
#ifndef __UPNP_H__
|
||||
#define __UPNP_H__
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <miniupnpc/miniwget.h>
|
||||
#include <miniupnpc/miniupnpc.h>
|
||||
#include <miniupnpc/upnpcommands.h>
|
||||
#include <miniupnpc/upnperrors.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define I2P_UPNP_TCP 1
|
||||
#define I2P_UPNP_UDP 2
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
class UPnP
|
||||
{
|
||||
public:
|
||||
|
||||
UPnP ();
|
||||
~UPnP ();
|
||||
void Close ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
void Discover ();
|
||||
void TryPortMapping (int type, int port);
|
||||
void CloseMapping (int type, int port);
|
||||
private:
|
||||
void Run ();
|
||||
|
||||
std::thread * m_Thread;
|
||||
struct UPNPUrls m_upnpUrls;
|
||||
struct IGDdatas m_upnpData;
|
||||
|
||||
// For miniupnpc
|
||||
char * m_MulticastIf = 0;
|
||||
char * m_Minissdpdpath = 0;
|
||||
struct UPNPDev * m_Devlist = 0;
|
||||
char m_NetworkAddr[64];
|
||||
char m_externalIPAddress[40];
|
||||
bool m_IsModuleLoaded;
|
||||
#ifndef _WIN32
|
||||
void *m_Module;
|
||||
#else
|
||||
HINSTANCE m_Module;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
14
Win32/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
*
|
||||
!*/
|
||||
|
||||
!*.h
|
||||
!*.cpp
|
||||
|
||||
!*.bat
|
||||
|
||||
!*.sln
|
||||
!*.vcproj
|
||||
!*.vcxproj
|
||||
!*.vcxproj.filters
|
||||
!*.iss
|
||||
!.gitignore
|
||||
113
Win32/DaemonWin32.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <thread>
|
||||
#include <clocale>
|
||||
#include "Config.h"
|
||||
#include "Daemon.h"
|
||||
#include "util.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Win32/Win32Service.h"
|
||||
#ifdef WIN32_APP
|
||||
#include "Win32/Win32App.h"
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
bool DaemonWin32::init(int argc, char* argv[])
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
SetConsoleCP(1251);
|
||||
SetConsoleOutputCP(1251);
|
||||
setlocale(LC_ALL, "Russian");
|
||||
setlocale(LC_TIME, "C");
|
||||
|
||||
if (!Daemon_Singleton::init(argc, argv))
|
||||
return false;
|
||||
|
||||
std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl);
|
||||
if (serviceControl == "install")
|
||||
{
|
||||
LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service");
|
||||
InstallService(
|
||||
SERVICE_NAME, // Name of service
|
||||
SERVICE_DISPLAY_NAME, // Name to display
|
||||
SERVICE_START_TYPE, // Service start type
|
||||
SERVICE_DEPENDENCIES, // Dependencies
|
||||
SERVICE_ACCOUNT, // Service running account
|
||||
SERVICE_PASSWORD // Password of the account
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else if (serviceControl == "remove")
|
||||
{
|
||||
LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service");
|
||||
UninstallService(SERVICE_NAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDaemon)
|
||||
{
|
||||
LogPrint(eLogDebug, "Daemon: running as service");
|
||||
I2PService service(SERVICE_NAME);
|
||||
if (!I2PService::Run(service))
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
LogPrint(eLogDebug, "Daemon: running as user");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DaemonWin32::start()
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
SetConsoleCP(1251);
|
||||
SetConsoleOutputCP(1251);
|
||||
setlocale(LC_ALL, "Russian");
|
||||
setlocale(LC_TIME, "C");
|
||||
#ifdef WIN32_APP
|
||||
if (!i2p::win32::StartWin32App ()) return false;
|
||||
|
||||
// override log
|
||||
i2p::config::SetOption("log", std::string ("file"));
|
||||
#endif
|
||||
bool ret = Daemon_Singleton::start();
|
||||
if (ret && i2p::log::Logger().GetLogType() == eLogFile)
|
||||
{
|
||||
// TODO: find out where this garbage to console comes from
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
|
||||
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
bool insomnia; i2p::config::GetOption("insomnia", insomnia);
|
||||
if (insomnia)
|
||||
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DaemonWin32::stop()
|
||||
{
|
||||
#ifdef WIN32_APP
|
||||
i2p::win32::StopWin32App ();
|
||||
#endif
|
||||
return Daemon_Singleton::stop();
|
||||
}
|
||||
|
||||
void DaemonWin32::run ()
|
||||
{
|
||||
#ifdef WIN32_APP
|
||||
i2p::win32::RunWin32App ();
|
||||
#else
|
||||
while (running)
|
||||
{
|
||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //_WIN32
|
||||
@@ -1,14 +0,0 @@
|
||||
@echo off
|
||||
convert Itoopie.svg ^
|
||||
-fuzz 90%% -fill transparent -floodfill 2x2 white -fuzz 20%% -fill #AE0E99 -opaque red ^
|
||||
-fill #FBBC11 -opaque yellow ^
|
||||
( -clone 0 -resize 256x256 ) ^
|
||||
( -clone 0 -resize 128x128 ) ^
|
||||
( -clone 0 -resize 64x64 ) ^
|
||||
( -clone 0 -resize 48x48 ) ^
|
||||
( -clone 0 -resize 32x32 ) ^
|
||||
( -clone 0 -resize 24x24 ) ^
|
||||
( -clone 0 -resize 16x16 ) ^
|
||||
( -size 150x57 xc:white -clone 0 -geometry 57x57+46+0 -composite -gravity center -write BMP3:ictoopie.bmp +delete ) ^
|
||||
( -clone 0 -write Itoopie_purple.png +delete ) ^
|
||||
-delete 0 ictoopie.ico
|
||||
@@ -1,282 +0,0 @@
|
||||
# NSIS Installer script. (Tested with NSIS 2.64 on Windows 7)
|
||||
# Author: Mikal Villa (Meeh)
|
||||
# Version: 1.1
|
||||
Name PurpleI2P
|
||||
|
||||
RequestExecutionLevel highest
|
||||
SetCompressor /SOLID lzma
|
||||
ShowInstDetails show
|
||||
|
||||
# General Symbol Definitions
|
||||
!define REGKEY "SOFTWARE\$(^Name)"
|
||||
!define VERSION 0.3.0.0
|
||||
!define COMPANY "The Privacy Solutions Project"
|
||||
!define URL "https://i2p.io"
|
||||
|
||||
# MUI Symbol Definitions
|
||||
!define MUI_ICON "ictoopie.ico"
|
||||
#!define MUI_WELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_RIGHT
|
||||
#!define MUI_HEADERIMAGE_BITMAP "../share/pixmaps/nsis-header.bmp"
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER PurpleI2P
|
||||
!define MUI_FINISHPAGE_RUN $INSTDIR\i2pd.exe
|
||||
!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\Readme.txt
|
||||
|
||||
|
||||
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
|
||||
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
|
||||
|
||||
# Included files
|
||||
!include Sections.nsh
|
||||
!include MUI2.nsh
|
||||
!include nsDialogs.nsh
|
||||
!include winmessages.nsh
|
||||
!include logiclib.nsh
|
||||
# Local included files
|
||||
!include nsi\helper_readme.nsh
|
||||
;!include nsi\servicelib.nsh
|
||||
|
||||
# Variables
|
||||
Var StartMenuGroup
|
||||
|
||||
# Installer pages
|
||||
# Execution flow of installer windows
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_README "../Readme.md"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
# Disabled for now. Use the bat
|
||||
;Page custom mode_selection # Meeh's hack for installing and starting service.
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
# Uninstall pages
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
# Installer languages
|
||||
!insertmacro MUI_LANGUAGE English
|
||||
|
||||
# Installer attributes
|
||||
OutFile PurpleI2P-0.3.0.0-win32-setup.exe
|
||||
InstallDir $PROGRAMFILES\PurpleI2P
|
||||
CRCCheck on
|
||||
XPStyle on
|
||||
BrandingText " "
|
||||
ShowInstDetails show
|
||||
VIProductVersion 0.3.0.0
|
||||
VIAddVersionKey ProductName PurpleI2P
|
||||
VIAddVersionKey ProductVersion "${VERSION}"
|
||||
VIAddVersionKey CompanyName "${COMPANY}"
|
||||
VIAddVersionKey CompanyWebsite "${URL}"
|
||||
VIAddVersionKey FileVersion "${VERSION}"
|
||||
VIAddVersionKey FileDescription ""
|
||||
VIAddVersionKey LegalCopyright ""
|
||||
InstallDirRegKey HKCU "${REGKEY}" Path
|
||||
ShowUninstDetails show
|
||||
|
||||
# Readme definitions
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
;Set up install lang strings for 1st lang
|
||||
${ReadmeLanguage} "${LANG_ENGLISH}" \
|
||||
"Read Me" \
|
||||
"Please review the following important information." \
|
||||
"About $(^name):" \
|
||||
"$\n Click on scrollbar arrows or press Page Down to review the entire text."
|
||||
|
||||
;Add 2nd language
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
|
||||
;set up install lang strings for second lang
|
||||
${ReadmeLanguage} "${LANG_NORWEGIAN}" \
|
||||
"Les meg!" \
|
||||
"Vennligst les informasjonen om hvordan du skal bruke PurpleI2P." \
|
||||
"Om $(^name):" \
|
||||
"$\n Klikk på scrollbaren til høyre for å se hele innholdet."
|
||||
|
||||
;--------------------------------
|
||||
|
||||
# Installer sections
|
||||
Section -Main SEC0000
|
||||
SetOutPath $INSTDIR
|
||||
SetOverwrite on
|
||||
File /oname=i2pd.exe Release\i2pd.exe
|
||||
File /oname=install_service.bat install_service.bat
|
||||
File /oname=uninstall_service.bat uninstall_service.bat
|
||||
File /oname=LICENSE.txt ..\LICENSE
|
||||
File /oname=Readme.txt ..\README.md
|
||||
SetOutPath $INSTDIR\src
|
||||
File /r /x *.nsi /x *.rc /x *.exe /x *.obj /x *.nsh /x *.sln /x *.vcxproj /x *.tlog /x *.log /x *.res /x *.pdb /x *.suo /x *.opensdf /x *.filters /x *.sdf /x *.iss /x *.aps /x .gitignore /x *.o ../\*.*
|
||||
SetOutPath $INSTDIR
|
||||
RMDir /r /REBOOTOK $INSTDIR\src\.git # Remove git directory
|
||||
RMDir /r /REBOOTOK $INSTDIR\src\Win32\Release # Removing release directory
|
||||
RMDir /r /REBOOTOK $INSTDIR\src\Win32\nsi
|
||||
WriteRegStr HKCU "${REGKEY}\Components" Main 1
|
||||
SectionEnd
|
||||
|
||||
Section -post SEC0001
|
||||
WriteRegStr HKCU "${REGKEY}" Path $INSTDIR
|
||||
SetOutPath $INSTDIR
|
||||
WriteUninstaller $INSTDIR\uninstall.exe
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
CreateDirectory $SMPROGRAMS\$StartMenuGroup
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\PurpleI2P.lnk" $INSTDIR\i2pd.exe
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Install PurpleI2P Service.lnk" $INSTDIR\install_service.bat
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P Service.lnk" $INSTDIR\uninstall_service.bat
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P.lnk" $INSTDIR\uninstall.exe
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)"
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}"
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe
|
||||
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe
|
||||
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
|
||||
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
|
||||
WriteRegStr HKCR "i2pd" "URL Protocol" ""
|
||||
WriteRegStr HKCR "i2pd" "" "URL:i2pd" # TODO: if a instance of own is found, relaunch with a proxyfied browser to open webage. (e.g i2pd://meeh.i2p)
|
||||
WriteRegStr HKCR "i2pd\DefaultIcon" "" $INSTDIR\i2pd.exe
|
||||
WriteRegStr HKCR "i2pd\shell\open\command" "" '"$INSTDIR\i2pd.exe" "%1"'
|
||||
SectionEnd
|
||||
|
||||
# Macro for selecting uninstaller sections
|
||||
!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID
|
||||
Push $R0
|
||||
ReadRegStr $R0 HKCU "${REGKEY}\Components" "${SECTION_NAME}"
|
||||
StrCmp $R0 1 0 next${UNSECTION_ID}
|
||||
!insertmacro SelectSection "${UNSECTION_ID}"
|
||||
GoTo done${UNSECTION_ID}
|
||||
next${UNSECTION_ID}:
|
||||
!insertmacro UnselectSection "${UNSECTION_ID}"
|
||||
done${UNSECTION_ID}:
|
||||
Pop $R0
|
||||
!macroend
|
||||
|
||||
|
||||
# Uninstaller sections
|
||||
Section /o -un.Main UNSEC0000
|
||||
Delete /REBOOTOK $INSTDIR\i2pd.exe
|
||||
Delete /REBOOTOK $INSTDIR\LICENSE.txt
|
||||
Delete /REBOOTOK $INSTDIR\Readme.txt
|
||||
Delete /REBOOTOK $INSTDIR\install_service.bat
|
||||
Delete /REBOOTOK $INSTDIR\uninstall_service.bat
|
||||
RMDir /r /REBOOTOK $INSTDIR\src
|
||||
DeleteRegValue HKCU "${REGKEY}\Components" Main
|
||||
SectionEnd
|
||||
|
||||
Section -un.post UNSEC0001
|
||||
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
|
||||
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P.lnk"
|
||||
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\PurpleI2P.lnk"
|
||||
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Install PurpleI2P Service.lnk"
|
||||
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\UnInstall PurpleI2P Service.lnk"
|
||||
Delete /REBOOTOK "$SMSTARTUP\PurpleI2P.lnk"
|
||||
Delete /REBOOTOK $INSTDIR\uninstall.exe
|
||||
Delete /REBOOTOK $INSTDIR\debug.log
|
||||
DeleteRegValue HKCU "${REGKEY}" StartMenuGroup
|
||||
DeleteRegValue HKCU "${REGKEY}" Path
|
||||
DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components"
|
||||
DeleteRegKey /IfEmpty HKCU "${REGKEY}"
|
||||
DeleteRegKey HKCR "i2pd"
|
||||
RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup
|
||||
RmDir /REBOOTOK $INSTDIR
|
||||
Push $R0
|
||||
StrCpy $R0 $StartMenuGroup 1
|
||||
StrCmp $R0 ">" no_smgroup
|
||||
no_smgroup:
|
||||
Pop $R0
|
||||
SectionEnd
|
||||
|
||||
; var hwndExecModeRadio
|
||||
; var hwndRunServiceNowRadio
|
||||
|
||||
; Function mode_selection
|
||||
; nsDialogs::Create 1018
|
||||
; Pop $0
|
||||
; ${NSD_CreateLabel} 0 10 75% 20u "How would you like PurpleI2P (i2pd) to run?"
|
||||
; Pop $0
|
||||
|
||||
; ${NSD_CreateRadioButton} 20 60 80% 25u "Service Mode"
|
||||
; Pop $hwndExecModeRadio
|
||||
; ${NSD_AddStyle} $hwndExecModeRadio ${WS_GROUP}
|
||||
|
||||
; ${NSD_CreateRadioButton} 20 90 80% 25u "Command line Mode"
|
||||
; Pop $0
|
||||
|
||||
; ${NSD_CreateButton} 20 150 -40 14u "Do it!"
|
||||
; Pop $0
|
||||
; ${NSD_OnClick} $0 perform_mode
|
||||
|
||||
; nsDialogs::Show
|
||||
; FunctionEnd
|
||||
|
||||
; Function start_now_selection
|
||||
; nsDialogs::Create 1018
|
||||
; Pop $0
|
||||
; ${NSD_CreateLabel} 0 10 75% 20u "Enable the service now?"
|
||||
; Pop $0
|
||||
|
||||
; ${NSD_CreateRadioButton} 20 60 80% 25u "Yes"
|
||||
; Pop $hwndRunServiceNowRadio
|
||||
; ${NSD_AddStyle} $hwndRunServiceNowRadio ${WS_GROUP}
|
||||
|
||||
; ${NSD_CreateRadioButton} 20 90 80% 25u "No"
|
||||
; Pop $0
|
||||
|
||||
; ${NSD_CreateButton} 20 150 -40 14u "Do it!"
|
||||
; Pop $0
|
||||
; ${NSD_OnClick} $0 perform_mode
|
||||
|
||||
; nsDialogs::Show
|
||||
; FunctionEnd
|
||||
|
||||
; Function perform_mode
|
||||
; ${NSD_GetState} $hwndExecModeRadio $0
|
||||
; ${If} $0 = ${BST_CHECKED}
|
||||
; Call service_mode
|
||||
; ${EndIF}
|
||||
; FunctionEnd
|
||||
|
||||
; Function start_now
|
||||
; ${NSD_GetState} $hwndRunServiceNowRadio $0
|
||||
; ${If} $0 = ${BST_CHECKED}
|
||||
; Call start_now_selection
|
||||
; ${EndIF}
|
||||
; FunctionEnd
|
||||
|
||||
; Function service_mode
|
||||
; Push "create"
|
||||
; Push "PurpleI2P Service"
|
||||
; Push "$INSTDIR\i2pd.exe;autostart=1;display=PurpleI2P"
|
||||
; Call Service
|
||||
; Pop $0 ; Actually more to write than !insertmacro, but much more fun :D
|
||||
; Push "start"
|
||||
; Push "PurpleI2P Service"
|
||||
; Call Service
|
||||
; Pop $0
|
||||
; Call start_now
|
||||
; !define MUI_FINISHPAGE_RUN_NOTCHECKED
|
||||
; !define MUI_FINISHPAGE_RUN_TEXT "No need to run now since we already installed and launched it as a Windows service!"
|
||||
; FunctionEnd
|
||||
|
||||
# Installer functions
|
||||
Function .onInit
|
||||
InitPluginsDir
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
FunctionEnd
|
||||
|
||||
# Uninstaller functions
|
||||
Function un.onInit
|
||||
ReadRegStr $INSTDIR HKCU "${REGKEY}" Path
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup
|
||||
!insertmacro SELECT_UNSECTION Main ${UNSEC0000}
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
FunctionEnd
|
||||
@@ -1,72 +1,36 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
MAINICON ICON "ictoopie.ico"
|
||||
IDI_ICON1 ICON "ictoopie_16.ico"
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
MAINICON ICON "mask.ico"
|
||||
#endif // English (United States) resources
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
#include "Resource.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
//
|
||||
// Resource.RC2 - resources Microsoft Visual C++ does not edit directly
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#error this file is not editable by Microsoft Visual C++
|
||||
#endif //APSTUDIO_INVOKED
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../libi2pd/version.h"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
|
||||
@@ -34,7 +25,7 @@ BEGIN
|
||||
VALUE "FileDescription", "C++ I2P daemon"
|
||||
VALUE "FileVersion", I2PD_VERSION
|
||||
VALUE "InternalName", CODENAME
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2015, The PurpleI2P Project"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2017, The PurpleI2P Project"
|
||||
VALUE "OriginalFilename", "i2pd"
|
||||
VALUE "ProductName", "Purple I2P"
|
||||
VALUE "ProductVersion", I2P_VERSION
|
||||
|
||||
@@ -1,162 +1,394 @@
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
//#include "../Daemon.h"
|
||||
#include "ClientContext.h"
|
||||
#include "Config.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
#include "Tunnel.h"
|
||||
#include "version.h"
|
||||
#include "resource.h"
|
||||
#include "Daemon.h"
|
||||
#include "Win32App.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#define ID_ABOUT 2000
|
||||
#define ID_EXIT 2001
|
||||
#define ID_CONSOLE 2002
|
||||
#define ID_APP 2003
|
||||
#define ID_GRACEFUL_SHUTDOWN 2004
|
||||
#define ID_STOP_GRACEFUL_SHUTDOWN 2005
|
||||
#define ID_RELOAD 2006
|
||||
|
||||
#define ID_TRAY_ICON 2050
|
||||
#define WM_TRAYICON (WM_USER + 1)
|
||||
|
||||
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
|
||||
#define FRAME_UPDATE_TIMER 2101
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||
{
|
||||
HMENU hPopup = CreatePopupMenu();
|
||||
InsertMenu (hPopup, 0, MF_BYPOSITION | MF_STRING, ID_ABOUT, "About...");
|
||||
InsertMenu (hPopup, 1, MF_BYPOSITION | MF_STRING, ID_EXIT , "Exit");
|
||||
SetMenuDefaultItem (hPopup, ID_ABOUT, FALSE);
|
||||
SetFocus (hWnd);
|
||||
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
|
||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||
{
|
||||
HMENU hPopup = CreatePopupMenu();
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
|
||||
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
||||
else
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "&Stop graceful shutdown");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
|
||||
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
|
||||
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
|
||||
|
||||
POINT p;
|
||||
if (!curpos)
|
||||
{
|
||||
GetCursorPos (&p);
|
||||
curpos = &p;
|
||||
}
|
||||
POINT p;
|
||||
if (!curpos)
|
||||
{
|
||||
GetCursorPos (&p);
|
||||
curpos = &p;
|
||||
}
|
||||
|
||||
WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
|
||||
SendMessage (hWnd, WM_COMMAND, cmd, 0);
|
||||
WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
|
||||
SendMessage (hWnd, WM_COMMAND, cmd, 0);
|
||||
|
||||
DestroyMenu(hPopup);
|
||||
}
|
||||
DestroyMenu(hPopup);
|
||||
}
|
||||
|
||||
static void AddTrayIcon (HWND hWnd)
|
||||
{
|
||||
NOTIFYICONDATA nid;
|
||||
memset(&nid, 0, sizeof(nid));
|
||||
nid.cbSize = sizeof(nid);
|
||||
nid.hWnd = hWnd;
|
||||
nid.uID = ID_TRAY_ICON;
|
||||
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||
nid.uCallbackMessage = WM_TRAYICON;
|
||||
nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (IDI_ICON1));
|
||||
strcpy (nid.szTip, "i2pd");
|
||||
Shell_NotifyIcon(NIM_ADD, &nid );
|
||||
}
|
||||
static void AddTrayIcon (HWND hWnd)
|
||||
{
|
||||
NOTIFYICONDATA nid;
|
||||
memset(&nid, 0, sizeof(nid));
|
||||
nid.cbSize = sizeof(nid);
|
||||
nid.hWnd = hWnd;
|
||||
nid.uID = ID_TRAY_ICON;
|
||||
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
|
||||
nid.uCallbackMessage = WM_TRAYICON;
|
||||
nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON));
|
||||
strcpy (nid.szTip, "i2pd");
|
||||
strcpy (nid.szInfo, "i2pd is starting");
|
||||
Shell_NotifyIcon(NIM_ADD, &nid );
|
||||
}
|
||||
|
||||
static void RemoveTrayIcon (HWND hWnd)
|
||||
{
|
||||
NOTIFYICONDATA nid;
|
||||
nid.hWnd = hWnd;
|
||||
nid.uID = ID_TRAY_ICON;
|
||||
Shell_NotifyIcon (NIM_DELETE, &nid);
|
||||
}
|
||||
static void RemoveTrayIcon (HWND hWnd)
|
||||
{
|
||||
NOTIFYICONDATA nid;
|
||||
nid.hWnd = hWnd;
|
||||
nid.uID = ID_TRAY_ICON;
|
||||
Shell_NotifyIcon (NIM_DELETE, &nid);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
{
|
||||
AddTrayIcon (hWnd);
|
||||
break;
|
||||
}
|
||||
case WM_CLOSE:
|
||||
{
|
||||
RemoveTrayIcon (hWnd);
|
||||
PostQuitMessage (0);
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case ID_ABOUT:
|
||||
{
|
||||
MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK );
|
||||
return 0;
|
||||
}
|
||||
case ID_EXIT:
|
||||
{
|
||||
PostMessage (hWnd, WM_CLOSE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_TRAYICON:
|
||||
{
|
||||
SetForegroundWindow (hWnd);
|
||||
switch (lParam)
|
||||
{
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
SetForegroundWindow (hWnd);
|
||||
ShowPopupMenu(hWnd, NULL, -1);
|
||||
PostMessage (hWnd, WM_APP + 1, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return DefWindowProc( hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
static void ShowUptime (std::stringstream& s, int seconds)
|
||||
{
|
||||
int num;
|
||||
|
||||
bool StartWin32App ()
|
||||
{
|
||||
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
|
||||
{
|
||||
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
|
||||
return false;
|
||||
}
|
||||
// register main window
|
||||
auto hInst = GetModuleHandle(NULL);
|
||||
WNDCLASSEX wclx;
|
||||
memset (&wclx, 0, sizeof(wclx));
|
||||
wclx.cbSize = sizeof(wclx);
|
||||
wclx.style = 0;
|
||||
wclx.lpfnWndProc = WndProc;
|
||||
wclx.cbClsExtra = 0;
|
||||
wclx.cbWndExtra = 0;
|
||||
wclx.hInstance = hInst;
|
||||
wclx.hIcon = LoadIcon (hInst, IDI_APPLICATION);
|
||||
wclx.hIconSm = LoadIcon (hInst, IDI_APPLICATION);
|
||||
wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||||
wclx.lpszMenuName = NULL;
|
||||
wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
|
||||
RegisterClassEx (&wclx);
|
||||
// create new window
|
||||
if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 150, NULL, NULL, hInst, NULL))
|
||||
{
|
||||
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((num = seconds / 86400) > 0) {
|
||||
s << num << " days, ";
|
||||
seconds -= num * 86400;
|
||||
}
|
||||
if ((num = seconds / 3600) > 0) {
|
||||
s << num << " hours, ";
|
||||
seconds -= num * 3600;
|
||||
}
|
||||
if ((num = seconds / 60) > 0) {
|
||||
s << num << " min, ";
|
||||
seconds -= num * 60;
|
||||
}
|
||||
s << seconds << " seconds\n";
|
||||
}
|
||||
|
||||
int RunWin32App ()
|
||||
{
|
||||
MSG msg;
|
||||
while (GetMessage (&msg, NULL, 0, 0 ))
|
||||
{
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
return msg.wParam;
|
||||
}
|
||||
template <typename size> static void ShowTransfered (std::stringstream& s, size transfer)
|
||||
{
|
||||
auto bytes = transfer & 0x03ff;
|
||||
transfer >>= 10;
|
||||
auto kbytes = transfer & 0x03ff;
|
||||
transfer >>= 10;
|
||||
auto mbytes = transfer & 0x03ff;
|
||||
transfer >>= 10;
|
||||
auto gbytes = transfer & 0x03ff;
|
||||
|
||||
if (gbytes)
|
||||
s << gbytes << " GB, ";
|
||||
if (mbytes)
|
||||
s << mbytes << " MB, ";
|
||||
if (kbytes)
|
||||
s << kbytes << " KB, ";
|
||||
s << bytes << " Bytes\n";
|
||||
}
|
||||
|
||||
static void PrintMainWindowText (std::stringstream& s)
|
||||
{
|
||||
s << "\n";
|
||||
s << "Status: ";
|
||||
switch (i2p::context.GetStatus())
|
||||
{
|
||||
case eRouterStatusOK: s << "OK"; break;
|
||||
case eRouterStatusTesting: s << "Testing"; break;
|
||||
case eRouterStatusFirewalled: s << "Firewalled"; break;
|
||||
case eRouterStatusError:
|
||||
{
|
||||
switch (i2p::context.GetError())
|
||||
{
|
||||
case eRouterErrorClockSkew: s << "Clock skew"; break;
|
||||
default: s << "Error";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: s << "Unknown";
|
||||
}
|
||||
s << "; ";
|
||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
||||
s << "\n";
|
||||
s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; ";
|
||||
s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n";
|
||||
s << "Received: "; ShowTransfered (s, i2p::transport::transports.GetTotalReceivedBytes());
|
||||
s << "Sent: "; ShowTransfered (s, i2p::transport::transports.GetTotalSentBytes());
|
||||
s << "\n";
|
||||
s << "Routers: " << i2p::data::netdb.GetNumRouters () << "; ";
|
||||
s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << "; ";
|
||||
s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "\n";
|
||||
s << "Tunnels: ";
|
||||
s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; ";
|
||||
s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; ";
|
||||
s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n";
|
||||
s << "\n";
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
{
|
||||
AddTrayIcon (hWnd);
|
||||
break;
|
||||
}
|
||||
case WM_CLOSE:
|
||||
{
|
||||
RemoveTrayIcon (hWnd);
|
||||
KillTimer (hWnd, FRAME_UPDATE_TIMER);
|
||||
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
||||
PostQuitMessage (0);
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case ID_ABOUT:
|
||||
{
|
||||
std::stringstream text;
|
||||
text << "Version: " << I2PD_VERSION << " " << CODENAME;
|
||||
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
|
||||
return 0;
|
||||
}
|
||||
case ID_EXIT:
|
||||
{
|
||||
PostMessage (hWnd, WM_CLOSE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
case ID_GRACEFUL_SHUTDOWN:
|
||||
{
|
||||
i2p::context.SetAcceptsTunnels (false);
|
||||
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
||||
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
||||
return 0;
|
||||
}
|
||||
case ID_STOP_GRACEFUL_SHUTDOWN:
|
||||
{
|
||||
i2p::context.SetAcceptsTunnels (true);
|
||||
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
||||
i2p::util::DaemonWin32::Instance ().isGraceful = false;
|
||||
return 0;
|
||||
}
|
||||
case ID_RELOAD:
|
||||
{
|
||||
i2p::client::context.ReloadConfig();
|
||||
std::stringstream text;
|
||||
text << "I2Pd reloading configs...";
|
||||
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
|
||||
return 0;
|
||||
}
|
||||
case ID_CONSOLE:
|
||||
{
|
||||
char buf[30];
|
||||
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||
snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort);
|
||||
ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL);
|
||||
return 0;
|
||||
}
|
||||
case ID_APP:
|
||||
{
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SYSCOMMAND:
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case SC_MINIMIZE:
|
||||
{
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
KillTimer (hWnd, FRAME_UPDATE_TIMER);
|
||||
return 0;
|
||||
}
|
||||
case SC_CLOSE:
|
||||
{
|
||||
std::string close; i2p::config::GetOption("close", close);
|
||||
if (0 == close.compare("ask"))
|
||||
switch(::MessageBox(hWnd, "Would you like to minimize instead of exiting?"
|
||||
" You can add 'close' configuration option. Valid values are: ask, minimize, exit.",
|
||||
"Minimize instead of exiting?", MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1))
|
||||
{
|
||||
case IDYES: close = "minimize"; break;
|
||||
case IDNO: close = "exit"; break;
|
||||
default: return 0;
|
||||
}
|
||||
if (0 == close.compare("minimize"))
|
||||
{
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
KillTimer (hWnd, FRAME_UPDATE_TIMER);
|
||||
return 0;
|
||||
}
|
||||
if (0 != close.compare("exit"))
|
||||
{
|
||||
::MessageBox(hWnd, close.c_str(), "Unknown close action in config", MB_OK | MB_ICONWARNING);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case WM_TRAYICON:
|
||||
{
|
||||
switch (lParam)
|
||||
{
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
SetForegroundWindow (hWnd);
|
||||
ShowPopupMenu(hWnd, NULL, -1);
|
||||
PostMessage (hWnd, WM_APP + 1, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_TIMER:
|
||||
{
|
||||
if (wParam == IDT_GRACEFUL_SHUTDOWN_TIMER)
|
||||
{
|
||||
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
|
||||
return 0;
|
||||
}
|
||||
if (wParam == FRAME_UPDATE_TIMER)
|
||||
{
|
||||
InvalidateRect(hWnd, NULL, TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_PAINT:
|
||||
{
|
||||
HDC hDC;
|
||||
PAINTSTRUCT ps;
|
||||
RECT rp;
|
||||
HFONT hFont;
|
||||
std::stringstream s; PrintMainWindowText (s);
|
||||
hDC = BeginPaint (hWnd, &ps);
|
||||
GetClientRect(hWnd, &rp);
|
||||
SetTextColor(hDC, 0x00D43B69);
|
||||
hFont = CreateFont(18,0,0,0,0,0,0,0,DEFAULT_CHARSET,0,0,0,0,TEXT("Times New Roman"));
|
||||
SelectObject(hDC,hFont);
|
||||
DrawText(hDC, TEXT(s.str().c_str()), s.str().length(), &rp, DT_CENTER|DT_VCENTER);
|
||||
DeleteObject(hFont);
|
||||
EndPaint(hWnd, &ps);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return DefWindowProc( hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool StartWin32App ()
|
||||
{
|
||||
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
|
||||
{
|
||||
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
|
||||
return false;
|
||||
}
|
||||
// register main window
|
||||
auto hInst = GetModuleHandle(NULL);
|
||||
WNDCLASSEX wclx;
|
||||
memset (&wclx, 0, sizeof(wclx));
|
||||
wclx.cbSize = sizeof(wclx);
|
||||
wclx.style = 0;
|
||||
wclx.lpfnWndProc = WndProc;
|
||||
//wclx.cbClsExtra = 0;
|
||||
//wclx.cbWndExtra = 0;
|
||||
wclx.hInstance = hInst;
|
||||
wclx.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(MAINICON));
|
||||
wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
//wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
||||
wclx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wclx.lpszMenuName = NULL;
|
||||
wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
|
||||
RegisterClassEx (&wclx);
|
||||
// create new window
|
||||
if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 210, NULL, NULL, hInst, NULL))
|
||||
{
|
||||
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int RunWin32App ()
|
||||
{
|
||||
MSG msg;
|
||||
while (GetMessage (&msg, NULL, 0, 0 ))
|
||||
{
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
return msg.wParam;
|
||||
}
|
||||
|
||||
void StopWin32App ()
|
||||
{
|
||||
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
|
||||
if (hWnd)
|
||||
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
|
||||
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
|
||||
}
|
||||
|
||||
bool GracefulShutdown ()
|
||||
{
|
||||
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
|
||||
if (hWnd)
|
||||
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0);
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
bool StopGracefulShutdown ()
|
||||
{
|
||||
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
|
||||
if (hWnd)
|
||||
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0);
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
void StopWin32App ()
|
||||
{
|
||||
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ namespace i2p
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
bool StartWin32App ();
|
||||
void StopWin32App ();
|
||||
int RunWin32App ();
|
||||
bool StartWin32App ();
|
||||
void StopWin32App ();
|
||||
int RunWin32App ();
|
||||
bool GracefulShutdown ();
|
||||
bool StopGracefulShutdown ();
|
||||
}
|
||||
}
|
||||
#endif // WIN32APP_H__
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
#include <strsafe.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "../Daemon.h"
|
||||
#include "../Log.h"
|
||||
#include "Daemon.h"
|
||||
#include "Log.h"
|
||||
|
||||
I2PService *I2PService::s_service = NULL;
|
||||
|
||||
BOOL I2PService::isService()
|
||||
{
|
||||
BOOL bIsService = FALSE;
|
||||
|
||||
HWINSTA hWinStation = GetProcessWindowStation();
|
||||
if (hWinStation != NULL)
|
||||
{
|
||||
@@ -31,28 +30,23 @@ BOOL I2PService::isService()
|
||||
BOOL I2PService::Run(I2PService &service)
|
||||
{
|
||||
s_service = &service;
|
||||
|
||||
SERVICE_TABLE_ENTRY serviceTable[] =
|
||||
{
|
||||
{ service.m_name, ServiceMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
return StartServiceCtrlDispatcher(serviceTable);
|
||||
}
|
||||
|
||||
|
||||
void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
assert(s_service != NULL);
|
||||
|
||||
s_service->m_statusHandle = RegisterServiceCtrlHandler(
|
||||
s_service->m_name, ServiceCtrlHandler);
|
||||
if (s_service->m_statusHandle == NULL)
|
||||
{
|
||||
throw GetLastError();
|
||||
}
|
||||
|
||||
s_service->Start(dwArgc, pszArgv);
|
||||
}
|
||||
|
||||
@@ -61,27 +55,23 @@ void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
|
||||
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
|
||||
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
|
||||
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
|
||||
case SERVICE_CONTROL_INTERROGATE: break;
|
||||
default: break;
|
||||
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
|
||||
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
|
||||
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
|
||||
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
|
||||
case SERVICE_CONTROL_INTERROGATE: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
I2PService::I2PService(PSTR pszServiceName,
|
||||
BOOL fCanStop,
|
||||
BOOL fCanShutdown,
|
||||
BOOL fCanPauseContinue)
|
||||
{
|
||||
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
|
||||
|
||||
m_statusHandle = NULL;
|
||||
|
||||
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
|
||||
m_status.dwCurrentState = SERVICE_START_PENDING;
|
||||
|
||||
DWORD dwControlsAccepted = 0;
|
||||
@@ -91,16 +81,14 @@ I2PService::I2PService(PSTR pszServiceName,
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
|
||||
if (fCanPauseContinue)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
|
||||
m_status.dwControlsAccepted = dwControlsAccepted;
|
||||
|
||||
m_status.dwControlsAccepted = dwControlsAccepted;
|
||||
m_status.dwWin32ExitCode = NO_ERROR;
|
||||
m_status.dwServiceSpecificExitCode = 0;
|
||||
m_status.dwCheckPoint = 0;
|
||||
m_status.dwWaitHint = 0;
|
||||
|
||||
m_fStopping = FALSE;
|
||||
|
||||
// Create a manual-reset event that is not signaled at first to indicate
|
||||
// Create a manual-reset event that is not signaled at first to indicate
|
||||
// the stopped signal of the service.
|
||||
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (m_hStoppedEvent == NULL)
|
||||
@@ -109,7 +97,6 @@ I2PService::I2PService(PSTR pszServiceName,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
I2PService::~I2PService(void)
|
||||
{
|
||||
if (m_hStoppedEvent)
|
||||
@@ -119,93 +106,73 @@ I2PService::~I2PService(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_START_PENDING);
|
||||
|
||||
OnStart(dwArgc, pszArgv);
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service Start", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED, dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
LogPrint(eLogInfo, "Win32Service in OnStart",
|
||||
EVENTLOG_INFORMATION_TYPE);
|
||||
|
||||
LogPrint(eLogInfo, "Win32Service in OnStart", EVENTLOG_INFORMATION_TYPE);
|
||||
Daemon.start();
|
||||
|
||||
//i2p::util::config::OptionParser(dwArgc, pszArgv);
|
||||
//i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||
//i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
|
||||
// i2p::util::config::GetArg("-port", 17070));
|
||||
|
||||
_worker = new std::thread(std::bind(&I2PService::WorkerThread, this));
|
||||
}
|
||||
|
||||
|
||||
void I2PService::WorkerThread()
|
||||
{
|
||||
while (!m_fStopping)
|
||||
{
|
||||
::Sleep(1000); // Simulate some lengthy operations.
|
||||
::Sleep(1000); // Simulate some lengthy operations.
|
||||
}
|
||||
|
||||
// Signal the stopped event.
|
||||
SetEvent(m_hStoppedEvent);
|
||||
}
|
||||
|
||||
|
||||
void I2PService::Stop()
|
||||
{
|
||||
DWORD dwOriginalState = m_status.dwCurrentState;
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_STOP_PENDING);
|
||||
|
||||
OnStop();
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogInfo, "Win32Service Stop", dwError);
|
||||
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::OnStop()
|
||||
{
|
||||
// Log a service stop message to the Application log.
|
||||
LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
|
||||
|
||||
Daemon.stop();
|
||||
|
||||
m_fStopping = TRUE;
|
||||
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
@@ -215,73 +182,59 @@ void I2PService::OnStop()
|
||||
delete _worker;
|
||||
}
|
||||
|
||||
|
||||
void I2PService::Pause()
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_PAUSE_PENDING);
|
||||
|
||||
OnPause();
|
||||
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service Pause", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::OnPause()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void I2PService::Continue()
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_CONTINUE_PENDING);
|
||||
|
||||
OnContinue();
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service Continue", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::OnContinue()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void I2PService::Shutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnShutdown();
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
@@ -294,23 +247,18 @@ void I2PService::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2PService::OnShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void I2PService::SetServiceStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode,
|
||||
DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
|
||||
|
||||
m_status.dwCurrentState = dwCurrentState;
|
||||
m_status.dwWin32ExitCode = dwWin32ExitCode;
|
||||
m_status.dwWaitHint = dwWaitHint;
|
||||
|
||||
m_status.dwCheckPoint =
|
||||
((dwCurrentState == SERVICE_RUNNING) ||
|
||||
(dwCurrentState == SERVICE_STOPPED)) ?
|
||||
@@ -335,12 +283,7 @@ void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
|
||||
}
|
||||
}
|
||||
|
||||
void InstallService(PSTR pszServiceName,
|
||||
PSTR pszDisplayName,
|
||||
DWORD dwStartType,
|
||||
PSTR pszDependencies,
|
||||
PSTR pszAccount,
|
||||
PSTR pszPassword)
|
||||
void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartType, PCSTR pszDependencies, PCSTR pszAccount, PCSTR pszPassword)
|
||||
{
|
||||
printf("Try to install Win32Service (%s).\n", pszServiceName);
|
||||
|
||||
@@ -354,10 +297,10 @@ void InstallService(PSTR pszServiceName,
|
||||
FreeHandles(schSCManager, schService);
|
||||
return;
|
||||
}
|
||||
strncat(szPath, " --daemon", MAX_PATH);
|
||||
|
||||
// Open the local default service control manager database
|
||||
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT |
|
||||
SC_MANAGER_CREATE_SERVICE);
|
||||
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
||||
if (schSCManager == NULL)
|
||||
{
|
||||
printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError());
|
||||
@@ -381,6 +324,7 @@ void InstallService(PSTR pszServiceName,
|
||||
pszAccount, // Service running account
|
||||
pszPassword // Password of the account
|
||||
);
|
||||
|
||||
if (schService == NULL)
|
||||
{
|
||||
printf("CreateService failed w/err 0x%08lx\n", GetLastError());
|
||||
@@ -394,7 +338,7 @@ void InstallService(PSTR pszServiceName,
|
||||
FreeHandles(schSCManager, schService);
|
||||
}
|
||||
|
||||
void UninstallService(PSTR pszServiceName)
|
||||
void UninstallService(PCSTR pszServiceName)
|
||||
{
|
||||
printf("Try to uninstall Win32Service (%s).\n", pszServiceName);
|
||||
|
||||
@@ -412,8 +356,7 @@ void UninstallService(PSTR pszServiceName)
|
||||
}
|
||||
|
||||
// Open the service with delete, stop, and query status permissions
|
||||
schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP |
|
||||
SERVICE_QUERY_STATUS | DELETE);
|
||||
schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
|
||||
if (schService == NULL)
|
||||
{
|
||||
printf("OpenService failed w/err 0x%08lx\n", GetLastError());
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
#include <thread>
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
// Internal name of the service
|
||||
#define SERVICE_NAME "i2pService"
|
||||
#define SERVICE_NAME "i2pdService"
|
||||
|
||||
// Displayed name of the service
|
||||
#define SERVICE_DISPLAY_NAME "i2p router service"
|
||||
#define SERVICE_DISPLAY_NAME "i2pd router service"
|
||||
|
||||
// Service start options.
|
||||
#define SERVICE_START_TYPE SERVICE_DEMAND_START
|
||||
@@ -25,7 +24,6 @@
|
||||
#define SERVICE_PASSWORD NULL
|
||||
#endif
|
||||
|
||||
|
||||
class I2PService
|
||||
{
|
||||
public:
|
||||
@@ -72,13 +70,15 @@ private:
|
||||
std::thread* _worker;
|
||||
};
|
||||
|
||||
void InstallService(PSTR pszServiceName,
|
||||
PSTR pszDisplayName,
|
||||
void InstallService(
|
||||
PCSTR pszServiceName,
|
||||
PCSTR pszDisplayName,
|
||||
DWORD dwStartType,
|
||||
PSTR pszDependencies,
|
||||
PSTR pszAccount,
|
||||
PSTR pszPassword);
|
||||
PCSTR pszDependencies,
|
||||
PCSTR pszAccount,
|
||||
PCSTR pszPassword
|
||||
);
|
||||
|
||||
void UninstallService(PSTR pszServiceName);
|
||||
void UninstallService(PCSTR pszServiceName);
|
||||
|
||||
#endif // WIN_32_SERVICE_H__
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.30723.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "i2pd", "i2pd.vcxproj", "{930568EC-31C9-406A-AD1C-9636DF5D8FAA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.Deploy.0 = Debug|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.Build.0 = Debug|x64
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.Build.0 = Release|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.Deploy.0 = Release|Win32
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.ActiveCfg = Release|x64
|
||||
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,292 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\AddressBook.cpp" />
|
||||
<ClCompile Include="..\aes.cpp" />
|
||||
<ClCompile Include="..\base64.cpp" />
|
||||
<ClCompile Include="..\BOB.cpp" />
|
||||
<ClCompile Include="..\CryptoConst.cpp" />
|
||||
<ClCompile Include="..\Daemon.cpp" />
|
||||
<ClCompile Include="..\DaemonWin32.cpp" />
|
||||
<ClCompile Include="..\Garlic.cpp" />
|
||||
<ClCompile Include="..\HTTPProxy.cpp" />
|
||||
<ClCompile Include="..\HTTPServer.cpp" />
|
||||
<ClCompile Include="..\I2NPProtocol.cpp" />
|
||||
<ClCompile Include="..\i2p.cpp" />
|
||||
<ClCompile Include="..\I2PEndian.cpp" />
|
||||
<ClCompile Include="..\I2PService.cpp" />
|
||||
<ClCompile Include="..\Identity.cpp" />
|
||||
<ClCompile Include="..\LeaseSet.cpp" />
|
||||
<ClCompile Include="..\Log.cpp" />
|
||||
<ClCompile Include="..\NetDb.cpp" />
|
||||
<ClCompile Include="..\NetDbRequests.cpp" />
|
||||
<ClCompile Include="..\NTCPSession.cpp" />
|
||||
<ClCompile Include="..\Profiling.cpp" />
|
||||
<ClCompile Include="..\Reseed.cpp" />
|
||||
<ClCompile Include="..\RouterContext.cpp" />
|
||||
<ClCompile Include="..\RouterInfo.cpp" />
|
||||
<ClCompile Include="..\Signature.cpp" />
|
||||
<ClCompile Include="..\SAM.cpp" />
|
||||
<ClCompile Include="..\SSU.cpp" />
|
||||
<ClCompile Include="..\SSUData.cpp" />
|
||||
<ClCompile Include="..\SSUSession.cpp" />
|
||||
<ClCompile Include="..\Streaming.cpp" />
|
||||
<ClCompile Include="..\Datagram.cpp" />
|
||||
<ClCompile Include="..\Destination.cpp" />
|
||||
<ClCompile Include="..\TransitTunnel.cpp" />
|
||||
<ClCompile Include="..\Transports.cpp" />
|
||||
<ClCompile Include="..\Tunnel.cpp" />
|
||||
<ClCompile Include="..\TunnelEndpoint.cpp" />
|
||||
<ClCompile Include="..\TunnelGateway.cpp" />
|
||||
<ClCompile Include="..\TunnelPool.cpp" />
|
||||
<ClCompile Include="..\UPnP.cpp" />
|
||||
<ClCompile Include="..\util.cpp" />
|
||||
<ClCompile Include="..\SOCKS.cpp" />
|
||||
<ClCompile Include="..\I2PTunnel.cpp" />
|
||||
<ClCompile Include="..\I2PControl.cpp" />
|
||||
<ClCompile Include="..\ClientContext.cpp" />
|
||||
<ClCompile Include="Win32Service.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\AddressBook.h" />
|
||||
<ClInclude Include="..\base64.h" />
|
||||
<ClInclude Include="..\BOB.h" />
|
||||
<ClInclude Include="..\CryptoConst.h" />
|
||||
<ClInclude Include="..\Daemon.h" />
|
||||
<ClInclude Include="..\ElGamal.h" />
|
||||
<ClInclude Include="..\Garlic.h" />
|
||||
<ClInclude Include="..\HTTPProxy.h" />
|
||||
<ClInclude Include="..\HTTPServer.h" />
|
||||
<ClInclude Include="..\I2NPProtocol.h" />
|
||||
<ClInclude Include="..\I2PEndian.h" />
|
||||
<ClInclude Include="..\I2PService.h" />
|
||||
<ClInclude Include="..\Identity.h" />
|
||||
<ClInclude Include="..\LeaseSet.h" />
|
||||
<ClInclude Include="..\LittleBigEndian.h" />
|
||||
<ClInclude Include="..\Log.h" />
|
||||
<ClInclude Include="..\NetDbRequests.h" />
|
||||
<ClInclude Include="..\NetDb.h" />
|
||||
<ClInclude Include="..\NTCPSession.h" />
|
||||
<ClInclude Include="..\Queue.h" />
|
||||
<ClInclude Include="..\Profiling.h" />
|
||||
<ClInclude Include="..\Reseed.h" />
|
||||
<ClInclude Include="..\RouterContext.h" />
|
||||
<ClInclude Include="..\RouterInfo.h" />
|
||||
<ClInclude Include="..\SAM.h" />
|
||||
<ClInclude Include="..\SSU.h" />
|
||||
<ClInclude Include="..\SSUData.h" />
|
||||
<ClInclude Include="..\SSUSession.h" />
|
||||
<ClInclude Include="..\Streaming.h" />
|
||||
<ClInclude Include="..\Datagram.h" />
|
||||
<ClInclude Include="..\Destination.h" />
|
||||
<ClInclude Include="..\Timestamp.h" />
|
||||
<ClInclude Include="..\TransitTunnel.h" />
|
||||
<ClInclude Include="..\Transports.h" />
|
||||
<ClInclude Include="..\Tunnel.h" />
|
||||
<ClInclude Include="..\TunnelBase.h" />
|
||||
<ClInclude Include="..\TunnelConfig.h" />
|
||||
<ClInclude Include="..\TunnelEndpoint.h" />
|
||||
<ClInclude Include="..\TunnelGateway.h" />
|
||||
<ClInclude Include="..\TunnelPool.h" />
|
||||
<ClInclude Include="..\UPnP.h" />
|
||||
<ClInclude Include="..\util.h" />
|
||||
<ClInclude Include="..\SOCKS.h" />
|
||||
<ClInclude Include="..\I2PTunnel.h" />
|
||||
<ClInclude Include="..\I2PControl.h" />
|
||||
<ClInclude Include="..\version.h" />
|
||||
<ClInclude Include="..\Signature.h" />
|
||||
<ClInclude Include="..\ClientContext.h" />
|
||||
<ClInclude Include="..\TransportSession.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Win32Service.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{930568EC-31C9-406A-AD1C-9636DF5D8FAA}</ProjectGuid>
|
||||
<RootNamespace>i2pd</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP);C:\build-lib\cryptopp;C:\build-lib\boost_1_57_0\</IncludePath>
|
||||
<LibraryPath>$(BOOST)\stage\lib;C:\build-lib\cryptopp;C:\build-lib\boost_1_57_0\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
|
||||
<TargetName>$(ProjectName)_d</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP)</IncludePath>
|
||||
<LibraryPath>$(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
|
||||
<TargetName>$(ProjectName)_d</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IncludePath>./..;$(IncludePath);$(BOOST);C:\build-lib\boost_1_57_0\;C:\build-lib</IncludePath>
|
||||
<LibraryPath>C:\build-lib\boost_1_57_0\stage\lib;C:\build-lib\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP)</IncludePath>
|
||||
<LibraryPath>$(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
|
||||
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_MBCS;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<Version>0.2</Version>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_MBCS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<Version>0.2</Version>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level2</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<Version>
|
||||
</Version>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
|
||||
<LinkErrorReporting>NoErrorReport</LinkErrorReporting>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AssemblyIdentity>
|
||||
</AssemblyIdentity>
|
||||
<ComponentFileName>
|
||||
</ComponentFileName>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<Version>
|
||||
</Version>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<MinimumRequiredVersion>5.02</MinimumRequiredVersion>
|
||||
<LinkErrorReporting>NoErrorReport</LinkErrorReporting>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AssemblyIdentity>
|
||||
</AssemblyIdentity>
|
||||
<ComponentFileName>
|
||||
</ComponentFileName>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,302 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Win32">
|
||||
<UniqueIdentifier>{a880a08c-16b8-4243-82ea-6bfc63bb7dab}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\Identity.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\LeaseSet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\NetDb.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\NTCPSession.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\RouterContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\RouterInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Streaming.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\TransitTunnel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Transports.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Tunnel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\TunnelEndpoint.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\TunnelGateway.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\base64.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Garlic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\HTTPServer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\I2NPProtocol.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\i2p.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\I2PEndian.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SOCKS.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SSU.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Reseed.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\UPnP.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\HTTPProxy.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\TunnelPool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\AddressBook.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32Service.cpp">
|
||||
<Filter>Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Daemon.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\DaemonWin32.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SSUData.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\CryptoConst.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\aes.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\I2PTunnel.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SAM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SSUSession.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Datagram.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Destination.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ClientContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\BOB.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\I2PControl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\I2PService.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Identity.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\LeaseSet.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\LittleBigEndian.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Log.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\NetDb.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\NTCPSession.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Queue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\RouterContext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\RouterInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Streaming.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Timestamp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TransitTunnel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Transports.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Tunnel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TunnelBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TunnelConfig.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TunnelEndpoint.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TunnelGateway.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\base64.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\CryptoConst.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ElGamal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Garlic.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\HTTPServer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\I2NPProtocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\I2PEndian.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SOCKS.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SSU.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Reseed.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\UPnP.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\HTTPProxy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TunnelPool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\AddressBook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win32Service.h">
|
||||
<Filter>Win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Daemon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SSUData.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\I2PTunnel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Signature.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SAM.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SSUSession.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Datagram.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Destination.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ClientContext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\TransportSession.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\BOB.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\I2PControl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\I2PService.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,149 +0,0 @@
|
||||
|
||||
#define I2Pd_AppName "i2pd"
|
||||
#define I2Pd_ver "0.2"
|
||||
|
||||
[Setup]
|
||||
AppName={#I2Pd_AppName}
|
||||
AppVersion={#I2Pd_ver}
|
||||
DefaultDirName={pf}\I2Pd
|
||||
DefaultGroupName=I2Pd
|
||||
UninstallDisplayIcon={app}\I2Pd.exe
|
||||
Compression=lzma2
|
||||
SolidCompression=yes
|
||||
OutputDir=.
|
||||
LicenseFile=.\..\LICENSE
|
||||
OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver}
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
|
||||
|
||||
[Files]
|
||||
Source: "x64\Release\i2pd.exe"; DestDir: "{app}"; DestName: "i2pd.exe"; Check: Is64BitInstallMode
|
||||
Source: "Release\i2pd.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode
|
||||
Source: "..\README.md"; DestDir: "{app}"; DestName: "Readme.txt"; AfterInstall: ConvertLineEndings
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\I2Pd"; Filename: "{app}\i2pd.exe"
|
||||
Name: "{group}\Readme"; Filename: "{app}\Readme.txt"
|
||||
|
||||
|
||||
[Registry]
|
||||
Root: HKCU; Subkey: "Environment"; ValueName: "Path"; ValueType: "string"; ValueData: "{app};{olddata}"; Check: NotOnPathAlready(); Flags: preservestringtype;
|
||||
|
||||
[Code]
|
||||
|
||||
var
|
||||
DefaultTop,
|
||||
DefaultLeft,
|
||||
DefaultHeight,
|
||||
DefaultBackTop,
|
||||
DefaultNextTop,
|
||||
DefaultCancelTop,
|
||||
DefaultBevelTop,
|
||||
DefaultOuterHeight: Integer;
|
||||
|
||||
const
|
||||
LicenseHeight = 400;
|
||||
LF = #10;
|
||||
CR = #13;
|
||||
CRLF = CR + LF;
|
||||
|
||||
procedure ConvertLineEndings();
|
||||
var
|
||||
FilePath : String;
|
||||
FileContents : String;
|
||||
begin
|
||||
FilePath := ExpandConstant(CurrentFileName)
|
||||
LoadStringFromFile(FilePath, FileContents);
|
||||
StringChangeEx(FileContents, LF, CRLF, False);
|
||||
SaveStringToFile(FilePath, FileContents, False);
|
||||
end;
|
||||
|
||||
procedure InitializeWizard();
|
||||
begin
|
||||
DefaultTop := WizardForm.Top;
|
||||
DefaultLeft := WizardForm.Left;
|
||||
DefaultHeight := WizardForm.Height;
|
||||
DefaultBackTop := WizardForm.BackButton.Top;
|
||||
DefaultNextTop := WizardForm.NextButton.Top;
|
||||
DefaultCancelTop := WizardForm.CancelButton.Top;
|
||||
DefaultBevelTop := WizardForm.Bevel.Top;
|
||||
DefaultOuterHeight := WizardForm.OuterNotebook.Height;
|
||||
|
||||
WizardForm.InnerPage.Height := WizardForm.InnerPage.Height + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.InnerNotebook.Height := WizardForm.InnerNotebook.Height + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.LicensePage.Height := WizardForm.LicensePage.Height + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.LicenseMemo.Height := WizardForm.LicenseMemo.Height + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.LicenseNotAcceptedRadio.Top := WizardForm.LicenseNotAcceptedRadio.Top + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.LicenseAcceptedRadio.Top := WizardForm.LicenseAcceptedRadio.Top + (LicenseHeight - DefaultHeight);
|
||||
|
||||
end;
|
||||
|
||||
procedure CurPageChanged(CurPageID: Integer);
|
||||
begin
|
||||
if CurPageID = wpLicense then
|
||||
begin
|
||||
WizardForm.Top := DefaultTop - (LicenseHeight - DefaultHeight) div 2;
|
||||
WizardForm.Height := LicenseHeight;
|
||||
WizardForm.OuterNotebook.Height := WizardForm.OuterNotebook.Height + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.CancelButton.Top := DefaultCancelTop + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.NextButton.Top := DefaultNextTop + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.BackButton.Top := DefaultBackTop + (LicenseHeight - DefaultHeight);
|
||||
WizardForm.Bevel.Top := DefaultBevelTop + (LicenseHeight - DefaultHeight);
|
||||
end
|
||||
else
|
||||
begin
|
||||
WizardForm.Top := DefaultTop;
|
||||
WizardForm.Left := DefaultLeft;
|
||||
WizardForm.Height := DefaultHeight;
|
||||
WizardForm.OuterNotebook.Height := DefaultOuterHeight;
|
||||
WizardForm.CancelButton.Top := DefaultCancelTop;
|
||||
WizardForm.NextButton.Top := DefaultNextTop;
|
||||
WizardForm.BackButton.Top := DefaultBackTop;
|
||||
WizardForm.Bevel.Top := DefaultBevelTop;
|
||||
end;
|
||||
end;
|
||||
|
||||
function NotOnPathAlready(): Boolean;
|
||||
var
|
||||
BinDir, Path: String;
|
||||
begin
|
||||
Log('Checking if i2pd dir is already in the %PATH%');
|
||||
if RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Path) then
|
||||
begin // Successfully read the value
|
||||
Log('HKCUEnvironmentPATH = ' + Path);
|
||||
BinDir := ExpandConstant('{app}');
|
||||
Log('Looking for i2pd dir in %PATH%: ' + BinDir + ' in ' + Path);
|
||||
if Pos(LowerCase(BinDir), Lowercase(Path)) = 0 then
|
||||
begin
|
||||
Log('Did not find i2pd dir in %PATH% so I will add it');
|
||||
Result := True;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Log('Found i2pd dir in %PATH% so will not add it again');
|
||||
Result := False;
|
||||
end
|
||||
end
|
||||
else // The key probably doesn't exist
|
||||
begin
|
||||
Log('Could not access HKCUEnvironmentPATH so I assume that it is OK to add it');
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
||||
var
|
||||
BinDir, Path: String;
|
||||
begin
|
||||
if (CurUninstallStep = usPostUninstall)
|
||||
and (RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'PATH', Path)) then
|
||||
begin
|
||||
BinDir := ExpandConstant('{app}');
|
||||
if Pos(LowerCase(BinDir) + ';', Lowercase(Path)) <> 0 then
|
||||
begin
|
||||
StringChange(Path, BinDir + ';', '');
|
||||
RegWriteStringValue(HKEY_CURRENT_USER, 'Environment', 'PATH', Path);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@@ -1 +0,0 @@
|
||||
i2pd --service=install
|
||||
41
Win32/installer.iss
Normal file
@@ -0,0 +1,41 @@
|
||||
#define I2Pd_AppName "i2pd"
|
||||
#define I2Pd_ver "2.21.0"
|
||||
#define I2Pd_Publisher "PurpleI2P"
|
||||
|
||||
[Setup]
|
||||
AppName={#I2Pd_AppName}
|
||||
AppVersion={#I2Pd_ver}
|
||||
AppPublisher={#I2Pd_Publisher}
|
||||
DefaultDirName={pf}\I2Pd
|
||||
DefaultGroupName=I2Pd
|
||||
UninstallDisplayIcon={app}\I2Pd.exe
|
||||
OutputDir=.
|
||||
LicenseFile=../LICENSE
|
||||
OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver}
|
||||
SetupIconFile=mask.ico
|
||||
InternalCompressLevel=ultra64
|
||||
Compression=lzma/ultra64
|
||||
SolidCompression=true
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
AppVerName={#I2Pd_AppName}
|
||||
ExtraDiskSpaceRequired=15
|
||||
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
||||
AppPublisherURL=http://i2pd.website/
|
||||
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
|
||||
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
|
||||
|
||||
[Files]
|
||||
Source: ..\i2pd_x86.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64
|
||||
Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64
|
||||
Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist
|
||||
Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
||||
Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
||||
Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
||||
Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
Name: {group}\I2Pd; Filename: {app}\i2pd.exe
|
||||
Name: {group}\Readme; Filename: {app}\Readme.txt
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: {app}
|
||||
BIN
Win32/mask.bmp
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Win32/mask.ico
Normal file
|
After Width: | Height: | Size: 153 KiB |
@@ -1,57 +0,0 @@
|
||||
!verbose push
|
||||
!verbose 3
|
||||
|
||||
!ifndef _MUI_EXTRAPAGES_NSH
|
||||
!define _MUI_EXTRAPAGES_NSH
|
||||
|
||||
!ifmacrondef MUI_EXTRAPAGE_README & MUI_PAGE_README & MUI_UNPAGE_README & ReadmeLangStrings
|
||||
|
||||
!macro MUI_EXTRAPAGE_README UN ReadmeFile
|
||||
!verbose push
|
||||
!verbose 3
|
||||
!define MUI_PAGE_HEADER_TEXT "$(${UN}ReadmeHeader)"
|
||||
!define MUI_PAGE_HEADER_SUBTEXT "$(${UN}ReadmeSubHeader)"
|
||||
!define MUI_LICENSEPAGE_TEXT_TOP "$(${UN}ReadmeTextTop)"
|
||||
!define MUI_LICENSEPAGE_TEXT_BOTTOM "$(${UN}ReadmeTextBottom)"
|
||||
!define MUI_LICENSEPAGE_BUTTON "$(^NextBtn)"
|
||||
!insertmacro MUI_${UN}PAGE_LICENSE "${ReadmeFile}"
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!define ReadmeRun "!insertmacro MUI_EXTRAPAGE_README"
|
||||
|
||||
|
||||
!macro MUI_PAGE_README ReadmeFile
|
||||
!verbose push
|
||||
!verbose 3
|
||||
${ReadmeRun} "" "${ReadmeFile}"
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
!macro MUI_UNPAGE_README ReadmeFile
|
||||
!verbose push
|
||||
!verbose 3
|
||||
${ReadmeRun} "UN" "${ReadmeFile}"
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
|
||||
!macro ReadmeLangStrings UN MUI_LANG ReadmeHeader ReadmeSubHeader ReadmeTextTop ReadmeTextBottom
|
||||
!verbose push
|
||||
!verbose 3
|
||||
LangString ${UN}ReadmeHeader ${MUI_LANG} "${ReadmeHeader}"
|
||||
LangString ${UN}ReadmeSubHeader ${MUI_LANG} "${ReadmeSubHeader}"
|
||||
LangString ${UN}ReadmeTextTop ${MUI_LANG} "${ReadmeTextTop}"
|
||||
LangString ${UN}ReadmeTextBottom ${MUI_LANG} "${ReadmeTextBottom}"
|
||||
!verbose pop
|
||||
!macroend
|
||||
|
||||
!define ReadmeLanguage `!insertmacro ReadmeLangStrings ""`
|
||||
|
||||
!define Un.ReadmeLanguage `!insertmacro ReadmeLangStrings "UN"`
|
||||
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!verbose pop
|
||||
@@ -1,419 +0,0 @@
|
||||
; NSIS SERVICE LIBRARY - servicelib.nsh
|
||||
; Version 1.8.1 - Jun 21th, 2013
|
||||
; Questions/Comments - dselkirk@hotmail.com
|
||||
;
|
||||
; Description:
|
||||
; Provides an interface to window services
|
||||
;
|
||||
; Inputs:
|
||||
; action - systemlib action ie. create, delete, start, stop, pause,
|
||||
; continue, installed, running, status
|
||||
; name - name of service to manipulate
|
||||
; param - action parameters; usage: var1=value1;var2=value2;...etc.
|
||||
; (don't forget to add a ';' after the last value!)
|
||||
;
|
||||
; Actions:
|
||||
; create - creates a new windows service
|
||||
; Parameters:
|
||||
; path - path to service executable
|
||||
; autostart - automatically start with system ie. 1|0
|
||||
; interact - interact with the desktop ie. 1|0
|
||||
; depend - service dependencies
|
||||
; user - user that runs the service
|
||||
; password - password of the above user
|
||||
; display - display name in service's console
|
||||
; description - Description of service
|
||||
; starttype - start type (supersedes autostart)
|
||||
; servicetype - service type (supersedes interact)
|
||||
;
|
||||
; delete - deletes a windows service
|
||||
; start - start a stopped windows service
|
||||
; stop - stops a running windows service
|
||||
; pause - pauses a running windows service
|
||||
; continue - continues a paused windows service
|
||||
; installed - is the provided service installed
|
||||
; Parameters:
|
||||
; action - if true then invokes the specified action
|
||||
; running - is the provided service running
|
||||
; Parameters:
|
||||
; action - if true then invokes the specified action
|
||||
; status - check the status of the provided service
|
||||
;
|
||||
; Usage:
|
||||
; Method 1:
|
||||
; Push "action"
|
||||
; Push "name"
|
||||
; Push "param"
|
||||
; Call Service
|
||||
; Pop $0 ;response
|
||||
;
|
||||
; Method 2:
|
||||
; !insertmacro SERVICE "action" "name" "param"
|
||||
;
|
||||
; History:
|
||||
; 1.0 - 09/15/2003 - Initial release
|
||||
; 1.1 - 09/16/2003 - Changed &l to i, thx brainsucker
|
||||
; 1.2 - 02/29/2004 - Fixed documentation.
|
||||
; 1.3 - 01/05/2006 - Fixed interactive flag and pop order (Kichik)
|
||||
; 1.4 - 12/07/2006 - Added display and depend, fixed datatypes (Vitoco)
|
||||
; 1.5 - 06/25/2008 - Added description of service.(DeSafe.com/liuqixing#gmail.com)
|
||||
; 1.5.1 - 06/12/2009 - Added use of __UNINSTALL__
|
||||
; 1.6 - 08/02/2010 - Fixed description implementation (Anders)
|
||||
; 1.7 - 04/11/2010 - Added get running service process id (Nico)
|
||||
; 1.8 - 24/03/2011 - Added starttype and servicetype (Sergius)
|
||||
; 1.8.1 - 21/06/2013 - Added dynamic ASCII & Unicode support (Zinthose)
|
||||
|
||||
!ifndef SERVICELIB
|
||||
!define SERVICELIB
|
||||
|
||||
!define SC_MANAGER_ALL_ACCESS 0x3F
|
||||
!define SC_STATUS_PROCESS_INFO 0x0
|
||||
!define SERVICE_ALL_ACCESS 0xF01FF
|
||||
|
||||
!define SERVICE_CONTROL_STOP 1
|
||||
!define SERVICE_CONTROL_PAUSE 2
|
||||
!define SERVICE_CONTROL_CONTINUE 3
|
||||
|
||||
!define SERVICE_STOPPED 0x1
|
||||
!define SERVICE_START_PENDING 0x2
|
||||
!define SERVICE_STOP_PENDING 0x3
|
||||
!define SERVICE_RUNNING 0x4
|
||||
!define SERVICE_CONTINUE_PENDING 0x5
|
||||
!define SERVICE_PAUSE_PENDING 0x6
|
||||
!define SERVICE_PAUSED 0x7
|
||||
|
||||
!define SERVICE_KERNEL_DRIVER 0x00000001
|
||||
!define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
|
||||
!define SERVICE_WIN32_OWN_PROCESS 0x00000010
|
||||
!define SERVICE_WIN32_SHARE_PROCESS 0x00000020
|
||||
!define SERVICE_INTERACTIVE_PROCESS 0x00000100
|
||||
|
||||
|
||||
!define SERVICE_BOOT_START 0x00000000
|
||||
!define SERVICE_SYSTEM_START 0x00000001
|
||||
!define SERVICE_AUTO_START 0x00000002
|
||||
!define SERVICE_DEMAND_START 0x00000003
|
||||
!define SERVICE_DISABLED 0x00000004
|
||||
|
||||
## Added by Zinthose for Native Unicode Support
|
||||
!ifdef NSIS_UNICODE
|
||||
!define APITAG "W"
|
||||
!else
|
||||
!define APITAG "A"
|
||||
!endif
|
||||
|
||||
!macro SERVICE ACTION NAME PARAM
|
||||
Push '${ACTION}'
|
||||
Push '${NAME}'
|
||||
Push '${PARAM}'
|
||||
!ifdef __UNINSTALL__
|
||||
Call un.Service
|
||||
!else
|
||||
Call Service
|
||||
!endif
|
||||
!macroend
|
||||
|
||||
!macro FUNC_GETPARAM
|
||||
Push $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $5
|
||||
Push $6
|
||||
Push $7
|
||||
Exch 8
|
||||
Pop $1 ;name
|
||||
Exch 8
|
||||
Pop $2 ;source
|
||||
StrCpy $0 ""
|
||||
StrLen $7 $2
|
||||
StrCpy $3 0
|
||||
lbl_loop:
|
||||
IntCmp $3 $7 0 0 lbl_done
|
||||
StrLen $4 "$1="
|
||||
StrCpy $5 $2 $4 $3
|
||||
StrCmp $5 "$1=" 0 lbl_next
|
||||
IntOp $5 $3 + $4
|
||||
StrCpy $3 $5
|
||||
lbl_loop2:
|
||||
IntCmp $3 $7 0 0 lbl_done
|
||||
StrCpy $6 $2 1 $3
|
||||
StrCmp $6 ";" 0 lbl_next2
|
||||
IntOp $6 $3 - $5
|
||||
StrCpy $0 $2 $6 $5
|
||||
Goto lbl_done
|
||||
lbl_next2:
|
||||
IntOp $3 $3 + 1
|
||||
Goto lbl_loop2
|
||||
lbl_next:
|
||||
IntOp $3 $3 + 1
|
||||
Goto lbl_loop
|
||||
lbl_done:
|
||||
Pop $5
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Exch 2
|
||||
Pop $6
|
||||
Pop $7
|
||||
Exch $0
|
||||
!macroend
|
||||
|
||||
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL
|
||||
Push $1
|
||||
Push ${NAME}
|
||||
Call ${UN}GETPARAM
|
||||
Pop $6
|
||||
StrCpy ${VAR} "${DEFAULT}"
|
||||
StrCmp $6 "" "${LABEL}" 0
|
||||
StrCpy ${VAR} $6
|
||||
!macroend
|
||||
|
||||
!macro FUNC_SERVICE UN
|
||||
Push $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $5
|
||||
Push $6
|
||||
Push $7
|
||||
Exch 8
|
||||
Pop $1 ;param
|
||||
Exch 8
|
||||
Pop $2 ;name
|
||||
Exch 8
|
||||
Pop $3 ;action
|
||||
;$0 return
|
||||
;$4 OpenSCManager
|
||||
;$5 OpenService
|
||||
|
||||
StrCpy $0 "false"
|
||||
System::Call 'advapi32::OpenSCManager${APITAG}(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4'
|
||||
IntCmp $4 0 lbl_done
|
||||
StrCmp $3 "create" lbl_create
|
||||
System::Call 'advapi32::OpenService${APITAG}(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5'
|
||||
IntCmp $5 0 lbl_done
|
||||
|
||||
lbl_select:
|
||||
StrCmp $3 "delete" lbl_delete
|
||||
StrCmp $3 "start" lbl_start
|
||||
StrCmp $3 "stop" lbl_stop
|
||||
StrCmp $3 "pause" lbl_pause
|
||||
StrCmp $3 "continue" lbl_continue
|
||||
StrCmp $3 "installed" lbl_installed
|
||||
StrCmp $3 "running" lbl_running
|
||||
StrCmp $3 "status" lbl_status
|
||||
StrCmp $3 "processid" lbl_processid
|
||||
Goto lbl_done
|
||||
|
||||
; create service
|
||||
lbl_create:
|
||||
Push $R1 ;depend
|
||||
Push $R2 ;user
|
||||
Push $R3 ;password
|
||||
Push $R4 ;servicetype/interact
|
||||
Push $R5 ;starttype/autostart
|
||||
Push $R6 ;path
|
||||
Push $R7 ;display
|
||||
Push $R8 ;description
|
||||
|
||||
!insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"
|
||||
StrCpy $R1 't "$R1"'
|
||||
lbl_depend:
|
||||
StrCmp $R1 "n" 0 lbl_machine ;old name of depend param
|
||||
!insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine"
|
||||
StrCpy $R1 't "$R1"'
|
||||
lbl_machine:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user"
|
||||
StrCpy $R2 't "$R2"'
|
||||
lbl_user:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password"
|
||||
StrCpy $R3 't "$R3"'
|
||||
lbl_password:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R4 "interact" "${SERVICE_WIN32_OWN_PROCESS}" "lbl_interact"
|
||||
StrCpy $6 ${SERVICE_WIN32_OWN_PROCESS}
|
||||
IntCmp $R4 0 +2
|
||||
IntOp $6 $6 | ${SERVICE_INTERACTIVE_PROCESS}
|
||||
StrCpy $R4 $6
|
||||
lbl_interact:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R4 "servicetype" "$R4" "lbl_servicetype"
|
||||
lbl_servicetype:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R5 "autostart" "${SERVICE_DEMAND_START}" "lbl_autostart"
|
||||
StrCpy $6 ${SERVICE_DEMAND_START}
|
||||
IntCmp $R5 0 +2
|
||||
StrCpy $6 ${SERVICE_AUTO_START}
|
||||
StrCpy $R5 $6
|
||||
lbl_autostart:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R5 "starttype" "$R5" "lbl_starttype"
|
||||
lbl_starttype:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R6 "path" "n" "lbl_path"
|
||||
lbl_path:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display"
|
||||
lbl_display:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R8 "description" "$2" "lbl_description"
|
||||
lbl_description:
|
||||
|
||||
System::Call 'advapi32::CreateService${APITAG}(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \
|
||||
i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6'
|
||||
|
||||
; write description of service (SERVICE_CONFIG_DESCRIPTION)
|
||||
System::Call 'advapi32::ChangeServiceConfig2${APITAG}(ir6,i1,*t "$R8")i.R7'
|
||||
strcmp $R7 "error" 0 lbl_descriptioncomplete
|
||||
WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\$2" "Description" $R8
|
||||
lbl_descriptioncomplete:
|
||||
|
||||
Pop $R8
|
||||
Pop $R7
|
||||
Pop $R6
|
||||
Pop $R5
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; delete service
|
||||
lbl_delete:
|
||||
System::Call 'advapi32::DeleteService(i r5) i.r6'
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; start service
|
||||
lbl_start:
|
||||
System::Call 'advapi32::StartService${APITAG}(i r5, i 0, i 0) i.r6'
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; stop service
|
||||
lbl_stop:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_STOP}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; pause service
|
||||
lbl_pause:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_PAUSE}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; continue service
|
||||
lbl_continue:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_CONTINUE}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; is installed
|
||||
lbl_installed:
|
||||
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
|
||||
StrCpy $3 $7
|
||||
Goto lbl_select
|
||||
|
||||
; is service running
|
||||
lbl_running:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
|
||||
System::Call '*$R1(i, i.r6)'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
IntFmt $6 "0x%X" $6
|
||||
StrCmp $6 ${SERVICE_RUNNING} 0 lbl_done
|
||||
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
|
||||
StrCpy $3 $7
|
||||
Goto lbl_select
|
||||
|
||||
lbl_status:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
|
||||
System::Call '*$R1(i, i .r6)'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
IntFmt $6 "0x%X" $6
|
||||
StrCpy $0 "running"
|
||||
IntCmp $6 ${SERVICE_RUNNING} lbl_done
|
||||
StrCpy $0 "stopped"
|
||||
IntCmp $6 ${SERVICE_STOPPED} lbl_done
|
||||
StrCpy $0 "start_pending"
|
||||
IntCmp $6 ${SERVICE_START_PENDING} lbl_done
|
||||
StrCpy $0 "stop_pending"
|
||||
IntCmp $6 ${SERVICE_STOP_PENDING} lbl_done
|
||||
StrCpy $0 "running"
|
||||
IntCmp $6 ${SERVICE_RUNNING} lbl_done
|
||||
StrCpy $0 "continue_pending"
|
||||
IntCmp $6 ${SERVICE_CONTINUE_PENDING} lbl_done
|
||||
StrCpy $0 "pause_pending"
|
||||
IntCmp $6 ${SERVICE_PAUSE_PENDING} lbl_done
|
||||
StrCpy $0 "paused"
|
||||
IntCmp $6 ${SERVICE_PAUSED} lbl_done
|
||||
StrCpy $0 "unknown"
|
||||
Goto lbl_done
|
||||
|
||||
lbl_processid:
|
||||
Push $R1
|
||||
Push $R2
|
||||
System::Call '*(i,i,i,i,i,i,i,i,i) i.R1'
|
||||
System::Call '*(i 0) i.R2'
|
||||
System::Call "advapi32::QueryServiceStatusEx(i r5, i ${SC_STATUS_PROCESS_INFO}, i $R1, i 36, i $R2) i"
|
||||
System::Call "*$R1(i,i,i,i,i,i,i, i .r0)"
|
||||
System::Free $R2
|
||||
System::Free $R1
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Goto lbl_done
|
||||
|
||||
lbl_good:
|
||||
StrCpy $0 "true"
|
||||
lbl_done:
|
||||
IntCmp $5 0 +2
|
||||
System::Call 'advapi32::CloseServiceHandle(i r5) n'
|
||||
IntCmp $4 0 +2
|
||||
System::Call 'advapi32::CloseServiceHandle(i r4) n'
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Exch 3
|
||||
Pop $5
|
||||
Pop $7
|
||||
Pop $6
|
||||
Exch $0
|
||||
!macroend
|
||||
|
||||
Function Service
|
||||
!insertmacro FUNC_SERVICE ""
|
||||
FunctionEnd
|
||||
|
||||
Function un.Service
|
||||
!insertmacro FUNC_SERVICE "un."
|
||||
FunctionEnd
|
||||
|
||||
Function GetParam
|
||||
!insertmacro FUNC_GETPARAM
|
||||
FunctionEnd
|
||||
|
||||
Function un.GetParam
|
||||
!insertmacro FUNC_GETPARAM
|
||||
FunctionEnd
|
||||
|
||||
!undef APITAG
|
||||
!endif
|
||||
@@ -1,16 +1,11 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Resource.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
#define MAINICON 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
i2pd --service=remove
|
||||
18
android/.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
gen
|
||||
tests
|
||||
bin
|
||||
libs
|
||||
log*
|
||||
obj
|
||||
.gradle
|
||||
.idea
|
||||
.externalNativeBuild
|
||||
ant.properties
|
||||
local.properties
|
||||
build.sh
|
||||
android.iml
|
||||
build
|
||||
gradle
|
||||
gradlew
|
||||
gradlew.bat
|
||||
|
||||
57
android/AndroidManifest.xml
Executable file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.purplei2p.i2pd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="1"
|
||||
android:versionName="2.21.0">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="28" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- normal perm -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- required in API 26+ -->
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
||||
>
|
||||
<receiver android:name=".NetworkStateChangeReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".I2PDPermsAskerActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".I2PDActivity"
|
||||
android:label="@string/app_name" />
|
||||
|
||||
<service
|
||||
android:name=".ForegroundService"
|
||||
android:enabled="true" />
|
||||
|
||||
<activity
|
||||
android:name=".I2PDPermsExplanationActivity"
|
||||
android:label="@string/title_activity_i2_pdperms_asker_prompt"
|
||||
android:parentActivityName=".I2PDPermsAskerActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
1
android/assets/certificates
Symbolic link
@@ -0,0 +1 @@
|
||||
../../contrib/certificates
|
||||
81
android/assets/i2pd.conf
Normal file
@@ -0,0 +1,81 @@
|
||||
## Configuration file for a typical i2pd user
|
||||
## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
|
||||
## for more options you can use in this file.
|
||||
|
||||
#logfile = /sdcard/i2pd/i2pd.log
|
||||
loglevel = none
|
||||
|
||||
# host = 1.2.3.4
|
||||
# port = 4567
|
||||
|
||||
ipv4 = true
|
||||
ipv6 = false
|
||||
|
||||
# ntcp = true
|
||||
# ntcpproxy = http://127.0.0.1:8118
|
||||
# ssu = true
|
||||
|
||||
bandwidth = L
|
||||
# share = 100
|
||||
|
||||
# notransit = true
|
||||
# floodfill = true
|
||||
|
||||
[ntcp2]
|
||||
enabled = true
|
||||
|
||||
[http]
|
||||
enabled = true
|
||||
address = 127.0.0.1
|
||||
port = 7070
|
||||
# auth = true
|
||||
# user = i2pd
|
||||
# pass = changeme
|
||||
|
||||
[httpproxy]
|
||||
enabled = true
|
||||
address = 127.0.0.1
|
||||
port = 4444
|
||||
# keys = http-proxy-keys.dat
|
||||
# addresshelper = true
|
||||
# outproxy = http://false.i2p
|
||||
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[socksproxy]
|
||||
enabled = true
|
||||
address = 127.0.0.1
|
||||
port = 4447
|
||||
# keys = socks-proxy-keys.dat
|
||||
# outproxy.enabled = false
|
||||
# outproxy = 127.0.0.1
|
||||
# outproxyport = 9050
|
||||
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[sam]
|
||||
enabled = false
|
||||
# address = 127.0.0.1
|
||||
# port = 7656
|
||||
|
||||
[precomputation]
|
||||
elgamal = true
|
||||
|
||||
[upnp]
|
||||
enabled = true
|
||||
# name = I2Pd
|
||||
|
||||
[reseed]
|
||||
verify = true
|
||||
## Path to local reseed data file (.su3) for manual reseeding
|
||||
# file = /path/to/i2pseeds.su3
|
||||
## or HTTPS URL to reseed from
|
||||
# file = https://legit-website.com/i2pseeds.su3
|
||||
## Path to local ZIP file or HTTPS URL to reseed from
|
||||
# zipfile = /path/to/netDb.zip
|
||||
## If you run i2pd behind a proxy server, set proxy server for reseeding here
|
||||
## Should be http://address:port or socks://address:port
|
||||
# proxy = http://127.0.0.1:8118
|
||||
## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
|
||||
# threshold = 25
|
||||
|
||||
[limits]
|
||||
transittunnels = 50
|
||||
33
android/assets/tunnels.conf
Normal file
@@ -0,0 +1,33 @@
|
||||
[IRC-IRC2P]
|
||||
#type = client
|
||||
#address = 127.0.0.1
|
||||
#port = 6668
|
||||
#destination = irc.postman.i2p
|
||||
#destinationport = 6667
|
||||
#keys = irc-keys.dat
|
||||
|
||||
#[IRC-ILITA]
|
||||
#type = client
|
||||
#address = 127.0.0.1
|
||||
#port = 6669
|
||||
#destination = irc.ilita.i2p
|
||||
#destinationport = 6667
|
||||
#keys = irc-keys.dat
|
||||
|
||||
#[SMTP]
|
||||
#type = client
|
||||
#address = 127.0.0.1
|
||||
#port = 7659
|
||||
#destination = smtp.postman.i2p
|
||||
#destinationport = 25
|
||||
#keys = smtp-keys.dat
|
||||
|
||||
#[POP3]
|
||||
#type = client
|
||||
#address = 127.0.0.1
|
||||
#port = 7660
|
||||
#destination = pop.postman.i2p
|
||||
#destinationport = 110
|
||||
#keys = pop3-keys.dat
|
||||
|
||||
# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/
|
||||
74
android/build.gradle
Normal file
@@ -0,0 +1,74 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-compat:28.0.0'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.1"
|
||||
defaultConfig {
|
||||
applicationId "org.purplei2p.i2pd"
|
||||
targetSdkVersion 28
|
||||
minSdkVersion 14
|
||||
versionCode 1
|
||||
versionName "2.21.0"
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a'
|
||||
abiFilters 'x86'
|
||||
}
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "-j4"
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
orignal {
|
||||
storeFile file("i2pdapk.jks")
|
||||
storePassword "android"
|
||||
keyAlias "i2pdapk"
|
||||
keyPassword "android"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
signingConfig signingConfigs.orignal
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path './jni/Android.mk'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
96
android/build.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="i2pd" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Insert sdk.dir=... into './local.properties'. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<fail
|
||||
message="ndk.dir is missing. Insert ndk.dir=... into './local.properties'."
|
||||
unless="ndk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
</project>
|
||||
1
android/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.parallel=true
|
||||
73
android/jni/Android.mk
Executable file
@@ -0,0 +1,73 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := i2pd
|
||||
LOCAL_CPP_FEATURES := rtti exceptions
|
||||
LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH)
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
boost_system \
|
||||
boost_date_time \
|
||||
boost_filesystem \
|
||||
boost_program_options \
|
||||
crypto ssl \
|
||||
miniupnpc
|
||||
LOCAL_LDLIBS := -lz
|
||||
|
||||
LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \
|
||||
$(wildcard $(LIB_SRC_PATH)/*.cpp)\
|
||||
$(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\
|
||||
$(DAEMON_SRC_PATH)/Daemon.cpp \
|
||||
$(DAEMON_SRC_PATH)/UPnP.cpp \
|
||||
$(DAEMON_SRC_PATH)/HTTPServer.cpp \
|
||||
$(DAEMON_SRC_PATH)/I2PControl.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_system
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_64_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_64_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_date_time
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_64_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_64_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_filesystem
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_64_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_64_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_program_options
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_64_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_64_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := crypto
|
||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1/$(TARGET_ARCH_ABI)/lib/libcrypto.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ssl
|
||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1/$(TARGET_ARCH_ABI)/lib/libssl.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1/include
|
||||
LOCAL_STATIC_LIBRARIES := crypto
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := miniupnpc
|
||||
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
41
android/jni/Application.mk
Executable file
@@ -0,0 +1,41 @@
|
||||
#APP_ABI := all
|
||||
APP_ABI := armeabi-v7a x86
|
||||
#APP_ABI := x86
|
||||
#APP_ABI := x86_64
|
||||
#APP_ABI := armeabi-v7a
|
||||
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
|
||||
APP_PLATFORM := android-14
|
||||
|
||||
# http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse
|
||||
NDK_TOOLCHAIN_VERSION := 4.9
|
||||
# APP_STL := stlport_shared --> does not seem to contain C++11 features
|
||||
APP_STL := gnustl_shared
|
||||
|
||||
# Enable c++11 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++11
|
||||
|
||||
APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||
endif
|
||||
|
||||
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
|
||||
#APP_OPTIM := debug
|
||||
|
||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||
# change to your own
|
||||
I2PD_LIBS_PATH = /path/to/libraries
|
||||
BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt
|
||||
OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt
|
||||
MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt
|
||||
IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs
|
||||
|
||||
# don't change me
|
||||
I2PD_SRC_PATH = $(PWD)/..
|
||||
|
||||
LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd
|
||||
LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client
|
||||
DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon
|
||||
207
android/jni/DaemonAndroid.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <exception>
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
//#include "mainwindow.h"
|
||||
#include "FS.h"
|
||||
#include "DaemonAndroid.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace android
|
||||
{
|
||||
/* Worker::Worker (DaemonAndroidImpl& daemon):
|
||||
m_Daemon (daemon)
|
||||
{
|
||||
}
|
||||
|
||||
void Worker::startDaemon()
|
||||
{
|
||||
Log.d(TAG"Performing daemon start...");
|
||||
m_Daemon.start();
|
||||
Log.d(TAG"Daemon started.");
|
||||
emit resultReady();
|
||||
}
|
||||
void Worker::restartDaemon()
|
||||
{
|
||||
Log.d(TAG"Performing daemon restart...");
|
||||
m_Daemon.restart();
|
||||
Log.d(TAG"Daemon restarted.");
|
||||
emit resultReady();
|
||||
}
|
||||
void Worker::stopDaemon() {
|
||||
Log.d(TAG"Performing daemon stop...");
|
||||
m_Daemon.stop();
|
||||
Log.d(TAG"Daemon stopped.");
|
||||
emit resultReady();
|
||||
}
|
||||
|
||||
Controller::Controller(DaemonAndroidImpl& daemon):
|
||||
m_Daemon (daemon)
|
||||
{
|
||||
Worker *worker = new Worker (m_Daemon);
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
|
||||
connect(this, &Controller::startDaemon, worker, &Worker::startDaemon);
|
||||
connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon);
|
||||
connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon);
|
||||
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
|
||||
workerThread.start();
|
||||
}
|
||||
Controller::~Controller()
|
||||
{
|
||||
Log.d(TAG"Closing and waiting for daemon worker thread...");
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
Log.d(TAG"Waiting for daemon worker thread finished.");
|
||||
if(m_Daemon.isRunning())
|
||||
{
|
||||
Log.d(TAG"Stopping the daemon...");
|
||||
m_Daemon.stop();
|
||||
Log.d(TAG"Stopped the daemon.");
|
||||
}
|
||||
}
|
||||
*/
|
||||
DaemonAndroidImpl::DaemonAndroidImpl ()
|
||||
//:
|
||||
/*mutex(nullptr), */
|
||||
//m_IsRunning(false),
|
||||
//m_RunningChangedCallback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DaemonAndroidImpl::~DaemonAndroidImpl ()
|
||||
{
|
||||
//delete mutex;
|
||||
}
|
||||
|
||||
bool DaemonAndroidImpl::init(int argc, char* argv[])
|
||||
{
|
||||
//mutex=new QMutex(QMutex::Recursive);
|
||||
//setRunningCallback(0);
|
||||
//m_IsRunning=false;
|
||||
|
||||
// make sure assets are ready before proceed
|
||||
i2p::fs::DetectDataDir("", false);
|
||||
int numAttempts = 0;
|
||||
do
|
||||
{
|
||||
if (i2p::fs::Exists (i2p::fs::DataDirPath("assets.ready"))) break; // assets ready
|
||||
numAttempts++;
|
||||
std::this_thread::sleep_for (std::chrono::seconds(1)); // otherwise wait for 1 more second
|
||||
}
|
||||
while (numAttempts <= 10); // 10 seconds max
|
||||
return Daemon.init(argc,argv);
|
||||
}
|
||||
|
||||
void DaemonAndroidImpl::start()
|
||||
{
|
||||
//QMutexLocker locker(mutex);
|
||||
//setRunning(true);
|
||||
Daemon.start();
|
||||
}
|
||||
|
||||
void DaemonAndroidImpl::stop()
|
||||
{
|
||||
//QMutexLocker locker(mutex);
|
||||
Daemon.stop();
|
||||
//setRunning(false);
|
||||
}
|
||||
|
||||
void DaemonAndroidImpl::restart()
|
||||
{
|
||||
//QMutexLocker locker(mutex);
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
/*
|
||||
void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb)
|
||||
{
|
||||
m_RunningChangedCallback = cb;
|
||||
}
|
||||
|
||||
bool DaemonAndroidImpl::isRunning()
|
||||
{
|
||||
return m_IsRunning;
|
||||
}
|
||||
|
||||
void DaemonAndroidImpl::setRunning(bool newValue)
|
||||
{
|
||||
bool oldValue = m_IsRunning;
|
||||
if(oldValue!=newValue)
|
||||
{
|
||||
m_IsRunning = newValue;
|
||||
if(m_RunningChangedCallback)
|
||||
m_RunningChangedCallback();
|
||||
}
|
||||
}
|
||||
*/
|
||||
static DaemonAndroidImpl daemon;
|
||||
static char* argv[1]={strdup("tmp")};
|
||||
/**
|
||||
* returns error details if failed
|
||||
* returns "ok" if daemon initialized and started okay
|
||||
*/
|
||||
std::string start(/*int argc, char* argv[]*/)
|
||||
{
|
||||
try
|
||||
{
|
||||
//int result;
|
||||
|
||||
{
|
||||
//Log.d(TAG"Initialising the daemon...");
|
||||
bool daemonInitSuccess = daemon.init(1,argv);
|
||||
if(!daemonInitSuccess)
|
||||
{
|
||||
//QMessageBox::critical(0, "Error", "Daemon init failed");
|
||||
return "Daemon init failed";
|
||||
}
|
||||
//Log.d(TAG"Initialised, creating the main window...");
|
||||
//MainWindow w;
|
||||
//Log.d(TAG"Before main window.show()...");
|
||||
//w.show ();
|
||||
|
||||
{
|
||||
//i2p::qt::Controller daemonQtController(daemon);
|
||||
//Log.d(TAG"Starting the daemon...");
|
||||
//emit daemonQtController.startDaemon();
|
||||
//daemon.start ();
|
||||
//Log.d(TAG"Starting GUI event loop...");
|
||||
//result = app.exec();
|
||||
//daemon.stop ();
|
||||
daemon.start();
|
||||
}
|
||||
}
|
||||
|
||||
//QMessageBox::information(&w, "Debug", "demon stopped");
|
||||
//Log.d(TAG"Exiting the application");
|
||||
//return result;
|
||||
}
|
||||
catch (boost::exception& ex)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << boost::diagnostic_information(ex);
|
||||
return ss.str();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ex.what();
|
||||
return ss.str();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return "unknown exception";
|
||||
}
|
||||
return "ok";
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
daemon.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
87
android/jni/DaemonAndroid.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef DAEMON_ANDROID_H
|
||||
#define DAEMON_ANDROID_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace android
|
||||
{
|
||||
class DaemonAndroidImpl
|
||||
{
|
||||
public:
|
||||
|
||||
DaemonAndroidImpl ();
|
||||
~DaemonAndroidImpl ();
|
||||
|
||||
//typedef void (*runningChangedCallback)();
|
||||
|
||||
/**
|
||||
* @return success
|
||||
*/
|
||||
bool init(int argc, char* argv[]);
|
||||
void start();
|
||||
void stop();
|
||||
void restart();
|
||||
//void setRunningCallback(runningChangedCallback cb);
|
||||
//bool isRunning();
|
||||
private:
|
||||
//void setRunning(bool running);
|
||||
private:
|
||||
//QMutex* mutex;
|
||||
//bool m_IsRunning;
|
||||
//runningChangedCallback m_RunningChangedCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns "ok" if daemon init failed
|
||||
* returns errinfo if daemon initialized and started okay
|
||||
*/
|
||||
std::string start();
|
||||
|
||||
// stops the daemon
|
||||
void stop();
|
||||
|
||||
/*
|
||||
class Worker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
Worker (DaemonAndroidImpl& daemon);
|
||||
|
||||
private:
|
||||
|
||||
DaemonAndroidImpl& m_Daemon;
|
||||
|
||||
public slots:
|
||||
void startDaemon();
|
||||
void restartDaemon();
|
||||
void stopDaemon();
|
||||
|
||||
signals:
|
||||
void resultReady();
|
||||
};
|
||||
|
||||
class Controller : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QThread workerThread;
|
||||
public:
|
||||
Controller(DaemonAndroidImpl& daemon);
|
||||
~Controller();
|
||||
private:
|
||||
DaemonAndroidImpl& m_Daemon;
|
||||
|
||||
public slots:
|
||||
void handleResults(){}
|
||||
signals:
|
||||
void startDaemon();
|
||||
void stopDaemon();
|
||||
void restartDaemon();
|
||||
};
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DAEMON_ANDROID_H
|
||||
66
android/jni/i2pd_android.cpp
Executable file
@@ -0,0 +1,66 @@
|
||||
|
||||
//#include <string.h>
|
||||
#include <jni.h>
|
||||
#include "org_purplei2p_i2pd_I2PD_JNI.h"
|
||||
#include "DaemonAndroid.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
|
||||
(JNIEnv * env, jclass clazz) {
|
||||
#if defined(__arm__)
|
||||
#if defined(__ARM_ARCH_7A__)
|
||||
#if defined(__ARM_NEON__)
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
#define ABI "armeabi-v7a/NEON (hard-float)"
|
||||
#else
|
||||
#define ABI "armeabi-v7a/NEON"
|
||||
#endif
|
||||
#else
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
#define ABI "armeabi-v7a (hard-float)"
|
||||
#else
|
||||
#define ABI "armeabi-v7a"
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define ABI "armeabi"
|
||||
#endif
|
||||
#elif defined(__i386__)
|
||||
#define ABI "x86"
|
||||
#elif defined(__x86_64__)
|
||||
#define ABI "x86_64"
|
||||
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
|
||||
#define ABI "mips64"
|
||||
#elif defined(__mips__)
|
||||
#define ABI "mips"
|
||||
#elif defined(__aarch64__)
|
||||
#define ABI "arm64-v8a"
|
||||
#else
|
||||
#define ABI "unknown"
|
||||
#endif
|
||||
|
||||
return env->NewStringUTF(ABI);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
|
||||
(JNIEnv * env, jclass clazz) {
|
||||
return env->NewStringUTF(i2p::android::start().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
|
||||
(JNIEnv * env, jclass clazz) {
|
||||
i2p::android::stop();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
|
||||
(JNIEnv * env, jclass clazz) {
|
||||
i2p::context.SetAcceptsTunnels (false);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
|
||||
(JNIEnv * env, jclass clazz, jboolean isConnected)
|
||||
{
|
||||
bool isConnectedBool = (bool) isConnected;
|
||||
i2p::transport::transports.SetOnline (isConnectedBool);
|
||||
}
|
||||
33
android/jni/org_purplei2p_i2pd_I2PD_JNI.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class org_purplei2p_i2pd_I2PD_JNI */
|
||||
|
||||
#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI
|
||||
#define _Included_org_purplei2p_i2pd_I2PD_JNI
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_purplei2p_i2pd_I2PD_JNI
|
||||
* Method: stringFromJNI
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
|
||||
(JNIEnv * env, jclass clazz, jboolean isConnected);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
20
android/proguard-project.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
14
android/project.properties
Normal file
@@ -0,0 +1,14 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-28
|
||||
BIN
android/res/drawable/icon.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
android/res/drawable/itoopie_notification_icon.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
27
android/res/layout/activity_perms_asker.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<LinearLayout android:id="@+id/main_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/vertical_page_margin"
|
||||
android:paddingLeft="@dimen/horizontal_page_margin"
|
||||
android:paddingRight="@dimen/horizontal_page_margin"
|
||||
android:paddingTop="@dimen/vertical_page_margin"
|
||||
tools:context=".I2PDPermsAskerActivity">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textview_retry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/horizontal_page_margin"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_request_write_ext_storage_perms"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Retry requesting the SD card write permissions"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
27
android/res/layout/activity_perms_explanation.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<LinearLayout android:id="@+id/layout_prompt"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/vertical_page_margin"
|
||||
android:paddingLeft="@dimen/horizontal_page_margin"
|
||||
android:paddingRight="@dimen/horizontal_page_margin"
|
||||
android:paddingTop="@dimen/vertical_page_margin"
|
||||
tools:context=".I2PDPermsAskerActivity">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textview_explanation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/horizontal_page_margin"
|
||||
android:text="SD card write access is required to write the keys and other files to the I2PD folder on SD card."
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="OK"
|
||||
/>
|
||||
</LinearLayout>
|
||||
16
android/res/menu/options_main.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".I2PDActivity">
|
||||
<item
|
||||
android:id="@+id/action_graceful_stop"
|
||||
android:title="@string/action_graceful_stop"
|
||||
android:orderInCategory="98"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/action_stop"
|
||||
android:title="@string/action_stop"
|
||||
android:orderInCategory="99"
|
||||
/>
|
||||
</menu>
|
||||
18
android/res/values/strings.xml
Executable file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">i2pd</string>
|
||||
<string name="action_stop">Stop</string>
|
||||
<string name="action_graceful_stop">Graceful Stop</string>
|
||||
<string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string>
|
||||
<string name="graceful_stop_is_in_progress">Graceful stop is in progress</string>
|
||||
<string name="already_stopped">Already stopped</string>
|
||||
<string name="uninitialized">i2pd initializing</string>
|
||||
<string name="starting">i2pd is starting</string>
|
||||
<string name="jniLibraryLoaded">i2pd: loaded JNI libraries</string>
|
||||
<string name="startedOkay">i2pd started</string>
|
||||
<string name="startFailed">i2pd start failed</string>
|
||||
<string name="gracefulShutdownInProgress">i2pd: graceful shutdown in progress</string>
|
||||
<string name="stopped">i2pd has stopped</string>
|
||||
<string name="remaining">remaining</string>
|
||||
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
||||
</resources>
|
||||
16
android/res/values/template-dimens.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<resources>
|
||||
|
||||
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
|
||||
|
||||
<dimen name="margin_tiny">4dp</dimen>
|
||||
<dimen name="margin_small">8dp</dimen>
|
||||
<dimen name="margin_medium">16dp</dimen>
|
||||
<dimen name="margin_large">32dp</dimen>
|
||||
<dimen name="margin_huge">64dp</dimen>
|
||||
|
||||
<!-- Semantic definitions -->
|
||||
|
||||
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
|
||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
||||
|
||||
</resources>
|
||||
1
android/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = "i2pd"
|
||||
136
android/src/org/purplei2p/i2pd/DaemonSingleton.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package org.purplei2p.i2pd;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class DaemonSingleton {
|
||||
private static final String TAG="i2pd";
|
||||
private static final DaemonSingleton instance = new DaemonSingleton();
|
||||
public interface StateUpdateListener { void daemonStateUpdate(); }
|
||||
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
||||
|
||||
public static DaemonSingleton getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
|
||||
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
|
||||
|
||||
private synchronized void setState(State newState) {
|
||||
if(newState==null)throw new NullPointerException();
|
||||
State oldState = state;
|
||||
if(oldState==null)throw new NullPointerException();
|
||||
if(oldState.equals(newState))return;
|
||||
state=newState;
|
||||
fireStateUpdate1();
|
||||
}
|
||||
public synchronized void stopAcceptingTunnels() {
|
||||
if(isStartedOkay()){
|
||||
setState(State.gracefulShutdownInProgress);
|
||||
I2PD_JNI.stopAcceptingTunnels();
|
||||
}
|
||||
}
|
||||
|
||||
private volatile boolean startedOkay;
|
||||
|
||||
public enum State {
|
||||
uninitialized(R.string.uninitialized),
|
||||
starting(R.string.starting),
|
||||
jniLibraryLoaded(R.string.jniLibraryLoaded),
|
||||
startedOkay(R.string.startedOkay),
|
||||
startFailed(R.string.startFailed),
|
||||
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
|
||||
stopped(R.string.stopped);
|
||||
|
||||
State(int statusStringResourceId) {
|
||||
this.statusStringResourceId = statusStringResourceId;
|
||||
}
|
||||
|
||||
private final int statusStringResourceId;
|
||||
|
||||
public int getStatusStringResourceId() {
|
||||
return statusStringResourceId;
|
||||
}
|
||||
};
|
||||
|
||||
private volatile State state = State.uninitialized;
|
||||
|
||||
public State getState() { return state; }
|
||||
|
||||
{
|
||||
setState(State.starting);
|
||||
new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
I2PD_JNI.loadLibraries();
|
||||
setState(State.jniLibraryLoaded);
|
||||
} catch (Throwable tr) {
|
||||
lastThrowable=tr;
|
||||
setState(State.startFailed);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
synchronized (DaemonSingleton.this) {
|
||||
daemonStartResult = I2PD_JNI.startDaemon();
|
||||
if("ok".equals(daemonStartResult)){
|
||||
setState(State.startedOkay);
|
||||
setStartedOkay(true);
|
||||
}else setState(State.startFailed);
|
||||
}
|
||||
} catch (Throwable tr) {
|
||||
lastThrowable=tr;
|
||||
setState(State.startFailed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}, "i2pdDaemonStart").start();
|
||||
}
|
||||
private Throwable lastThrowable;
|
||||
private String daemonStartResult="N/A";
|
||||
|
||||
private void fireStateUpdate1() {
|
||||
Log.i(TAG, "daemon state change: "+state);
|
||||
for(StateUpdateListener listener : stateUpdateListeners) {
|
||||
try {
|
||||
listener.daemonStateUpdate();
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG, "exception in listener ignored", tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Throwable getLastThrowable() {
|
||||
return lastThrowable;
|
||||
}
|
||||
|
||||
public String getDaemonStartResult() {
|
||||
return daemonStartResult;
|
||||
}
|
||||
|
||||
private final Object startedOkayLock = new Object();
|
||||
|
||||
public boolean isStartedOkay() {
|
||||
synchronized (startedOkayLock) {
|
||||
return startedOkay;
|
||||
}
|
||||
}
|
||||
|
||||
private void setStartedOkay(boolean startedOkay) {
|
||||
synchronized (startedOkayLock) {
|
||||
this.startedOkay = startedOkay;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopDaemon() {
|
||||
if(isStartedOkay()){
|
||||
try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);}
|
||||
setStartedOkay(false);
|
||||
setState(State.stopped);
|
||||
}
|
||||
}
|
||||
}
|
||||
149
android/src/org/purplei2p/i2pd/ForegroundService.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package org.purplei2p.i2pd;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class ForegroundService extends Service {
|
||||
private static final String TAG="FgService";
|
||||
|
||||
private volatile boolean shown;
|
||||
|
||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
||||
new DaemonSingleton.StateUpdateListener() {
|
||||
|
||||
@Override
|
||||
public void daemonStateUpdate() {
|
||||
try {
|
||||
synchronized (ForegroundService.this) {
|
||||
if (shown) cancelNotification();
|
||||
showNotification();
|
||||
}
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG,"error ignored",tr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
|
||||
// Unique Identification Number for the Notification.
|
||||
// We use it on Notification start, and to cancel it.
|
||||
private int NOTIFICATION = 1;
|
||||
|
||||
/**
|
||||
* Class for clients to access. Because we know this service always
|
||||
* runs in the same process as its clients, we don't need to deal with
|
||||
* IPC.
|
||||
*/
|
||||
public class LocalBinder extends Binder {
|
||||
ForegroundService getService() {
|
||||
return ForegroundService.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||
|
||||
synchronized (this) {
|
||||
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
|
||||
if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
|
||||
}
|
||||
// Tell the user we started.
|
||||
// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
|
||||
cancelNotification();
|
||||
}
|
||||
|
||||
private synchronized void cancelNotification() {
|
||||
// Cancel the persistent notification.
|
||||
notificationManager.cancel(NOTIFICATION);
|
||||
|
||||
stopForeground(true);
|
||||
|
||||
// Tell the user we stopped.
|
||||
// Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
|
||||
shown=false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
// This is the object that receives interactions from clients. See
|
||||
// RemoteService for a more complete example.
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
/**
|
||||
* Show a notification while this service is running.
|
||||
*/
|
||||
private synchronized void showNotification() {
|
||||
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||
CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
|
||||
|
||||
// The PendingIntent to launch our activity if the user selects this notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||
new Intent(this, I2PDActivity.class), 0);
|
||||
|
||||
// If earlier version channel ID is not used
|
||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||
String channelId = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? createNotificationChannel() : "";
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
Notification notification = new NotificationCompat.Builder(this, channelId)
|
||||
.setOngoing(true)
|
||||
.setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon
|
||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
||||
.setCategory(Notification.CATEGORY_SERVICE)
|
||||
.setTicker(text) // the status text
|
||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
||||
.setContentText(text) // the contents of the entry
|
||||
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||
.build();
|
||||
|
||||
// Send the notification.
|
||||
//mNM.notify(NOTIFICATION, notification);
|
||||
startForeground(NOTIFICATION, notification);
|
||||
shown = true;
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private synchronized String createNotificationChannel() {
|
||||
String channelId = getString(R.string.app_name);
|
||||
CharSequence channelName = "I2Pd service";
|
||||
NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||
//chan.setLightColor(Color.PURPLE);
|
||||
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||
NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
service.createNotificationChannel(chan);
|
||||
return channelId;
|
||||
}
|
||||
|
||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||
}
|
||||
|
||||
419
android/src/org/purplei2p/i2pd/I2PDActivity.java
Executable file
@@ -0,0 +1,419 @@
|
||||
package org.purplei2p.i2pd;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
// For future package update checking
|
||||
import org.purplei2p.i2pd.BuildConfig;
|
||||
|
||||
public class I2PDActivity extends Activity {
|
||||
private static final String TAG = "i2pdActvt";
|
||||
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
||||
|
||||
private TextView textView;
|
||||
private boolean assetsCopied;
|
||||
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
||||
|
||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||
|
||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
||||
new DaemonSingleton.StateUpdateListener() {
|
||||
@Override
|
||||
public void daemonStateUpdate()
|
||||
{
|
||||
processAssets();
|
||||
runOnUiThread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if(textView==null) return;
|
||||
Throwable tr = daemon.getLastThrowable();
|
||||
if(tr!=null) {
|
||||
textView.setText(throwableToString(tr));
|
||||
return;
|
||||
}
|
||||
DaemonSingleton.State state = daemon.getState();
|
||||
textView.setText(
|
||||
String.valueOf(state)+
|
||||
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+
|
||||
(DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"")
|
||||
);
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG,"error ignored",tr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
private static volatile long graceStartedMillis;
|
||||
private static final Object graceStartedMillis_LOCK=new Object();
|
||||
|
||||
private static String formatGraceTimeRemaining() {
|
||||
long remainingSeconds;
|
||||
synchronized (graceStartedMillis_LOCK){
|
||||
remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D);
|
||||
}
|
||||
long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D);
|
||||
long remSec=remainingSeconds-remainingMinutes*60;
|
||||
return remainingMinutes+":"+(remSec/10)+remSec%10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
textView = new TextView(this);
|
||||
setContentView(textView);
|
||||
daemon.addStateChangeListener(daemonStateUpdatedListener);
|
||||
daemonStateUpdatedListener.daemonStateUpdate();
|
||||
|
||||
// set the app be foreground
|
||||
doBindService();
|
||||
|
||||
final Timer gracefulQuitTimer = getGracefulQuitTimer();
|
||||
if(gracefulQuitTimer!=null){
|
||||
long gracefulStopAtMillis;
|
||||
synchronized (graceStartedMillis_LOCK) {
|
||||
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
|
||||
}
|
||||
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
textView = null;
|
||||
daemon.removeStateChangeListener(daemonStateUpdatedListener);
|
||||
//cancelGracefulStop();
|
||||
try{
|
||||
doUnbindService();
|
||||
}catch(Throwable tr){
|
||||
Log.e(TAG, "", tr);
|
||||
}
|
||||
}
|
||||
|
||||
private static void cancelGracefulStop() {
|
||||
Timer gracefulQuitTimer = getGracefulQuitTimer();
|
||||
if(gracefulQuitTimer!=null) {
|
||||
gracefulQuitTimer.cancel();
|
||||
setGracefulQuitTimer(null);
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence throwableToString(Throwable tr) {
|
||||
StringWriter sw = new StringWriter(8192);
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
tr.printStackTrace(pw);
|
||||
pw.close();
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
// private LocalService mBoundService;
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
// interact with the service. Because we have bound to a explicit
|
||||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
// mBoundService = ((LocalService.LocalBinder)service).getService();
|
||||
|
||||
// Tell the user about this for our demo.
|
||||
// Toast.makeText(Binding.this, R.string.local_service_connected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
// This is called when the connection with the service has been
|
||||
// unexpectedly disconnected -- that is, its process crashed.
|
||||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
// mBoundService = null;
|
||||
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
};
|
||||
|
||||
private static volatile boolean mIsBound;
|
||||
|
||||
private void doBindService() {
|
||||
synchronized (I2PDActivity.class) {
|
||||
if (mIsBound) return;
|
||||
// Establish a connection with the service. We use an explicit
|
||||
// class name because we want a specific service implementation that
|
||||
// we know will be running in our own process (and thus won't be
|
||||
// supporting component replacement by other applications).
|
||||
bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE);
|
||||
mIsBound = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void doUnbindService() {
|
||||
synchronized (I2PDActivity.class) {
|
||||
if (mIsBound) {
|
||||
// Detach our existing connection.
|
||||
unbindService(mConnection);
|
||||
mIsBound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.options_main, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
switch(id){
|
||||
case R.id.action_stop:
|
||||
i2pdStop();
|
||||
return true;
|
||||
case R.id.action_graceful_stop:
|
||||
i2pdGracefulStop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void i2pdStop() {
|
||||
cancelGracefulStop();
|
||||
new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "stopping");
|
||||
try{
|
||||
daemon.stopDaemon();
|
||||
}catch (Throwable tr) {
|
||||
Log.e(TAG, "", tr);
|
||||
}
|
||||
}
|
||||
|
||||
},"stop").start();
|
||||
}
|
||||
|
||||
private static volatile Timer gracefulQuitTimer;
|
||||
|
||||
private void i2pdGracefulStop() {
|
||||
if(daemon.getState()==DaemonSingleton.State.stopped){
|
||||
Toast.makeText(this, R.string.already_stopped,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if(getGracefulQuitTimer()!=null){
|
||||
Toast.makeText(this, R.string.graceful_stop_is_already_in_progress,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Toast.makeText(this, R.string.graceful_stop_is_in_progress,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
Log.d(TAG, "grac stopping");
|
||||
if(daemon.isStartedOkay()) {
|
||||
daemon.stopAcceptingTunnels();
|
||||
long gracefulStopAtMillis;
|
||||
synchronized (graceStartedMillis_LOCK) {
|
||||
graceStartedMillis = System.currentTimeMillis();
|
||||
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
|
||||
}
|
||||
rescheduleGraceStop(null,gracefulStopAtMillis);
|
||||
}else{
|
||||
i2pdStop();
|
||||
}
|
||||
} catch(Throwable tr) {
|
||||
Log.e(TAG,"",tr);
|
||||
}
|
||||
}
|
||||
|
||||
},"gracInit").start();
|
||||
}
|
||||
|
||||
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
|
||||
if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel();
|
||||
final Timer gracefulQuitTimer = new Timer(true);
|
||||
setGracefulQuitTimer(gracefulQuitTimer);
|
||||
gracefulQuitTimer.schedule(new TimerTask(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
i2pdStop();
|
||||
}
|
||||
|
||||
}, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis()));
|
||||
final TimerTask tickerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
daemonStateUpdatedListener.daemonStateUpdate();
|
||||
}
|
||||
};
|
||||
gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/);
|
||||
}
|
||||
|
||||
private static Timer getGracefulQuitTimer() {
|
||||
return gracefulQuitTimer;
|
||||
}
|
||||
|
||||
private static void setGracefulQuitTimer(Timer gracefulQuitTimer) {
|
||||
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the asset at the specified path to this app's data directory. If the
|
||||
* asset is a directory, its contents are also copied.
|
||||
*
|
||||
* @param path
|
||||
* Path to asset, relative to app's assets directory.
|
||||
*/
|
||||
private void copyAsset(String path) {
|
||||
AssetManager manager = getAssets();
|
||||
|
||||
// If we have a directory, we make it and recurse. If a file, we copy its
|
||||
// contents.
|
||||
try {
|
||||
String[] contents = manager.list(path);
|
||||
|
||||
// The documentation suggests that list throws an IOException, but doesn't
|
||||
// say under what conditions. It'd be nice if it did so when the path was
|
||||
// to a file. That doesn't appear to be the case. If the returned array is
|
||||
// null or has 0 length, we assume the path is to a file. This means empty
|
||||
// directories will get turned into files.
|
||||
if (contents == null || contents.length == 0)
|
||||
throw new IOException();
|
||||
|
||||
// Make the directory.
|
||||
File dir = new File(i2pdpath, path);
|
||||
dir.mkdirs();
|
||||
|
||||
// Recurse on the contents.
|
||||
for (String entry : contents) {
|
||||
copyAsset(path + "/" + entry);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
copyFileAsset(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the asset file specified by path to app's data directory. Assumes
|
||||
* parent directories have already been created.
|
||||
*
|
||||
* @param path
|
||||
* Path to asset, relative to app's assets directory.
|
||||
*/
|
||||
private void copyFileAsset(String path) {
|
||||
File file = new File(i2pdpath, path);
|
||||
if(!file.exists()) try {
|
||||
InputStream in = getAssets().open(path);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
int read = in.read(buffer);
|
||||
while (read != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
read = in.read(buffer);
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteRecursive(File fileOrDirectory) {
|
||||
if (fileOrDirectory.isDirectory()) {
|
||||
for (File child : fileOrDirectory.listFiles()) {
|
||||
deleteRecursive(child);
|
||||
}
|
||||
}
|
||||
fileOrDirectory.delete();
|
||||
}
|
||||
|
||||
private void processAssets() {
|
||||
if (!assetsCopied) try {
|
||||
assetsCopied = true; // prevent from running on every state update
|
||||
|
||||
File holderfile = new File(i2pdpath, "assets.ready");
|
||||
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
|
||||
StringBuilder text = new StringBuilder();
|
||||
|
||||
if (holderfile.exists()) try { // if holder file exists, read assets version string
|
||||
BufferedReader br = new BufferedReader(new FileReader(holderfile));
|
||||
String line;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
text.append(line);
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
|
||||
// if version differs from current app version or null, try to delete certificates folder
|
||||
if (!text.toString().contains(versionName)) try {
|
||||
holderfile.delete();
|
||||
File certpath = new File(i2pdpath, "certificates");
|
||||
deleteRecursive(certpath);
|
||||
}
|
||||
catch (Throwable tr) {
|
||||
Log.e(TAG, "", tr);
|
||||
}
|
||||
|
||||
// copy assets. If processed file exists, it won't be overwrited
|
||||
copyAsset("certificates");
|
||||
copyAsset("i2pd.conf");
|
||||
copyAsset("subscriptions.txt");
|
||||
copyAsset("tunnels.conf");
|
||||
|
||||
// update holder file about successful copying
|
||||
FileWriter writer = new FileWriter(holderfile);
|
||||
writer.append(versionName);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
catch (Throwable tr)
|
||||
{
|
||||
Log.e(TAG,"copy assets",tr);
|
||||
}
|
||||
}
|
||||
}
|
||||