mirror of
https://github.com/monero-project/monero.git
synced 2025-12-19 02:32:46 -08:00
Compare commits
1335 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5675d48bd4 | ||
|
|
44a2b23b98 | ||
|
|
2a32a25fa0 | ||
|
|
c23bddeb17 | ||
|
|
bb11c91412 | ||
|
|
5fd259d1d4 | ||
|
|
f4c56980ae | ||
|
|
ca1e2fec78 | ||
|
|
15b0ff2c32 | ||
|
|
8133a64260 | ||
|
|
373ce4ab09 | ||
|
|
60a293df79 | ||
|
|
3fd08bd37e | ||
|
|
3deef4018e | ||
|
|
67bdf65cbf | ||
|
|
bbb07f8847 | ||
|
|
fda88c8d28 | ||
|
|
64ab224c0e | ||
|
|
d0328d05b1 | ||
|
|
12b86e4402 | ||
|
|
21d0a40cff | ||
|
|
2f7358ef75 | ||
|
|
da3930ccbb | ||
|
|
33485154d6 | ||
|
|
c6375a14af | ||
|
|
585e6b35e6 | ||
|
|
d685d5d987 | ||
|
|
87d332df1a | ||
|
|
6d78c6d2e4 | ||
|
|
677f1d43db | ||
|
|
7369d746fd | ||
|
|
aa680bf3c6 | ||
|
|
9b74395c4b | ||
|
|
e83666d9aa | ||
|
|
2289ead568 | ||
|
|
2f9a5528a7 | ||
|
|
8d6967be39 | ||
|
|
c65062ad5e | ||
|
|
ff1cdf30d7 | ||
|
|
31b1c6c10d | ||
|
|
a3662baefb | ||
|
|
cf4aa65316 | ||
|
|
0ffad5a359 | ||
|
|
bf72432734 | ||
|
|
d8f402ad8f | ||
|
|
e75e41d07d | ||
|
|
52af8c1582 | ||
|
|
97864d454f | ||
|
|
19cdd10750 | ||
|
|
8ee10e707b | ||
|
|
fd1faac2e0 | ||
|
|
2d8a6a6f0c | ||
|
|
20bedf320e | ||
|
|
4bd9e247a2 | ||
|
|
0c61be37d4 | ||
|
|
aeb30c8381 | ||
|
|
fa65da25c9 | ||
|
|
0fe4b0282a | ||
|
|
0debbb20a0 | ||
|
|
12a77ba868 | ||
|
|
b09e170344 | ||
|
|
2cafbb701a | ||
|
|
6707f0afce | ||
|
|
2392c4c41e | ||
|
|
2147859ac9 | ||
|
|
ea15e72d73 | ||
|
|
df0cffede0 | ||
|
|
317ab21a03 | ||
|
|
cc81a37155 | ||
|
|
e2ad372b87 | ||
|
|
727e67cada | ||
|
|
b5345ef4f0 | ||
|
|
80794b3114 | ||
|
|
5524bc3151 | ||
|
|
3dd34a49ef | ||
|
|
c22d22e2db | ||
|
|
8f8cc09ba1 | ||
|
|
c656dd0ede | ||
|
|
c088d38a57 | ||
|
|
70b8c6d77a | ||
|
|
0c6c3eb3f2 | ||
|
|
9a859844f4 | ||
|
|
80344740bd | ||
|
|
4c7f8ac04f | ||
|
|
4466b6d1b0 | ||
|
|
0d15fab49a | ||
|
|
4859a00134 | ||
|
|
1d32a5a445 | ||
|
|
4b2cc123ff | ||
|
|
5a283078ec | ||
|
|
7b74760756 | ||
|
|
1249a2a550 | ||
|
|
67dd4933e6 | ||
|
|
42b34b3545 | ||
|
|
b59cd0745b | ||
|
|
827afcb7ea | ||
|
|
d0a610183a | ||
|
|
78ecb2ad0b | ||
|
|
3ff67323b7 | ||
|
|
061930d6b4 | ||
|
|
124cbe3cf3 | ||
|
|
9e6bcbc014 | ||
|
|
fa0c168947 | ||
|
|
7b14a96c03 | ||
|
|
4bfb58328d | ||
|
|
e457cc7891 | ||
|
|
a861cbb465 | ||
|
|
53dde37ceb | ||
|
|
f980b2ca89 | ||
|
|
86cf8cac86 | ||
|
|
74522c7e84 | ||
|
|
fa73d6cbf1 | ||
|
|
1d093eff67 | ||
|
|
e0df740bc9 | ||
|
|
b6fc7f283f | ||
|
|
1b54bcdc08 | ||
|
|
973cc7ffdf | ||
|
|
9721b37bd5 | ||
|
|
718941bee0 | ||
|
|
cb2d5110ff | ||
|
|
85211cda22 | ||
|
|
170526dc02 | ||
|
|
085ef96768 | ||
|
|
79479a3614 | ||
|
|
5ee3798da3 | ||
|
|
12c70fedc0 | ||
|
|
e5a1628c88 | ||
|
|
6f60613ffb | ||
|
|
4c24eb050b | ||
|
|
1cf4665d2a | ||
|
|
d64b9c1c9e | ||
|
|
da2c662cf2 | ||
|
|
68ccc10b29 | ||
|
|
c1f651175a | ||
|
|
35e01a6e50 | ||
|
|
3da1edfde5 | ||
|
|
6edb1b3e46 | ||
|
|
cb2d5ac788 | ||
|
|
dee41efa20 | ||
|
|
70495665f9 | ||
|
|
2ec15a6931 | ||
|
|
c6e200a8ab | ||
|
|
8655ba04ba | ||
|
|
9c6eb75c65 | ||
|
|
88e83f9427 | ||
|
|
08abb670e1 | ||
|
|
d1f204d640 | ||
|
|
7fdc178abb | ||
|
|
e499ff3322 | ||
|
|
7ed5ab47ea | ||
|
|
359517c7f5 | ||
|
|
20495b27e8 | ||
|
|
6ce769c123 | ||
|
|
a1891ebea9 | ||
|
|
7591c528d0 | ||
|
|
0e8d60c06c | ||
|
|
f90bbe2a5c | ||
|
|
181a008aa3 | ||
|
|
3ff5ce63c5 | ||
|
|
f43d59d8b3 | ||
|
|
1307e3cc12 | ||
|
|
635929eaca | ||
|
|
7482253a6d | ||
|
|
b3d595582a | ||
|
|
e49f6d439d | ||
|
|
7007bd1489 | ||
|
|
980e476c89 | ||
|
|
bfd2532ea5 | ||
|
|
86226754a9 | ||
|
|
bff9fb9c8b | ||
|
|
49ffb156f0 | ||
|
|
61770ec2da | ||
|
|
14f479bb9c | ||
|
|
62610a3a53 | ||
|
|
f09156eb65 | ||
|
|
7f7d42f890 | ||
|
|
a796cb341e | ||
|
|
3db039828e | ||
|
|
9fc78023e2 | ||
|
|
569b9b2b50 | ||
|
|
74628941d5 | ||
|
|
c93b7692b4 | ||
|
|
38756d00ff | ||
|
|
c63e9633b5 | ||
|
|
0bab692eee | ||
|
|
b76ba219d9 | ||
|
|
6db8a60a18 | ||
|
|
a4151bed58 | ||
|
|
0dc892a538 | ||
|
|
05c44db23b | ||
|
|
dc2747439c | ||
|
|
b1af32b48d | ||
|
|
15e895399c | ||
|
|
ea46a5527a | ||
|
|
9b3b7f050b | ||
|
|
5cc53c7e49 | ||
|
|
1ea75abd72 | ||
|
|
a2dd125b1e | ||
|
|
9b0daf49db | ||
|
|
43c6e452fa | ||
|
|
8048de268a | ||
|
|
a6ea26e7fa | ||
|
|
a963da9001 | ||
|
|
1e2d6f898e | ||
|
|
f5be5b7e7b | ||
|
|
61ac6983f2 | ||
|
|
24dd5e87af | ||
|
|
5a04301b32 | ||
|
|
58621e3f65 | ||
|
|
0f36efbded | ||
|
|
5ef8b76b32 | ||
|
|
52b33b5284 | ||
|
|
b6ae718456 | ||
|
|
8494ffbc37 | ||
|
|
cf308cfb20 | ||
|
|
64ebeb5aa5 | ||
|
|
6244c782de | ||
|
|
04591af7fd | ||
|
|
f6ee93e214 | ||
|
|
ce52d94cb7 | ||
|
|
54b15447d4 | ||
|
|
159a6e9669 | ||
|
|
4d87304683 | ||
|
|
158c3ecff3 | ||
|
|
f57ee382b8 | ||
|
|
90df52e12f | ||
|
|
84e23156ac | ||
|
|
5be43fcdba | ||
|
|
74597bd15a | ||
|
|
042b86c473 | ||
|
|
8bbed27573 | ||
|
|
51ebedb803 | ||
|
|
e31aac80e5 | ||
|
|
48c0cb1ba6 | ||
|
|
f233c01c8f | ||
|
|
9707998a08 | ||
|
|
67ce4910bc | ||
|
|
0c57df9770 | ||
|
|
f4f7eeba80 | ||
|
|
16a5534704 | ||
|
|
71e2876033 | ||
|
|
55e150ff8a | ||
|
|
a839a6fa8a | ||
|
|
fbaf5375c3 | ||
|
|
d732c73e71 | ||
|
|
ad4649ac81 | ||
|
|
c8640a3d74 | ||
|
|
328bebbe4b | ||
|
|
1c9196b0c5 | ||
|
|
b7d6ec8364 | ||
|
|
fa23a5006d | ||
|
|
f1307bbd7b | ||
|
|
c97d1bd3d4 | ||
|
|
600353e2b2 | ||
|
|
41f935ddb2 | ||
|
|
c6ba7d110f | ||
|
|
5d4ef719b9 | ||
|
|
19d7f568ce | ||
|
|
bda8c5983b | ||
|
|
214fd81e93 | ||
|
|
87b5ede908 | ||
|
|
5dd722beaa | ||
|
|
14ec6ed80d | ||
|
|
5d91b26c0f | ||
|
|
04bd19257d | ||
|
|
94dd5cb4a0 | ||
|
|
d37e8f8868 | ||
|
|
878205f143 | ||
|
|
02f13d6cdf | ||
|
|
04ebfbfefa | ||
|
|
40fc9d7b68 | ||
|
|
9a10148c01 | ||
|
|
d8becf2ee1 | ||
|
|
91aa90fc79 | ||
|
|
ff4bcaed81 | ||
|
|
06aea2cf0a | ||
|
|
525975acc4 | ||
|
|
cb0b559451 | ||
|
|
dc0b312f8a | ||
|
|
340feedee2 | ||
|
|
5eb79983be | ||
|
|
f1b76c8424 | ||
|
|
53af9768ce | ||
|
|
d75cff1a0e | ||
|
|
599436a452 | ||
|
|
58f3fc68e4 | ||
|
|
380009e541 | ||
|
|
23909bb04d | ||
|
|
335fc8ab23 | ||
|
|
a5031a7d02 | ||
|
|
2fac03e682 | ||
|
|
51efb21713 | ||
|
|
98cb3fee75 | ||
|
|
ff07cdc9c8 | ||
|
|
f675fedc49 | ||
|
|
ab594cfee9 | ||
|
|
e050853ed3 | ||
|
|
4014f31a73 | ||
|
|
c0f155d3a0 | ||
|
|
630cc0f9ca | ||
|
|
fed3430b70 | ||
|
|
921ebdce45 | ||
|
|
27c0c742ca | ||
|
|
42fc89b672 | ||
|
|
bdc9cae3e3 | ||
|
|
999d4d83e9 | ||
|
|
f584a2de92 | ||
|
|
a02d745844 | ||
|
|
044c5b5572 | ||
|
|
82836be47e | ||
|
|
c3bb6becd9 | ||
|
|
f5f985c018 | ||
|
|
33d17c37e8 | ||
|
|
8db68a57f5 | ||
|
|
6955976b2d | ||
|
|
6a23cd07aa | ||
|
|
94717021ef | ||
|
|
9706938016 | ||
|
|
13a8d64fe6 | ||
|
|
35d68b2c6d | ||
|
|
125f823bda | ||
|
|
605ad09a3e | ||
|
|
f9522fd0e2 | ||
|
|
218f1a1d69 | ||
|
|
44e4bbd15c | ||
|
|
cde5103b7a | ||
|
|
5689851f85 | ||
|
|
645c898e2d | ||
|
|
8609ed86c4 | ||
|
|
b66420e54d | ||
|
|
7995dcff94 | ||
|
|
bbdbccfba0 | ||
|
|
c577bc8762 | ||
|
|
9e1ded69dd | ||
|
|
40dc53c6e2 | ||
|
|
6426cc8f54 | ||
|
|
02d66db4b4 | ||
|
|
0722aea3df | ||
|
|
d765cd91df | ||
|
|
a0d2c745c7 | ||
|
|
5cea355232 | ||
|
|
464afd4d2d | ||
|
|
76043b17fd | ||
|
|
a73a42a6b0 | ||
|
|
a04faf56dc | ||
|
|
8f96cfc20a | ||
|
|
44bfe6048b | ||
|
|
a282c5756c | ||
|
|
f98bf48b1d | ||
|
|
5a09d79caf | ||
|
|
3b599d2b7e | ||
|
|
d3bb72fff1 | ||
|
|
32754784db | ||
|
|
eb71ebbecd | ||
|
|
be9d4f0411 | ||
|
|
841231e5bd | ||
|
|
fdccf7e6c3 | ||
|
|
0c6ea4f8a6 | ||
|
|
a0b494aa71 | ||
|
|
57ea25017a | ||
|
|
50d8f73f06 | ||
|
|
389cd6c466 | ||
|
|
f31b89012d | ||
|
|
f09f18fc64 | ||
|
|
05365e1726 | ||
|
|
b592cb3f0a | ||
|
|
8261ba69e6 | ||
|
|
7d2c89b6c7 | ||
|
|
3255887f5e | ||
|
|
bdab3436d3 | ||
|
|
bb708ab8c3 | ||
|
|
d5f1cef73c | ||
|
|
8df918f8c7 | ||
|
|
8da82256d4 | ||
|
|
c9e0e944e9 | ||
|
|
038e6cd33e | ||
|
|
21b939e1e6 | ||
|
|
5f8f290505 | ||
|
|
f4e3dca113 | ||
|
|
007937e217 | ||
|
|
ae8841f2ab | ||
|
|
78f965a9e2 | ||
|
|
91e1a7e3e2 | ||
|
|
973daf853b | ||
|
|
f973a2f81a | ||
|
|
fb7d6db051 | ||
|
|
ae5f7c71d7 | ||
|
|
88b7cb9bda | ||
|
|
ace1440b65 | ||
|
|
a0174ad534 | ||
|
|
e1f3dfccc8 | ||
|
|
421a6d0340 | ||
|
|
a237f90c5b | ||
|
|
e4da88a223 | ||
|
|
a85b5759f3 | ||
|
|
07c4276cbe | ||
|
|
cf3a376cb5 | ||
|
|
340830de5b | ||
|
|
4e13ab306a | ||
|
|
235df7f484 | ||
|
|
b2319a03a6 | ||
|
|
c3bec61da2 | ||
|
|
1dd524151d | ||
|
|
1b75ad91aa | ||
|
|
ac0714dcd7 | ||
|
|
3fc22e7b78 | ||
|
|
d09620b0e2 | ||
|
|
11de4d59ea | ||
|
|
71f8249a08 | ||
|
|
6fc2dc3927 | ||
|
|
e3da0ca828 | ||
|
|
ea286d1a14 | ||
|
|
3d397325bf | ||
|
|
4a60e9e66e | ||
|
|
fbfad8ee1b | ||
|
|
5414970dcd | ||
|
|
d17c0fc2d0 | ||
|
|
31417d57da | ||
|
|
fa489a26ef | ||
|
|
6bcd3b2df1 | ||
|
|
8fbbefb8db | ||
|
|
2f724e5849 | ||
|
|
f5e65452ce | ||
|
|
a4c13ea092 | ||
|
|
4284f1777d | ||
|
|
cd13bcb4d2 | ||
|
|
8b1c11c3c9 | ||
|
|
9ea7fbed8a | ||
|
|
907ce14b18 | ||
|
|
d621f9e558 | ||
|
|
62cc3b6447 | ||
|
|
024860b49d | ||
|
|
1555e7673d | ||
|
|
40eb22aeb4 | ||
|
|
545e2b003c | ||
|
|
977c2186c9 | ||
|
|
05f3dcf738 | ||
|
|
072102cfd2 | ||
|
|
0a182576d0 | ||
|
|
b52abd1370 | ||
|
|
740bc24c95 | ||
|
|
4b932ff314 | ||
|
|
89e20bb9af | ||
|
|
89b2f3061b | ||
|
|
a374a522df | ||
|
|
45e9838bb1 | ||
|
|
dd8e3266b2 | ||
|
|
a57392016b | ||
|
|
e2529347b6 | ||
|
|
3029d0efb3 | ||
|
|
8ac2496c5d | ||
|
|
6cb1ad1fa2 | ||
|
|
391c918d87 | ||
|
|
d1db32511c | ||
|
|
694470fae7 | ||
|
|
b7ae09111d | ||
|
|
81b370d5a1 | ||
|
|
cf3b108ef5 | ||
|
|
c9a2cf9d4c | ||
|
|
6c48494c5a | ||
|
|
b3dd7f9ab2 | ||
|
|
c17102c385 | ||
|
|
28ecac2671 | ||
|
|
ed09652a17 | ||
|
|
f76fd38baa | ||
|
|
bef164f5ce | ||
|
|
5566951eba | ||
|
|
bbf4c21048 | ||
|
|
6f12b525e8 | ||
|
|
777684e0c1 | ||
|
|
1ff5b5f10a | ||
|
|
7199fc8373 | ||
|
|
5f9353bde1 | ||
|
|
66ecee0942 | ||
|
|
1a66db8f33 | ||
|
|
12fff108ea | ||
|
|
6df83b3efb | ||
|
|
533187f0c3 | ||
|
|
9a9fb0483f | ||
|
|
999b0f399d | ||
|
|
0385999cda | ||
|
|
e53dd76a49 | ||
|
|
ae1d816768 | ||
|
|
ed082a747a | ||
|
|
e0b5a8349f | ||
|
|
865bb03ecf | ||
|
|
470ac0bfc7 | ||
|
|
c1691ed58e | ||
|
|
042924b355 | ||
|
|
3d59ec7e68 | ||
|
|
29a77c9b19 | ||
|
|
0a6da8929d | ||
|
|
f65d739c41 | ||
|
|
acbe0b4849 | ||
|
|
a059e91d7f | ||
|
|
710b2e80c6 | ||
|
|
5d86c9f4d5 | ||
|
|
a6d5bb75fe | ||
|
|
ac1aba90f8 | ||
|
|
bff90264b8 | ||
|
|
7f4beaa44a | ||
|
|
72d113dd38 | ||
|
|
54bcd260ff | ||
|
|
a255a5407f | ||
|
|
5fce581ce3 | ||
|
|
a7d78dda77 | ||
|
|
7ff19f1ec4 | ||
|
|
5e5b8512d6 | ||
|
|
6c72d6a058 | ||
|
|
e65d66fe04 | ||
|
|
a467321800 | ||
|
|
a3d779013d | ||
|
|
6e98599634 | ||
|
|
934d8b57c0 | ||
|
|
e9fb44ed3c | ||
|
|
93e10f1cc4 | ||
|
|
4a8f96f95d | ||
|
|
35755a91a0 | ||
|
|
110b683152 | ||
|
|
9ed496bbc5 | ||
|
|
c8dd4c58ce | ||
|
|
878c4ee913 | ||
|
|
4be94be168 | ||
|
|
e9ca165b1a | ||
|
|
9c2bcabcdd | ||
|
|
de68b00596 | ||
|
|
6353e5b0e5 | ||
|
|
6e9b659c07 | ||
|
|
17e8ce8c35 | ||
|
|
2037083b5f | ||
|
|
fcaac0e9e6 | ||
|
|
bf665e5991 | ||
|
|
541e1ff474 | ||
|
|
4600d0a9bb | ||
|
|
a28950da73 | ||
|
|
ea359b50cb | ||
|
|
1e6d875783 | ||
|
|
7a56fd6c93 | ||
|
|
2c8b23e331 | ||
|
|
72663f4b83 | ||
|
|
5bab044984 | ||
|
|
db9dc7c2df | ||
|
|
14620ca0bd | ||
|
|
0c1ad0ff1a | ||
|
|
e7fabbd470 | ||
|
|
a8ac4f0a70 | ||
|
|
aa02ff7f35 | ||
|
|
a55bb37508 | ||
|
|
09bbf96d85 | ||
|
|
dc35c73642 | ||
|
|
89d707566a | ||
|
|
10e137be3a | ||
|
|
eb20f7209e | ||
|
|
37be70bbd7 | ||
|
|
893f5a301e | ||
|
|
5b63246813 | ||
|
|
f5bd346573 | ||
|
|
d8a88d058e | ||
|
|
0a7885bf19 | ||
|
|
548075b1f5 | ||
|
|
0ee018b407 | ||
|
|
9ae566d0dd | ||
|
|
aae14a107a | ||
|
|
62efe5f656 | ||
|
|
17c7c62d55 | ||
|
|
a38343bf68 | ||
|
|
933e08f2f3 | ||
|
|
64377c90b5 | ||
|
|
e251a2d7d5 | ||
|
|
cc30639f97 | ||
|
|
89e100bc8c | ||
|
|
c9063c0b8f | ||
|
|
d1530f06bb | ||
|
|
5f17d79527 | ||
|
|
899497069b | ||
|
|
a96f9baeb4 | ||
|
|
b1313aefd8 | ||
|
|
f64a0f2243 | ||
|
|
93b32892f7 | ||
|
|
6e6794786a | ||
|
|
e98f1114a0 | ||
|
|
a0af28ceba | ||
|
|
a50c4a4fad | ||
|
|
e3d2b135e7 | ||
|
|
119803f26e | ||
|
|
4737f61c81 | ||
|
|
721d1ca5ef | ||
|
|
6d315459b6 | ||
|
|
2bee92dbd0 | ||
|
|
d17179d14b | ||
|
|
5a4827ae21 | ||
|
|
0ad87db01f | ||
|
|
11e24bb2ba | ||
|
|
92c2d79d10 | ||
|
|
20387386b9 | ||
|
|
f543377789 | ||
|
|
5a7983585e | ||
|
|
a8646b0957 | ||
|
|
31616af33d | ||
|
|
16f12f0628 | ||
|
|
a73a886cb1 | ||
|
|
7432f13898 | ||
|
|
8188f6bfe8 | ||
|
|
a65a64f8e0 | ||
|
|
4ec8a4c2b6 | ||
|
|
bff1bf27d9 | ||
|
|
91d4109023 | ||
|
|
aaeb164cf6 | ||
|
|
558cfc31ca | ||
|
|
f065234b71 | ||
|
|
00cbf72064 | ||
|
|
9bccf1b11e | ||
|
|
c94f8facf5 | ||
|
|
287ef36ed8 | ||
|
|
2242d8ebd6 | ||
|
|
72f38bcc91 | ||
|
|
4b34531307 | ||
|
|
70e71a1845 | ||
|
|
7769a6e757 | ||
|
|
9d157b519d | ||
|
|
995969b190 | ||
|
|
350e99ae57 | ||
|
|
37eebd9dcf | ||
|
|
7c03349869 | ||
|
|
266492e919 | ||
|
|
5b7c6ced80 | ||
|
|
33f3cfdec0 | ||
|
|
c1e9ccc794 | ||
|
|
cc8a478887 | ||
|
|
8bbcbcfb0d | ||
|
|
73e8510717 | ||
|
|
dbfbd3b698 | ||
|
|
a85f750ee8 | ||
|
|
45fa27b56a | ||
|
|
c97005723c | ||
|
|
4a6fc007c6 | ||
|
|
a6f1d8fc4c | ||
|
|
d3aaf74080 | ||
|
|
0effe196e4 | ||
|
|
df810a8250 | ||
|
|
50cd179a60 | ||
|
|
24ae71404f | ||
|
|
df140d90ee | ||
|
|
af82836ac6 | ||
|
|
d5fbfd677c | ||
|
|
c5316d2929 | ||
|
|
82411cdf3a | ||
|
|
a48e41787b | ||
|
|
a6f1959d1c | ||
|
|
f33a696ec7 | ||
|
|
9aac64c238 | ||
|
|
4fb39a9d20 | ||
|
|
d628ed2c14 | ||
|
|
585445d0bc | ||
|
|
ae6c92c2a5 | ||
|
|
50b8af5b45 | ||
|
|
f9a2b5279d | ||
|
|
63d7cd8882 | ||
|
|
e9175cec07 | ||
|
|
d023831327 | ||
|
|
3fa5975520 | ||
|
|
9d134e8647 | ||
|
|
1a666c3016 | ||
|
|
c1c9eeaaf7 | ||
|
|
8d787e2414 | ||
|
|
b46620b062 | ||
|
|
250c4cb3e0 | ||
|
|
c642d3224c | ||
|
|
e5b5d041f5 | ||
|
|
2f8e0af7f9 | ||
|
|
6de3a70347 | ||
|
|
3396a9f2af | ||
|
|
585c917691 | ||
|
|
b54e19d00e | ||
|
|
c6102d5c1b | ||
|
|
22e51c5d29 | ||
|
|
badec326d8 | ||
|
|
74b216a17f | ||
|
|
09e060febb | ||
|
|
1dfed893e0 | ||
|
|
a68496deec | ||
|
|
8fcede28df | ||
|
|
7d07c64fe5 | ||
|
|
efc4c7b09f | ||
|
|
5d062e476e | ||
|
|
b67877af6f | ||
|
|
088930facc | ||
|
|
8b57e899d4 | ||
|
|
94c26b00b7 | ||
|
|
4a76ec899f | ||
|
|
ba0767477d | ||
|
|
ea047307da | ||
|
|
5bcb25f3f8 | ||
|
|
cfa2564a40 | ||
|
|
3835903650 | ||
|
|
5fee85616d | ||
|
|
50ebf66150 | ||
|
|
87d57d9c59 | ||
|
|
b553c282fb | ||
|
|
02097c87eb | ||
|
|
749ebacebd | ||
|
|
f36c5f1e08 | ||
|
|
f6211322e5 | ||
|
|
63f0e074eb | ||
|
|
d423668954 | ||
|
|
9bf017edf2 | ||
|
|
0d90123cac | ||
|
|
e66866c1fc | ||
|
|
b375dde57f | ||
|
|
8cb58dbb69 | ||
|
|
a861992359 | ||
|
|
4b48565c9e | ||
|
|
f75477819c | ||
|
|
d18ff58a1c | ||
|
|
3964b30f2d | ||
|
|
223fe5bbe2 | ||
|
|
4728ab977a | ||
|
|
f2d0f0174f | ||
|
|
734f7c26d5 | ||
|
|
74bc86a272 | ||
|
|
c7dd0b1535 | ||
|
|
3153349325 | ||
|
|
cd71774d77 | ||
|
|
e4437b2551 | ||
|
|
3e761c137d | ||
|
|
eb62dcc871 | ||
|
|
296641e047 | ||
|
|
4e92ef4aa4 | ||
|
|
9ae33b51fb | ||
|
|
1cf2f5a5c2 | ||
|
|
e24cd86c18 | ||
|
|
d35d626181 | ||
|
|
2f9ecd4fba | ||
|
|
78a99fe7da | ||
|
|
11f8e0d33f | ||
|
|
9e10fac223 | ||
|
|
460836a2b7 | ||
|
|
1965c819f6 | ||
|
|
e10bf1d6c0 | ||
|
|
3787ffca80 | ||
|
|
14c6c910d7 | ||
|
|
6aedd3d82b | ||
|
|
27b7320fed | ||
|
|
321691a698 | ||
|
|
2c468dd429 | ||
|
|
db1c7d80b1 | ||
|
|
d47dac9a88 | ||
|
|
1a7e18bfdf | ||
|
|
b8a08f199a | ||
|
|
7a44f38a7f | ||
|
|
da18898f0e | ||
|
|
b49c6ab45d | ||
|
|
f113b92b93 | ||
|
|
6fd4b827fb | ||
|
|
b5c74e4041 | ||
|
|
f3be9991d7 | ||
|
|
11a00df699 | ||
|
|
378d2bb1ff | ||
|
|
b7f85a30cd | ||
|
|
5310574382 | ||
|
|
12adb4a3f3 | ||
|
|
4f7bce6d20 | ||
|
|
96ce57d551 | ||
|
|
ea873ceb2c | ||
|
|
beee286c7b | ||
|
|
44484acf2d | ||
|
|
2b188151d4 | ||
|
|
cf2b151116 | ||
|
|
9a2157d71a | ||
|
|
57f15994a5 | ||
|
|
ada6a8a2de | ||
|
|
6f9310bde8 | ||
|
|
1ef92074ad | ||
|
|
8c84d48caa | ||
|
|
3435038a4d | ||
|
|
1e7f783f69 | ||
|
|
4cb6b265ee | ||
|
|
0e7722ff40 | ||
|
|
2f88c14f53 | ||
|
|
45c98e948b | ||
|
|
954cc459d2 | ||
|
|
ed6f2e8323 | ||
|
|
b944949bb0 | ||
|
|
6a66ecc079 | ||
|
|
b352330a3f | ||
|
|
089df0a7a4 | ||
|
|
2b38973b5c | ||
|
|
bc8d325216 | ||
|
|
29b34ed156 | ||
|
|
eabe3bf20c | ||
|
|
032fd3543d | ||
|
|
5db8df7bb6 | ||
|
|
38b9226f44 | ||
|
|
b4c90d5645 | ||
|
|
a2b90426bd | ||
|
|
4d05955d53 | ||
|
|
2c51c4d186 | ||
|
|
583a7b5c74 | ||
|
|
a1cd4db4e6 | ||
|
|
a6f0abb7c3 | ||
|
|
520756c3c5 | ||
|
|
8262da8137 | ||
|
|
9effa55311 | ||
|
|
240054a7f8 | ||
|
|
3bdda60f3e | ||
|
|
e4dbea976e | ||
|
|
d666339853 | ||
|
|
700d218c5d | ||
|
|
0abddd648d | ||
|
|
f50704ec01 | ||
|
|
ada0e23a84 | ||
|
|
14d0e00235 | ||
|
|
7de43154d3 | ||
|
|
5901331669 | ||
|
|
822577eb42 | ||
|
|
9f17b1a30f | ||
|
|
6a5dfb88d2 | ||
|
|
72d40f13a4 | ||
|
|
dc110a4391 | ||
|
|
27b477f68d | ||
|
|
5aab25b60a | ||
|
|
3ac5a785e0 | ||
|
|
1a4298685a | ||
|
|
80a088a4fe | ||
|
|
1b55769e26 | ||
|
|
c758e031f6 | ||
|
|
40946a2981 | ||
|
|
ec217cd163 | ||
|
|
44a5b03841 | ||
|
|
708758b737 | ||
|
|
45101550f2 | ||
|
|
72deb4846d | ||
|
|
33329f5bd1 | ||
|
|
dcf684c704 | ||
|
|
04a50a7ea4 | ||
|
|
e960be55ed | ||
|
|
c3599fa7b9 | ||
|
|
56586bde9e | ||
|
|
5cfddd74e9 | ||
|
|
2bdad8d695 | ||
|
|
5f48a1b000 | ||
|
|
ecbd3f0798 | ||
|
|
41060f2090 | ||
|
|
8ab127bda9 | ||
|
|
f0190bc45e | ||
|
|
efdd783c20 | ||
|
|
058eed369b | ||
|
|
417b126fc4 | ||
|
|
5664826a84 | ||
|
|
5c3badb749 | ||
|
|
80749e59a8 | ||
|
|
86d8a33a4b | ||
|
|
95f59f8c1f | ||
|
|
13cd544de3 | ||
|
|
2b67346ded | ||
|
|
e74b3ab5f7 | ||
|
|
50fadea8fa | ||
|
|
31a189b7dd | ||
|
|
b252afb0b0 | ||
|
|
49efd3add9 | ||
|
|
b67d35a76a | ||
|
|
98e34ca157 | ||
|
|
88c752b476 | ||
|
|
826f49485e | ||
|
|
59d96eedd8 | ||
|
|
7d9e085dcd | ||
|
|
565c99f670 | ||
|
|
6994c85201 | ||
|
|
d11dbe7dc2 | ||
|
|
d2059dfab2 | ||
|
|
d596722dfa | ||
|
|
a5a0a3c894 | ||
|
|
216f062eb8 | ||
|
|
4bf7849297 | ||
|
|
d282cfcc46 | ||
|
|
efb72e74e2 | ||
|
|
f640512c53 | ||
|
|
e3cae4ae2e | ||
|
|
969ad710ba | ||
|
|
08c3f38031 | ||
|
|
e8a7525ceb | ||
|
|
5892f653c7 | ||
|
|
ba633d33a8 | ||
|
|
675434ffab | ||
|
|
fb9e4e15ed | ||
|
|
c32830937c | ||
|
|
5a3b1e983c | ||
|
|
bed2d9f231 | ||
|
|
2e9136767e | ||
|
|
bf1348b7e2 | ||
|
|
dc53e9eef2 | ||
|
|
26bd7aac03 | ||
|
|
2cde2c02ca | ||
|
|
69ab14d91e | ||
|
|
a493c0b196 | ||
|
|
424b76a4e5 | ||
|
|
83ec209f42 | ||
|
|
a427235e30 | ||
|
|
b6a2230e6f | ||
|
|
c488eca5e8 | ||
|
|
72c6b81115 | ||
|
|
9925edcb1e | ||
|
|
b560ed4ac6 | ||
|
|
67693415ff | ||
|
|
0288310e3b | ||
|
|
53f040445f | ||
|
|
cca95c1c7a | ||
|
|
d43fde8a9b | ||
|
|
3f171b931f | ||
|
|
59c9d165f8 | ||
|
|
6e78915061 | ||
|
|
e246dd1443 | ||
|
|
f4e2539a32 | ||
|
|
92fe31fd44 | ||
|
|
4e7bcad58f | ||
|
|
b0e992237e | ||
|
|
b1df7f114d | ||
|
|
47687399fb | ||
|
|
6a261fa1bc | ||
|
|
e6c29eb5fc | ||
|
|
c64e10c2d7 | ||
|
|
71770d1a78 | ||
|
|
af48b6cf22 | ||
|
|
882db8e9d9 | ||
|
|
142e5e1eb4 | ||
|
|
8bdc86beb4 | ||
|
|
61dfa310d7 | ||
|
|
8ec2a8d2b0 | ||
|
|
422ecc98e4 | ||
|
|
5adcb5a48c | ||
|
|
9faef1f83a | ||
|
|
3b6839cc96 | ||
|
|
38a1b9c956 | ||
|
|
28d0b11fde | ||
|
|
cf2e75ebb3 | ||
|
|
b2ac939eb3 | ||
|
|
f2986ccfc1 | ||
|
|
ad95e65028 | ||
|
|
e4dfd2fb63 | ||
|
|
23c73269ca | ||
|
|
d2c7d0f6b0 | ||
|
|
68652cd94d | ||
|
|
0b1045ed7d | ||
|
|
2937fdbbbf | ||
|
|
21a1e0252f | ||
|
|
345ed4823c | ||
|
|
7403e56fb4 | ||
|
|
cb54eeaa31 | ||
|
|
d1b7ad3f1a | ||
|
|
c7750b2570 | ||
|
|
9ed3e1bb6a | ||
|
|
eacf2124b6 | ||
|
|
8277e67f11 | ||
|
|
9296960081 | ||
|
|
9781ecaa70 | ||
|
|
003a51d399 | ||
|
|
4feaa790e2 | ||
|
|
d1b31c0f45 | ||
|
|
cadada2d65 | ||
|
|
962c72b624 | ||
|
|
7378526393 | ||
|
|
dd3485492d | ||
|
|
32d7d04858 | ||
|
|
9459f33178 | ||
|
|
8027ce0c75 | ||
|
|
99ee3fd17e | ||
|
|
8d1562077f | ||
|
|
d30b64f457 | ||
|
|
30e38cd6a3 | ||
|
|
6ea3e3ccc7 | ||
|
|
27c3a0ea9f | ||
|
|
bceaf4b788 | ||
|
|
ce7fcbb4ae | ||
|
|
5d00659e1d | ||
|
|
7549116ec3 | ||
|
|
bab1e9a397 | ||
|
|
1c782a923d | ||
|
|
3473af00ad | ||
|
|
db0a5392a5 | ||
|
|
92978b2c0f | ||
|
|
4efc926d28 | ||
|
|
c833a39a4d | ||
|
|
b14d109bae | ||
|
|
0cc50bdd11 | ||
|
|
805625b541 | ||
|
|
031b060af0 | ||
|
|
e56bf442c3 | ||
|
|
9547e79af5 | ||
|
|
5da4650cba | ||
|
|
602f31d187 | ||
|
|
c3c281e699 | ||
|
|
bcb7b0a9af | ||
|
|
eb21389953 | ||
|
|
31cf4e7362 | ||
|
|
cbdfa7576a | ||
|
|
cd34fc655d | ||
|
|
c3d7a198bf | ||
|
|
4f5b130de9 | ||
|
|
f97526e641 | ||
|
|
03ff363982 | ||
|
|
3471907160 | ||
|
|
a9a9b64b13 | ||
|
|
b5cb8861c7 | ||
|
|
b01990124e | ||
|
|
fcb299b4ae | ||
|
|
da9174c8ee | ||
|
|
f4fe39ca92 | ||
|
|
58c87786ae | ||
|
|
345396e056 | ||
|
|
011c5a8a7c | ||
|
|
3aa008e4c6 | ||
|
|
10b625079b | ||
|
|
614400e5af | ||
|
|
c3eff820be | ||
|
|
ab2b3480b2 | ||
|
|
72aa788a0e | ||
|
|
bbcc3a125f | ||
|
|
5bb95fc613 | ||
|
|
a6f61b8419 | ||
|
|
5fb3f97a55 | ||
|
|
10bf54bfc9 | ||
|
|
ca2e2c2453 | ||
|
|
cc03036e3e | ||
|
|
f9e60dcd55 | ||
|
|
05de1bc398 | ||
|
|
fc91e6a75a | ||
|
|
edfd7f6e07 | ||
|
|
084aef700b | ||
|
|
15eb2bcf6f | ||
|
|
1cb5905e71 | ||
|
|
3cef7fbbb6 | ||
|
|
ef987e5e49 | ||
|
|
aa9561909a | ||
|
|
774a21394a | ||
|
|
fba9332de8 | ||
|
|
8c8482ac98 | ||
|
|
48aa9cf035 | ||
|
|
2bf029be17 | ||
|
|
9bd9906e8f | ||
|
|
95f3e193f0 | ||
|
|
ca94d0a43c | ||
|
|
69d2ad3967 | ||
|
|
3ae79a59e4 | ||
|
|
ea6549e9da | ||
|
|
cc1462e0b7 | ||
|
|
4629ead8c5 | ||
|
|
6b145763f7 | ||
|
|
99f584376e | ||
|
|
c02e1cb943 | ||
|
|
58e825060e | ||
|
|
5f7a8741b9 | ||
|
|
4ecab0d80c | ||
|
|
66665003bd | ||
|
|
55a8e982c0 | ||
|
|
7b6a9e91eb | ||
|
|
a39cd745c9 | ||
|
|
ad91ffe7e5 | ||
|
|
6f39ba5909 | ||
|
|
72626a04d8 | ||
|
|
8141973e00 | ||
|
|
feed6175ea | ||
|
|
98357db400 | ||
|
|
0644eed772 | ||
|
|
e92c4fff1a | ||
|
|
36dd3e238f | ||
|
|
629e3101ab | ||
|
|
daf66621dc | ||
|
|
1e8cc6764e | ||
|
|
8028b5324e | ||
|
|
9c06a7fd04 | ||
|
|
cccf4b9889 | ||
|
|
17247b23bf | ||
|
|
a3de797e57 | ||
|
|
add98edfc3 | ||
|
|
8e79271a19 | ||
|
|
f798a2ab85 | ||
|
|
ee45b7a6db | ||
|
|
e12f073f65 | ||
|
|
036d0d8838 | ||
|
|
bd068afa44 | ||
|
|
ab9c287d92 | ||
|
|
f098989396 | ||
|
|
13dd102e94 | ||
|
|
20f7152769 | ||
|
|
b70ab128fc | ||
|
|
4cdf0a35c9 | ||
|
|
f9293b69d8 | ||
|
|
f8b97aef34 | ||
|
|
7c3f79cb9f | ||
|
|
6cc7d26140 | ||
|
|
a854cec3ba | ||
|
|
1c4d65c011 | ||
|
|
03a54ee0c9 | ||
|
|
6bdd3a59b5 | ||
|
|
82dbeedd1b | ||
|
|
c3b8ddff93 | ||
|
|
4d6976fbce | ||
|
|
39aaea8e62 | ||
|
|
96a35cd2f4 | ||
|
|
3db3a6ee1a | ||
|
|
4bcd284c76 | ||
|
|
d5fbba45e8 | ||
|
|
8698dd36f2 | ||
|
|
6608531271 | ||
|
|
d10425025a | ||
|
|
17246d051d | ||
|
|
0fd2508b89 | ||
|
|
7c0c5c1724 | ||
|
|
cbcdf8ad35 | ||
|
|
78d560a933 | ||
|
|
87c658f83b | ||
|
|
843769f88f | ||
|
|
5e61687fdf | ||
|
|
5161f16f4a | ||
|
|
0e0e6c5f39 | ||
|
|
71ac698b78 | ||
|
|
deb6728bc3 | ||
|
|
4b6be1529e | ||
|
|
f22dbef28b | ||
|
|
a480bf6b14 | ||
|
|
990e08f090 | ||
|
|
693c190881 | ||
|
|
d86ae2bec6 | ||
|
|
64da0983d5 | ||
|
|
e389bd9e60 | ||
|
|
ab69d5b367 | ||
|
|
ac7df193ca | ||
|
|
16b8b66adc | ||
|
|
5833d66f65 | ||
|
|
dc98019b59 | ||
|
|
3b46617bd9 | ||
|
|
6fe39d9017 | ||
|
|
43abf6ff45 | ||
|
|
c313bea450 | ||
|
|
0af5d16872 | ||
|
|
2836284798 | ||
|
|
ec71ce8d2d | ||
|
|
2a0bf7834c | ||
|
|
c50bbbfedd | ||
|
|
e459d8604d | ||
|
|
422a36ca2a | ||
|
|
ec323d8c3f | ||
|
|
ce866d1cc6 | ||
|
|
6da9335a9e | ||
|
|
b2e1568335 | ||
|
|
99ffc49740 | ||
|
|
1207d8ad0d | ||
|
|
c5be70eab4 | ||
|
|
9cda94d0aa | ||
|
|
f00797a1f2 | ||
|
|
10c6afd316 | ||
|
|
91083a43be | ||
|
|
31de98793f | ||
|
|
51baab2112 | ||
|
|
865f5bef34 | ||
|
|
8bd2c2e551 | ||
|
|
935f50471c | ||
|
|
c23bd75df6 | ||
|
|
65e33b1bc5 | ||
|
|
d561f4ad92 | ||
|
|
0aefb2f60a | ||
|
|
629d5b7689 | ||
|
|
3ff54bdd7a | ||
|
|
f5f4109f9a | ||
|
|
3f269e988c | ||
|
|
eaf8470b29 | ||
|
|
c903c5541e | ||
|
|
eb1fb6011a | ||
|
|
0693cff925 | ||
|
|
feb499aaae | ||
|
|
d276a16526 | ||
|
|
b3ca0c627a | ||
|
|
ba3968f6ce | ||
|
|
d98db4868d | ||
|
|
dea53962a3 | ||
|
|
81c384e408 | ||
|
|
fb76d43980 | ||
|
|
3b6d5f255d | ||
|
|
fcf66925c1 | ||
|
|
296f8c160f | ||
|
|
5b5017e267 | ||
|
|
c9f13c5e54 | ||
|
|
176b70a0d4 | ||
|
|
1d3179816b | ||
|
|
4a0176740d | ||
|
|
50b230d12c | ||
|
|
46550c0b4f | ||
|
|
2806842200 | ||
|
|
2a2f02e375 | ||
|
|
cbb39b499b | ||
|
|
e75fd059dd | ||
|
|
56c44b78b4 | ||
|
|
433adee594 | ||
|
|
0b6031adbf | ||
|
|
faa33fc326 | ||
|
|
e51afeb90f | ||
|
|
006bb0e957 | ||
|
|
36b84ded95 | ||
|
|
aeeb24991a | ||
|
|
71c7577370 | ||
|
|
5738e07fba | ||
|
|
36ba311cf4 | ||
|
|
a081b39c01 | ||
|
|
db56a03ff2 | ||
|
|
7961878e81 | ||
|
|
19be7225cc | ||
|
|
d81cb08704 | ||
|
|
0d3918e15b | ||
|
|
dbb838f4d0 | ||
|
|
afb85a028f | ||
|
|
5eed5b056b | ||
|
|
758c0eb79f | ||
|
|
4026e7b7de | ||
|
|
aff28178e6 | ||
|
|
1229c68587 | ||
|
|
e309055819 | ||
|
|
046ab33d1b | ||
|
|
e68ea86cc4 | ||
|
|
a813ab50fe | ||
|
|
f1dde1a429 | ||
|
|
5ae00f0ff5 | ||
|
|
db44a909ba | ||
|
|
c6ec939626 | ||
|
|
59021496d8 | ||
|
|
15dcc5afd3 | ||
|
|
278562d2c2 | ||
|
|
6cbfe0f849 | ||
|
|
ba9744d400 | ||
|
|
866463f37b | ||
|
|
2a996f492f | ||
|
|
da05900524 | ||
|
|
13c5da2aa3 | ||
|
|
0ce4618bea | ||
|
|
c284b0fff7 | ||
|
|
fdb1cda965 | ||
|
|
06de09daf4 | ||
|
|
1736b7ef6b | ||
|
|
d655e88b44 | ||
|
|
03497f0268 | ||
|
|
209a633a3c | ||
|
|
3082e71b5a | ||
|
|
c594e578a9 | ||
|
|
23cf963332 | ||
|
|
223055a861 | ||
|
|
fc0a2b837b | ||
|
|
f4b3989c61 | ||
|
|
ff1bb6bc68 | ||
|
|
60fe1b61e0 | ||
|
|
79b4e1f997 | ||
|
|
c21350823f | ||
|
|
19c4041df5 | ||
|
|
0478ac6848 | ||
|
|
1607cb7e0c | ||
|
|
9d1d3a454e | ||
|
|
9731b4e54f | ||
|
|
9188b3468c | ||
|
|
80abc3bc4a | ||
|
|
ada7c7da8f | ||
|
|
f390a0e2dc | ||
|
|
21c5af5a8a | ||
|
|
fa0ee42cc9 | ||
|
|
29333c417e | ||
|
|
4585ada453 | ||
|
|
cebae0c510 | ||
|
|
5f4ac6b909 | ||
|
|
adee16440a | ||
|
|
542571f5cb | ||
|
|
591d83686e | ||
|
|
c0a0fcaff0 | ||
|
|
37ed96e611 | ||
|
|
94b6feef24 | ||
|
|
505116771e | ||
|
|
0020ad7d99 | ||
|
|
f3fdefe001 | ||
|
|
52db01ea6d | ||
|
|
474c249c90 | ||
|
|
dd580d7bc7 | ||
|
|
374762654e | ||
|
|
a5d0af95b5 | ||
|
|
6f539159e8 | ||
|
|
522ab79e9c | ||
|
|
99580adf66 | ||
|
|
12abe86ac0 | ||
|
|
38f00d07f7 | ||
|
|
049b7e9a93 | ||
|
|
af9a799925 | ||
|
|
4fe5c351cd | ||
|
|
04bdce54b7 | ||
|
|
5a66365cdd | ||
|
|
c31e42e2bb | ||
|
|
1976eddd89 | ||
|
|
d55e2266ca | ||
|
|
c7f9d0d971 | ||
|
|
9777de1890 | ||
|
|
e170cbe013 | ||
|
|
6847999fb8 | ||
|
|
dca146f823 | ||
|
|
233ba51ad9 | ||
|
|
f5176cb6e8 | ||
|
|
1551ce98f2 | ||
|
|
b9b9028e50 | ||
|
|
07b9138cad | ||
|
|
2ac8007544 | ||
|
|
d1d6e27ab6 | ||
|
|
81702b5451 | ||
|
|
2bddb8ebee | ||
|
|
fc40b3e732 | ||
|
|
5fcf7c1c18 | ||
|
|
e3639f5cc3 | ||
|
|
9e4b3724c7 | ||
|
|
9a2cd72257 | ||
|
|
55fa0479a0 | ||
|
|
427054c3d5 | ||
|
|
c367d7df31 | ||
|
|
b9a28677e2 | ||
|
|
d36669fd75 | ||
|
|
66e6af89ce | ||
|
|
29735c8f8f | ||
|
|
527aa3e604 | ||
|
|
73e50749e2 | ||
|
|
c6f26ecae2 | ||
|
|
1e8920c225 | ||
|
|
18c36561f6 | ||
|
|
00898fe750 | ||
|
|
5f5cfdfa77 | ||
|
|
aa47ea41a7 | ||
|
|
944b6079d9 | ||
|
|
b00da61eab | ||
|
|
2506d51d60 | ||
|
|
f7e551d0b8 | ||
|
|
4bb0bff233 | ||
|
|
515a2d9fe8 | ||
|
|
1a2284dea0 | ||
|
|
374b58d131 | ||
|
|
bdc3d7496f |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
*
|
||||
142
CMakeLists.txt
142
CMakeLists.txt
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -27,6 +27,9 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
if (IOS)
|
||||
INCLUDE(CmakeLists_IOS.txt)
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
@@ -77,9 +80,14 @@ if (ARM_TEST STREQUAL "arm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARM_ID STREQUAL "aarch64")
|
||||
if (ARM_ID STREQUAL "aarch64" OR ARM_ID STREQUAL "arm64" OR ARM_ID STREQUAL "armv8-a")
|
||||
set(ARM 1)
|
||||
set(ARM8 1)
|
||||
set(ARCH "armv8-a")
|
||||
endif()
|
||||
|
||||
if(ARCH_ID STREQUAL "ppc64le")
|
||||
set(PPC64LE 1)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR ARM)
|
||||
@@ -88,6 +96,14 @@ else()
|
||||
set(OPT_FLAGS_RELEASE "-Ofast")
|
||||
endif()
|
||||
|
||||
# BUILD_TAG is used to select the build type to check for a new version
|
||||
if(BUILD_TAG)
|
||||
message(STATUS "Building build tag ${BUILD_TAG}")
|
||||
add_definitions("-DBUILD_TAG=${BUILD_TAG}")
|
||||
else()
|
||||
message(STATUS "Building without build tag")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
|
||||
|
||||
@@ -149,12 +165,15 @@ message(STATUS "Building for a ${ARCH_WIDTH}-bit system")
|
||||
|
||||
# Check if we're on FreeBSD so we can exclude the local miniupnpc (it should be installed from ports instead)
|
||||
# CMAKE_SYSTEM_NAME checks are commonly known, but specifically taken from libsdl's CMakeLists
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD.*")
|
||||
set(FREEBSD TRUE)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly.*|FreeBSD")
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD.*|FreeBSD")
|
||||
set(FREEBSD TRUE)
|
||||
endif()
|
||||
|
||||
# Check if we're on DragonFly BSD. See the README.md for build instructions.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "DragonFly.*")
|
||||
set(DRAGONFLY TRUE)
|
||||
endif()
|
||||
|
||||
# Check if we're on OpenBSD. See the README.md for build instructions.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*")
|
||||
set(OPENBSD TRUE)
|
||||
@@ -167,10 +186,13 @@ endif()
|
||||
# elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
|
||||
# set(BSDI TRUE)
|
||||
|
||||
include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version")
|
||||
include_directories(external/easylogging++ src contrib/epee/include external "${CMAKE_BINARY_DIR}/version")
|
||||
|
||||
if(APPLE)
|
||||
include_directories(SYSTEM /usr/include/malloc)
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC OR MINGW)
|
||||
@@ -188,6 +210,7 @@ endif()
|
||||
if (BUILD_SHARED_LIBS)
|
||||
message(STATUS "Building internal libraries with position independent code")
|
||||
set(PIC_FLAG "-fPIC")
|
||||
add_definitions("-DBUILD_SHARED_LIBS")
|
||||
else()
|
||||
message(STATUS "Building internal libraries as static")
|
||||
endif()
|
||||
@@ -213,8 +236,8 @@ if(STATIC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# default database:
|
||||
# should be lmdb for testing, memory for production still
|
||||
# Set default blockchain storage location:
|
||||
# memory was the default in Cryptonote before Monero implimented LMDB, it still works but is unneccessary.
|
||||
# set(DATABASE memory)
|
||||
set(DATABASE lmdb)
|
||||
|
||||
@@ -267,14 +290,25 @@ endif()
|
||||
|
||||
add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}")
|
||||
|
||||
find_package(Libunwind)
|
||||
# Can't install hook in static build on OSX, because OSX linker does not support --wrap
|
||||
# On ARM, having libunwind package (with .so's only) installed breaks static link.
|
||||
if(LIBUNWIND_FOUND AND NOT (STATIC AND (APPLE OR ARM)))
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
else()
|
||||
if (APPLE)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif (ARM AND STATIC)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
else()
|
||||
find_package(Libunwind)
|
||||
if(LIBUNWIND_FOUND)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
else()
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(STACK_TRACE "Install a hook that dumps stack on exception" ${DEFAULT_STACK_TRACE})
|
||||
@@ -285,16 +319,35 @@ else()
|
||||
message(STATUS "Stack trace on exception disabled")
|
||||
endif()
|
||||
|
||||
# Handle OpenSSL, used for sha256sum on binary updates
|
||||
if (APPLE AND NOT IOS)
|
||||
if (NOT OpenSSL_DIR)
|
||||
EXECUTE_PROCESS(COMMAND brew --prefix openssl
|
||||
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
message(STATUS "Using OpenSSL found at ${OPENSSL_ROOT_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(STATIC AND NOT IOS)
|
||||
if(UNIX)
|
||||
set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES};${CMAKE_DL_LIBS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
# Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP)
|
||||
|
||||
add_subdirectory(external)
|
||||
|
||||
# Final setup for miniupnpc
|
||||
if(UPNP_STATIC)
|
||||
if(UPNP_STATIC OR IOS)
|
||||
add_definitions("-DUPNP_STATIC")
|
||||
else()
|
||||
add_definitions("-DUPNP_DYNAMIC")
|
||||
@@ -305,8 +358,9 @@ endif()
|
||||
include_directories(${UNBOUND_INCLUDE})
|
||||
link_directories(${UNBOUND_LIBRARY_DIRS})
|
||||
|
||||
# Final setup for rapidjson
|
||||
include_directories(external/rapidjson)
|
||||
# Final setup for easylogging++
|
||||
include_directories(${EASYLOGGING_INCLUDE})
|
||||
link_directories(${EASYLOGGING_LIBRARY_DIRS})
|
||||
|
||||
# Final setup for liblmdb
|
||||
include_directories(${LMDB_INCLUDE})
|
||||
@@ -336,6 +390,11 @@ else()
|
||||
message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}")
|
||||
if(ARCH STREQUAL "default")
|
||||
set(ARCH_FLAG "")
|
||||
elseif(PPC64LE)
|
||||
set(ARCH_FLAG "-mcpu=${ARCH}")
|
||||
elseif(IOS AND ARCH STREQUAL "arm64")
|
||||
message(STATUS "IOS: Changing arch from arm64 to armv8")
|
||||
set(ARCH_FLAG "-march=armv8")
|
||||
else()
|
||||
set(ARCH_FLAG "-march=${ARCH}")
|
||||
endif()
|
||||
@@ -344,7 +403,6 @@ else()
|
||||
set(WARNINGS_AS_ERRORS_FLAG "-Werror")
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNINGS "${WARNINGS} -Wno-deprecated-register -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration")
|
||||
if(ARM)
|
||||
set(WARNINGS "${WARNINGS} -Wno-error=inline-asm")
|
||||
endif()
|
||||
@@ -372,6 +430,13 @@ else()
|
||||
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
|
||||
endif()
|
||||
|
||||
try_compile(STATIC_ASSERT_CPP_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.cpp" COMPILE_DEFINITIONS "-std=c++11")
|
||||
if(STATIC_ASSERT_CPP_RES)
|
||||
set(STATIC_ASSERT_CPP_FLAG "")
|
||||
else()
|
||||
set(STATIC_ASSERT_CPP_FLAG "-Dstatic_assert=_Static_assert")
|
||||
endif()
|
||||
|
||||
option(COVERAGE "Enable profiling for test coverage report" 0)
|
||||
|
||||
if(COVERAGE)
|
||||
@@ -386,10 +451,12 @@ else()
|
||||
|
||||
option(NO_AES "Explicitly disable AES support" ${NO_AES})
|
||||
|
||||
if(NOT NO_AES AND NOT ARM)
|
||||
if(NOT NO_AES AND NOT ARM AND NOT PPC64LE)
|
||||
message(STATUS "AES support enabled")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
elseif(PPC64LE)
|
||||
message(STATUS "AES support not available on ppc64le")
|
||||
elseif(ARM6)
|
||||
message(STATUS "AES support not available on ARMv6")
|
||||
elseif(ARM7)
|
||||
@@ -407,7 +474,7 @@ else()
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
# is fixed in the code (Issue #847), force compiler to be conservative.
|
||||
@@ -491,6 +558,14 @@ else()
|
||||
|
||||
endif(ARM)
|
||||
|
||||
if(ANDROID AND NOT BUILD_GUI_DEPS STREQUAL "ON" OR IOS)
|
||||
#From Android 5: "only position independent executables (PIE) are supported"
|
||||
message(STATUS "Enabling PIE executable")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fPIE -pie")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0")
|
||||
endif()
|
||||
@@ -503,7 +578,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED USE_LTO_DEFAULT)
|
||||
set(USE_LTO_DEFAULT true)
|
||||
set(USE_LTO_DEFAULT false)
|
||||
endif()
|
||||
set(USE_LTO ${USE_LTO_DEFAULT} CACHE BOOL "Use Link-Time Optimization (Release mode only)")
|
||||
|
||||
@@ -519,7 +594,7 @@ else()
|
||||
set(RELEASE_FLAGS "${RELEASE_FLAGS} -ffat-lto-objects")
|
||||
endif()
|
||||
# Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0) AND NOT OPENBSD)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0) AND NOT OPENBSD AND NOT DRAGONFLY)
|
||||
# When invoking cmake on distributions on which gcc's binaries are prefixed
|
||||
# with an arch-specific triplet, the user must specify -DCHOST=<prefix>
|
||||
if (DEFINED CHOST)
|
||||
@@ -544,7 +619,7 @@ else()
|
||||
# On Windows, this is as close to fully-static as we get:
|
||||
# this leaves only deps on /c/Windows/system32/*.dll
|
||||
set(STATIC_FLAGS "-static")
|
||||
elseif (NOT (APPLE OR FREEBSD OR OPENBSD))
|
||||
elseif (NOT (APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
|
||||
# On Linux, we don't support fully static build, but these can be static
|
||||
set(STATIC_FLAGS "-static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
@@ -577,8 +652,13 @@ endif()
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
if(MINGW)
|
||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi)
|
||||
elseif(APPLE OR FREEBSD OR OPENBSD)
|
||||
elseif(APPLE OR OPENBSD OR ANDROID)
|
||||
set(EXTRA_LIBRARIES "")
|
||||
elseif(FREEBSD)
|
||||
set(EXTRA_LIBRARIES execinfo)
|
||||
elseif(DRAGONFLY)
|
||||
find_library(COMPAT compat)
|
||||
set(EXTRA_LIBRARIES execinfo ${COMPAT})
|
||||
elseif(NOT MSVC)
|
||||
find_library(RT rt)
|
||||
set(EXTRA_LIBRARIES ${RT})
|
||||
@@ -586,7 +666,23 @@ endif()
|
||||
|
||||
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND ARCH_WIDTH EQUAL "32")
|
||||
option(USE_READLINE "Build with GNU readline support." ON)
|
||||
if(USE_READLINE)
|
||||
find_package(Readline)
|
||||
if(READLINE_FOUND AND GNU_READLINE_FOUND)
|
||||
add_definitions(-DHAVE_READLINE)
|
||||
include_directories(${Readline_INCLUDE_DIR})
|
||||
list(APPEND EXTRA_LIBRARIES ${Readline_LIBRARY})
|
||||
message(STATUS "Found readline library at: ${Readline_ROOT_DIR}")
|
||||
else()
|
||||
message(STATUS "Could not find GNU readline library so building without readline support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(ATOMIC libatomic.a)
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND ARCH_WIDTH EQUAL "32" AND NOT IOS)
|
||||
find_library(ATOMIC atomic)
|
||||
list(APPEND EXTRA_LIBRARIES ${ATOMIC})
|
||||
endif()
|
||||
|
||||
164
CMakeLists_IOS.txt
Normal file
164
CMakeLists_IOS.txt
Normal file
@@ -0,0 +1,164 @@
|
||||
# Portions Copyright (c) 2017, The Monero Project
|
||||
# This file is based off of the https://code.google.com/archive/p/ios-cmake/
|
||||
# It has been altered for Monero iOS development
|
||||
#
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# IOS_PLATFORM = OS (default) or SIMULATOR or SIMULATOR64
|
||||
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
|
||||
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
|
||||
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
|
||||
#
|
||||
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
|
||||
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
|
||||
# If set manually, it will override the default location and force the user of a particular Developer Platform
|
||||
#
|
||||
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
|
||||
# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
|
||||
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
|
||||
# If set manually, this will force the use of a specific SDK version
|
||||
|
||||
|
||||
# Standard settings
|
||||
set (CMAKE_SYSTEM_NAME Darwin)
|
||||
set (CMAKE_SYSTEM_VERSION 1)
|
||||
set (UNIX True)
|
||||
set (APPLE True)
|
||||
set (IOS True)
|
||||
|
||||
# Required as of cmake 2.8.10
|
||||
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
|
||||
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||
if (CMAKE_UNAME)
|
||||
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
|
||||
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
|
||||
endif (CMAKE_UNAME)
|
||||
|
||||
# Force the compilers to gcc for iOS
|
||||
include (CMakeForceCompiler)
|
||||
# set (MAKE_C_COMPILER "/usr/bin/gcc Apple")
|
||||
# set (CMAKE_CXX_COMPILER "/usr/bin/g++ Apple")
|
||||
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
|
||||
|
||||
# Skip the platform compiler checks for cross compiling
|
||||
set (CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||
set (CMAKE_C_COMPILER_WORKS TRUE)
|
||||
|
||||
# All iOS/Darwin specific settings - some may be redundant
|
||||
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
|
||||
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||
set (CMAKE_SHARED_MODULE_PREFIX "lib")
|
||||
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
|
||||
set (CMAKE_MODULE_EXISTS 1)
|
||||
set (CMAKE_DL_LIBS "")
|
||||
|
||||
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
|
||||
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
|
||||
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
|
||||
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
|
||||
|
||||
# Hidden visibilty is required for cxx on iOS
|
||||
set (CMAKE_C_FLAGS_INIT "")
|
||||
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
|
||||
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
||||
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
|
||||
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
|
||||
|
||||
# Setup iOS platform unless specified manually with IOS_PLATFORM
|
||||
if (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM "OS")
|
||||
endif (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
|
||||
|
||||
# Setup building for arm64 or not
|
||||
if (NOT DEFINED BUILD_ARM64)
|
||||
set (BUILD_ARM64 true)
|
||||
endif (NOT DEFINED BUILD_ARM64)
|
||||
set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not")
|
||||
|
||||
# Check the platform selection and setup for developer root
|
||||
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
|
||||
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
|
||||
set (SIMULATOR true)
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64")
|
||||
set (SIMULATOR true)
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||
else (${IOS_PLATFORM} STREQUAL "OS")
|
||||
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
|
||||
endif (${IOS_PLATFORM} STREQUAL "OS")
|
||||
|
||||
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
|
||||
# Note Xcode 4.3 changed the installation location, choose the most recent one available
|
||||
exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR)
|
||||
set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
if (EXISTS ${XCODE_POST_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
|
||||
elseif(EXISTS ${XCODE_PRE_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
|
||||
endif (EXISTS ${XCODE_POST_43_ROOT})
|
||||
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
|
||||
|
||||
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
|
||||
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
|
||||
if (_CMAKE_IOS_SDKS)
|
||||
list (SORT _CMAKE_IOS_SDKS)
|
||||
list (REVERSE _CMAKE_IOS_SDKS)
|
||||
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
|
||||
else (_CMAKE_IOS_SDKS)
|
||||
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
|
||||
endif (_CMAKE_IOS_SDKS)
|
||||
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
|
||||
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
|
||||
|
||||
# Set the sysroot default to the most recent SDK
|
||||
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
|
||||
|
||||
# set the architecture for iOS
|
||||
if (NOT DEFINED ARCH)
|
||||
set (ARCH armv7)
|
||||
endif()
|
||||
set (IOS_ARCH ${ARCH})
|
||||
|
||||
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")
|
||||
message(STATUS "ios arch: ${IOS_ARCH}")
|
||||
|
||||
# Set the find root to the iOS developer roots and to user defined paths
|
||||
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root")
|
||||
|
||||
# default to searching for frameworks first
|
||||
set (CMAKE_FIND_FRAMEWORK FIRST)
|
||||
|
||||
# set up the default search directories for frameworks
|
||||
set (CMAKE_SYSTEM_FRAMEWORK_PATH
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
|
||||
)
|
||||
|
||||
message(STATUS "IOS CMAKE conf finished")
|
||||
@@ -1,8 +1,17 @@
|
||||
A good way to help is to test, and report bugs.
|
||||
See http://www.chiark.greenend.org.uk/~sgtatham/bugs.html if you
|
||||
want to help that way. Testing is invaluable in making a piece
|
||||
# Contributing to Monero
|
||||
|
||||
A good way to help is to test, and report bugs. See
|
||||
[How to Report Bugs Effectively (by Simon Tatham)](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html)
|
||||
if you want to help that way. Testing is invaluable in making a piece
|
||||
of software solid and usable.
|
||||
|
||||
|
||||
## General Guidelines
|
||||
|
||||
* Comments are encouraged.
|
||||
* If modifying code for which Doxygen headers exist, that header must be modified to match.
|
||||
* Tests would be nice to have if you're adding functionality.
|
||||
|
||||
Patches are preferably to be sent via a github pull request. If that
|
||||
can't be done, patches in "git format-patch" format can be sent
|
||||
(eg, posted to fpaste.org with a long enough timeout and a link
|
||||
@@ -16,15 +25,12 @@ modifying is encourgaged. Proper squashing should be done (eg, if
|
||||
you're making a buggy patch, then a later patch to fix the bug,
|
||||
both patches should be merged).
|
||||
|
||||
## Commits and Pull Requests
|
||||
|
||||
Commit messages should be sensible. That means a subject line that
|
||||
describes the patch, with an optional longer body that gives details,
|
||||
documentation, etc.
|
||||
|
||||
Comments are encouraged.
|
||||
|
||||
If modifying code for which Doxygen headers exist, that header must
|
||||
be modified to match.
|
||||
|
||||
When submitting a pull request on github, make sure your branch is
|
||||
rebased. No merge commits nor stray commits from other people in
|
||||
your submitted branch, please. You may be asked to rebase if there
|
||||
@@ -32,5 +38,3 @@ are conflicts (even trivially resolvable ones).
|
||||
|
||||
PGP signing commits is strongly encouraged. That should explain why
|
||||
the previous paragraph is here.
|
||||
|
||||
Tests would be nice to have if you're adding functionality.
|
||||
52
Dockerfile
52
Dockerfile
@@ -1,40 +1,36 @@
|
||||
FROM debian:testing
|
||||
MAINTAINER eiabea <developer@eiabea.com>
|
||||
FROM ubuntu:16.04
|
||||
|
||||
# Install clone dependencies
|
||||
RUN set -e && \
|
||||
apt-get update -q && \
|
||||
apt-get install -q -y --no-install-recommends ca-certificates git && \
|
||||
git clone https://github.com/monero-project/monero.git src && \
|
||||
apt-get purge -y git && \
|
||||
apt-get clean -q -y && \
|
||||
apt-get autoclean -q -y && \
|
||||
apt-get autoremove -q -y
|
||||
ENV SRC_DIR /usr/local/src/monero
|
||||
|
||||
WORKDIR /src
|
||||
RUN set -x \
|
||||
&& buildDeps=' \
|
||||
ca-certificates \
|
||||
cmake \
|
||||
g++ \
|
||||
git \
|
||||
libboost1.58-all-dev \
|
||||
libssl-dev \
|
||||
make \
|
||||
pkg-config \
|
||||
' \
|
||||
&& apt-get -qq update \
|
||||
&& apt-get -qq --no-install-recommends install $buildDeps
|
||||
|
||||
# Install make dependencies
|
||||
RUN set -e && \
|
||||
apt-get update -q && \
|
||||
apt-get install -q -y --no-install-recommends build-essential ca-certificates g++ gcc cmake \
|
||||
pkg-config libunbound2 libevent-2.0-5 libgtest-dev libboost-all-dev libdb5.3++-dev libdb5.3-dev libssl-dev && \
|
||||
make -j 4 && \
|
||||
apt-get purge -y g++ gcc cmake pkg-config && \
|
||||
apt-get clean -q -y && \
|
||||
apt-get autoclean -q -y && \
|
||||
apt-get autoremove -q -y && \
|
||||
mkdir /monero && \
|
||||
mv /src/build/release/bin/* /monero && \
|
||||
rm -rf /src
|
||||
RUN git clone https://github.com/monero-project/monero.git $SRC_DIR
|
||||
WORKDIR $SRC_DIR
|
||||
RUN make -j$(nproc) release-static
|
||||
|
||||
WORKDIR /monero
|
||||
RUN cp build/release/bin/* /usr/local/bin/ \
|
||||
\
|
||||
&& rm -r $SRC_DIR \
|
||||
&& apt-get -qq --auto-remove purge $buildDeps
|
||||
|
||||
# Contains the blockchain
|
||||
VOLUME /root/.bitmonero
|
||||
|
||||
# Generate your wallet via accessing the container and run:
|
||||
# cd /wallet
|
||||
# /./bitmonero/monero-wallet-cli
|
||||
# monero-wallet-cli
|
||||
VOLUME /wallet
|
||||
|
||||
ENV LOG_LEVEL 0
|
||||
@@ -46,4 +42,4 @@ ENV RPC_BIND_PORT 18081
|
||||
EXPOSE 18080
|
||||
EXPOSE 18081
|
||||
|
||||
CMD ./monerod --log-level=$LOG_LEVEL --p2p-bind-ip=$P2P_BIND_IP --p2p-bind-port=$P2P_BIND_PORT --rpc-bind-ip=$RPC_BIND_IP --rpc-bind-port=$RPC_BIND_PORT
|
||||
CMD monerod --log-level=$LOG_LEVEL --p2p-bind-ip=$P2P_BIND_IP --p2p-bind-port=$P2P_BIND_PORT --rpc-bind-ip=$RPC_BIND_IP --rpc-bind-port=$RPC_BIND_PORT
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014-2016, The Monero Project
|
||||
Copyright (c) 2014-2017, The Monero Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
58
Makefile
58
Makefile
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -41,7 +41,11 @@ debug-test:
|
||||
|
||||
debug-all:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||
|
||||
debug-static-all:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||
|
||||
cmake-release:
|
||||
mkdir -p build/release
|
||||
@@ -58,39 +62,59 @@ release-all:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
|
||||
release-static:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
|
||||
coverage:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test
|
||||
|
||||
release-static-armv6:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
# Targets for specific prebuilt builds which will be advertised for updates by their build tag
|
||||
|
||||
release-static-armv7:
|
||||
release-static-linux-armv6:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv6" ../.. && $(MAKE)
|
||||
|
||||
release-static-armv8:
|
||||
release-static-linux-armv7:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv7" ../.. && $(MAKE)
|
||||
|
||||
release-static: release-static-64
|
||||
|
||||
release-static-64:
|
||||
release-static-android:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android" ../.. && $(MAKE)
|
||||
|
||||
release-static-32:
|
||||
release-static-linux-armv8:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv8" ../.. && $(MAKE)
|
||||
|
||||
release-static-linux-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" ../.. && $(MAKE)
|
||||
|
||||
release-static-freebsd-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" ../.. && $(MAKE)
|
||||
|
||||
release-static-mac-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" ../.. && $(MAKE)
|
||||
|
||||
release-static-linux-i686:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x86" ../.. && $(MAKE)
|
||||
|
||||
release-static-win64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
|
||||
|
||||
release-static-win32:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
|
||||
|
||||
fuzz:
|
||||
mkdir -p build/fuzz
|
||||
cd build/fuzz && cmake -D BUILD_TESTS=ON -D USE_LTO=OFF -D CMAKE_C_COMPILER=afl-gcc -D CMAKE_CXX_COMPILER=afl-g++ -D ARCH="x86-64" -D CMAKE_BUILD_TYPE=fuzz -D BUILD_TAG="linux-x64" ../.. && $(MAKE)
|
||||
|
||||
clean:
|
||||
@echo "WARNING: Back-up your wallet if it exists within ./build!" ; \
|
||||
|
||||
45
README.i18n
45
README.i18n
@@ -1,45 +0,0 @@
|
||||
The Monero command line tools can be translated in various languages.
|
||||
In order to use the same translation workflow as the future GUI, they
|
||||
use Qt Linguist translation files. However, to avoid the dependencies
|
||||
on Qt this normally implies, they use a custom loader to read those
|
||||
files at runtime. In order to update, or build translations files, you
|
||||
do need to have Qt tools installed, however. For translating, you need
|
||||
either the Qt Linguist GUI, or another tool that supports Qt ts files,
|
||||
such as Transifex. To run, you do not need anything Qt.
|
||||
|
||||
To update ts files after changing source code:
|
||||
|
||||
./utils/translations/update-translations.sh
|
||||
|
||||
To add a new language, eg Spanish (ISO code es):
|
||||
|
||||
cp translations/monero.ts translations/monero_es.ts
|
||||
|
||||
To edit translations for Spanish:
|
||||
|
||||
linguist translations/monero_es.ts
|
||||
|
||||
To build translations after modifying them:
|
||||
|
||||
./utils/translations/build-translations.sh
|
||||
|
||||
To test a translation:
|
||||
|
||||
LANG=es ./build/release/bin/monero-wallet-cli
|
||||
|
||||
To add new translatable sources in the source:
|
||||
|
||||
Use the tr(string) function if possible. If the code is in a class,
|
||||
and this class doesn't already have a tr() static function, add one,
|
||||
which uses a context named after what lupdate uses for the context,
|
||||
usually the fully qualified class name (eg, cryptonote::simple_wallet).
|
||||
If you need to use tr in code that's not in a class, you can use the
|
||||
fully qualified version (eg, simple_wallet::tr) of the one matching
|
||||
the context you want.
|
||||
Use QT_TRANSLATE_NOOP(string) if you want to specify a context manually.
|
||||
|
||||
If you're getting messages of the form:
|
||||
|
||||
Class 'cryptonote::simple_wallet' lacks Q_OBJECT macro
|
||||
|
||||
all is fine, we don't actually need that here.
|
||||
44
README.i18n.md
Normal file
44
README.i18n.md
Normal file
@@ -0,0 +1,44 @@
|
||||
Monero daemon internationalization
|
||||
==================================
|
||||
|
||||
The Monero command line tools can be translated in various languages.
|
||||
|
||||
In order to use the same translation workflow as the [Monero Core GUI](https://github.com/monero-project/monero-core), they use Qt Linguist translation files. However, to avoid the dependencies on Qt this normally implies, they use a custom loader to read those files at runtime.
|
||||
|
||||
### Tools for translators
|
||||
|
||||
In order to create, update or build translations files, you need to have Qt tools installed. For translating, you need either the **Qt Linguist GUI** ([part of QT Creator](https://www.qt.io/download-open-source/#allDownloadsDiv-9) or a [3rd-party standalone version](https://github.com/lelegard/qtlinguist-installers/releases)), or another tool that supports Qt ts files, such as Transifex. The files are XML, so they can be edited in any plain text editor if needed.
|
||||
|
||||
### Creating / modifying translations
|
||||
|
||||
You do not need anything from Qt in order to use the final translations.
|
||||
|
||||
To update ts files after changing source code:
|
||||
|
||||
./utils/translations/update-translations.sh
|
||||
|
||||
To add a new language, eg Spanish (ISO code es):
|
||||
|
||||
cp translations/monero.ts translations/monero_es.ts
|
||||
|
||||
To edit translations for Spanish:
|
||||
|
||||
linguist translations/monero_es.ts
|
||||
|
||||
To build translations after modifying them:
|
||||
|
||||
./utils/translations/build-translations.sh
|
||||
|
||||
To test a translation:
|
||||
|
||||
LANG=es ./build/release/bin/monero-wallet-cli
|
||||
|
||||
To add new translatable strings in the source code:
|
||||
|
||||
Use the `tr(string)` function if possible. If the code is in a class, and this class doesn't already have a `tr()` static function, add one, which uses a context named after what `lupdate` uses for the context, usually the fully qualified class name (eg, `cryptonote::simple_wallet`). If you need to use `tr()` in code that's not in a class, you can use the fully qualified version (eg, `simple_wallet::tr`) of the one matching the context you want. Use `QT_TRANSLATE_NOOP(string)` if you want to specify a context manually.
|
||||
|
||||
If you're getting messages of the form:
|
||||
|
||||
Class 'cryptonote::simple_wallet' lacks Q_OBJECT macro
|
||||
|
||||
all is fine, we don't actually need that here.
|
||||
140
README.md
140
README.md
@@ -1,6 +1,7 @@
|
||||
# Monero
|
||||
|
||||
Copyright (c) 2014-2016, The Monero Project
|
||||
Copyright (c) 2014-2017, The Monero Project
|
||||
Portions Copyright (c) 2012-2013, The Cryptonote developers
|
||||
|
||||
## Development Resources
|
||||
|
||||
@@ -21,7 +22,8 @@ Copyright (c) 2014-2016, The Monero Project
|
||||
| OSX 10.10 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.10)
|
||||
| OSX 10.11 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.11)
|
||||
| OSX 10.12 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.12)
|
||||
| FreeBSD 10.3 | amd64 | [](https://build.getmonero.org/builders/monero-static-freebsd64)
|
||||
| FreeBSD 11 | amd64 | [](https://build.getmonero.org/builders/monero-static-freebsd64)
|
||||
| DragonFly BSD 4.6 | amd64 | [](https://build.getmonero.org/builders/monero-static-dragonflybsd-amd64)
|
||||
| Windows (MSYS2/MinGW) | i686 | [](https://build.getmonero.org/builders/monero-static-win32)
|
||||
| Windows (MSYS2/MinGW) | amd64 | [](https://build.getmonero.org/builders/monero-static-win64)
|
||||
|
||||
@@ -49,7 +51,7 @@ This is the core implementation of Monero. It is open source and completely free
|
||||
|
||||
As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability.
|
||||
|
||||
**Anyone is welcome to contribute to Monero's codebase!** If you have a fix or code change, feel free to submit is as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request.
|
||||
**Anyone is welcome to contribute to Monero's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request.
|
||||
|
||||
## Supporting the Project
|
||||
|
||||
@@ -61,6 +63,8 @@ The Monero donation address is: `44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft
|
||||
|
||||
The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
|
||||
|
||||
*Note: you can easily donate XMR to the Monero donation address by using the `donate` command. Type `help` in the command-line wallet for details.*
|
||||
|
||||
Core development funding and/or some supporting services are also graciously provided by sponsors:
|
||||
|
||||
[<img width="80" src="https://static.getmonero.org/images/sponsors/mymonero.png"/>](https://mymonero.com)
|
||||
@@ -77,25 +81,40 @@ There are also several mining pools that kindly donate a portion of their fees,
|
||||
|
||||
See [LICENSE](LICENSE).
|
||||
|
||||
## Monero software updates and consensus protocol changes (hard forking)
|
||||
# Contributing
|
||||
|
||||
Monero uses a hardforking mechanism to implement new features which requires that
|
||||
users of Monero software run current versions and update their software on a
|
||||
regular schedule. Here is the current schedule, versions, and compatability.
|
||||
Dates are provided in the format YYYYMMDD.
|
||||
If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidelines.
|
||||
|
||||
## Vulnerability Response Process
|
||||
|
||||
See [Vulnerability Response Process](VULNERABILITY_RESPONSE_PROCESS.md).
|
||||
|
||||
## Monero software updates and consensus protocol changes (hard fork schedule)
|
||||
|
||||
Monero uses a fixed-schedule hard fork mechanism to implement new features. This means that users of Monero (end users and service providers) need to run current versions and update their software on a regular schedule. Here is the current schedule, versions, and compatibility.
|
||||
Dates are provided in the format YYYY-MM-DD.
|
||||
|
||||
|
||||
| Date | Consensus version | Minimum Monero Version | Recommended Monero Version | Details |
|
||||
| Fork Date | Consensus version | Minimum Monero Version | Recommended Monero Version | Details |
|
||||
| ----------------- | ----------------- | ---------------------- | -------------------------- | ------------------ |
|
||||
| 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations |
|
||||
| 2017-01-05 | v4 | v0.10.1 | v0.10.1 | Allow normal and RingCT transactions |
|
||||
| 2017-09-21 | v5 | v0.10.1 | v0.10.1 | Allow only RingCT transactions |
|
||||
| 2017-01-05 | v4 | v0.10.1 | v0.10.2.1 | Allow normal and RingCT transactions |
|
||||
| 2017-04-15 | v5 | v0.10.3.0 | v0.10.3.1 | Adjusted minimum blocksize and fee algorithm |
|
||||
| 2017-09-21 | v6 | Not determined as of 2017-03-27 | Not determined as of 2017-03-27 | Allow only RingCT transactions |
|
||||
|
||||
## Installing Monero from a Package
|
||||
|
||||
Packages are available for
|
||||
|
||||
* Arch Linux via AUR: [`bitmonero-git`](https://aur.archlinux.org/packages/bitmonero-git)
|
||||
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
||||
|
||||
snap install monero --beta
|
||||
|
||||
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
||||
|
||||
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
|
||||
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
|
||||
- Bleeding edge: [`bitmonero-git`](https://aur.archlinux.org/packages/bitmonero-git)
|
||||
|
||||
* OS X via [Homebrew](http://brew.sh)
|
||||
|
||||
@@ -132,17 +151,17 @@ library archives (`.a`).
|
||||
| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | NO | |
|
||||
| CMake | 3.0.0 | NO | `cmake` | `cmake` | NO | |
|
||||
| pkg-config | any | NO | `pkg-config` | `base-devel` | NO | |
|
||||
| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | NO | |
|
||||
| BerkeleyDB | 4.8 | NO | `libdb{,++}-dev` | `db` | NO | |
|
||||
| libevent | 2.0 | NO | `libevent-dev` | `libevent` | NO | |
|
||||
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | NO | |
|
||||
| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | NO | C++ libraries |
|
||||
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | NO | sha256 sum |
|
||||
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | NO | DNS resolver |
|
||||
| libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | YES | NAT punching |
|
||||
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | YES | stack traces |
|
||||
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | YES | ? |
|
||||
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | YES | ? |
|
||||
| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | YES | test suite |
|
||||
| Doxygen | any | NO | `doxygen` | `doxygen` | YES | documentation |
|
||||
| Graphviz | any | NO | `graphviz` | `graphviz` | YES | documentation |
|
||||
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | YES | Stack traces |
|
||||
| liblzma | any | NO | `liblzma-dev` | `xz` | YES | For libunwind |
|
||||
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | YES | SSL toolkit |
|
||||
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | YES | XML parsing |
|
||||
| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | YES | Test suite |
|
||||
| Doxygen | any | NO | `doxygen` | `doxygen` | YES | Documentation |
|
||||
| Graphviz | any | NO | `graphviz` | `graphviz` | YES | Documentation |
|
||||
|
||||
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
|
||||
build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ```
|
||||
@@ -189,7 +208,7 @@ invokes cmake commands as needed.
|
||||
|
||||
HAVE_DOT=YES doxygen Doxyfile
|
||||
|
||||
#### On the Raspberry Pi
|
||||
#### On the Raspberry Pi 2
|
||||
|
||||
Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from https://www.raspberrypi.org/downloads/raspbian/
|
||||
|
||||
@@ -207,23 +226,23 @@ Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from ht
|
||||
* Install the latest version of boost (this may first require invoking `apt-get remove --purge libboost*` to remove a previous version if you're not using a clean install):
|
||||
```
|
||||
cd
|
||||
wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.bz2
|
||||
tar xvfo boost_1_62_0.tar.bz2
|
||||
cd boost_1_62_0
|
||||
wget https://sourceforge.net/projects/boost/files/boost/1.64.0/boost_1_64_0.tar.bz2
|
||||
tar xvfo boost_1_64_0.tar.bz2
|
||||
cd boost_1_64_0
|
||||
./bootstrap.sh
|
||||
sudo ./b2
|
||||
```
|
||||
* Wait ~8 hours
|
||||
|
||||
```
|
||||
sudo ./bjam install
|
||||
|
||||
```
|
||||
* Wait ~4 hours
|
||||
|
||||
* Change to the root of the source code directory and build:
|
||||
|
||||
```
|
||||
cd monero
|
||||
make release
|
||||
|
||||
```
|
||||
* Wait ~4 hours
|
||||
|
||||
* The resulting executables can be found in `build/release/bin`
|
||||
@@ -285,7 +304,7 @@ application.
|
||||
|
||||
### On FreeBSD:
|
||||
|
||||
The project can be built from scratch by following instructions for Linux above.
|
||||
The project can be built from scratch by following instructions for Linux above. If you are running monero in a jail you need to add the flag: `allow.sysvipc=1` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
|
||||
|
||||
We expect to add Monero into the ports tree in the near future, which will aid in managing installations using ports or packages.
|
||||
|
||||
@@ -304,6 +323,15 @@ You will have to add the serialization, date_time, and regex modules to Boost wh
|
||||
|
||||
To build: `env CC=egcc CXX=eg++ CPP=ecpp DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/path/to/the/boost/you/built make release-static-64`
|
||||
|
||||
### On Linux for Android (using docker):
|
||||
|
||||
# Build image (select android64.Dockerfile for aarch64)
|
||||
cd utils/build_scripts/ && docker build -f android32.Dockerfile -t monero-android .
|
||||
# Create container
|
||||
docker create -it --name monero-android monero-android bash
|
||||
# Get binaries
|
||||
docker cp monero-android:/opt/android/monero/build/release/bin .
|
||||
|
||||
### Building Portable Statically Linked Binaries
|
||||
|
||||
By default, in either dynamically or statically linked builds, binaries target the specific host processor on which the build happens and are not portable to other processors. Portable binaries can be built using the following targets:
|
||||
@@ -346,7 +374,7 @@ monero-wallet-cli, and possibly monerod, if you get crashes refreshing.
|
||||
|
||||
## Internationalization
|
||||
|
||||
See README.i18n
|
||||
See [README.i18n.md](README.i18n.md).
|
||||
|
||||
## Using Tor
|
||||
|
||||
@@ -374,14 +402,54 @@ While monerod and monero-wallet-cli do not use readline directly, most of the fu
|
||||
|
||||
Note: rlwrap will save things like your seed and private keys, if you supply them on prompt. You may want to not use rlwrap when you use simplewallet to restore from seed, etc.
|
||||
|
||||
# Contributing
|
||||
|
||||
If you want to help out, see CONTRIBUTING for a set of guidelines.
|
||||
|
||||
# Debugging
|
||||
|
||||
This section contains general instructions for debugging failed installs or problems encountered with Monero. First ensure you are running the latest version built from the github repo.
|
||||
|
||||
## Obtaining Stack Traces and Core Dumps on Unix Systems
|
||||
|
||||
We generally use the tool `gdb` (GNU debugger) to provide stack trace functionality, and `ulimit` to provide core dumps in builds which crash or segfault.
|
||||
|
||||
* To use gdb in order to obtain a stack trace for a build that has stalled:
|
||||
|
||||
Run the build.
|
||||
|
||||
Once it stalls, enter the following command:
|
||||
|
||||
```
|
||||
gdb /path/to/monerod `pidof monerod`
|
||||
```
|
||||
|
||||
Type `thread apply all bt` within gdb in order to obtain the stack trace
|
||||
|
||||
* If however the core dumps or segfaults:
|
||||
|
||||
Enter `ulimit -c unlimited` on the command line to enable unlimited filesizes for core dumps
|
||||
|
||||
Run the build.
|
||||
|
||||
When it terminates with an output along the lines of "Segmentation fault (core dumped)", there should be a core dump file in the same directory as monerod.
|
||||
|
||||
You can now analyse this core dump with `gdb` as follows:
|
||||
|
||||
`gdb /path/to/monerod /path/to/dumpfile`
|
||||
|
||||
Print the stack trace with `bt`
|
||||
|
||||
* To run monero within gdb:
|
||||
|
||||
Type `gdb /path/to/monerod`
|
||||
|
||||
Pass command-line options with `--args` followed by the relevant arguments
|
||||
|
||||
Type `run` to run monerod
|
||||
|
||||
## Analysing Memory Corruption
|
||||
|
||||
We use the tool `valgrind` for this.
|
||||
|
||||
Run with `valgrind /path/to/monerod`. It will be slow.
|
||||
|
||||
## LMDB
|
||||
|
||||
Instructions for debugging suspected blockchain corruption as per @HYC
|
||||
|
||||
143
VULNERABILITY_RESPONSE_PROCESS.md
Normal file
143
VULNERABILITY_RESPONSE_PROCESS.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Monero Vulnerability Response Process
|
||||
|
||||
## Preamble
|
||||
|
||||
Researchers/Hackers: while you research/hack, we ask that you please refrain from committing the following:
|
||||
- Denial of Service / Active exploiting against the network
|
||||
- Social Engineering of Monero staff or contractors
|
||||
- Any physical or electronic attempts against Monero community property and/or data centers
|
||||
|
||||
## I. Point of Contacts for Security Issues
|
||||
|
||||
```
|
||||
ric@getmonero.org
|
||||
BDA6 BD70 42B7 21C4 67A9 759D 7455 C5E3 C0CD CEB9
|
||||
|
||||
luigi1111@getmonero.org
|
||||
8777 AB8F 778E E894 87A2 F8E7 F4AC A018 3641 E010
|
||||
|
||||
moneromooo.monero@gmail.com
|
||||
48B0 8161 FBDA DFE3 93AD FC3E 686F 0745 4D6C EFC3
|
||||
```
|
||||
|
||||
## II. Security Response Team
|
||||
|
||||
- fluffypony
|
||||
- luigi1111
|
||||
- moneromooo
|
||||
|
||||
## III. Incident Response
|
||||
|
||||
1. Researcher submits report via one or both of two methods:
|
||||
- a. Email
|
||||
- b. [HackerOne](https://hackerone.com/monero)
|
||||
|
||||
2. Response Team designates a Response Manager who is in charge of the particular report based on availability and/or knowledge-set
|
||||
|
||||
3. In no more than 3 working days, Response Team should gratefully respond to researcher using only encrypted, secure channels
|
||||
|
||||
4. Response Manager makes inquiries to satisfy any needed information to confirm if submission is indeed a vulnerability
|
||||
- a. If submission proves to be vulnerable, proceed to next step
|
||||
- b. If not vulnerable:
|
||||
- i. Response Manager responds with reasons why submission is not a vulnerability
|
||||
- ii. Response Manager moves discussion to a new or existing ticket on GitHub if necessary
|
||||
|
||||
5. If over email, Response Manager opens a HackerOne issue for new submission
|
||||
|
||||
6. Establish severity of vulnerability:
|
||||
- a. HIGH: impacts network as a whole, has potential to break entire network, results in the loss of monero, or is on a scale of great catastrophe
|
||||
- b. MEDIUM: impacts individual nodes, wallets, or must be carefully exploited
|
||||
- c. LOW: is not easily exploitable
|
||||
|
||||
7. Respond according to the severity of the vulnerability:
|
||||
- a. HIGH severities must be notified on website and reddit /r/Monero within 3 working days of classification
|
||||
- i. The notification should list appropriate steps for users to take, if any
|
||||
- ii. The notification must not include any details that could suggest an exploitation path
|
||||
- iii. The latter takes precedence over the former
|
||||
- b. MEDIUM and HIGH severities will require a Point Release
|
||||
- c. LOW severities will be addressed in the next Regular Release
|
||||
|
||||
8. Response Team applies appropriate patch(es)
|
||||
- a. Response Manager designates a PRIVATE git "hotfix branch" to work in
|
||||
- b. Patches are reviewed with the researcher
|
||||
- c. Any messages associated with PUBLIC commits during the time of review should not make reference to the security nature of the PRIVATE branch or its commits
|
||||
- d. Vulnerability announcement is drafted
|
||||
- i. Include the severity of the vulnerability
|
||||
- ii. Include all vulnerable systems/apps/code
|
||||
- iii. Include solutions (if any) if patch cannot be applied
|
||||
- e. Release date is discussed
|
||||
|
||||
9. At release date, Response Team coordinates with developers to finalize update:
|
||||
- a. Response Manager propagates the "hotfix branch" to trunk
|
||||
- b. Response Manager includes vulnerability announcement draft in release notes
|
||||
- c. Proceed with the Point or Regular Release
|
||||
|
||||
## IV. Post-release Disclosure Process
|
||||
|
||||
1. Response Team has 90 days to fulfill all points within section III
|
||||
|
||||
2. If the Incident Response process in section III is successfully completed:
|
||||
- a. Response Manager contacts researcher and asks if researcher wishes for credit
|
||||
- b. Finalize vulnerability announcement draft and include the following:
|
||||
- i. Project name and URL
|
||||
- ii. Versions known to be affected
|
||||
- iii. Versions known to be not affected (for example, the vulnerable code was introduced in a recent version, and older versions are therefore unaffected)
|
||||
- iv. Versions not checked
|
||||
- v. Type of vulnerability and its impact
|
||||
- vi. If already obtained or applicable, a CVE-ID
|
||||
- vii. The planned, coordinated release date
|
||||
- viii. Mitigating factors (for example, the vulnerability is only exposed in uncommon, non-default configurations)
|
||||
- ix. Workarounds (configuration changes users can make to reduce their exposure to the vulnerability)
|
||||
- x. If applicable, credits to the original reporter
|
||||
- c. Release finalized vulnerability announcement on website and reddit /r/Monero
|
||||
- d. For HIGH severities, release finalized vulnerability announcement on well-known mailing lists:
|
||||
- i. oss-security@lists.openwall.com
|
||||
- ii. bugtraq@securityfocus.com
|
||||
- e. If applicable, developers request a CVE-ID
|
||||
- i. The commit that applied the fix is made reference too in a future commit and includes a CVE-ID
|
||||
|
||||
3. If the Incident Response process in section III is *not* successfully completed:
|
||||
- a. Response Team and developers organize an IRC meeting to discuss why/what points in section III were not resolved and how the team can resolve them in the future
|
||||
- b. Any developer meetings immediately following the incident should include points made in section V
|
||||
- c. If disputes arise about whether or when to disclose information about a vulnerability, the Response Team will publicly discuss the issue via IRC and attempt to reach consensus
|
||||
- d. If consensus on a timely disclosure is not met (no later than 90 days), the researcher (after 90 days) has every right to expose the vulnerability to the public
|
||||
|
||||
## V. Incident Analysis
|
||||
|
||||
1. Isolate codebase
|
||||
- a. Response Team and developers should coordinate to work on the following:
|
||||
- i. Problematic implementation of classes/libraries/functions, etc.
|
||||
- ii. Focus on apps/distro packaging, etc.
|
||||
- iii. Operator/config error, etc.
|
||||
|
||||
2. Auditing
|
||||
- a. Response Team and developers should coordinate to work on the following:
|
||||
- i. Auditing of problem area(s) as discussed in point 1
|
||||
- ii. Generate internal reports and store for future reference
|
||||
- iii. If results are not sensitive, share with the public via IRC or GitHub
|
||||
|
||||
3. Response Team has 45 days following completion of section III to ensure completion of section V
|
||||
|
||||
## VI. Resolutions
|
||||
|
||||
Any further questions or resolutions regarding the incident(s) between the researcher and response + development team after public disclosure can be addressed via the following:
|
||||
|
||||
- [GitHub](https://github.com/monero-project/monero/issues/)
|
||||
- [HackerOne](https://hackerone.com/monero)
|
||||
- [Reddit /r/Monero](https://reddit.com/r/Monero/)
|
||||
- IRC
|
||||
- Email
|
||||
|
||||
## VII. Continuous Improvement
|
||||
|
||||
1. Response Team and developers should hold annual meetings to review the previous year's incidents
|
||||
|
||||
2. Response Team or designated person(s) should give a brief presentation, including:
|
||||
- a. Areas of Monero affected by the incidents
|
||||
- b. Any network downtime or monetary cost (if any) of the incidents
|
||||
- c. Ways in which the incidents could have been avoided (if any)
|
||||
- d. How effective this process was in dealing with the incidents
|
||||
|
||||
3. After the presentation, Response Team and developers should discuss:
|
||||
- a. Potential changes to development processes to reduce future incidents
|
||||
- b. Potential changes to this process to improve future responses
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
@@ -17,6 +17,22 @@ find_path(LIBUNWIND_INCLUDE_DIR libunwind.h
|
||||
)
|
||||
|
||||
find_library(LIBUNWIND_LIBRARIES NAMES unwind )
|
||||
if(NOT LIBUNWIND_LIBRARIES STREQUAL "LIBUNWIND_LIBRARIES-NOTFOUND")
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
set(LIBUNWIND_LIBRARIES "gcc_eh;${LIBUNWIND_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# some versions of libunwind need liblzma, and we don't use pkg-config
|
||||
# so we just look whether liblzma is installed, and add it if it is.
|
||||
# It might not be actually needed, but doesn't hurt if it is not.
|
||||
# We don't need any headers, just the lib, as it's privately needed.
|
||||
message(STATUS "looking for liblzma")
|
||||
find_library(LIBLZMA_LIBRARIES lzma )
|
||||
if(NOT LIBLZMA_LIBRARIES STREQUAL "LIBLZMA_LIBRARIES-NOTFOUND")
|
||||
message(STATUS "liblzma found")
|
||||
set(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES};${LIBLZMA_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
# MINIUPNP_FOUND, if false, do not try to link to miniupnp
|
||||
# MINIUPNP_LIBRARY, the miniupnp variant
|
||||
# MINIUPNP_INCLUDE_DIR, where to find miniupnpc.h and family)
|
||||
# MINIUPNPC_VERSION_PRE1_6 --> set if we detect the version of miniupnpc is
|
||||
# pre 1.6
|
||||
# MINIUPNPC_VERSION_PRE1_5 --> set if we detect the version of miniupnpc is
|
||||
# pre 1.5
|
||||
# MINIUPNPC_VERSION_1_7_OR_HIGHER, set if we detect the version of miniupnpc is 1.7 or higher
|
||||
#
|
||||
# Note that the expected include convention is
|
||||
# #include "miniupnpc.h"
|
||||
@@ -16,170 +13,47 @@
|
||||
# This is because, the miniupnpc location is not standardized and may exist
|
||||
# in locations other than miniupnpc/
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Mark Vejvoda
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distributed this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (MINIUPNP_INCLUDE_DIR AND MINIUPNP_LIBRARY)
|
||||
# Already in cache, be silent
|
||||
set(MINIUPNP_FIND_QUIETLY TRUE)
|
||||
endif ()
|
||||
|
||||
find_path(MINIUPNP_INCLUDE_DIR miniupnpc.h
|
||||
PATH_SUFFIXES miniupnpc)
|
||||
find_library(MINIUPNP_LIBRARY miniupnpc)
|
||||
HINTS $ENV{MINIUPNP_INCLUDE_DIR}
|
||||
PATH_SUFFIXES miniupnpc
|
||||
)
|
||||
|
||||
if (MINIUPNP_INCLUDE_DIR AND MINIUPNP_LIBRARY)
|
||||
set (MINIUPNP_FOUND TRUE)
|
||||
endif ()
|
||||
find_library(MINIUPNP_LIBRARY miniupnpc
|
||||
HINTS $ENV{MINIUPNP_LIBRARY}
|
||||
)
|
||||
|
||||
if (MINIUPNP_FOUND)
|
||||
include(CheckCXXSourceRuns)
|
||||
if (NOT MINIUPNP_FIND_QUIETLY)
|
||||
message (STATUS "Found the miniupnpc libraries at ${MINIUPNP_LIBRARY}")
|
||||
message (STATUS "Found the miniupnpc headers at ${MINIUPNP_INCLUDE_DIR}")
|
||||
endif ()
|
||||
find_library(MINIUPNP_STATIC_LIBRARY libminiupnpc.a
|
||||
HINTS $ENV{MINIUPNP_STATIC_LIBRARY}
|
||||
)
|
||||
|
||||
message(STATUS "Detecting version of miniupnpc in path: ${MINIUPNP_INCLUDE_DIR}")
|
||||
set(MINIUPNP_INCLUDE_DIRS ${MINIUPNP_INCLUDE_DIR})
|
||||
set(MINIUPNP_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
set(MINIUPNP_STATIC_LIBRARIES ${MINIUPNP_STATIC_LIBRARY})
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MINIUPNP_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
check_cxx_source_runs("
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
#include <upnpcommands.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
static struct UPNPUrls urls;
|
||||
static struct IGDdatas data;
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
MiniUPnPc DEFAULT_MSG
|
||||
MINIUPNP_INCLUDE_DIR
|
||||
MINIUPNP_LIBRARY
|
||||
)
|
||||
|
||||
GetUPNPUrls (&urls, &data, \"myurl\",0);
|
||||
|
||||
return 0;
|
||||
}"
|
||||
MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
|
||||
IF (NOT MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MINIUPNP_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
check_cxx_source_runs("
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
#include <upnpcommands.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
struct UPNPDev *devlist = NULL;
|
||||
int upnp_delay = 5000;
|
||||
const char *upnp_multicastif = NULL;
|
||||
const char *upnp_minissdpdsock = NULL;
|
||||
int upnp_sameport = 0;
|
||||
int upnp_ipv6 = 0;
|
||||
int upnp_error = 0;
|
||||
devlist = upnpDiscover(upnp_delay, upnp_multicastif, upnp_minissdpdsock, upnp_sameport, upnp_ipv6, &upnp_error);
|
||||
|
||||
return 0;
|
||||
}"
|
||||
MINIUPNPC_VERSION_PRE1_7)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT MINIUPNPC_VERSION_PRE1_7 AND NOT MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MINIUPNP_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
check_cxx_source_runs("
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
#include <upnpcommands.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
struct UPNPDev *devlist = NULL;
|
||||
int upnp_delay = 5000;
|
||||
const char *upnp_multicastif = NULL;
|
||||
const char *upnp_minissdpdsock = NULL;
|
||||
int upnp_sameport = 0;
|
||||
int upnp_ipv6 = 0;
|
||||
int upnp_error = 0;
|
||||
devlist = upnpDiscover(upnp_delay, upnp_multicastif, upnp_minissdpdsock, upnp_sameport);
|
||||
|
||||
return 0;
|
||||
}"
|
||||
MINIUPNPC_VERSION_PRE1_6)
|
||||
|
||||
ENDIF()
|
||||
|
||||
IF (NOT MINIUPNPC_VERSION_PRE1_6 AND NOT MINIUPNPC_VERSION_PRE1_7 AND NOT MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MINIUPNP_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
check_cxx_source_runs("
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
#include <upnpcommands.h>
|
||||
#include <stdio.h>
|
||||
static struct UPNPUrls urls;
|
||||
static struct IGDdatas data;
|
||||
int main()
|
||||
{
|
||||
char externalIP[16] = \"\";
|
||||
UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIP);
|
||||
|
||||
return 0;
|
||||
}"
|
||||
MINIUPNPC_VERSION_1_5_OR_HIGHER)
|
||||
ENDIF()
|
||||
|
||||
IF (NOT MINIUPNPC_VERSION_1_5_OR_HIGHER AND NOT MINIUPNPC_VERSION_PRE1_6 AND NOT MINIUPNPC_VERSION_PRE1_7 AND NOT MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MINIUPNP_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MINIUPNP_LIBRARY})
|
||||
check_cxx_source_runs("
|
||||
#include <miniwget.h>
|
||||
#include <miniupnpc.h>
|
||||
#include <upnpcommands.h>
|
||||
#include <stdio.h>
|
||||
static struct UPNPUrls urls;
|
||||
static struct IGDdatas data;
|
||||
int main()
|
||||
{
|
||||
char externalIP[16] = \"\";
|
||||
UPNP_GetExternalIPAddress(urls.controlURL, data.servicetype, externalIP);
|
||||
|
||||
return 0;
|
||||
}"
|
||||
MINIUPNPC_VERSION_PRE1_5)
|
||||
IF(MINIUPNPC_FOUND)
|
||||
file(STRINGS "${MINIUPNP_INCLUDE_DIR}/miniupnpc.h" MINIUPNPC_API_VERSION_STR REGEX "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+[0-9]+")
|
||||
if(MINIUPNPC_API_VERSION_STR MATCHES "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+([0-9]+)")
|
||||
set(MINIUPNPC_API_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
|
||||
if (${MINIUPNPC_API_VERSION} GREATER "10" OR ${MINIUPNPC_API_VERSION} EQUAL "10")
|
||||
message(STATUS "Found miniupnpc API version " ${MINIUPNPC_API_VERSION})
|
||||
set(MINIUPNP_FOUND true)
|
||||
set(MINIUPNPC_VERSION_1_7_OR_HIGHER true)
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
IF(MINIUPNPC_VERSION_PRE1_5)
|
||||
message(STATUS "Found miniupnpc version is pre v1.5")
|
||||
ENDIF()
|
||||
IF(MINIUPNPC_VERSION_PRE1_6)
|
||||
message(STATUS "Found miniupnpc version is pre v1.6")
|
||||
ENDIF()
|
||||
IF(MINIUPNPC_VERSION_PRE1_7)
|
||||
message(STATUS "Found miniupnpc version is pre v1.7")
|
||||
ENDIF()
|
||||
|
||||
IF(NOT MINIUPNPC_VERSION_PRE1_5 AND NOT MINIUPNPC_VERSION_PRE1_6 AND NOT MINIUPNPC_VERSION_PRE1_7)
|
||||
IF(MINIUPNPC_VERSION_1_5_OR_HIGHER)
|
||||
message(STATUS "Found miniupnpc version is v1.5 or higher")
|
||||
ELSE()
|
||||
message(STATUS "Found miniupnpc version is v1.7 or higher")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
else ()
|
||||
message (STATUS "Could not find miniupnp")
|
||||
endif ()
|
||||
|
||||
MARK_AS_ADVANCED(MINIUPNP_INCLUDE_DIR MINIUPNP_LIBRARY)
|
||||
mark_as_advanced(MINIUPNP_INCLUDE_DIR MINIUPNP_LIBRARY MINIUPNP_STATIC_LIBRARY)
|
||||
# --------------------------------- FindMiniupnpc End ---------------------------------
|
||||
|
||||
66
cmake/FindReadline.cmake
Normal file
66
cmake/FindReadline.cmake
Normal file
@@ -0,0 +1,66 @@
|
||||
# - Try to find readline include dirs and libraries
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(Readline)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# Readline_ROOT_DIR Set this variable to the root installation of
|
||||
# readline if the module has problems finding the
|
||||
# proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# READLINE_FOUND System has readline, include and lib dirs found
|
||||
# GNU_READLINE_FOUND Version of readline found is GNU readline, not libedit!
|
||||
# Readline_INCLUDE_DIR The readline include directories.
|
||||
# Readline_LIBRARY The readline library.
|
||||
|
||||
find_path(Readline_ROOT_DIR
|
||||
NAMES include/readline/readline.h
|
||||
PATHS /opt/local/ /usr/local/ /usr/
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
find_path(Readline_INCLUDE_DIR
|
||||
NAMES readline/readline.h
|
||||
PATHS ${Readline_ROOT_DIR}/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
find_library(Readline_LIBRARY
|
||||
NAMES readline
|
||||
PATHS ${Readline_ROOT_DIR}/lib
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
set(READLINE_FOUND TRUE)
|
||||
else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
FIND_LIBRARY(Readline_LIBRARY NAMES readline PATHS Readline_ROOT_DIR)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
|
||||
MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY)
|
||||
endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
|
||||
|
||||
mark_as_advanced(
|
||||
Readline_ROOT_DIR
|
||||
Readline_INCLUDE_DIR
|
||||
Readline_LIBRARY
|
||||
)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${Readline_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY})
|
||||
INCLUDE(CheckCXXSourceCompiles)
|
||||
CHECK_CXX_SOURCE_COMPILES(
|
||||
"
|
||||
#include <stdio.h>
|
||||
#include <readline/readline.h>
|
||||
int
|
||||
main()
|
||||
{
|
||||
char * s = rl_copy_text(0, 0);
|
||||
}
|
||||
" GNU_READLINE_FOUND)
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
// Copyright (c) 2014-2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
34
cmake/test-static-assert.cpp
Normal file
34
cmake/test-static-assert.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2014-2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static_assert(1, "FAIL");
|
||||
int main(int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -26,5 +26,5 @@
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
add_subdirectory(otshell_utils)
|
||||
add_subdirectory(epee)
|
||||
|
||||
|
||||
30
contrib/epee/CMakeLists.txt
Normal file
30
contrib/epee/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
# permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
# conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
# of conditions and the following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "console_handler.h"
|
||||
#include "demo_http_server.h"
|
||||
#include "net/http_client.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
|
||||
|
||||
template<class t_request, class t_response>
|
||||
bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false)
|
||||
{
|
||||
epee::net_utils::http::http_simple_client http_client;
|
||||
bool r = http_client.connect(ip, port, 1000);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to connect");
|
||||
if(use_json)
|
||||
{
|
||||
if(use_jrpc)
|
||||
{
|
||||
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
|
||||
req_t.jsonrpc = "2.0";
|
||||
req_t.id = epee::serialization::storage_entry(10);
|
||||
req_t.method = "command_example_1";
|
||||
req_t.params = req;
|
||||
epee::json_rpc::response<t_response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
|
||||
if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rsp = resp_t.result;
|
||||
return true;
|
||||
}else
|
||||
return epee::net_utils::invoke_http_json_remote_command2(url, req, rsp, http_client);
|
||||
}
|
||||
else
|
||||
return epee::net_utils::invoke_http_bin_remote_command2(url, req, rsp, http_client);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
//set up logging options
|
||||
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
log_space::log_singletone::add_logger(LOGGER_FILE,
|
||||
log_space::log_singletone::get_default_log_file().c_str(),
|
||||
log_space::log_singletone::get_default_log_folder().c_str());
|
||||
|
||||
|
||||
|
||||
LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
|
||||
|
||||
|
||||
demo::demo_http_server srv;
|
||||
|
||||
start_default_console(&srv, "#");
|
||||
|
||||
std::string bind_param = "0.0.0.0";
|
||||
std::string port = "83";
|
||||
|
||||
if(!srv.init(port, bind_param))
|
||||
{
|
||||
LOG_ERROR("Failed to initialize srv!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//log loop
|
||||
srv.run();
|
||||
size_t count = 0;
|
||||
while (!srv.is_stop())
|
||||
{
|
||||
|
||||
demo::COMMAND_EXAMPLE_1::request req;
|
||||
req.sub = demo::get_test_data();
|
||||
demo::COMMAND_EXAMPLE_1::response rsp;
|
||||
bool r = false;
|
||||
if(count%2)
|
||||
{//invoke json
|
||||
r = communicate("/request_api_json_1", req, rsp, "127.0.0.1", port, true, true);
|
||||
}else{
|
||||
r = communicate("/request_api_bin_1", req, rsp, "127.0.0.1", port, false);
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to invoke http request");
|
||||
CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
|
||||
//misc_utils::sleep_no_w(1000);
|
||||
++count;
|
||||
}
|
||||
bool r = srv.wait_stop();
|
||||
CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
|
||||
srv.deinit();
|
||||
|
||||
LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
|
||||
return 1;
|
||||
|
||||
CATCH_ENTRY_L0("main", 1);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
namespace demo
|
||||
{
|
||||
bool demo_http_server::init(const std::string& bind_port, const std::string& bind_ip)
|
||||
{
|
||||
|
||||
|
||||
//set self as callback handler
|
||||
m_net_server.get_config_object().m_phandler = this;
|
||||
|
||||
//here set folder for hosting reqests
|
||||
m_net_server.get_config_object().m_folder = "";
|
||||
|
||||
LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
|
||||
return m_net_server.init_server(bind_port, bind_ip);
|
||||
}
|
||||
|
||||
bool demo_http_server::run()
|
||||
{
|
||||
m_stop = false;
|
||||
//here you can set worker threads count
|
||||
int thrds_count = 4;
|
||||
|
||||
//go to loop
|
||||
LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
|
||||
if(!m_net_server.run_server(thrds_count, false))
|
||||
{
|
||||
LOG_ERROR("Failed to run net tcp server!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_http_server::deinit()
|
||||
{
|
||||
return m_net_server.deinit_server();
|
||||
}
|
||||
|
||||
bool demo_http_server::send_stop_signal()
|
||||
{
|
||||
m_stop = true;
|
||||
m_net_server.send_stop_signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_http_server::on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool demo_http_server::on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool demo_http_server::on_hosting_request( const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context)
|
||||
{
|
||||
//read file from filesystem here
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_http_server::on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(req.sub == demo::get_test_data(), false, "wrong request");
|
||||
res.m_success = true;
|
||||
res.subs.push_back(req.sub);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_http_server::on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt)
|
||||
{
|
||||
error_resp.code = 232432;
|
||||
error_resp.message = "bla bla bla";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool demo_http_server::on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "net/http_server_cp2.h"
|
||||
#include "transport_defs.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace demo
|
||||
{
|
||||
|
||||
class demo_http_server: public net_utils::http::i_http_server_handler<epee::net_utils::connection_context_base>
|
||||
{
|
||||
public:
|
||||
typedef epee::net_utils::connection_context_base connection_context;
|
||||
|
||||
demo_http_server():m_stop(false){}
|
||||
bool run();
|
||||
bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
|
||||
bool deinit();
|
||||
bool send_stop_signal();
|
||||
bool is_stop(){return m_stop;}
|
||||
bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
|
||||
private:
|
||||
|
||||
|
||||
CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
|
||||
|
||||
BEGIN_URI_MAP2()
|
||||
MAP_URI2("/requestr_uri_1", on_requestr_uri_1)
|
||||
MAP_URI2("/requestr_uri_2", on_requestr_uri_1)
|
||||
//MAP_URI_AUTO_XML2("/request_api_xml_1", on_request_api_1, COMMAND_EXAMPLE_1)
|
||||
//MAP_URI_AUTO_XML2("/request_api_xml_2", on_request_api_2, COMMAND_EXAMPLE_2)
|
||||
MAP_URI_AUTO_JON2("/request_api_json_1", on_request_api_1, COMMAND_EXAMPLE_1)
|
||||
MAP_URI_AUTO_JON2("/request_api_json_2", on_request_api_2, COMMAND_EXAMPLE_2)
|
||||
MAP_URI_AUTO_BIN2("/request_api_bin_1", on_request_api_1, COMMAND_EXAMPLE_1)
|
||||
MAP_URI_AUTO_BIN2("/request_api_bin_2", on_request_api_2, COMMAND_EXAMPLE_2)
|
||||
BEGIN_JSON_RPC_MAP("/request_json_rpc")
|
||||
MAP_JON_RPC("command_example_1", on_request_api_1, COMMAND_EXAMPLE_1)
|
||||
MAP_JON_RPC("command_example_2", on_request_api_2, COMMAND_EXAMPLE_2)
|
||||
MAP_JON_RPC_WE("command_example_1_we", on_request_api_1_with_error, COMMAND_EXAMPLE_1)
|
||||
END_JSON_RPC_MAP()
|
||||
CHAIN_URI_MAP2(on_hosting_request)
|
||||
END_URI_MAP2()
|
||||
|
||||
|
||||
|
||||
bool on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context);
|
||||
|
||||
|
||||
bool on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context);
|
||||
|
||||
|
||||
|
||||
|
||||
bool on_hosting_request( const net_utils::http::http_request_info& query_info,
|
||||
net_utils::http::http_response_info& response,
|
||||
const net_utils::connection_context_base& m_conn_context);
|
||||
|
||||
bool on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt);
|
||||
bool on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt);
|
||||
|
||||
bool on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt);
|
||||
|
||||
net_utils::boosted_http_server_custum_handling m_net_server;
|
||||
std::atomic<bool> m_stop;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "demo_levin_server.h"
|
||||
#include "console_handler.h"
|
||||
|
||||
|
||||
template<class t_request>
|
||||
bool communicate(net_utils::boosted_levin_async_server& transport, int id, t_request& req, const std::string& ip, const std::string& port, bool use_async)
|
||||
{
|
||||
if(use_async)
|
||||
{
|
||||
//IMPORTANT: do not pass local parameters from stack by reference! connect_async returns immediately, and callback will call in any thread later
|
||||
transport.connect_async(ip, port, 10000, [&transport, id, req, ip, port](net_utils::connection_context_base& ctx, const boost::system::error_code& ec_)
|
||||
{
|
||||
if(!!ec_)
|
||||
{
|
||||
LOG_ERROR("Failed to connect to " << ip << ":" << port);
|
||||
}else
|
||||
{//connected ok!
|
||||
|
||||
epee::net_utils::async_invoke_remote_command2<demo::COMMAND_EXAMPLE_1::response>(ctx.m_connection_id, id, req, transport.get_config_object(), [&transport, ip, port](int res_code, demo::COMMAND_EXAMPLE_1::response& rsp, net_utils::connection_context_base& ctx)
|
||||
{
|
||||
if(res_code < 0)
|
||||
{
|
||||
LOG_ERROR("Failed to invoke to " << ip << ":" << port);
|
||||
}else
|
||||
{//invoked ok
|
||||
CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoked ok", LOG_LEVEL_0);
|
||||
}
|
||||
transport.get_config_object().close(ctx.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoke requested", LOG_LEVEL_0);
|
||||
}
|
||||
});
|
||||
}else
|
||||
{
|
||||
net_utils::connection_context_base ctx = AUTO_VAL_INIT(ctx);
|
||||
bool r = transport.connect(ip, port, 10000, ctx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to connect to " << ip << ":" << port);
|
||||
demo::COMMAND_EXAMPLE_1::response rsp = AUTO_VAL_INIT(rsp);
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoke requested", LOG_LEVEL_0);
|
||||
r = epee::net_utils::invoke_remote_command2(ctx.m_connection_id, id, req, rsp, transport.get_config_object());
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to invoke levin request");
|
||||
CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
|
||||
transport.get_config_object().close(ctx.m_connection_id);
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoked ok", LOG_LEVEL_0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
//set up logging options
|
||||
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
log_space::log_singletone::add_logger(LOGGER_FILE,
|
||||
log_space::log_singletone::get_default_log_file().c_str(),
|
||||
log_space::log_singletone::get_default_log_folder().c_str());
|
||||
|
||||
|
||||
|
||||
LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
|
||||
|
||||
|
||||
demo::demo_levin_server srv;
|
||||
|
||||
start_default_console(&srv, "#");
|
||||
|
||||
std::string bind_param = "0.0.0.0";
|
||||
std::string port = "12345";
|
||||
|
||||
if(!srv.init(port, bind_param))
|
||||
{
|
||||
LOG_ERROR("Failed to initialize srv!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
srv.run();
|
||||
|
||||
size_t c = 1;
|
||||
while (!srv.is_stop())
|
||||
{
|
||||
|
||||
demo::COMMAND_EXAMPLE_1::request req;
|
||||
req.sub = demo::get_test_data();
|
||||
bool r = communicate(srv.get_server(), demo::COMMAND_EXAMPLE_1::ID, req, "127.0.0.1", port, (c%2 == 0));
|
||||
misc_utils::sleep_no_w(1000);
|
||||
++c;
|
||||
}
|
||||
bool r = srv.wait_stop();
|
||||
CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
|
||||
|
||||
|
||||
srv.deinit();
|
||||
|
||||
LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
|
||||
return 1;
|
||||
|
||||
CATCH_ENTRY_L0("main", 1);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
namespace demo
|
||||
{
|
||||
bool demo_levin_server::init(const std::string& bind_port, const std::string& bind_ip)
|
||||
{
|
||||
m_net_server.get_config_object().m_pcommands_handler = this;
|
||||
LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
|
||||
return m_net_server.init_server(bind_port, bind_ip);
|
||||
}
|
||||
|
||||
bool demo_levin_server::run()
|
||||
{
|
||||
m_stop = false;
|
||||
//here you can set worker threads count
|
||||
int thrds_count = 4;
|
||||
m_net_server.get_config_object().m_invoke_timeout = 10000;
|
||||
m_net_server.get_config_object().m_pcommands_handler = this;
|
||||
|
||||
//go to loop
|
||||
LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
|
||||
if(!m_net_server.run_server(thrds_count, false))
|
||||
{
|
||||
LOG_ERROR("Failed to run net tcp server!");
|
||||
}
|
||||
|
||||
LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_levin_server::deinit()
|
||||
{
|
||||
return m_net_server.deinit_server();
|
||||
}
|
||||
|
||||
bool demo_levin_server::send_stop_signal()
|
||||
{
|
||||
m_net_server.send_stop_signal();
|
||||
return true;
|
||||
}
|
||||
int demo_levin_server::handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(arg.sub == demo::get_test_data(), false, "wrong request");
|
||||
rsp.m_success = true;
|
||||
rsp.subs.push_back(arg.sub);
|
||||
LOG_PRINT_GREEN("Server COMMAND_EXAMPLE_1 ok", LOG_LEVEL_0);
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "net/levin_server_cp2.h"
|
||||
#include "transport_defs.h"
|
||||
#include "storages/levin_abstract_invoke2.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace demo
|
||||
{
|
||||
|
||||
class demo_levin_server: public levin::levin_commands_handler<>
|
||||
{
|
||||
public:
|
||||
bool run();
|
||||
bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
|
||||
bool deinit();
|
||||
bool send_stop_signal();
|
||||
bool is_stop(){return m_stop;}
|
||||
bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
|
||||
net_utils::boosted_levin_async_server& get_server(){return m_net_server;}
|
||||
private:
|
||||
|
||||
|
||||
CHAIN_LEVIN_INVOKE_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map
|
||||
CHAIN_LEVIN_NOTIFY_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing
|
||||
|
||||
BEGIN_INVOKE_MAP2(demo_levin_server)
|
||||
HANDLE_INVOKE_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_command_1)
|
||||
HANDLE_INVOKE_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_command_2)
|
||||
HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_notify_1)
|
||||
HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_notify_2)
|
||||
END_INVOKE_MAP2()
|
||||
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
int handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context);
|
||||
int handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context);
|
||||
int handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context);
|
||||
int handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context);
|
||||
//----------------------------------------------------------------------------------
|
||||
net_utils::boosted_levin_async_server m_net_server;
|
||||
std::atomic<bool> m_stop;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
#endif
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
#include "readline_buffer.h"
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class async_stdin_reader
|
||||
@@ -48,6 +52,9 @@ namespace epee
|
||||
, m_has_read_request(false)
|
||||
, m_read_status(state_init)
|
||||
{
|
||||
#ifdef HAVE_READLINE
|
||||
m_readline_buffer.start();
|
||||
#endif
|
||||
m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
|
||||
}
|
||||
|
||||
@@ -56,6 +63,13 @@ namespace epee
|
||||
stop();
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
rdln::readline_buffer& get_readline_buffer()
|
||||
{
|
||||
return m_readline_buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Not thread safe. Only one thread can call this method at once.
|
||||
bool get_line(std::string& line)
|
||||
{
|
||||
@@ -98,6 +112,9 @@ namespace epee
|
||||
|
||||
m_request_cv.notify_one();
|
||||
m_reader_thread.join();
|
||||
#ifdef HAVE_READLINE
|
||||
m_readline_buffer.stop();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +150,7 @@ namespace epee
|
||||
bool wait_stdin_data()
|
||||
{
|
||||
#if !defined(WIN32)
|
||||
#ifdef __OpenBSD__
|
||||
#if defined(__OpenBSD__) || defined(__ANDROID__)
|
||||
int stdin_fileno = fileno(stdin);
|
||||
#else
|
||||
int stdin_fileno = ::fileno(stdin);
|
||||
@@ -183,11 +200,23 @@ namespace epee
|
||||
|
||||
std::string line;
|
||||
bool read_ok = true;
|
||||
#ifdef HAVE_READLINE
|
||||
reread:
|
||||
#endif
|
||||
if (wait_stdin_data())
|
||||
{
|
||||
if (m_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
#ifdef HAVE_READLINE
|
||||
switch (m_readline_buffer.get_line(line))
|
||||
{
|
||||
case rdln::empty: goto eof;
|
||||
case rdln::partial: goto reread;
|
||||
case rdln::full: break;
|
||||
}
|
||||
#else
|
||||
std::getline(std::cin, line);
|
||||
#endif
|
||||
read_ok = !std::cin.eof() && !std::cin.fail();
|
||||
}
|
||||
}
|
||||
@@ -196,6 +225,9 @@ namespace epee
|
||||
read_ok = false;
|
||||
}
|
||||
if (std::cin.eof()) {
|
||||
#ifdef HAVE_READLINE
|
||||
eof:
|
||||
#endif
|
||||
m_read_status = state_eos;
|
||||
m_response_cv.notify_one();
|
||||
break;
|
||||
@@ -229,6 +261,9 @@ namespace epee
|
||||
private:
|
||||
boost::thread m_reader_thread;
|
||||
std::atomic<bool> m_run;
|
||||
#ifdef HAVE_READLINE
|
||||
rdln::readline_buffer m_readline_buffer;
|
||||
#endif
|
||||
|
||||
std::string m_line;
|
||||
bool m_has_read_request;
|
||||
@@ -256,13 +291,13 @@ namespace epee
|
||||
}
|
||||
|
||||
template<class t_server, class chain_handler>
|
||||
bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
|
||||
bool run(t_server* psrv, chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "")
|
||||
{
|
||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
|
||||
}
|
||||
|
||||
template<class chain_handler>
|
||||
bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
|
||||
bool run(chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
|
||||
{
|
||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, exit_handler);
|
||||
}
|
||||
@@ -275,20 +310,29 @@ namespace epee
|
||||
|
||||
void print_prompt()
|
||||
{
|
||||
if (!m_prompt.empty())
|
||||
std::string prompt = m_prompt();
|
||||
if (!prompt.empty())
|
||||
{
|
||||
epee::log_space::set_console_color(epee::log_space::console_color_yellow, true);
|
||||
std::cout << m_prompt;
|
||||
if (' ' != m_prompt.back())
|
||||
#ifdef HAVE_READLINE
|
||||
std::string color_prompt = "\001\033[1;33m\002" + prompt;
|
||||
if (' ' != prompt.back())
|
||||
color_prompt += " ";
|
||||
color_prompt += "\001\033[0m\002";
|
||||
m_stdin_reader.get_readline_buffer().set_prompt(color_prompt);
|
||||
#else
|
||||
epee::set_console_color(epee::console_color_yellow, true);
|
||||
std::cout << prompt;
|
||||
if (' ' != prompt.back())
|
||||
std::cout << ' ';
|
||||
epee::log_space::reset_console_color();
|
||||
epee::reset_console_color();
|
||||
std::cout.flush();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename t_cmd_handler>
|
||||
bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
|
||||
bool run(std::function<std::string(void)> prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
|
||||
{
|
||||
bool continue_handle = true;
|
||||
m_prompt = prompt;
|
||||
@@ -310,7 +354,7 @@ namespace epee
|
||||
}
|
||||
if (!get_line_ret)
|
||||
{
|
||||
LOG_PRINT("Failed to read line.", LOG_LEVEL_0);
|
||||
MERROR("Failed to read line.");
|
||||
}
|
||||
string_tools::trim(command);
|
||||
|
||||
@@ -329,6 +373,9 @@ namespace epee
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_READLINE
|
||||
rdln::suspend_readline pause_readline;
|
||||
#endif
|
||||
std::cout << "unknown command: " << command << std::endl;
|
||||
std::cout << usage;
|
||||
}
|
||||
@@ -346,7 +393,7 @@ namespace epee
|
||||
private:
|
||||
async_stdin_reader m_stdin_reader;
|
||||
std::atomic<bool> m_running = {true};
|
||||
std::string m_prompt;
|
||||
std::function<std::string(void)> m_prompt;
|
||||
};
|
||||
|
||||
|
||||
@@ -432,6 +479,9 @@ namespace epee
|
||||
lookup::mapped_type & vt = m_command_handlers[cmd];
|
||||
vt.first = hndlr;
|
||||
vt.second = usage;
|
||||
#ifdef HAVE_READLINE
|
||||
rdln::readline_buffer::add_completion(cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool process_command_vec(const std::vector<std::string>& cmd)
|
||||
@@ -465,19 +515,23 @@ namespace epee
|
||||
std::unique_ptr<boost::thread> m_console_thread;
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
bool start_handling(const std::string& prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
|
||||
bool start_handling(std::function<std::string(void)> prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
|
||||
{
|
||||
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string, exit_handler)));
|
||||
m_console_thread->detach();
|
||||
return true;
|
||||
}
|
||||
bool start_handling(const std::string &prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
|
||||
{
|
||||
return start_handling([prompt](){ return prompt; }, usage_string, exit_handler);
|
||||
}
|
||||
|
||||
void stop_handling()
|
||||
{
|
||||
m_console_handler.stop();
|
||||
}
|
||||
|
||||
bool run_handling(const std::string& prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
|
||||
bool run_handling(std::function<std::string(void)> prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
|
||||
{
|
||||
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string, exit_handler);
|
||||
}
|
||||
|
||||
@@ -28,197 +28,13 @@
|
||||
#ifndef _FILE_IO_UTILS_H_
|
||||
#define _FILE_IO_UTILS_H_
|
||||
|
||||
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
||||
#ifndef MAKE64
|
||||
#define MAKE64(low,high) ((__int64)(((DWORD)(low)) | ((__int64)((DWORD)(high))) << 32))
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
#include <psapi.h>
|
||||
#include <strsafe.h>
|
||||
#include <string.h>
|
||||
#include <mbstring.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace file_io_utils
|
||||
{
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
|
||||
inline
|
||||
std::string get_temp_file_name_a()
|
||||
{
|
||||
std::string str_result;
|
||||
char sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
|
||||
return str_result;
|
||||
|
||||
char sz_temp_file[MAX_PATH*2] = {0};
|
||||
if(!::GetTempFileNameA( sz_temp, "mail", 0, sz_temp_file))
|
||||
return str_result;
|
||||
sz_temp_file[sizeof(sz_temp_file)-1] = 0; //be happy!
|
||||
str_result = sz_temp_file;
|
||||
return str_result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_LEXICAL_CAST_INCLUDED
|
||||
inline
|
||||
bool get_not_used_filename(const std::string& folder, OUT std::string& result_name)
|
||||
{
|
||||
DWORD folder_attr = ::GetFileAttributesA(folder.c_str());
|
||||
if(folder_attr == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
if(!(folder_attr&FILE_ATTRIBUTE_DIRECTORY))
|
||||
return false;
|
||||
|
||||
|
||||
std::string base_name = folder + "\\tmp";
|
||||
std::string tmp_name;
|
||||
bool name_found = false;
|
||||
int current_index = 0;
|
||||
tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
|
||||
while(!name_found)
|
||||
{
|
||||
if(INVALID_FILE_ATTRIBUTES == ::GetFileAttributesA(tmp_name.c_str()))
|
||||
name_found = true;
|
||||
else
|
||||
{
|
||||
current_index++;
|
||||
tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
|
||||
}
|
||||
}
|
||||
result_name = tmp_name;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline
|
||||
std::string get_temp_folder_a()
|
||||
{
|
||||
std::string str_result;
|
||||
char sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
|
||||
return str_result;
|
||||
sz_temp[(sizeof(sz_temp)/sizeof(sz_temp[0])) -1] = 0;
|
||||
str_result = sz_temp;
|
||||
return str_result;
|
||||
}
|
||||
|
||||
std::string convert_from_device_path_to_standart(const std::string& path)
|
||||
{
|
||||
|
||||
|
||||
STRSAFE_LPSTR pszFilename = (STRSAFE_LPSTR)path.c_str();
|
||||
|
||||
// Translate path with device name to drive letters.
|
||||
char szTemp[4000] = {0};
|
||||
|
||||
if (::GetLogicalDriveStringsA(sizeof(szTemp)-1, szTemp))
|
||||
{
|
||||
char szName[MAX_PATH];
|
||||
char szDrive[3] = " :";
|
||||
BOOL bFound = FALSE;
|
||||
char* p = szTemp;
|
||||
|
||||
do
|
||||
{
|
||||
// Copy the drive letter to the template string
|
||||
*szDrive = *p;
|
||||
|
||||
// Look up each device name
|
||||
if (::QueryDosDeviceA(szDrive, szName, sizeof(szName)))
|
||||
{
|
||||
UINT uNameLen = strlen(szName);
|
||||
|
||||
if (uNameLen < MAX_PATH)
|
||||
{
|
||||
bFound = _mbsnbicmp((const unsigned char*)pszFilename, (const unsigned char*)szName,
|
||||
uNameLen) == 0;
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
// Reconstruct pszFilename using szTempFile
|
||||
// Replace device path with DOS path
|
||||
char szTempFile[MAX_PATH] = {0};
|
||||
StringCchPrintfA(szTempFile,
|
||||
MAX_PATH,
|
||||
"%s%s",
|
||||
szDrive,
|
||||
pszFilename+uNameLen);
|
||||
return szTempFile;
|
||||
//::StringCchCopyNA(pszFilename, MAX_PATH+1, szTempFile, strlen(szTempFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the next NULL character.
|
||||
while (*p++);
|
||||
} while (!bFound && *p); // end of string
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
inline
|
||||
std::string get_process_path_by_pid(DWORD pid)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
HANDLE hprocess = 0;
|
||||
if( hprocess = ::OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pid) )
|
||||
{
|
||||
char buff[MAX_PATH]= {0};
|
||||
if(!::GetModuleFileNameExA( hprocess, 0, buff, MAX_PATH - 1 ))
|
||||
res = "Unknown_b";
|
||||
else
|
||||
{
|
||||
buff[MAX_PATH - 1]=0; //be happy!
|
||||
res = buff;
|
||||
std::string::size_type a = res.rfind( '\\' );
|
||||
if ( a != std::string::npos )
|
||||
res.erase( 0, a+1);
|
||||
|
||||
}
|
||||
::CloseHandle( hprocess );
|
||||
}else
|
||||
res = "Unknown_a";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
std::wstring get_temp_file_name_w()
|
||||
{
|
||||
std::wstring str_result;
|
||||
wchar_t sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathW( sizeof(sz_temp)/sizeof(sz_temp[0]), sz_temp ))
|
||||
return str_result;
|
||||
|
||||
wchar_t sz_temp_file[MAX_PATH+1] = {0};
|
||||
if(!::GetTempFileNameW( sz_temp, L"mail", 0, sz_temp_file))
|
||||
return str_result;
|
||||
|
||||
sz_temp_file[(sizeof(sz_temp_file)/sizeof(sz_temp_file[0]))-1] = 0; //be happy!
|
||||
str_result = sz_temp_file;
|
||||
return str_result;
|
||||
}
|
||||
#endif
|
||||
inline
|
||||
bool is_file_exist(const std::string& path)
|
||||
{
|
||||
@@ -226,35 +42,6 @@ namespace file_io_utils
|
||||
return boost::filesystem::exists(p);
|
||||
}
|
||||
|
||||
/*
|
||||
inline
|
||||
bool save_string_to_handle(HANDLE hfile, const std::string& str)
|
||||
{
|
||||
|
||||
|
||||
|
||||
if( INVALID_HANDLE_VALUE != hfile )
|
||||
{
|
||||
DWORD dw;
|
||||
if( !::WriteFile( hfile, str.data(), (DWORD) str.size(), &dw, NULL) )
|
||||
{
|
||||
int err_code = GetLastError();
|
||||
//LOG_PRINT("Failed to write to file handle: " << hfile<< " Last error code:" << err_code << " : " << log_space::get_win32_err_descr(err_code), LOG_LEVEL_2);
|
||||
return false;
|
||||
}
|
||||
::CloseHandle(hfile);
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
//LOG_WIN32_ERROR(::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
inline
|
||||
bool save_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||
{
|
||||
@@ -275,32 +62,6 @@ namespace file_io_utils
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
inline
|
||||
bool load_form_handle(HANDLE hfile, std::string& str)
|
||||
{
|
||||
if( INVALID_HANDLE_VALUE != hfile )
|
||||
{
|
||||
bool res = true;
|
||||
DWORD dw = 0;
|
||||
DWORD fsize = ::GetFileSize(hfile, &dw);
|
||||
if(fsize > 300000000)
|
||||
{
|
||||
::CloseHandle(hfile);
|
||||
return false;
|
||||
}
|
||||
if(fsize)
|
||||
{
|
||||
str.resize(fsize);
|
||||
if(!::ReadFile( hfile, (LPVOID)str.data(), (DWORD)str.size(), &dw, NULL))
|
||||
res = false;
|
||||
}
|
||||
::CloseHandle(hfile);
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
inline
|
||||
bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
|
||||
{
|
||||
@@ -371,84 +132,6 @@ namespace file_io_utils
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool remove_dir_and_subirs(const char* path_to_dir);
|
||||
|
||||
inline
|
||||
bool clean_dir(const char* path_to_dir)
|
||||
{
|
||||
if(!path_to_dir)
|
||||
return false;
|
||||
|
||||
std::string folder = path_to_dir;
|
||||
WIN32_FIND_DATAA find_data = {0};
|
||||
HANDLE hfind = ::FindFirstFileA((folder + "\\*.*").c_str(), &find_data);
|
||||
if(INVALID_HANDLE_VALUE == hfind)
|
||||
return false;
|
||||
do{
|
||||
if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
|
||||
continue;
|
||||
|
||||
if(find_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if(!remove_dir_and_subirs((folder + "\\" + find_data.cFileName).c_str()))
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
if(!::DeleteFileA((folder + "\\" + find_data.cFileName).c_str()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}while(::FindNextFileA(hfind, &find_data));
|
||||
::FindClose(hfind);
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline bool get_folder_content(const std::string& path, std::list<WIN32_FIND_DATAA>& OUT target_list)
|
||||
{
|
||||
WIN32_FIND_DATAA find_data = {0};
|
||||
HANDLE hfind = ::FindFirstFileA((path + "\\*.*").c_str(), &find_data);
|
||||
if(INVALID_HANDLE_VALUE == hfind)
|
||||
return false;
|
||||
do{
|
||||
if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
|
||||
continue;
|
||||
|
||||
target_list.push_back(find_data);
|
||||
|
||||
}while(::FindNextFileA(hfind, &find_data));
|
||||
::FindClose(hfind);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
inline bool get_folder_content(const std::string& path, std::list<std::string>& OUT target_list, bool only_files = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( boost::filesystem::directory_iterator itr( path ); itr != end_itr; ++itr )
|
||||
{
|
||||
if ( only_files && boost::filesystem::is_directory(itr->status()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
target_list.push_back(itr->path().filename().string());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
65
contrib/epee/include/hex.h
Normal file
65
contrib/epee/include/hex.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "span.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
struct to_hex
|
||||
{
|
||||
//! \return A std::string containing hex of `src`.
|
||||
static std::string string(const span<const std::uint8_t> src);
|
||||
|
||||
//! \return An array containing hex of `src`.
|
||||
template<std::size_t N>
|
||||
static std::array<char, N * 2> array(const std::array<std::uint8_t, N>& src) noexcept
|
||||
{
|
||||
std::array<char, N * 2> out{{}};
|
||||
static_assert(N <= 128, "keep the stack size down");
|
||||
buffer_unchecked(out.data(), {src.data(), src.size()});
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Append `src` as hex to `out`.
|
||||
static void buffer(std::ostream& out, const span<const std::uint8_t> src);
|
||||
|
||||
//! Append `< + src + >` as hex to `out`.
|
||||
static void formatted(std::ostream& out, const span<const std::uint8_t> src);
|
||||
|
||||
private:
|
||||
//! Write `src` bytes as hex to `out`. `out` must be twice the length
|
||||
static void buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept;
|
||||
};
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace md5
|
||||
static void MD5Init(MD5_CTX * context);
|
||||
static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen );
|
||||
static void MD5Final ( unsigned char digest[16], MD5_CTX *context );
|
||||
static void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest);
|
||||
static inline void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest);
|
||||
|
||||
|
||||
inline bool md5( unsigned char *input, int ilen, unsigned char output[16] )
|
||||
|
||||
@@ -58,14 +58,11 @@ These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
/* do i need all of this just for htonl()? damn. */
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/param.h>
|
||||
//#include <sys/socket.h>
|
||||
//#include <netinet/in.h>
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include "md5global.h"
|
||||
#include "md5_l.h"
|
||||
#include "hmac-md5.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,17 +48,17 @@ namespace epee
|
||||
namespace misc_utils
|
||||
{
|
||||
|
||||
inline uint64_t get_tick_count()
|
||||
inline uint64_t get_ns_count()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return ::GetTickCount64();
|
||||
return ::GetTickCount64() * 1000000;
|
||||
#elif defined(WIN32)
|
||||
static LARGE_INTEGER pcfreq = {0};
|
||||
LARGE_INTEGER ticks;
|
||||
if (!pcfreq.QuadPart)
|
||||
QueryPerformanceFrequency(&pcfreq);
|
||||
QueryPerformanceCounter(&ticks);
|
||||
ticks.QuadPart *= 1000; /* we want msec */
|
||||
ticks.QuadPart *= 1000000000; /* we want nsec */
|
||||
return ticks.QuadPart / pcfreq.QuadPart;
|
||||
#elif defined(__MACH__)
|
||||
clock_serv_t cclock;
|
||||
@@ -68,16 +68,21 @@ namespace misc_utils
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
|
||||
return (mts.tv_sec * 1000000000) + (mts.tv_nsec);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
|
||||
return (ts.tv_sec * 1000000000) + (ts.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64_t get_tick_count()
|
||||
{
|
||||
return get_ns_count() / 1000000;
|
||||
}
|
||||
|
||||
|
||||
inline int call_sys_cmd(const std::string& cmd)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
@@ -293,7 +296,7 @@ namespace net_utils
|
||||
}
|
||||
//----------------------------------------------------------------------------------------
|
||||
template<class THandler>
|
||||
bool abstract_tcp_server<THandler>::invoke_connection(SOCKET hnew_sock, long ip_from, int post_from)
|
||||
bool abstract_tcp_server<THandler>::invoke_connection(SOCKET hnew_sock, const network_address &remote_address)
|
||||
{
|
||||
m_connections_lock.lock();
|
||||
m_connections.push_back(thread_context());
|
||||
@@ -301,8 +304,7 @@ namespace net_utils
|
||||
m_connections.back().m_socket = hnew_sock;
|
||||
m_connections.back().powner = this;
|
||||
m_connections.back().m_self_it = --m_connections.end();
|
||||
m_connections.back().m_context.m_remote_ip = ip_from;
|
||||
m_connections.back().m_context.m_remote_port = post_from;
|
||||
m_connections.back().m_context.m_remote_address = remote_address;
|
||||
m_connections.back().m_htread = threads_helper::create_thread(ConnectionHandlerProc, &m_connections.back());
|
||||
|
||||
return true;
|
||||
|
||||
@@ -55,9 +55,11 @@
|
||||
#include "net_utils_base.h"
|
||||
#include "syncobj.h"
|
||||
#include "../../../../src/p2p/connection_basic.hpp"
|
||||
#include "../../../../contrib/otshell_utils/utils.hpp"
|
||||
#include "../../../../src/p2p/network_throttle-detail.hpp"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
|
||||
|
||||
namespace epee
|
||||
@@ -67,7 +69,7 @@ namespace net_utils
|
||||
|
||||
struct i_connection_filter
|
||||
{
|
||||
virtual bool is_remote_ip_allowed(uint32_t adress)=0;
|
||||
virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address)=0;
|
||||
protected:
|
||||
virtual ~i_connection_filter(){}
|
||||
};
|
||||
|
||||
@@ -51,9 +51,8 @@
|
||||
|
||||
#include "../../../../src/cryptonote_core/cryptonote_core.h" // e.g. for the send_stop_signal()
|
||||
|
||||
#include "../../../../contrib/otshell_utils/utils.hpp"
|
||||
#include "../../../../src/p2p/data_logger.hpp"
|
||||
using namespace nOT::nUtils; // TODO
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define CONNECTION_CLEANUP_TIME 30 // seconds
|
||||
|
||||
@@ -83,7 +82,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_throttle_speed_in("speed_in", "throttle_speed_in"),
|
||||
m_throttle_speed_out("speed_out", "throttle_speed_out")
|
||||
{
|
||||
_info_c("net/sleepRPC", "test, connection constructor set m_connection_type="<<m_connection_type);
|
||||
MINFO("test, connection constructor set m_connection_type="<<m_connection_type);
|
||||
}
|
||||
PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -134,6 +133,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
boost::system::error_code ec;
|
||||
auto remote_ep = socket_.remote_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
|
||||
CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here");
|
||||
|
||||
auto local_ep = socket_.local_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
|
||||
@@ -146,14 +146,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
// that stuff turns out to be included, even though it's from src... Taking advantage
|
||||
random_uuid = crypto::rand<boost::uuids::uuid>();
|
||||
|
||||
context.set_details(random_uuid, ip_, remote_ep.port(), is_income);
|
||||
context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
|
||||
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
|
||||
" to " << local_ep.address().to_string() << ':' << local_ep.port() <<
|
||||
", total sockets objects " << m_ref_sock_count);
|
||||
|
||||
if(m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip))
|
||||
if(m_pfilter && !m_pfilter->is_remote_host_allowed(context.m_remote_address))
|
||||
{
|
||||
_dbg2("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection");
|
||||
_dbg2("[sock " << socket_.native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
@@ -209,14 +209,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
bool connection<t_protocol_handler>::add_ref()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
|
||||
CRITICAL_REGION_LOCAL(m_self_refs_lock);
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
|
||||
|
||||
// Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted
|
||||
auto self = safe_shared_from_this();
|
||||
if(!self)
|
||||
return false;
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
|
||||
CRITICAL_REGION_LOCAL(self->m_self_refs_lock);
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
|
||||
if(m_was_shutdown)
|
||||
return false;
|
||||
m_self_refs.push_back(self);
|
||||
@@ -229,7 +229,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
boost::shared_ptr<connection<t_protocol_handler> > back_connection_copy;
|
||||
LOG_PRINT_L4("[sock " << socket_.native_handle() << "] release");
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] release");
|
||||
CRITICAL_REGION_BEGIN(m_self_refs_lock);
|
||||
CHECK_AND_ASSERT_MES(m_self_refs.size(), false, "[sock " << socket_.native_handle() << "] m_self_refs empty at connection<t_protocol_handler>::release() call");
|
||||
//erasing from container without additional copy can cause start deleting object, including m_self_refs
|
||||
@@ -266,8 +266,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
address = endpoint.address().to_string();
|
||||
port = boost::lexical_cast<std::string>(endpoint.port());
|
||||
}
|
||||
_mark_c("net/kind" ,
|
||||
" connection type " << to_string( m_connection_type ) << " "
|
||||
MINFO(" connection type " << to_string( m_connection_type ) << " "
|
||||
<< socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port()
|
||||
<< " <--> " << address << ":" << port);
|
||||
}
|
||||
@@ -306,7 +305,6 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
delay *= 0.5;
|
||||
if (delay > 0) {
|
||||
long int ms = (long int)(delay * 100);
|
||||
epee::net_utils::data_logger::get_instance().add_data("sleep_down", ms);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(ms));
|
||||
}
|
||||
} while(delay > 0);
|
||||
@@ -397,14 +395,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
const t_safe chunksize_max = chunksize_good * 2 ;
|
||||
const bool allow_split = (m_connection_type == e_connection_type_RPC) ? false : true; // do not split RPC data
|
||||
|
||||
ASRT(! (chunksize_max<0) ); // make sure it is unsigned before removin sign with cast:
|
||||
CHECK_AND_ASSERT_MES(! (chunksize_max<0), false, "Negative chunksize_max" ); // make sure it is unsigned before removin sign with cast:
|
||||
long long unsigned int chunksize_max_unsigned = static_cast<long long unsigned int>( chunksize_max ) ;
|
||||
|
||||
if (allow_split && (cb > chunksize_max_unsigned)) {
|
||||
{ // LOCK: chunking
|
||||
epee::critical_region_t<decltype(m_chunking_lock)> send_guard(m_chunking_lock); // *** critical ***
|
||||
|
||||
_dbg3_c("net/out/size", "do_send() will SPLIT into small chunks, from packet="<<cb<<" B for ptr="<<ptr);
|
||||
MDEBUG("do_send() will SPLIT into small chunks, from packet="<<cb<<" B for ptr="<<ptr);
|
||||
t_safe all = cb; // all bytes to send
|
||||
t_safe pos = 0; // current sending position
|
||||
// 01234567890
|
||||
@@ -419,39 +417,39 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
while (pos < all) {
|
||||
t_safe lenall = all-pos; // length from here to end
|
||||
t_safe len = std::min( chunksize_good , lenall); // take a smaller part
|
||||
ASRT(len<=chunksize_good);
|
||||
CHECK_AND_ASSERT_MES(len<=chunksize_good, false, "len too large");
|
||||
// pos=8; len=4; all=10; len=3;
|
||||
|
||||
ASRT(! (len<0) ); // check before we cast away sign:
|
||||
CHECK_AND_ASSERT_MES(! (len<0), false, "negative len"); // check before we cast away sign:
|
||||
unsigned long long int len_unsigned = static_cast<long long int>( len );
|
||||
ASRT(len>0); // (redundand)
|
||||
ASRT(len_unsigned < std::numeric_limits<size_t>::max()); // yeap we want strong < then max size, to be sure
|
||||
CHECK_AND_ASSERT_MES(len>0, false, "len not strictly positive"); // (redundant)
|
||||
CHECK_AND_ASSERT_MES(len_unsigned < std::numeric_limits<size_t>::max(), false, "Invalid len_unsigned"); // yeap we want strong < then max size, to be sure
|
||||
|
||||
void *chunk_start = ((char*)ptr) + pos;
|
||||
_fact_c("net/out/size","chunk_start="<<chunk_start<<" ptr="<<ptr<<" pos="<<pos);
|
||||
ASRT(chunk_start >= ptr); // not wrapped around address?
|
||||
MDEBUG("chunk_start="<<chunk_start<<" ptr="<<ptr<<" pos="<<pos);
|
||||
CHECK_AND_ASSERT_MES(chunk_start >= ptr, false, "Pointer wraparound"); // not wrapped around address?
|
||||
//std::memcpy( (void*)buf, chunk_start, len);
|
||||
|
||||
_dbg3_c("net/out/size", "part of " << lenall << ": pos="<<pos << " len="<<len);
|
||||
MDEBUG("part of " << lenall << ": pos="<<pos << " len="<<len);
|
||||
|
||||
bool ok = do_send_chunk(chunk_start, len); // <====== ***
|
||||
|
||||
all_ok = all_ok && ok;
|
||||
if (!all_ok) {
|
||||
_dbg1_c("net/out/size", "do_send() DONE ***FAILED*** from packet="<<cb<<" B for ptr="<<ptr);
|
||||
_dbg1("do_send() SEND was aborted in middle of big package - this is mostly harmless "
|
||||
MDEBUG("do_send() DONE ***FAILED*** from packet="<<cb<<" B for ptr="<<ptr);
|
||||
MDEBUG("do_send() SEND was aborted in middle of big package - this is mostly harmless "
|
||||
<< " (e.g. peer closed connection) but if it causes trouble tell us at #monero-dev. " << cb);
|
||||
return false; // partial failure in sending
|
||||
}
|
||||
pos = pos+len; ASRT(pos >0);
|
||||
pos = pos+len;
|
||||
CHECK_AND_ASSERT_MES(pos >0, false, "pos <= 0");
|
||||
|
||||
// (in catch block, or uniq pointer) delete buf;
|
||||
} // each chunk
|
||||
|
||||
_dbg3_c("net/out/size", "do_send() DONE SPLIT from packet="<<cb<<" B for ptr="<<ptr);
|
||||
_dbg3 ( "do_send() DONE SPLIT from packet="<<cb<<" B for ptr="<<ptr);
|
||||
MDEBUG("do_send() DONE SPLIT from packet="<<cb<<" B for ptr="<<ptr);
|
||||
|
||||
_info_c("net/sleepRPC", "do_send() m_connection_type = " << m_connection_type);
|
||||
MDEBUG("do_send() m_connection_type = " << m_connection_type);
|
||||
|
||||
return all_ok; // done - e.g. queued - all the chunks of current do_send call
|
||||
} // LOCK: chunking
|
||||
@@ -505,15 +503,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
}*/
|
||||
|
||||
long int ms = 250 + (rand()%50);
|
||||
_info_c("net/sleep", "Sleeping because QUEUE is FULL, in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<cb); // XXX debug sleep
|
||||
MDEBUG("Sleeping because QUEUE is FULL, in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<cb); // XXX debug sleep
|
||||
m_send_que_lock.unlock();
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) );
|
||||
m_send_que_lock.lock();
|
||||
_dbg1("sleep for queue: " << ms);
|
||||
|
||||
if (retry > retry_limit) {
|
||||
_erro("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
// _dbg1_c("net/sleep", "send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
MWARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
shutdown();
|
||||
return false;
|
||||
}
|
||||
@@ -525,10 +522,10 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
if(m_send_que.size() > 1)
|
||||
{ // active operation should be in progress, nothing to do, just wait last operation callback
|
||||
auto size_now = cb;
|
||||
_info_c("net/out/size", "do_send() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
|
||||
MDEBUG("do_send() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
|
||||
//do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function
|
||||
|
||||
LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
}
|
||||
else
|
||||
{ // no active operation
|
||||
@@ -540,11 +537,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
}
|
||||
|
||||
auto size_now = m_send_que.front().size();
|
||||
_dbg1_c("net/out/size", "do_send() NOW SENSD: packet="<<size_now<<" B");
|
||||
MDEBUG("do_send() NOW SENSD: packet="<<size_now<<" B");
|
||||
if (speed_limit_is_enabled())
|
||||
do_send_handler_write( ptr , size_now ); // (((H)))
|
||||
|
||||
ASRT( size_now == m_send_que.front().size() );
|
||||
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size");
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) ,
|
||||
//strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
|
||||
@@ -602,7 +599,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Async send calledback " << cb);
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << cb);
|
||||
|
||||
if (e)
|
||||
{
|
||||
@@ -635,10 +632,10 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
{
|
||||
//have more data to send
|
||||
auto size_now = m_send_que.front().size();
|
||||
_dbg1_c("net/out/size", "handle_write() NOW SENDS: packet="<<size_now<<" B" <<", from queue size="<<m_send_que.size());
|
||||
MDEBUG("handle_write() NOW SENDS: packet="<<size_now<<" B" <<", from queue size="<<m_send_que.size());
|
||||
if (speed_limit_is_enabled())
|
||||
do_send_handler_write_from_queue(e, m_send_que.front().size() , m_send_que.size()); // (((H)))
|
||||
ASRT( size_now == m_send_que.front().size() );
|
||||
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size");
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now) ,
|
||||
// strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
|
||||
@@ -660,8 +657,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
void connection<t_protocol_handler>::setRpcStation()
|
||||
{
|
||||
m_connection_type = e_connection_type_RPC;
|
||||
_fact_c("net/sleepRPC", "set m_connection_type = RPC ");
|
||||
_info_c("net/kind", "set m_connection_type = RPC ");
|
||||
MDEBUG("set m_connection_type = RPC ");
|
||||
}
|
||||
|
||||
|
||||
@@ -683,7 +679,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_sock_count(0), m_sock_number(0), m_threads_count(0),
|
||||
m_pfilter(NULL), m_thread_index(0),
|
||||
m_connection_type( connection_type ),
|
||||
new_connection_(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type))
|
||||
new_connection_()
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
@@ -697,7 +693,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_sock_count(0), m_sock_number(0), m_threads_count(0),
|
||||
m_pfilter(NULL), m_thread_index(0),
|
||||
m_connection_type(connection_type),
|
||||
new_connection_(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, connection_type))
|
||||
new_connection_()
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
@@ -735,7 +731,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
acceptor_.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
_fact_c("net/RPClog", "start accept");
|
||||
MDEBUG("start accept");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
@@ -752,7 +749,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
uint32_t p = 0;
|
||||
|
||||
if (port.size() && !string_tools::get_xtype_from_string(p, port)) {
|
||||
LOG_ERROR("Failed to convert port no = " << port);
|
||||
MERROR("Failed to convert port no = " << port);
|
||||
return false;
|
||||
}
|
||||
return this->init_server(p, address);
|
||||
@@ -766,7 +763,7 @@ POP_WARNINGS
|
||||
uint32_t local_thr_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
|
||||
std::string thread_name = std::string("[") + m_thread_name_prefix;
|
||||
thread_name += boost::to_string(local_thr_index) + "]";
|
||||
log_space::log_singletone::set_thread_log_prefix(thread_name);
|
||||
MLOG_SET_THREAD_NAME(thread_name);
|
||||
// _fact("Thread name: " << m_thread_name_prefix);
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
@@ -795,8 +792,7 @@ POP_WARNINGS
|
||||
auto it = server_type_map.find(m_thread_name_prefix);
|
||||
if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name));
|
||||
auto connection_type = it->second; // the value of type
|
||||
_info_c("net/RPClog", "Set server type to: " << connection_type << " from name: " << m_thread_name_prefix);
|
||||
_info_c("net/RPClog", "prefix_name = " << prefix_name);
|
||||
MINFO("Set server type to: " << connection_type << " from name: " << m_thread_name_prefix << ", prefix_name = " << prefix_name);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
@@ -811,7 +807,7 @@ POP_WARNINGS
|
||||
TRY_ENTRY();
|
||||
m_threads_count = threads_count;
|
||||
m_main_thread_id = boost::this_thread::get_id();
|
||||
log_space::log_singletone::set_thread_log_prefix("[SRV_MAIN]");
|
||||
MLOG_SET_THREAD_NAME("[SRV_MAIN]");
|
||||
add_idle_handler(boost::bind(&boosted_tcp_server::cleanup_connections, this), 5000);
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
@@ -932,13 +928,12 @@ POP_WARNINGS
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e)
|
||||
{
|
||||
_fact_c("net/RPClog", "handle_accept");
|
||||
MDEBUG("handle_accept");
|
||||
TRY_ENTRY();
|
||||
if (!e)
|
||||
{
|
||||
if (m_connection_type == e_connection_type_RPC) {
|
||||
_note_c("net/rpc", "New server for RPC connections");
|
||||
_fact_c("net/RPClog", "New server for RPC connections");
|
||||
MDEBUG("New server for RPC connections");
|
||||
new_connection_->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move(new_connection_));
|
||||
@@ -964,7 +959,7 @@ POP_WARNINGS
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||
connections_mutex.lock();
|
||||
connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l));
|
||||
LOG_PRINT_L2("connections_ size now " << connections_.size());
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
@@ -1051,7 +1046,7 @@ POP_WARNINGS
|
||||
}
|
||||
else
|
||||
{
|
||||
_erro("[sock " << new_connection_->socket().native_handle() << "] Failed to start connection, connections_count = " << m_sock_count);
|
||||
_erro("[sock " << new_connection_l->socket().native_handle() << "] Failed to start connection, connections_count = " << m_sock_count);
|
||||
}
|
||||
|
||||
new_connection_l->save_dbg_log();
|
||||
@@ -1068,7 +1063,7 @@ POP_WARNINGS
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) );
|
||||
connections_mutex.lock();
|
||||
connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l));
|
||||
LOG_PRINT_L2("connections_ size now " << connections_.size());
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
#include "net_utils_base.h"
|
||||
#include "pragma_comp_defs.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define LEVIN_DEFAULT_DATA_BUFF_SIZE 2000
|
||||
|
||||
namespace epee
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
@@ -468,7 +471,7 @@ bool cp_server_impl<TProtocol>::run_server(int threads_count = 0)
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
template<class TProtocol>
|
||||
bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, long ip_from, int port_from)
|
||||
bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, const network_address &address_from)
|
||||
{
|
||||
PROFILE_FUNC("[add_new_connection]");
|
||||
|
||||
@@ -484,8 +487,7 @@ bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, long ip_from
|
||||
m_connections_lock.unlock();
|
||||
conn.init_buffers();
|
||||
conn.m_sock = new_sock;
|
||||
conn.context.m_remote_ip = ip_from;
|
||||
conn.context.m_remote_port = port_from;
|
||||
conn.context.m_remote_address = address_from;
|
||||
conn.m_completion_port = m_completion_port;
|
||||
{
|
||||
PROFILE_FUNC("[add_new_connection] CreateIoCompletionPort");
|
||||
|
||||
170
contrib/epee/include/net/http_auth.h
Normal file
170
contrib/epee/include/net/http_auth.h
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright (c) 2014-2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "http_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
struct login
|
||||
{
|
||||
login() : username(), password() {}
|
||||
login(std::string username_, std::string password_)
|
||||
: username(std::move(username_)), password(std::move(password_))
|
||||
{}
|
||||
|
||||
std::string username;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
//! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
|
||||
class http_server_auth
|
||||
{
|
||||
public:
|
||||
struct session
|
||||
{
|
||||
session(login credentials_)
|
||||
: credentials(std::move(credentials_)), nonce(), counter(0)
|
||||
{}
|
||||
|
||||
login credentials;
|
||||
std::string nonce;
|
||||
std::uint32_t counter;
|
||||
};
|
||||
|
||||
http_server_auth() : user() {}
|
||||
http_server_auth(login credentials);
|
||||
|
||||
//! \return Auth response, or `boost::none` iff `request` had valid auth.
|
||||
boost::optional<http_response_info> get_response(const http_request_info& request)
|
||||
{
|
||||
if (user)
|
||||
return do_get_response(request);
|
||||
return boost::none;
|
||||
}
|
||||
private:
|
||||
boost::optional<http_response_info> do_get_response(const http_request_info& request);
|
||||
|
||||
boost::optional<session> user;
|
||||
};
|
||||
|
||||
//! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
|
||||
class http_client_auth
|
||||
{
|
||||
public:
|
||||
enum status : std::uint8_t { kSuccess = 0, kBadPassword, kParseFailure };
|
||||
|
||||
struct session
|
||||
{
|
||||
session(login credentials_)
|
||||
: credentials(std::move(credentials_)), server(), counter(0)
|
||||
{}
|
||||
|
||||
struct keys
|
||||
{
|
||||
using algorithm =
|
||||
std::function<std::string(const session&, boost::string_ref, boost::string_ref)>;
|
||||
|
||||
keys() : nonce(), opaque(), realm(), generator() {}
|
||||
keys(std::string nonce_, std::string opaque_, std::string realm_, algorithm generator_)
|
||||
: nonce(std::move(nonce_))
|
||||
, opaque(std::move(opaque_))
|
||||
, realm(std::move(realm_))
|
||||
, generator(std::move(generator_))
|
||||
{}
|
||||
|
||||
std::string nonce;
|
||||
std::string opaque;
|
||||
std::string realm;
|
||||
algorithm generator;
|
||||
};
|
||||
|
||||
login credentials;
|
||||
keys server;
|
||||
std::uint32_t counter;
|
||||
};
|
||||
|
||||
http_client_auth() : user() {}
|
||||
http_client_auth(login credentials);
|
||||
|
||||
/*!
|
||||
Clients receiving a 401 response code from the server should call this
|
||||
function to process the server auth. Then, before every client request,
|
||||
`get_auth_field()` should be called to retrieve the newest
|
||||
authorization request.
|
||||
|
||||
\return `kBadPassword` if client will never be able to authenticate,
|
||||
`kParseFailure` if all server authentication responses were invalid,
|
||||
and `kSuccess` if `get_auth_field` is ready to generate authorization
|
||||
fields.
|
||||
*/
|
||||
status handle_401(const http_response_info& response)
|
||||
{
|
||||
if (user)
|
||||
return do_handle_401(response);
|
||||
return kBadPassword;
|
||||
}
|
||||
|
||||
/*!
|
||||
After calling `handle_401`, clients should call this function to
|
||||
generate an authentication field for every request.
|
||||
|
||||
\return A HTTP "Authorization" field if `handle_401(...)` previously
|
||||
returned `kSuccess`.
|
||||
*/
|
||||
boost::optional<std::pair<std::string, std::string>> get_auth_field(
|
||||
const boost::string_ref method, const boost::string_ref uri)
|
||||
{
|
||||
if (user)
|
||||
return do_get_auth_field(method, uri);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
private:
|
||||
status do_handle_401(const http_response_info&);
|
||||
boost::optional<std::pair<std::string, std::string>> do_get_auth_field(boost::string_ref, boost::string_ref);
|
||||
|
||||
boost::optional<session> user;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,15 @@
|
||||
#pragma once
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "string_tools.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
@@ -86,6 +93,15 @@ namespace net_utils
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static inline void add_field(std::string& out, const boost::string_ref name, const boost::string_ref value)
|
||||
{
|
||||
out.append(name.data(), name.size()).append(": ");
|
||||
out.append(value.data(), value.size()).append("\r\n");
|
||||
}
|
||||
static inline void add_field(std::string& out, const std::pair<std::string, std::string>& field)
|
||||
{
|
||||
add_field(out, field.first, field.second);
|
||||
}
|
||||
|
||||
|
||||
struct http_header_info
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
//#include <mbstring.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -45,6 +47,7 @@
|
||||
#include "string_tools.h"
|
||||
#include "reg_exp_definer.h"
|
||||
#include "http_base.h"
|
||||
#include "http_auth.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
#include "net_parse_helpers.h"
|
||||
|
||||
@@ -52,6 +55,9 @@
|
||||
|
||||
//#pragma comment(lib, "shlwapi.lib")
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
extern epee::critical_section gregexp_lock;
|
||||
|
||||
|
||||
@@ -101,14 +107,14 @@ using namespace std;
|
||||
//---------------------------------------------------------------------------
|
||||
static inline const char* get_hex_vals()
|
||||
{
|
||||
static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
static const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
return hexVals;
|
||||
}
|
||||
|
||||
static inline const char* get_unsave_chars()
|
||||
{
|
||||
//static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
|
||||
static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
|
||||
static const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
|
||||
return unsave_chars;
|
||||
}
|
||||
|
||||
@@ -233,9 +239,6 @@ using namespace std;
|
||||
|
||||
class http_simple_client: public i_target_handler
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
private:
|
||||
enum reciev_machine_state
|
||||
{
|
||||
@@ -260,7 +263,7 @@ using namespace std;
|
||||
blocked_mode_client m_net_client;
|
||||
std::string m_host_buff;
|
||||
std::string m_port;
|
||||
unsigned int m_timeout;
|
||||
http_client_auth m_auth;
|
||||
std::string m_header_cache;
|
||||
http_response_info m_response_info;
|
||||
size_t m_len_in_summary;
|
||||
@@ -273,23 +276,48 @@ using namespace std;
|
||||
critical_section m_lock;
|
||||
|
||||
public:
|
||||
void set_host_name(const std::string& name)
|
||||
explicit http_simple_client()
|
||||
: i_target_handler()
|
||||
, m_net_client()
|
||||
, m_host_buff()
|
||||
, m_port()
|
||||
, m_auth()
|
||||
, m_header_cache()
|
||||
, m_response_info()
|
||||
, m_len_in_summary(0)
|
||||
, m_len_in_remain(0)
|
||||
, m_pcontent_encoding_handler(nullptr)
|
||||
, m_state()
|
||||
, m_chunked_state()
|
||||
, m_chunked_cache()
|
||||
, m_lock()
|
||||
{}
|
||||
|
||||
const std::string &get_host() const { return m_host_buff; };
|
||||
const std::string &get_port() const { return m_port; };
|
||||
|
||||
bool set_server(const std::string& address, boost::optional<login> user)
|
||||
{
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user));
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
m_host_buff = name;
|
||||
disconnect();
|
||||
m_host_buff = std::move(host);
|
||||
m_port = std::move(port);
|
||||
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
|
||||
}
|
||||
bool connect(const std::string& host, int port, unsigned int timeout)
|
||||
{
|
||||
return connect(host, std::to_string(port), timeout);
|
||||
}
|
||||
bool connect(const std::string& host, const std::string& port, unsigned int timeout)
|
||||
|
||||
bool connect(std::chrono::milliseconds timeout)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
m_host_buff = host;
|
||||
m_port = port;
|
||||
m_timeout = timeout;
|
||||
|
||||
return m_net_client.connect(host, port, timeout, timeout);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool disconnect()
|
||||
@@ -311,60 +339,97 @@ using namespace std;
|
||||
piece_of_transfer.clear();
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
virtual bool on_header(const http_response_info &headers)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline
|
||||
bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return invoke(uri, "GET", body, ppresponse_info, additional_params);
|
||||
return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if(!is_connected())
|
||||
{
|
||||
LOG_PRINT("Reconnecting...", LOG_LEVEL_3);
|
||||
if(!connect(m_host_buff, m_port, m_timeout))
|
||||
MDEBUG("Reconnecting...");
|
||||
if(!connect(timeout))
|
||||
{
|
||||
LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3);
|
||||
MDEBUG("Failed to connect to " << m_host_buff << ":" << m_port);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_response_info.clear();
|
||||
std::string req_buff = method + " ";
|
||||
req_buff += uri + " HTTP/1.1\r\n" +
|
||||
"Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n";
|
||||
|
||||
std::string req_buff{};
|
||||
req_buff.reserve(2048);
|
||||
req_buff.append(method.data(), method.size()).append(" ").append(uri.data(), uri.size()).append(" HTTP/1.1\r\n");
|
||||
add_field(req_buff, "Host", m_host_buff);
|
||||
add_field(req_buff, "Content-Length", std::to_string(body.size()));
|
||||
|
||||
//handle "additional_params"
|
||||
for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++)
|
||||
req_buff += it->first + ": " + it->second + "\r\n";
|
||||
req_buff += "\r\n";
|
||||
//--
|
||||
for(const auto& field : additional_params)
|
||||
add_field(req_buff, field);
|
||||
|
||||
bool res = m_net_client.send(req_buff);
|
||||
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
|
||||
if(body.size())
|
||||
res = m_net_client.send(body);
|
||||
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
|
||||
for (unsigned sends = 0; sends < 2; ++sends)
|
||||
{
|
||||
const std::size_t initial_size = req_buff.size();
|
||||
const auto auth = m_auth.get_auth_field(method, uri);
|
||||
if (auth)
|
||||
add_field(req_buff, *auth);
|
||||
|
||||
if(ppresponse_info)
|
||||
*ppresponse_info = &m_response_info;
|
||||
req_buff += "\r\n";
|
||||
//--
|
||||
|
||||
m_state = reciev_machine_state_header;
|
||||
return handle_reciev();
|
||||
bool res = m_net_client.send(req_buff, timeout);
|
||||
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
|
||||
if(body.size())
|
||||
res = m_net_client.send(body, timeout);
|
||||
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
|
||||
|
||||
|
||||
m_response_info.clear();
|
||||
m_state = reciev_machine_state_header;
|
||||
if (!handle_reciev(timeout))
|
||||
return false;
|
||||
if (m_response_info.m_response_code != 401)
|
||||
{
|
||||
if(ppresponse_info)
|
||||
*ppresponse_info = std::addressof(m_response_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (m_auth.handle_401(m_response_info))
|
||||
{
|
||||
case http_client_auth::kSuccess:
|
||||
break;
|
||||
case http_client_auth::kBadPassword:
|
||||
sends = 2;
|
||||
break;
|
||||
default:
|
||||
case http_client_auth::kParseFailure:
|
||||
LOG_ERROR("Bad server response for authentication");
|
||||
return false;
|
||||
}
|
||||
req_buff.resize(initial_size); // rollback for new auth generation
|
||||
}
|
||||
LOG_ERROR("Client has incorrect username/password for server requiring authentication");
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return invoke(uri, "POST", body, ppresponse_info, additional_params);
|
||||
return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params);
|
||||
}
|
||||
private:
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool handle_reciev()
|
||||
inline bool handle_reciev(std::chrono::milliseconds timeout)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
bool keep_handling = true;
|
||||
@@ -374,9 +439,9 @@ using namespace std;
|
||||
{
|
||||
if(need_more_data)
|
||||
{
|
||||
if(!m_net_client.recv(recv_buffer))
|
||||
if(!m_net_client.recv(recv_buffer, timeout))
|
||||
{
|
||||
LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3);
|
||||
MERROR("Unexpected recv fail");
|
||||
m_state = reciev_machine_state_error;
|
||||
}
|
||||
if(!recv_buffer.size())
|
||||
@@ -448,6 +513,12 @@ using namespace std;
|
||||
m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end());
|
||||
|
||||
analize_cached_header_and_invoke_state();
|
||||
if (!on_header(m_response_info))
|
||||
{
|
||||
MDEBUG("Connection cancelled by on_header");
|
||||
m_state = reciev_machine_state_done;
|
||||
return false;
|
||||
}
|
||||
m_header_cache.clear();
|
||||
if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done))
|
||||
need_more_data = true;
|
||||
@@ -464,13 +535,17 @@ using namespace std;
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if(!recv_buff.size())
|
||||
{
|
||||
LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3);
|
||||
MERROR("Warning: Content-Len mode, but connection unexpectedly closed");
|
||||
m_state = reciev_machine_state_done;
|
||||
return true;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()");
|
||||
m_len_in_remain -= recv_buff.size();
|
||||
m_pcontent_encoding_handler->update_in(recv_buff);
|
||||
if (!m_pcontent_encoding_handler->update_in(recv_buff))
|
||||
{
|
||||
m_state = reciev_machine_state_done;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_len_in_remain == 0)
|
||||
m_state = reciev_machine_state_done;
|
||||
@@ -578,7 +653,7 @@ using namespace std;
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if(!recv_buff.size())
|
||||
{
|
||||
LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3);
|
||||
MERROR("Warning: CHUNKED mode, but connection unexpectedly closed");
|
||||
m_state = reciev_machine_state_done;
|
||||
return true;
|
||||
}
|
||||
@@ -643,7 +718,11 @@ using namespace std;
|
||||
m_len_in_remain = 0;
|
||||
}
|
||||
|
||||
m_pcontent_encoding_handler->update_in(chunk_body);
|
||||
if (!m_pcontent_encoding_handler->update_in(chunk_body))
|
||||
{
|
||||
m_state = reciev_machine_state_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_len_in_remain)
|
||||
m_chunked_state = http_chunked_state_chunk_head;
|
||||
@@ -665,7 +744,7 @@ using namespace std;
|
||||
inline
|
||||
bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process)
|
||||
{
|
||||
LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4);
|
||||
MTRACE("http_stream_filter::parse_cached_header(*)");
|
||||
|
||||
STATIC_REGEXP_EXPR_1(rexp_mach_field,
|
||||
"\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
|
||||
@@ -708,7 +787,7 @@ using namespace std;
|
||||
else if(result[i++].matched)//"User-Agent"
|
||||
body_info.m_user_agent = result[field_val];
|
||||
else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
|
||||
{;}
|
||||
body_info.m_etc_fields.emplace_back(result[11], result[field_val]);
|
||||
else
|
||||
{CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<<m_cache_to_process);}
|
||||
|
||||
@@ -833,7 +912,7 @@ using namespace std;
|
||||
}else
|
||||
{ //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
|
||||
m_state = reciev_machine_state_error;
|
||||
LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache, LOG_LEVEL_2);
|
||||
MERROR("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -875,33 +954,6 @@ using namespace std;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
//inline
|
||||
template<class t_transport>
|
||||
bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list())
|
||||
{
|
||||
http::url_content u_c;
|
||||
bool res = parse_url(url, u_c);
|
||||
|
||||
if(!tr.is_connected() && !u_c.host.empty())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url);
|
||||
|
||||
if(!u_c.port)
|
||||
u_c.port = 80;//default for http
|
||||
|
||||
res = tr.connect(u_c.host, static_cast<int>(u_c.port), timeout);
|
||||
CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port);
|
||||
}
|
||||
|
||||
return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "storages/serializeble_struct_helper.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
template<class TArg, class TResult, class TTransport>
|
||||
bool invoke_http_json_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
StorageNamed::InMemStorageSpace::json::store_t_to_json(out_struct, req_param);
|
||||
|
||||
const http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return StorageNamed::InMemStorageSpace::json::load_t_from_json(result_struct, pri->m_body);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class TArg, class TResult, class TTransport>
|
||||
bool invoke_http_bin_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
epee::StorageNamed::save_struct_as_storage_to_buff(out_struct, req_param);
|
||||
|
||||
const http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return epee::StorageNamed::load_struct_from_storage_buff(result_struct, pri->m_body);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#include <atlutil.h>
|
||||
#pragma comment(lib, "Wininet.lib")
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
|
||||
@@ -30,11 +30,16 @@
|
||||
#ifndef _HTTP_SERVER_H_
|
||||
#define _HTTP_SERVER_H_
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <string>
|
||||
#include "net_utils_base.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
#include "http_auth.h"
|
||||
#include "http_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
@@ -49,7 +54,7 @@ namespace net_utils
|
||||
struct http_server_config
|
||||
{
|
||||
std::string m_folder;
|
||||
std::string m_required_user_agent;
|
||||
boost::optional<login> m_user;
|
||||
critical_section m_lock;
|
||||
};
|
||||
|
||||
@@ -169,11 +174,20 @@ namespace net_utils
|
||||
http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context)
|
||||
: simple_http_connection_handler<t_connection_context>(psnd_hndlr, config),
|
||||
m_config(config),
|
||||
m_conn_context(conn_context)
|
||||
m_conn_context(conn_context),
|
||||
m_auth(m_config.m_user ? http_server_auth{*m_config.m_user} : http_server_auth{})
|
||||
{}
|
||||
inline bool handle_request(const http_request_info& query_info, http_response_info& response)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!");
|
||||
|
||||
const auto auth_response = m_auth.get_response(query_info);
|
||||
if (auth_response)
|
||||
{
|
||||
response = std::move(*auth_response);
|
||||
return true;
|
||||
}
|
||||
|
||||
//fill with default values
|
||||
response.m_mime_tipe = "text/plain";
|
||||
response.m_response_code = 200;
|
||||
@@ -202,6 +216,7 @@ namespace net_utils
|
||||
//simple_http_connection_handler::config_type m_stub_config;
|
||||
config_type& m_config;
|
||||
t_connection_context& m_conn_context;
|
||||
http_server_auth m_auth;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "file_io_utils.h"
|
||||
#include "net_parse_helpers.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
#define HTTP_MAX_URI_LEN 9000
|
||||
#define HTTP_MAX_HEADER_LEN 100000
|
||||
|
||||
@@ -133,7 +136,7 @@ namespace net_utils
|
||||
std::string boundary;
|
||||
if(!match_boundary(content_type, boundary))
|
||||
{
|
||||
LOG_PRINT("Failed to match boundary in content type: " << content_type, LOG_LEVEL_0);
|
||||
MERROR("Failed to match boundary in content type: " << content_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -155,7 +158,7 @@ namespace net_utils
|
||||
pos = body.find(boundary, std::distance(body.begin(), it_begin));
|
||||
if(std::string::npos == pos)
|
||||
{
|
||||
LOG_PRINT("Error: Filed to match closing multipart tag", LOG_LEVEL_0);
|
||||
MERROR("Error: Filed to match closing multipart tag");
|
||||
it_end = body.end();
|
||||
}else
|
||||
{
|
||||
@@ -177,7 +180,7 @@ namespace net_utils
|
||||
out_values.push_back(multipart_entry());
|
||||
if(!handle_part_of_multipart(it_begin, it_end, out_values.back()))
|
||||
{
|
||||
LOG_PRINT("Failed to handle_part_of_multipart", LOG_LEVEL_0);
|
||||
MERROR("Failed to handle_part_of_multipart");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -331,8 +334,6 @@ namespace net_utils
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
|
||||
{
|
||||
LOG_FRAME("simple_http_connection_handler<t_connection_context>::handle_recognize_protocol_out(*)", LOG_LEVEL_3);
|
||||
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
|
||||
// 123 4 5 6 7 8 9 10 11 12
|
||||
//size_t match_len = 0;
|
||||
@@ -379,8 +380,6 @@ namespace net_utils
|
||||
{
|
||||
//LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, pos));
|
||||
|
||||
LOG_FRAME("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3);
|
||||
|
||||
m_query_info.m_full_request_buf_size = pos;
|
||||
m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
|
||||
|
||||
@@ -391,13 +390,6 @@ namespace net_utils
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_config.m_required_user_agent.empty() && m_query_info.m_header_info.m_user_agent != m_config.m_required_user_agent)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): unexpected user agent: " << m_query_info.m_header_info.m_user_agent);
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cache.erase(0, pos);
|
||||
|
||||
std::string req_command_str = m_query_info.m_full_request_str;
|
||||
@@ -479,8 +471,6 @@ namespace net_utils
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos)
|
||||
{
|
||||
LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_3);
|
||||
|
||||
STATIC_REGEXP_EXPR_1(rexp_mach_field,
|
||||
"\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
|
||||
// 12 3 4 5 6 7 8 9 10
|
||||
@@ -557,7 +547,7 @@ namespace net_utils
|
||||
LOG_PRINT_L3("HTTP_RESPONSE_HEAD: << \r\n" << response_data);
|
||||
|
||||
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
|
||||
if(response.m_body.size())
|
||||
if(response.m_body.size() && (query_info.m_http_method != http::http_method_head))
|
||||
m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
|
||||
return res;
|
||||
}
|
||||
@@ -576,7 +566,7 @@ namespace net_utils
|
||||
m_config.m_lock.unlock();
|
||||
if(!file_io_utils::load_file_to_string(destination_file_path.c_str(), response.m_body))
|
||||
{
|
||||
LOG_PRINT("URI \""<< query_info.m_full_request_str.substr(0, query_info.m_full_request_str.size()-2) << "\" [" << destination_file_path << "] Not Found (404 )" , LOG_LEVEL_1);
|
||||
MWARNING("URI \""<< query_info.m_full_request_str.substr(0, query_info.m_full_request_str.size()-2) << "\" [" << destination_file_path << "] Not Found (404 )");
|
||||
response.m_body = get_not_found_response_body(query_info.m_URI);
|
||||
response.m_response_code = 404;
|
||||
response.m_response_comment = "Not found";
|
||||
@@ -584,7 +574,7 @@ namespace net_utils
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_PRINT(" -->> " << query_info.m_full_request_str << "\r\n<<--OK" , LOG_LEVEL_3);
|
||||
MDEBUG(" -->> " << query_info.m_full_request_str << "\r\n<<--OK");
|
||||
response.m_response_code = 200;
|
||||
response.m_response_comment = "OK";
|
||||
response.m_mime_tipe = get_file_mime_tipe(uri_to_path);
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include "abstract_tcp_server_cp.h"
|
||||
#include "http_server.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include "abstract_tcp_server2.h"
|
||||
#include "http_protocol_handler.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
|
||||
@@ -31,12 +31,15 @@
|
||||
#include "storages/portable_storage.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
|
||||
#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
|
||||
epee::net_utils::http::http_response_info& response, \
|
||||
context_type& m_conn_context) \
|
||||
{\
|
||||
LOG_PRINT_L2("HTTP [" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \
|
||||
LOG_PRINT_L2("HTTP [" << m_conn_context.m_remote_address.host_str() << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \
|
||||
response.m_response_code = 200; \
|
||||
response.m_response_comment = "Ok"; \
|
||||
if(!handle_http_request_map(query_info, response, m_conn_context)) \
|
||||
@@ -77,7 +80,7 @@
|
||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
||||
response_info.m_mime_tipe = "application/json"; \
|
||||
response_info.m_header_info.m_content_type = " application/json"; \
|
||||
LOG_PRINT( s_pattern << " processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
|
||||
MDEBUG( s_pattern << " processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms"); \
|
||||
}
|
||||
|
||||
#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) MAP_URI_AUTO_JON2_IF(s_pattern, callback_f, command_type, true)
|
||||
@@ -104,7 +107,7 @@
|
||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
||||
response_info.m_mime_tipe = " application/octet-stream"; \
|
||||
response_info.m_header_info.m_content_type = " application/octet-stream"; \
|
||||
LOG_PRINT( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
|
||||
MDEBUG( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms"); \
|
||||
}
|
||||
|
||||
#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);handled = true;}
|
||||
@@ -166,7 +169,7 @@
|
||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
||||
response_info.m_mime_tipe = "application/json"; \
|
||||
response_info.m_header_info.m_content_type = " application/json"; \
|
||||
LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2);
|
||||
MDEBUG( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms");
|
||||
|
||||
#define MAP_JON_RPC_WE_IF(method_name, callback_f, command_type, cond) \
|
||||
else if((callback_name == method_name) && (cond)) \
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include "net/http_server_cp2.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
@@ -52,7 +55,8 @@ namespace epee
|
||||
: m_net_server(external_io_service)
|
||||
{}
|
||||
|
||||
bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0", const std::string &user_agent = "")
|
||||
bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
|
||||
boost::optional<net_utils::http::login> user = boost::none)
|
||||
{
|
||||
|
||||
//set self as callback handler
|
||||
@@ -61,10 +65,9 @@ namespace epee
|
||||
//here set folder for hosting reqests
|
||||
m_net_server.get_config_object().m_folder = "";
|
||||
|
||||
// workaround till we get auth/encryption
|
||||
m_net_server.get_config_object().m_required_user_agent = user_agent;
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
|
||||
LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
|
||||
MGINFO("Binding on " << bind_ip << ":" << bind_port);
|
||||
bool res = m_net_server.init_server(bind_port, bind_ip);
|
||||
if(!res)
|
||||
{
|
||||
@@ -77,15 +80,14 @@ namespace epee
|
||||
bool run(size_t threads_count, bool wait = true)
|
||||
{
|
||||
//go to loop
|
||||
LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0);
|
||||
_fact_c("net/RPClog", "Run net_service loop( " << threads_count << " threads)...");
|
||||
MINFO("Run net_service loop( " << threads_count << " threads)...");
|
||||
if(!m_net_server.run_server(threads_count, wait))
|
||||
{
|
||||
LOG_ERROR("Failed to run net tcp server!");
|
||||
}
|
||||
|
||||
if(wait)
|
||||
LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
|
||||
MINFO("net_service loop stopped.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
#include "string_tools.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace levin
|
||||
@@ -95,7 +99,7 @@ int levin_client_impl::invoke(int command, const std::string& in_buff, std::stri
|
||||
|
||||
if(head.m_signature!=LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_PRINT_L1("Signature missmatch in response");
|
||||
LOG_PRINT_L1("Signature mismatch in response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -156,7 +160,7 @@ inline
|
||||
|
||||
if(head.m_signature!=LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_PRINT_L1("Signature missmatch in response");
|
||||
LOG_PRINT_L1("Signature mismatch in response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "net_helper.h"
|
||||
#include "levin_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
@@ -405,7 +408,7 @@ namespace levin
|
||||
|
||||
if(head.m_signature!=LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_ERROR("Signature missmatch in response");
|
||||
LOG_ERROR("Signature mismatch in response");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -489,8 +492,7 @@ namespace levin
|
||||
{
|
||||
|
||||
net_utils::connection_context_base conn_context;
|
||||
conn_context.m_remote_ip = m_ip;
|
||||
conn_context.m_remote_port = m_port;
|
||||
conn_context.m_remote_address = m_address;
|
||||
if(head.m_have_to_return_data)
|
||||
{
|
||||
std::string return_buff;
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "levin_base.h"
|
||||
#include "serializeble_struct_helper.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace levin
|
||||
@@ -91,7 +94,7 @@ namespace levin
|
||||
}
|
||||
if(head.m_cb != buff.size()-sizeof(levin::bucket_head))
|
||||
{
|
||||
LOG_PRINT_L3("sizes missmatch, at load_struct_from_levin_message");
|
||||
LOG_PRINT_L3("sizes mismatch, at load_struct_from_levin_message");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -118,7 +121,7 @@ namespace levin
|
||||
}
|
||||
if(head.m_cb != buff.size()-sizeof(levin::bucket_head))
|
||||
{
|
||||
LOG_ERROR("sizes missmatch, at load_struct_from_levin_message");
|
||||
LOG_ERROR("sizes mismatch, at load_struct_from_levin_message");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include "levin_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace levin
|
||||
@@ -85,7 +88,7 @@ namespace levin
|
||||
{
|
||||
if(!m_config.m_pcommands_handler)
|
||||
{
|
||||
LOG_ERROR("Command handler not set!");
|
||||
LOG_ERROR_CC(m_conn_context, "Command handler not set!");
|
||||
return false;
|
||||
}
|
||||
m_cach_in_buffer.append((const char*)ptr, cb);
|
||||
@@ -100,7 +103,7 @@ namespace levin
|
||||
{
|
||||
if(m_cach_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cach_in_buffer.data()) != LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_ERROR("Signature missmatch on accepted connection");
|
||||
LOG_ERROR_CC(m_conn_context, "Signature mismatch on accepted connection");
|
||||
return false;
|
||||
}
|
||||
is_continue = false;
|
||||
@@ -110,7 +113,7 @@ namespace levin
|
||||
bucket_head* phead = (bucket_head*)m_cach_in_buffer.data();
|
||||
if(LEVIN_SIGNATURE != phead->m_signature)
|
||||
{
|
||||
LOG_ERROR("Signature missmatch on accepted connection");
|
||||
LOG_ERROR_CC(m_conn_context, "Signature mismatch on accepted connection");
|
||||
return false;
|
||||
}
|
||||
m_current_head = *phead;
|
||||
@@ -154,7 +157,7 @@ namespace levin
|
||||
m_state = conn_state_reading_head;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Undefined state in levin_server_impl::connection_handler, m_state=" << m_state);
|
||||
LOG_ERROR_CC(m_conn_context, "Undefined state in levin_server_impl::connection_handler, m_state=" << m_state);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
@@ -38,6 +39,12 @@
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#ifndef MIN_BYTES_WANTED
|
||||
#define MIN_BYTES_WANTED 512
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
@@ -81,6 +88,8 @@ public:
|
||||
bool request_callback(boost::uuids::uuid connection_id);
|
||||
template<class callback_t>
|
||||
bool foreach_connection(callback_t cb);
|
||||
template<class callback_t>
|
||||
bool for_connection(const boost::uuids::uuid &connection_id, callback_t cb);
|
||||
size_t get_connections_count();
|
||||
|
||||
async_protocol_handler_config():m_pcommands_handler(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE)
|
||||
@@ -136,22 +145,24 @@ public:
|
||||
virtual bool is_timer_started() const=0;
|
||||
virtual void cancel()=0;
|
||||
virtual bool cancel_timer()=0;
|
||||
virtual void reset_timer()=0;
|
||||
};
|
||||
template <class callback_t>
|
||||
struct anvoke_handler: invoke_response_handler_base
|
||||
{
|
||||
anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
|
||||
:m_cb(cb), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false),
|
||||
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false),
|
||||
m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command)
|
||||
{
|
||||
if(m_con.start_outer_call())
|
||||
{
|
||||
MDEBUG(con.get_context_ref() << "anvoke_handler, timeout: " << timeout);
|
||||
m_timer.expires_from_now(boost::posix_time::milliseconds(timeout));
|
||||
m_timer.async_wait([&con, command, cb](const boost::system::error_code& ec)
|
||||
m_timer.async_wait([&con, command, cb, timeout](const boost::system::error_code& ec)
|
||||
{
|
||||
if(ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
LOG_PRINT_CC(con.get_context_ref(), "Timeout on invoke operation happened, command: " << command, LOG_LEVEL_2);
|
||||
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
|
||||
std::string fake;
|
||||
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
|
||||
con.close();
|
||||
@@ -168,6 +179,7 @@ public:
|
||||
bool m_timer_started;
|
||||
bool m_cancel_timer_called;
|
||||
bool m_timer_cancelled;
|
||||
uint64_t m_timeout;
|
||||
int m_command;
|
||||
virtual bool handle(int res, const std::string& buff, typename async_protocol_handler::connection_context& context)
|
||||
{
|
||||
@@ -200,6 +212,28 @@ public:
|
||||
}
|
||||
return m_timer_cancelled;
|
||||
}
|
||||
virtual void reset_timer()
|
||||
{
|
||||
boost::system::error_code ignored_ec;
|
||||
if (!m_cancel_timer_called && m_timer.cancel(ignored_ec) > 0)
|
||||
{
|
||||
callback_t& cb = m_cb;
|
||||
uint64_t timeout = m_timeout;
|
||||
async_protocol_handler& con = m_con;
|
||||
int command = m_command;
|
||||
m_timer.expires_from_now(boost::posix_time::milliseconds(m_timeout));
|
||||
m_timer.async_wait([&con, cb, command, timeout](const boost::system::error_code& ec)
|
||||
{
|
||||
if(ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
|
||||
std::string fake;
|
||||
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
|
||||
con.close();
|
||||
con.finish_outer_call();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
critical_section m_invoke_response_handlers_lock;
|
||||
std::list<boost::shared_ptr<invoke_response_handler_base> > m_invoke_response_handlers;
|
||||
@@ -244,15 +278,15 @@ public:
|
||||
}
|
||||
CHECK_AND_ASSERT_MES_NO_RET(0 == boost::interprocess::ipcdetail::atomic_read32(&m_wait_count), "Failed to wait for operation completion. m_wait_count = " << m_wait_count);
|
||||
|
||||
LOG_PRINT_CC(m_connection_context, "~async_protocol_handler()", LOG_LEVEL_4);
|
||||
MTRACE(m_connection_context << "~async_protocol_handler()");
|
||||
}
|
||||
|
||||
bool start_outer_call()
|
||||
{
|
||||
LOG_PRINT_CC_L4(m_connection_context, "[levin_protocol] -->> start_outer_call");
|
||||
MTRACE(m_connection_context << "[levin_protocol] -->> start_outer_call");
|
||||
if(!m_pservice_endpoint->add_ref())
|
||||
{
|
||||
LOG_PRINT_CC_RED(m_connection_context, "[levin_protocol] -->> start_outer_call failed", LOG_LEVEL_4);
|
||||
MERROR(m_connection_context << "[levin_protocol] -->> start_outer_call failed");
|
||||
return false;
|
||||
}
|
||||
boost::interprocess::ipcdetail::atomic_inc32(&m_wait_count);
|
||||
@@ -260,7 +294,7 @@ public:
|
||||
}
|
||||
bool finish_outer_call()
|
||||
{
|
||||
LOG_PRINT_CC_L4(m_connection_context, "[levin_protocol] <<-- finish_outer_call");
|
||||
MTRACE(m_connection_context << "[levin_protocol] <<-- finish_outer_call");
|
||||
boost::interprocess::ipcdetail::atomic_dec32(&m_wait_count);
|
||||
m_pservice_endpoint->release();
|
||||
return true;
|
||||
@@ -316,13 +350,13 @@ public:
|
||||
|
||||
if(!m_config.m_pcommands_handler)
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Commands handler not set!");
|
||||
MERROR(m_connection_context << "Commands handler not set!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_cache_in_buffer.size() + cb > m_config.m_max_packet_size)
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
|
||||
MWARNING(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
|
||||
<< ", packet received " << m_cache_in_buffer.size() + cb
|
||||
<< ", connection will be closed.");
|
||||
return false;
|
||||
@@ -339,6 +373,13 @@ public:
|
||||
if(m_cache_in_buffer.size() < m_current_head.m_cb)
|
||||
{
|
||||
is_continue = false;
|
||||
if(cb >= MIN_BYTES_WANTED && !m_invoke_response_handlers.empty())
|
||||
{
|
||||
//async call scenario
|
||||
boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
|
||||
response_handler->reset_timer();
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
{
|
||||
@@ -353,7 +394,7 @@ public:
|
||||
|
||||
bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
|
||||
|
||||
LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_RECIEVED. [len=" << m_current_head.m_cb
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET_RECIEVED. [len=" << m_current_head.m_cb
|
||||
<< ", flags" << m_current_head.m_flags
|
||||
<< ", r?=" << m_current_head.m_have_to_return_data
|
||||
<<", cmd = " << m_current_head.m_command
|
||||
@@ -381,7 +422,7 @@ public:
|
||||
//use sync call scenario
|
||||
if(!boost::interprocess::ipcdetail::atomic_read32(&m_wait_count) && !boost::interprocess::ipcdetail::atomic_read32(&m_close_called))
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "no active invoke when response came, wtf?");
|
||||
MERROR(m_connection_context << "no active invoke when response came, wtf?");
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
@@ -413,7 +454,7 @@ public:
|
||||
if(!m_pservice_endpoint->do_send(send_buff.data(), send_buff.size()))
|
||||
return false;
|
||||
CRITICAL_REGION_END();
|
||||
LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << m_current_head.m_cb
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET_SENT. [len=" << m_current_head.m_cb
|
||||
<< ", flags" << m_current_head.m_flags
|
||||
<< ", r?=" << m_current_head.m_have_to_return_data
|
||||
<<", cmd = " << m_current_head.m_command
|
||||
@@ -431,7 +472,7 @@ public:
|
||||
{
|
||||
if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.data()) != LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
|
||||
MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
|
||||
return false;
|
||||
}
|
||||
is_continue = false;
|
||||
@@ -585,19 +626,25 @@ public:
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
|
||||
LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << head.m_cb
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET_SENT. [len=" << head.m_cb
|
||||
<< ", f=" << head.m_flags
|
||||
<< ", r?=" << head.m_have_to_return_data
|
||||
<< ", cmd = " << head.m_command
|
||||
<< ", ver=" << head.m_protocol_version);
|
||||
|
||||
uint64_t ticks_start = misc_utils::get_tick_count();
|
||||
size_t prev_size = 0;
|
||||
|
||||
while(!boost::interprocess::ipcdetail::atomic_read32(&m_invoke_buf_ready) && !m_deletion_initiated && !m_protocol_released)
|
||||
{
|
||||
if(m_cache_in_buffer.size() - prev_size >= MIN_BYTES_WANTED)
|
||||
{
|
||||
prev_size = m_cache_in_buffer.size();
|
||||
ticks_start = misc_utils::get_tick_count();
|
||||
}
|
||||
if(misc_utils::get_tick_count() - ticks_start > m_config.m_invoke_timeout)
|
||||
{
|
||||
LOG_PRINT_CC_L2(m_connection_context, "invoke timeout (" << m_config.m_invoke_timeout << "), closing connection ");
|
||||
MWARNING(m_connection_context << "invoke timeout (" << m_config.m_invoke_timeout << "), closing connection ");
|
||||
close();
|
||||
return LEVIN_ERROR_CONNECTION_TIMEDOUT;
|
||||
}
|
||||
@@ -650,7 +697,7 @@ public:
|
||||
return -1;
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << head.m_cb <<
|
||||
LOG_DEBUG_CC(m_connection_context, "LEVIN_PACKET_SENT. [len=" << head.m_cb <<
|
||||
", f=" << head.m_flags <<
|
||||
", r?=" << head.m_have_to_return_data <<
|
||||
", cmd = " << head.m_command <<
|
||||
@@ -759,6 +806,18 @@ bool async_protocol_handler_config<t_connection_context>::foreach_connection(cal
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, callback_t cb)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
|
||||
if (!aph)
|
||||
return false;
|
||||
if(!cb(aph->get_context_ref()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
size_t async_protocol_handler_config<t_connection_context>::get_connections_count()
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/preprocessor/selection/min.hpp>
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
@@ -46,6 +47,9 @@
|
||||
//#include "profile_tools.h"
|
||||
#include "../string_tools.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#ifndef MAKE_IP
|
||||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
|
||||
#endif
|
||||
@@ -95,7 +99,7 @@ namespace net_utils
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
check_deadline();
|
||||
@@ -108,26 +112,16 @@ namespace net_utils
|
||||
shutdown();
|
||||
}
|
||||
|
||||
inline void set_recv_timeout(int reciev_timeout)
|
||||
{
|
||||
m_reciev_timeout = reciev_timeout;
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip);
|
||||
return connect(addr, std::to_string(port), timeout, bind_ip);
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
m_connect_timeout = connect_timeout;
|
||||
m_reciev_timeout = reciev_timeout;
|
||||
m_connected = false;
|
||||
if(!m_reciev_timeout)
|
||||
m_reciev_timeout = m_connect_timeout;
|
||||
|
||||
try
|
||||
{
|
||||
m_socket.close();
|
||||
@@ -161,7 +155,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
|
||||
m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout));
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
@@ -176,23 +170,23 @@ namespace net_utils
|
||||
if (!ec && m_socket.is_open())
|
||||
{
|
||||
m_connected = true;
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3);
|
||||
MWARNING("Some problems at connect, message: " << ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
catch(const boost::system::system_error& er)
|
||||
{
|
||||
LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4);
|
||||
MDEBUG("Some problems at connect, message: " << er.what());
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_PRINT("Some fatal problems.", LOG_LEVEL_4);
|
||||
MDEBUG("Some fatal problems.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -228,12 +222,12 @@ namespace net_utils
|
||||
|
||||
|
||||
inline
|
||||
bool send(const std::string& buff)
|
||||
bool send(const std::string& buff, std::chrono::milliseconds timeout)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -261,7 +255,7 @@ namespace net_utils
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +313,7 @@ namespace net_utils
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +341,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
inline
|
||||
bool recv(std::string& buff)
|
||||
bool recv(std::string& buff, std::chrono::milliseconds timeout)
|
||||
{
|
||||
|
||||
try
|
||||
@@ -355,7 +349,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -387,21 +381,21 @@ namespace net_utils
|
||||
|
||||
if (ec)
|
||||
{
|
||||
LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value());
|
||||
MTRACE("READ ENDS: Connection err_code " << ec.value());
|
||||
if(ec == boost::asio::error::eof)
|
||||
{
|
||||
LOG_PRINT_L4("Connection err_code eof.");
|
||||
MTRACE("Connection err_code eof.");
|
||||
//connection closed there, empty
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_PRINT_L3("Problems at read: " << ec.message());
|
||||
MDEBUG("Problems at read: " << ec.message());
|
||||
m_connected = false;
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered);
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
MTRACE("READ ENDS: Success. bytes_tr: " << bytes_transfered);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
|
||||
/*if(!bytes_transfered)
|
||||
@@ -429,7 +423,7 @@ namespace net_utils
|
||||
|
||||
}
|
||||
|
||||
inline bool recv_n(std::string& buff, int64_t sz)
|
||||
inline bool recv_n(std::string& buff, int64_t sz, std::chrono::milliseconds timeout)
|
||||
{
|
||||
|
||||
try
|
||||
@@ -437,7 +431,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -474,12 +468,12 @@ namespace net_utils
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
|
||||
if(bytes_transfered != buff.size())
|
||||
{
|
||||
LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size());
|
||||
LOG_ERROR("Transferred mismatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -536,7 +530,7 @@ namespace net_utils
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
|
||||
if (m_deadline.expires_at() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
@@ -547,7 +541,7 @@ namespace net_utils
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
m_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
}
|
||||
|
||||
// Put the actor back to sleep.
|
||||
@@ -559,11 +553,9 @@ namespace net_utils
|
||||
protected:
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::ip::tcp::socket m_socket;
|
||||
int m_connect_timeout;
|
||||
int m_reciev_timeout;
|
||||
bool m_initialized;
|
||||
bool m_connected;
|
||||
boost::asio::deadline_timer m_deadline;
|
||||
boost::asio::steady_timer m_deadline;
|
||||
volatile uint32_t m_shutdowned;
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "http_base.h"
|
||||
#include "reg_exp_definer.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
@@ -29,8 +29,16 @@
|
||||
#ifndef _NET_UTILS_BASE_H_
|
||||
#define _NET_UTILS_BASE_H_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "net/local_ip.h"
|
||||
#include "string_tools.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#ifndef MAKE_IP
|
||||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
|
||||
@@ -41,14 +49,110 @@ namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
struct network_address_base
|
||||
{
|
||||
public:
|
||||
bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
|
||||
bool operator!=(const network_address_base &other) const { return !operator==(other); }
|
||||
bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
|
||||
bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
|
||||
virtual std::string str() const = 0;
|
||||
virtual std::string host_str() const = 0;
|
||||
virtual bool is_loopback() const = 0;
|
||||
virtual bool is_local() const = 0;
|
||||
virtual uint8_t get_type_id() const = 0;
|
||||
protected:
|
||||
// A very simple non cryptographic hash function by Fowler, Noll, Vo
|
||||
uint64_t fnv1a(const uint8_t *data, size_t len) const {
|
||||
uint64_t h = 0xcbf29ce484222325;
|
||||
while (len--)
|
||||
h = (h ^ *data++) * 0x100000001b3;
|
||||
return h;
|
||||
}
|
||||
uint64_t m_host_id;
|
||||
uint64_t m_full_id;
|
||||
};
|
||||
struct ipv4_network_address: public network_address_base
|
||||
{
|
||||
void init_ids()
|
||||
{
|
||||
m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
|
||||
m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
|
||||
}
|
||||
public:
|
||||
ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
|
||||
uint32_t ip() const { return m_ip; }
|
||||
uint16_t port() const { return m_port; }
|
||||
virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
|
||||
virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
|
||||
virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
|
||||
virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
|
||||
virtual uint8_t get_type_id() const { return ID; }
|
||||
public: // serialization
|
||||
static const uint8_t ID = 1;
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
uint32_t m_ip;
|
||||
uint16_t m_port;
|
||||
#pragma pack(pop)
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_ip)
|
||||
KV_SERIALIZE(m_port)
|
||||
if (!is_store)
|
||||
const_cast<ipv4_network_address&>(this_ref).init_ids();
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
class network_address: public boost::shared_ptr<network_address_base>
|
||||
{
|
||||
public:
|
||||
network_address() {}
|
||||
network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {}
|
||||
bool operator==(const network_address &other) const { return (*this)->operator==(*other); }
|
||||
bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); }
|
||||
bool operator<(const network_address &other) const { return (*this)->operator<(*other); }
|
||||
bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); }
|
||||
std::string str() const { return (*this) ? (*this)->str() : "<none>"; }
|
||||
std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; }
|
||||
bool is_loopback() const { return (*this)->is_loopback(); }
|
||||
bool is_local() const { return (*this)->is_local(); }
|
||||
uint8_t get_type_id() const { return (*this)->get_type_id(); }
|
||||
template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); }
|
||||
template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); }
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
uint8_t type = is_store ? this_ref.get_type_id() : 0;
|
||||
epee::serialization::selector<is_store>::serialize(type, stg, hparent_section, "type");
|
||||
switch (type)
|
||||
{
|
||||
case ipv4_network_address::ID:
|
||||
if (!is_store)
|
||||
const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0));
|
||||
KV_SERIALIZE(template as<ipv4_network_address>());
|
||||
break;
|
||||
default: MERROR("Unsupported network address type: " << type); return false;
|
||||
}
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
|
||||
{
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
if (epee::string_tools::parse_peer_from_string(ip, port, string))
|
||||
{
|
||||
if (default_port && !port)
|
||||
port = default_port;
|
||||
address.reset(new ipv4_network_address(ip, port));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct connection_context_base
|
||||
{
|
||||
const boost::uuids::uuid m_connection_id;
|
||||
const uint32_t m_remote_ip;
|
||||
const uint32_t m_remote_port;
|
||||
const network_address m_remote_address;
|
||||
const bool m_is_income;
|
||||
const time_t m_started;
|
||||
time_t m_last_recv;
|
||||
@@ -59,12 +163,11 @@ namespace net_utils
|
||||
double m_current_speed_up;
|
||||
|
||||
connection_context_base(boost::uuids::uuid connection_id,
|
||||
long remote_ip, int remote_port, bool is_income,
|
||||
const network_address &remote_address, bool is_income,
|
||||
time_t last_recv = 0, time_t last_send = 0,
|
||||
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
|
||||
m_connection_id(connection_id),
|
||||
m_remote_ip(remote_ip),
|
||||
m_remote_port(remote_port),
|
||||
m_remote_address(remote_address),
|
||||
m_is_income(is_income),
|
||||
m_started(time(NULL)),
|
||||
m_last_recv(last_recv),
|
||||
@@ -76,8 +179,7 @@ namespace net_utils
|
||||
{}
|
||||
|
||||
connection_context_base(): m_connection_id(),
|
||||
m_remote_ip(0),
|
||||
m_remote_port(0),
|
||||
m_remote_address(new ipv4_network_address(0,0)),
|
||||
m_is_income(false),
|
||||
m_started(time(NULL)),
|
||||
m_last_recv(0),
|
||||
@@ -90,17 +192,17 @@ namespace net_utils
|
||||
|
||||
connection_context_base& operator=(const connection_context_base& a)
|
||||
{
|
||||
set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income);
|
||||
set_details(a.m_connection_id, a.m_remote_address, a.m_is_income);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class t_protocol_handler>
|
||||
friend class connection;
|
||||
void set_details(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income)
|
||||
void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income)
|
||||
{
|
||||
this->~connection_context_base();
|
||||
new(this) connection_context_base(connection_id, remote_ip, remote_port, is_income);
|
||||
new(this) connection_context_base(connection_id, remote_address, is_income);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -130,7 +232,7 @@ namespace net_utils
|
||||
std::string print_connection_context(const connection_context_base& ctx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
|
||||
ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -138,24 +240,28 @@ namespace net_utils
|
||||
std::string print_connection_context_short(const connection_context_base& ctx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC":" OUT");
|
||||
ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
#define LOG_PRINT_CC(ct, message, log_level) LOG_PRINT("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_GREEN(ct, message, log_level) LOG_PRINT_GREEN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_RED(ct, message, log_level) LOG_PRINT_RED("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_BLUE(ct, message, log_level) LOG_PRINT_BLUE("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_YELLOW(ct, message, log_level) LOG_PRINT_YELLOW("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_CYAN(ct, message, log_level) LOG_PRINT_CYAN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_PRINT_CC_MAGENTA(ct, message, log_level) LOG_PRINT_MAGENTA("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
||||
#define LOG_ERROR_CC(ct, message) LOG_PRINT_RED("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, LOG_LEVEL_2)
|
||||
inline MAKE_LOGGABLE(connection_context_base, ct, os)
|
||||
{
|
||||
os << "[" << epee::net_utils::print_connection_context_short(ct) << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
#define LOG_PRINT_CC_L0(ct, message) LOG_PRINT_L0("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
|
||||
#define LOG_PRINT_CC_L1(ct, message) LOG_PRINT_L1("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
|
||||
#define LOG_PRINT_CC_L2(ct, message) LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
|
||||
#define LOG_PRINT_CC_L3(ct, message) LOG_PRINT_L3("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
|
||||
#define LOG_PRINT_CC_L4(ct, message) LOG_PRINT_L4("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
|
||||
#define LOG_ERROR_CC(ct, message) MERROR(ct << message)
|
||||
#define LOG_WARNING_CC(ct, message) MWARNING(ct << message)
|
||||
#define LOG_INFO_CC(ct, message) MINFO(ct << message)
|
||||
#define LOG_DEBUG_CC(ct, message) MDEBUG(ct << message)
|
||||
#define LOG_TRACE_CC(ct, message) MTRACE(ct << message)
|
||||
#define LOG_CC(level, ct, message) MLOG(level, ct << message)
|
||||
|
||||
#define LOG_PRINT_CC_L0(ct, message) LOG_PRINT_L0(ct << message)
|
||||
#define LOG_PRINT_CC_L1(ct, message) LOG_PRINT_L1(ct << message)
|
||||
#define LOG_PRINT_CC_L2(ct, message) LOG_PRINT_L2(ct << message)
|
||||
#define LOG_PRINT_CC_L3(ct, message) LOG_PRINT_L3(ct << message)
|
||||
#define LOG_PRINT_CC_L4(ct, message) LOG_PRINT_L4(ct << message)
|
||||
|
||||
#define LOG_PRINT_CCONTEXT_L0(message) LOG_PRINT_CC_L0(context, message)
|
||||
#define LOG_PRINT_CCONTEXT_L1(message) LOG_PRINT_CC_L1(context, message)
|
||||
@@ -163,13 +269,6 @@ namespace net_utils
|
||||
#define LOG_PRINT_CCONTEXT_L3(message) LOG_PRINT_CC_L3(context, message)
|
||||
#define LOG_ERROR_CCONTEXT(message) LOG_ERROR_CC(context, message)
|
||||
|
||||
#define LOG_PRINT_CCONTEXT_GREEN(message, log_level) LOG_PRINT_CC_GREEN(context, message, log_level)
|
||||
#define LOG_PRINT_CCONTEXT_RED(message, log_level) LOG_PRINT_CC_RED(context, message, log_level)
|
||||
#define LOG_PRINT_CCONTEXT_BLUE(message, log_level) LOG_PRINT_CC_BLUE(context, message, log_level)
|
||||
#define LOG_PRINT_CCONTEXT_YELLOW(message, log_level) LOG_PRINT_CC_YELLOW(context, message, log_level)
|
||||
#define LOG_PRINT_CCONTEXT_CYAN(message, log_level) LOG_PRINT_CC_CYAN(context, message, log_level)
|
||||
#define LOG_PRINT_CCONTEXT_MAGENTA(message, log_level) LOG_PRINT_CC_MAGENTA(context, message, log_level)
|
||||
|
||||
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message)
|
||||
|
||||
}
|
||||
|
||||
@@ -52,13 +52,20 @@ namespace epee
|
||||
#endif
|
||||
|
||||
#define START_WAY_POINTS() uint64_t _____way_point_time = epee::misc_utils::get_tick_count();
|
||||
#define WAY_POINT(name) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();}
|
||||
#define WAY_POINT2(name, avrg_obj) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();}
|
||||
#define WAY_POINT(name) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; MDEBUG("Way point " << name << ": " << delta);_____way_point_time = misc_utils::get_tick_count();}
|
||||
#define WAY_POINT2(name, avrg_obj) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); MDEBUG("Way point " << name << ": " << delta);_____way_point_time = misc_utils::get_tick_count();}
|
||||
|
||||
|
||||
#define TIME_MEASURE_START(var_name) uint64_t var_name = epee::misc_utils::get_tick_count();
|
||||
#define TIME_MEASURE_PAUSE(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
|
||||
#define TIME_MEASURE_RESTART(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
|
||||
#define TIME_MEASURE_FINISH(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
|
||||
|
||||
#define TIME_MEASURE_NS_START(var_name) uint64_t var_name = epee::misc_utils::get_ns_count();
|
||||
#define TIME_MEASURE_NS_PAUSE(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
|
||||
#define TIME_MEASURE_NS_RESTART(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
|
||||
#define TIME_MEASURE_NS_FINISH(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
|
||||
|
||||
namespace profile_tools
|
||||
{
|
||||
struct local_call_account
|
||||
@@ -67,7 +74,7 @@ namespace profile_tools
|
||||
{}
|
||||
~local_call_account()
|
||||
{
|
||||
LOG_PRINT2("profile_details.log", "PROFILE "<<m_pname<<":av_time:\t" << (m_count_of_call ? (m_summary_time_used/m_count_of_call):0) <<" sum_time:\t"<<m_summary_time_used<<" call_count:\t" << m_count_of_call, LOG_LEVEL_0);
|
||||
MINFO("PROFILE "<<m_pname<<":av_time:\t" << (m_count_of_call ? (m_summary_time_used/m_count_of_call):0) <<" sum_time:\t"<<m_summary_time_used<<" call_count:\t" << m_count_of_call);
|
||||
}
|
||||
|
||||
size_t m_count_of_call;
|
||||
|
||||
45
contrib/epee/include/readline_buffer.h
Normal file
45
contrib/epee/include/readline_buffer.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace rdln
|
||||
{
|
||||
typedef enum { empty, partial, full } linestatus;
|
||||
class readline_buffer : public std::stringbuf
|
||||
{
|
||||
public:
|
||||
readline_buffer();
|
||||
void start();
|
||||
void stop();
|
||||
bool is_running() const
|
||||
{
|
||||
return m_cout_buf != NULL;
|
||||
}
|
||||
linestatus get_line(std::string& line) const;
|
||||
void set_prompt(const std::string& prompt);
|
||||
static void add_completion(const std::string& command);
|
||||
static const std::vector<std::string>& get_completions();
|
||||
|
||||
protected:
|
||||
virtual int sync();
|
||||
|
||||
private:
|
||||
std::streambuf* m_cout_buf;
|
||||
static std::vector<std::string>& completion_commands();
|
||||
};
|
||||
|
||||
class suspend_readline
|
||||
{
|
||||
public:
|
||||
suspend_readline();
|
||||
~suspend_readline();
|
||||
private:
|
||||
readline_buffer* m_buffer;
|
||||
bool m_restart;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -70,6 +70,15 @@ public: \
|
||||
#define KV_SERIALIZE_N(varialble, val_name) \
|
||||
epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name);
|
||||
|
||||
template<typename T> inline void serialize_default(const T &t, T v) { }
|
||||
template<typename T> inline void serialize_default(T &t, T v) { t = v; }
|
||||
|
||||
#define KV_SERIALIZE_OPT_N(variable, val_name, default_value) \
|
||||
do { \
|
||||
if (!epee::serialization::selector<is_store>::serialize(this_ref.variable, stg, hparent_section, val_name)) \
|
||||
epee::serialize_default(this_ref.variable, default_value); \
|
||||
} while (0);
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
|
||||
epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
|
||||
|
||||
@@ -86,6 +95,7 @@ public: \
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,6 @@ namespace epee
|
||||
static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
if(!container.size()) return true;
|
||||
typename stl_container::const_iterator it = container.begin();
|
||||
std::string mb;
|
||||
mb.resize(sizeof(typename stl_container::value_type)*container.size());
|
||||
typename stl_container::value_type* p_elem = (typename stl_container::value_type*)mb.data();
|
||||
|
||||
130
contrib/epee/include/span.h
Normal file
130
contrib/epee/include/span.h
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
/*!
|
||||
\brief Non-owning sequence of data. Does not deep copy
|
||||
|
||||
Inspired by `gsl::span` and/or `boost::iterator_range`. This class is
|
||||
intended to be used as a parameter type for functions that need to take a
|
||||
writable or read-only sequence of data. Most common cases are `span<char>`
|
||||
and `span<std::uint8_t>`. Using as a class member is only recommended if
|
||||
clearly documented as not doing a deep-copy. C-arrays are easily convertible
|
||||
to this type.
|
||||
|
||||
\note Conversion from C string literal to `span<const char>` will include
|
||||
the NULL-terminator.
|
||||
\note Never allows derived-to-base pointer conversion; an array of derived
|
||||
types is not an array of base types.
|
||||
*/
|
||||
template<typename T>
|
||||
class span
|
||||
{
|
||||
/* Supporting class types is tricky - the {ptr,len} constructor will allow
|
||||
derived-to-base conversions. This is NOT desireable because an array of
|
||||
derived types is not an array of base types. It is possible to handle
|
||||
this case, implement when/if needed. */
|
||||
static_assert(!std::is_class<T>(), "no class types are currently allowed");
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
|
||||
constexpr span() noexcept : ptr(nullptr), len(0) {}
|
||||
constexpr span(std::nullptr_t) noexcept : span() {}
|
||||
|
||||
constexpr span(T* const src_ptr, const std::size_t count) noexcept
|
||||
: ptr(src_ptr), len(count) {}
|
||||
|
||||
//! Conversion from C-array. Prevents common bugs with sizeof + arrays.
|
||||
template<std::size_t N>
|
||||
constexpr span(T (&src)[N]) noexcept : span(src, N) {}
|
||||
|
||||
constexpr span(const span&) noexcept = default;
|
||||
span& operator=(const span&) noexcept = default;
|
||||
|
||||
constexpr iterator begin() const noexcept { return ptr; }
|
||||
constexpr const_iterator cbegin() const noexcept { return ptr; }
|
||||
|
||||
constexpr iterator end() const noexcept { return begin() + size(); }
|
||||
constexpr const_iterator cend() const noexcept { return cbegin() + size(); }
|
||||
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
constexpr pointer data() const noexcept { return ptr; }
|
||||
constexpr std::size_t size() const noexcept { return len; }
|
||||
constexpr std::size_t size_bytes() const noexcept { return size() * sizeof(value_type); }
|
||||
|
||||
private:
|
||||
T* ptr;
|
||||
std::size_t len;
|
||||
};
|
||||
|
||||
//! \return `span<const T::value_type>` from a STL compatible `src`.
|
||||
template<typename T>
|
||||
constexpr span<const typename T::value_type> to_span(const T& src)
|
||||
{
|
||||
// compiler provides diagnostic if size() is not size_t.
|
||||
return {src.data(), src.size()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool has_padding() noexcept
|
||||
{
|
||||
return !std::is_pod<T>() || alignof(T) != 1;
|
||||
}
|
||||
|
||||
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
||||
template<typename T>
|
||||
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
|
||||
{
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
|
||||
}
|
||||
|
||||
//! \return `span<const std::uint8_t>` which represents the bytes at `&src`.
|
||||
template<typename T>
|
||||
span<const std::uint8_t> as_byte_span(const T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "inmemtoxml.h"
|
||||
|
||||
//#include "levin/levin_server.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
class activity_printer_base
|
||||
{
|
||||
public:
|
||||
activity_printer_base(){}
|
||||
virtual ~activity_printer_base(){}
|
||||
};
|
||||
|
||||
template<class A>
|
||||
class notify_activity_printer: public activity_printer_base
|
||||
{
|
||||
public:
|
||||
notify_activity_printer(int level, A& arg, bool is_notify_mode = true):m_ref_arg(arg), m_level(level), m_is_notify_mode(is_notify_mode)
|
||||
{
|
||||
m_command_name = typeid(m_ref_arg).name();
|
||||
m_command_name.erase(0, 7);
|
||||
m_command_name.erase(m_command_name.size()-10, m_command_name.size()-1);
|
||||
if(level == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(m_command_name, level);
|
||||
}
|
||||
else if(level+1 == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(" -->>" << m_command_name, level);
|
||||
}
|
||||
else if(level+2 == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(" -->>" << m_command_name << "\n" << StorageNamed::xml::get_t_as_xml(m_ref_arg), level);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~notify_activity_printer()
|
||||
{
|
||||
if(m_is_notify_mode)
|
||||
{
|
||||
if(m_level+1 == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(" <<--" << m_command_name, m_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected:
|
||||
std::string m_command_name;
|
||||
A& m_ref_arg;
|
||||
int m_level;
|
||||
bool m_is_notify_mode;
|
||||
};
|
||||
|
||||
template<class A, class R>
|
||||
class command_activity_printer: public notify_activity_printer<A>
|
||||
{
|
||||
public:
|
||||
command_activity_printer(int level, A& arg, R& rsp):notify_activity_printer(level, arg, false), m_ref_rsp(rsp)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~command_activity_printer()
|
||||
{
|
||||
if(m_level+1 == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(" <<--" << m_command_name, m_level);
|
||||
}
|
||||
else if(m_level+2 == log_space::get_set_log_detalisation_level())
|
||||
{
|
||||
LOG_PRINT(" <<--" << m_command_name << "\n" << StorageNamed::trace_as_xml(m_ref_rsp), m_level);
|
||||
}
|
||||
}
|
||||
private:
|
||||
R& m_ref_rsp;
|
||||
};
|
||||
|
||||
template<class A, class R>
|
||||
activity_printer_base* create_activity_printer(int level, A& arg, R& rsp)
|
||||
{
|
||||
return new command_activity_printer<A, R>(level, arg, rsp);
|
||||
}
|
||||
|
||||
template<class A>
|
||||
activity_printer_base* create_activity_printer(int level, A& arg)
|
||||
{
|
||||
return new notify_activity_printer<A>(level, arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define PRINT_COMMAND_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct, out_struct));
|
||||
#define PRINT_NOTIFY_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct));
|
||||
|
||||
#define PRINT_ACTIVITY(level) \
|
||||
{std::string some_str = typeid(in_struct).name(); \
|
||||
some_str.erase(0, 7); \
|
||||
some_str.erase(some_str.size()-10, some_str.size()-1); \
|
||||
LOG_PRINT(some_str, level);}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include "portable_storage_template_helper.h"
|
||||
#include "net/http_base.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
@@ -35,28 +38,28 @@ namespace epee
|
||||
namespace net_utils
|
||||
{
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_json(out_struct, req_param))
|
||||
return false;
|
||||
|
||||
const http::http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
if(!pri)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,28 +69,28 @@ namespace epee
|
||||
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_bin_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_binary(out_struct, req_param))
|
||||
return false;
|
||||
|
||||
const http::http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
if(!pri)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -95,15 +98,15 @@ namespace epee
|
||||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_rpc(const std::string& url, const std::string& method_name, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0")
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
{
|
||||
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
|
||||
req_t.jsonrpc = "2.0";
|
||||
req_t.id = req_id;
|
||||
req_t.method = method_name;
|
||||
req_t.method = std::move(method_name);
|
||||
req_t.params = out_struct;
|
||||
epee::json_rpc::response<t_response, epee::json_rpc::error> resp_t = AUTO_VAL_INIT(resp_t);
|
||||
if(!epee::net_utils::invoke_http_json_remote_command2(url, req_t, resp_t, transport, timeout, http_method))
|
||||
if(!epee::net_utils::invoke_http_json(uri, req_t, resp_t, transport, timeout, http_method))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -117,9 +120,9 @@ namespace epee
|
||||
}
|
||||
|
||||
template<class t_command, class t_transport>
|
||||
bool invoke_http_json_rpc(const std::string& url, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0")
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
{
|
||||
return invoke_http_json_rpc(url, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
|
||||
return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include "net/levin_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
@@ -48,7 +51,7 @@ namespace epee
|
||||
int res = transport.invoke(command, buff_to_send, buff_to_recv);
|
||||
if( res <=0 )
|
||||
{
|
||||
LOG_PRINT_RED("Failed to invoke command " << command << " return code " << res, LOG_LEVEL_1);
|
||||
MERROR("Failed to invoke command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
serialization::portable_storage stg_ret;
|
||||
@@ -112,7 +115,7 @@ namespace epee
|
||||
{
|
||||
typename serialization::portable_storage stg;
|
||||
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
|
||||
std::string buff_to_send, buff_to_recv;
|
||||
std::string buff_to_send;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
|
||||
{
|
||||
@@ -148,13 +151,13 @@ namespace epee
|
||||
|
||||
serialization::portable_storage stg;
|
||||
out_struct.store(stg);
|
||||
std::string buff_to_send, buff_to_recv;
|
||||
std::string buff_to_send;
|
||||
stg.store_to_binary(buff_to_send);
|
||||
|
||||
int res = transport.notify(command, buff_to_send, conn_id);
|
||||
if(res <=0 )
|
||||
{
|
||||
LOG_PRINT_RED_L0("Failed to notify command " << command << " return code " << res);
|
||||
MERROR("Failed to notify command " << command << " return code " << res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace epee
|
||||
pbuff->m_signature_b != PORTABLE_STORAGE_SIGNATUREB
|
||||
)
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format - signature missmatch");
|
||||
LOG_ERROR("portable_storage: wrong binary format - signature mismatch");
|
||||
return false;
|
||||
}
|
||||
if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
|
||||
|
||||
@@ -365,12 +365,12 @@ namespace epee
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
LOG_PRINT_RED_L0("Failed to parse json, what: " << ex.what());
|
||||
MERROR("Failed to parse json, what: " << ex.what());
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_PRINT_RED_L0("Failed to parse json");
|
||||
MERROR("Failed to parse json");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#define _STRING_CODING_H_
|
||||
|
||||
#include <string>
|
||||
//#include "md5_l.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace string_encoding
|
||||
@@ -62,23 +62,6 @@ namespace string_encoding
|
||||
(char*)str_trgt.data(), (int)str_trgt.size(), 0, 0);
|
||||
return str_trgt;*/
|
||||
}
|
||||
#ifdef WINDOWS_PLATFORM_EX
|
||||
inline std::string convert_to_ansii_win(const std::wstring& str_from)
|
||||
{
|
||||
|
||||
int code_page = CP_ACP;
|
||||
std::string str_trgt;
|
||||
if(!str_from.size())
|
||||
return str_trgt;
|
||||
int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 );
|
||||
if(!cb)
|
||||
return str_trgt;
|
||||
str_trgt.resize(cb);
|
||||
::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(),
|
||||
(char*)str_trgt.data(), (int)str_trgt.size(), 0, 0);
|
||||
return str_trgt;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::string convert_to_ansii(const std::string& str_from)
|
||||
{
|
||||
@@ -254,41 +237,6 @@ namespace string_encoding
|
||||
return ret;
|
||||
}
|
||||
|
||||
//md5
|
||||
#ifdef MD5_H
|
||||
inline
|
||||
std::string get_buf_as_hex_string(const void* pbuf, size_t len)
|
||||
{
|
||||
std::ostringstream result;
|
||||
|
||||
const unsigned char* p_buff = (const unsigned char*)pbuf;
|
||||
|
||||
for(unsigned int i=0;i<len;i++)
|
||||
{ // convert md to hex-represented string (hex-letters in upper case!)
|
||||
result << std::setw(2) << std::setfill('0')
|
||||
<< std::setbase(16) << std::nouppercase
|
||||
<< (int)*p_buff++;
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
inline
|
||||
std::string get_md5_as_hexstring(const void* pbuff, size_t len)
|
||||
{
|
||||
unsigned char output[16] = {0};
|
||||
md5::md5((unsigned char*)pbuff, static_cast<unsigned int>(len), output);
|
||||
return get_buf_as_hex_string(output, sizeof(output));
|
||||
}
|
||||
|
||||
inline
|
||||
std::string get_md5_as_hexstring(const std::string& src)
|
||||
{
|
||||
return get_md5_as_hexstring(src.data(), src.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,18 +29,22 @@
|
||||
#ifndef _STRING_TOOLS_H_
|
||||
#define _STRING_TOOLS_H_
|
||||
|
||||
//#include <objbase.h>
|
||||
// Previously pulled in by ASIO, further cleanup still required ...
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
//#include <strsafe.h>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "hex.h"
|
||||
#include "span.h"
|
||||
#include "warnings.h"
|
||||
|
||||
|
||||
@@ -56,38 +60,12 @@ namespace epee
|
||||
{
|
||||
namespace string_tools
|
||||
{
|
||||
inline std::wstring get_str_from_guid(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::wstring>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id)
|
||||
{
|
||||
if(str_id.size() < 36)
|
||||
return false;
|
||||
|
||||
if('{' == *str_id.begin())
|
||||
str_id.erase(0, 1);
|
||||
|
||||
if('}' == *(--str_id.end()))
|
||||
str_id.erase(--str_id.end());
|
||||
|
||||
try
|
||||
{
|
||||
inetifer = boost::lexical_cast<boost::uuids::uuid>(str_id);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
|
||||
{
|
||||
std::string local_str_id = str_id;
|
||||
@@ -110,33 +88,10 @@ namespace string_tools
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class CharT>
|
||||
std::basic_string<CharT> buff_to_hex(const std::basic_string<CharT>& s)
|
||||
{
|
||||
using namespace std;
|
||||
basic_stringstream<CharT> hexStream;
|
||||
hexStream << hex << noshowbase << setw(2);
|
||||
|
||||
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
|
||||
{
|
||||
hexStream << "0x"<< static_cast<unsigned int>(static_cast<unsigned char>(*it)) << " ";
|
||||
}
|
||||
return hexStream.str();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class CharT>
|
||||
std::basic_string<CharT> buff_to_hex_nodelimer(const std::basic_string<CharT>& s)
|
||||
inline std::string buff_to_hex_nodelimer(const std::string& src)
|
||||
{
|
||||
using namespace std;
|
||||
basic_stringstream<CharT> hexStream;
|
||||
hexStream << hex << noshowbase;
|
||||
|
||||
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
|
||||
{
|
||||
hexStream << setw(2) << setfill('0') << static_cast<unsigned int>(static_cast<unsigned char>(*it));
|
||||
}
|
||||
return hexStream.str();
|
||||
return to_hex::string(to_byte_span(to_span(src)));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class CharT>
|
||||
@@ -218,22 +173,6 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
return true;
|
||||
}
|
||||
POP_WARNINGS
|
||||
//---------------------------------------------------
|
||||
template<typename int_t>
|
||||
bool get_xnum_from_hex_string(const std::string str, int_t& res )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << str;
|
||||
ss >> res;
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class XType>
|
||||
inline bool xtype_to_string(const XType& val, std::string& str)
|
||||
@@ -249,106 +188,12 @@ POP_WARNINGS
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::string> command_line_params_a;
|
||||
typedef std::map<std::wstring, std::wstring> command_line_params_w;
|
||||
|
||||
template<class t_string>
|
||||
bool parse_commandline(std::map<t_string, t_string>& res, int argc, char** argv)
|
||||
{
|
||||
t_string key;
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(!argv[i])
|
||||
break;
|
||||
t_string s = argv[i];
|
||||
std::string::size_type p = s.find('=');
|
||||
if(std::string::npos == p)
|
||||
{
|
||||
res[s] = "";
|
||||
}else
|
||||
{
|
||||
std::string ss;
|
||||
t_string nm = s.substr(0, p);
|
||||
t_string vl = s.substr(p+1, s.size());
|
||||
res[nm] = vl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* template<typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<std::string, std::string>& res, const std::basic_string<typename t_string::value_type> & key, t_type& val)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
template<class t_string, typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, t_type& val)
|
||||
{
|
||||
typename std::map<t_string, t_string>::const_iterator it = res.find(key);
|
||||
if(it == res.end())
|
||||
return false;
|
||||
|
||||
if(it->second.size())
|
||||
{
|
||||
return get_xtype_from_string(val, it->second);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_string, typename t_type>
|
||||
t_type get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, const t_type& default_value)
|
||||
{
|
||||
typename std::map<t_string, t_string>::const_iterator it = res.find(key);
|
||||
if(it == res.end())
|
||||
return default_value;
|
||||
|
||||
if(it->second.size())
|
||||
{
|
||||
t_type s;
|
||||
get_xtype_from_string(s, it->second);
|
||||
return s;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
template<class t_string>
|
||||
bool have_in_command_line(const std::map<t_string, t_string>& res, const std::basic_string<typename t_string::value_type>& key)
|
||||
{
|
||||
typename std::map<t_string, t_string>::const_iterator it = res.find(key);
|
||||
if(it == res.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//#ifdef _WINSOCK2API_
|
||||
inline std::string get_ip_string_from_int32(uint32_t ip)
|
||||
{
|
||||
in_addr adr;
|
||||
adr.s_addr = ip;
|
||||
const char* pbuf = inet_ntoa(adr);
|
||||
if(pbuf)
|
||||
return pbuf;
|
||||
else
|
||||
return "[failed]";
|
||||
}
|
||||
std::string get_ip_string_from_int32(uint32_t ip);
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str)
|
||||
{
|
||||
ip = inet_addr(ip_str.c_str());
|
||||
if(INADDR_NONE == ip)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str);
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres)
|
||||
inline bool parse_peer_from_string(uint32_t& ip, uint16_t& port, const std::string& addres)
|
||||
{
|
||||
//parse ip and address
|
||||
std::string::size_type p = addres.find(':');
|
||||
@@ -376,17 +221,6 @@ POP_WARNINGS
|
||||
return true;
|
||||
}
|
||||
|
||||
//#endif
|
||||
//----------------------------------------------------------------------------
|
||||
template<typename t>
|
||||
inline std::string get_t_as_hex_nwidth(const t& v, std::streamsize w = 8)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setfill ('0') << std::setw (w) << std::hex << std::noshowbase;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline std::string num_to_string_fast(int64_t val)
|
||||
{
|
||||
/*
|
||||
@@ -396,68 +230,6 @@ POP_WARNINGS
|
||||
return boost::lexical_cast<std::string>(val);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool string_to_num_fast(const std::string& buff, int64_t& val)
|
||||
{
|
||||
//return get_xtype_from_string(val, buff);
|
||||
#if (defined _MSC_VER)
|
||||
val = _atoi64(buff.c_str());
|
||||
#else
|
||||
val = atoll(buff.c_str());
|
||||
#endif
|
||||
/*
|
||||
* val = atoi64(buff.c_str());
|
||||
*/
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool string_to_num_fast(const std::string& buff, int& val)
|
||||
{
|
||||
val = atoi(buff.c_str());
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline std::string system_time_to_string(const SYSTEMTIME& st)
|
||||
{
|
||||
|
||||
/*
|
||||
TIME_ZONE_INFORMATION tzi;
|
||||
GetTimeZoneInformation(&tzi);
|
||||
SystemTimeToTzSpecificLocalTime(&tzi, &stUTC, &stLocal);
|
||||
*/
|
||||
|
||||
char szTime[25], szDate[25];
|
||||
::GetTimeFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
TIME_FORCE24HOURFORMAT, // options
|
||||
&st, // time
|
||||
NULL, // time format string
|
||||
szTime, // formatted string buffer
|
||||
25 // size of string buffer
|
||||
);
|
||||
|
||||
::GetDateFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
NULL, // options
|
||||
&st, // date
|
||||
NULL, // date format
|
||||
szDate, // formatted string buffer
|
||||
25 // size of buffer
|
||||
);
|
||||
szTime[24] = szDate[24] = 0; //be happy :)
|
||||
|
||||
std::string res = szDate;
|
||||
(res += " " )+= szTime;
|
||||
return res;
|
||||
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
inline bool compare_no_case(const std::string& str1, const std::string& str2)
|
||||
{
|
||||
@@ -465,33 +237,6 @@ POP_WARNINGS
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool compare_no_case(const std::wstring& str1, const std::wstring& str2)
|
||||
{
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool is_match_prefix(const std::string& str1, const std::string& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& get_current_module_name()
|
||||
{
|
||||
static std::string module_name;
|
||||
@@ -569,13 +314,23 @@ POP_WARNINGS
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false)
|
||||
{
|
||||
if (s.size() < n)
|
||||
{
|
||||
if (prepend)
|
||||
s = std::string(n - s.size(), c) + s;
|
||||
else
|
||||
s.append(n - s.size(), c);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class t_pod_type>
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
|
||||
std::string buff;
|
||||
buff.assign(reinterpret_cast<const char*>(&s), sizeof(s));
|
||||
return buff_to_hex_nodelimer(buff);
|
||||
return to_hex::string(as_byte_span(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class t_pod_type>
|
||||
@@ -606,20 +361,6 @@ POP_WARNINGS
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_filename_from_path(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('\\');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
inline std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
@@ -630,127 +371,6 @@ POP_WARNINGS
|
||||
res = str.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WININET_
|
||||
inline std::string get_string_from_systemtime(const SYSTEMTIME& sys_time)
|
||||
{
|
||||
std::string result_string;
|
||||
|
||||
char buff[100] = {0};
|
||||
BOOL res = ::InternetTimeFromSystemTimeA(&sys_time, INTERNET_RFC1123_FORMAT, buff, 99);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime to string");
|
||||
}
|
||||
|
||||
result_string = buff;
|
||||
return result_string;
|
||||
|
||||
}
|
||||
//-------------------------------------------------------------------------------------
|
||||
inline SYSTEMTIME get_systemtime_from_string(const std::string& buff)
|
||||
{
|
||||
SYSTEMTIME result_time = {0};
|
||||
|
||||
BOOL res = ::InternetTimeToSystemTimeA(buff.c_str(), &result_time, NULL);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime from string " << buff << "interval set to 15 minutes");
|
||||
}
|
||||
|
||||
return result_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
static const DWORD INFO_BUFFER_SIZE = 10000;
|
||||
|
||||
static const wchar_t* get_pc_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetComputerNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static const wchar_t* get_user_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetUserNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LM_
|
||||
static const wchar_t* get_domain_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = 0;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
LPWSTR domain( NULL );
|
||||
NETSETUP_JOIN_STATUS status;
|
||||
info[0] = 0;
|
||||
|
||||
if (NET_API_STATUS result = NetGetJoinInformation( NULL, &domain, &status ))
|
||||
{
|
||||
LOG_ERROR("get_domain_name error: " << log_space::get_win32_err_descr(result));
|
||||
} else
|
||||
{
|
||||
StringCchCopyW( info, sizeof(info)/sizeof( info[0] ), domain );
|
||||
NetApiBufferFree((void*)domain);
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline
|
||||
std::string load_resource_string_a(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
char buff[2000] = {0};
|
||||
|
||||
::LoadStringA( h, id, buff, sizeof(buff));
|
||||
buff[sizeof(buff)-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
inline
|
||||
std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
wchar_t buff[2000] = {0};
|
||||
|
||||
::LoadStringW( h, id, buff, sizeof(buff) / sizeof( buff[0] ) );
|
||||
buff[(sizeof(buff)/sizeof(buff[0]))-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif //_STRING_TOOLS_H_
|
||||
|
||||
52
contrib/epee/src/CMakeLists.txt
Normal file
52
contrib/epee/src/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
# permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
# conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
# of conditions and the following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (USE_READLINE AND GNU_READLINE_FOUND)
|
||||
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp readline_buffer.cpp)
|
||||
else()
|
||||
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp)
|
||||
endif()
|
||||
|
||||
# Build and install libepee if we're building for GUI
|
||||
if (BUILD_GUI_DEPS)
|
||||
if(IOS)
|
||||
set(lib_folder lib-${ARCH})
|
||||
else()
|
||||
set(lib_folder lib)
|
||||
endif()
|
||||
install(TARGETS epee
|
||||
ARCHIVE DESTINATION ${lib_folder})
|
||||
endif()
|
||||
|
||||
target_link_libraries(epee
|
||||
PUBLIC
|
||||
cncrypto
|
||||
easylogging
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
82
contrib/epee/src/hex.cpp
Normal file
82
contrib/epee/src/hex.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "hex.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void write_hex(T&& out, const span<const std::uint8_t> src)
|
||||
{
|
||||
static constexpr const char hex[] = u8"0123456789abcdef";
|
||||
static_assert(sizeof(hex) == 17, "bad string size");
|
||||
for (const std::uint8_t byte : src)
|
||||
{
|
||||
*out = hex[byte >> 4];
|
||||
++out;
|
||||
*out = hex[byte & 0x0F];
|
||||
++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_hex::string(const span<const std::uint8_t> src)
|
||||
{
|
||||
if (std::numeric_limits<std::size_t>::max() / 2 < src.size())
|
||||
throw std::range_error("hex_view::to_string exceeded maximum size");
|
||||
|
||||
std::string out{};
|
||||
out.resize(src.size() * 2);
|
||||
buffer_unchecked(std::addressof(out[0]), src);
|
||||
return out;
|
||||
}
|
||||
|
||||
void to_hex::buffer(std::ostream& out, const span<const std::uint8_t> src)
|
||||
{
|
||||
write_hex(std::ostreambuf_iterator<char>{out}, src);
|
||||
}
|
||||
|
||||
void to_hex::formatted(std::ostream& out, const span<const std::uint8_t> src)
|
||||
{
|
||||
out.put('<');
|
||||
buffer(out, src);
|
||||
out.put('>');
|
||||
}
|
||||
|
||||
void to_hex::buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept
|
||||
{
|
||||
return write_hex(out, src);
|
||||
}
|
||||
}
|
||||
778
contrib/epee/src/http_auth.cpp
Normal file
778
contrib/epee/src/http_auth.cpp
Normal file
@@ -0,0 +1,778 @@
|
||||
// Copyright (c) 2014-2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "net/http_auth.h"
|
||||
|
||||
#include <array>
|
||||
#include <boost/algorithm/string/find_iterator.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/fusion/adapted/std_tuple.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/iter_fold.hpp>
|
||||
#include <boost/fusion/algorithm/query/any.hpp>
|
||||
#include <boost/fusion/iterator/distance.hpp>
|
||||
#include <boost/fusion/iterator/value_of.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/begin.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/size.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <boost/range/algorithm/find_if.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/range/join.hpp>
|
||||
#include <boost/spirit/include/karma_generate.hpp>
|
||||
#include <boost/spirit/include/karma_uint.hpp>
|
||||
#include <boost/spirit/include/qi_alternative.hpp>
|
||||
#include <boost/spirit/include/qi_and_predicate.hpp>
|
||||
#include <boost/spirit/include/qi_char.hpp>
|
||||
#include <boost/spirit/include/qi_char_class.hpp>
|
||||
#include <boost/spirit/include/qi_difference.hpp>
|
||||
#include <boost/spirit/include/qi_kleene.hpp>
|
||||
#include <boost/spirit/include/qi_parse.hpp>
|
||||
#include <boost/spirit/include/qi_plus.hpp>
|
||||
#include <boost/spirit/include/qi_no_case.hpp>
|
||||
#include <boost/spirit/include/qi_not_predicate.hpp>
|
||||
#include <boost/spirit/include/qi_raw.hpp>
|
||||
#include <boost/spirit/include/qi_rule.hpp>
|
||||
#include <boost/spirit/include/qi_sequence.hpp>
|
||||
#include <boost/spirit/include/qi_string.hpp>
|
||||
#include <boost/spirit/include/qi_symbols.hpp>
|
||||
#include <boost/spirit/include/qi_uint.hpp>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "hex.h"
|
||||
#include "md5_l.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
/* This file uses the `u8` prefix and specifies all chars by ASCII numeric
|
||||
value. This is for maximum portability - C++ does not actually specify ASCII
|
||||
as the encoding type for unprefixed string literals, etc. Although rare, the
|
||||
effort required to support rare compiler encoding types is low.
|
||||
|
||||
Also be careful of qi::ascii character classes (`qi::asci::alpha`, etc.) -
|
||||
non-ASCII characters will cause undefined behavior in the table lookup until
|
||||
boost 1.60. The expression `&qi::ascii::char_` will fail on non-ASCII
|
||||
characters without "consuming" the input character. */
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace http = epee::net_utils::http;
|
||||
|
||||
// string_ref is only constexpr if length is given
|
||||
template<std::size_t N>
|
||||
constexpr boost::string_ref ceref(const char (&arg)[N])
|
||||
{
|
||||
return boost::string_ref(arg, N - 1);
|
||||
}
|
||||
|
||||
constexpr const auto client_auth_field = ceref(u8"Authorization");
|
||||
constexpr const auto server_auth_field = ceref(u8"WWW-authenticate");
|
||||
constexpr const auto auth_realm = ceref(u8"monero-rpc");
|
||||
constexpr const char comma = 44;
|
||||
constexpr const char equal_sign = 61;
|
||||
constexpr const char quote = 34;
|
||||
constexpr const char zero = 48;
|
||||
constexpr const auto sess_algo = ceref(u8"-sess");
|
||||
|
||||
constexpr const unsigned client_reserve_size = 512; //!< std::string::reserve size for clients
|
||||
|
||||
//// Digest Algorithms
|
||||
|
||||
struct md5_
|
||||
{
|
||||
static constexpr const boost::string_ref name = ceref(u8"MD5");
|
||||
|
||||
struct update
|
||||
{
|
||||
template<typename T>
|
||||
void operator()(const T& arg) const
|
||||
{
|
||||
const boost::iterator_range<const char*> data(boost::as_literal(arg));
|
||||
md5::MD5Update(
|
||||
std::addressof(ctx),
|
||||
reinterpret_cast<const std::uint8_t*>(data.begin()),
|
||||
data.size()
|
||||
);
|
||||
}
|
||||
void operator()(const std::string& arg) const
|
||||
{
|
||||
(*this)(boost::string_ref(arg));
|
||||
}
|
||||
|
||||
md5::MD5_CTX& ctx;
|
||||
};
|
||||
|
||||
template<typename... T>
|
||||
std::array<char, 32> operator()(const T&... args) const
|
||||
{
|
||||
md5::MD5_CTX ctx{};
|
||||
md5::MD5Init(std::addressof(ctx));
|
||||
boost::fusion::for_each(std::tie(args...), update{ctx});
|
||||
|
||||
std::array<std::uint8_t, 16> digest{{}};
|
||||
md5::MD5Final(digest.data(), std::addressof(ctx));
|
||||
return epee::to_hex::array(digest);
|
||||
}
|
||||
};
|
||||
constexpr const boost::string_ref md5_::name;
|
||||
|
||||
//! Digest Algorithms available for HTTP Digest Auth. Sort better algos to the left
|
||||
constexpr const std::tuple<md5_> digest_algorithms{};
|
||||
|
||||
//// Various String Utilities
|
||||
|
||||
struct ascii_tolower_
|
||||
{
|
||||
template<typename Char>
|
||||
constexpr Char operator()(Char value) const noexcept
|
||||
{
|
||||
static_assert(std::is_integral<Char>::value, "only integral types supported");
|
||||
return (65 <= value && value <= 90) ? (value + 32) : value;
|
||||
}
|
||||
};
|
||||
constexpr const ascii_tolower_ ascii_tolower{};
|
||||
|
||||
struct ascii_iequal_
|
||||
{
|
||||
template<typename Char>
|
||||
constexpr bool operator()(Char left, Char right) const noexcept
|
||||
{
|
||||
return ascii_tolower(left) == ascii_tolower(right);
|
||||
}
|
||||
};
|
||||
constexpr const ascii_iequal_ ascii_iequal{};
|
||||
|
||||
struct http_list_separator_
|
||||
{
|
||||
template<typename Char>
|
||||
bool operator()(Char value) const noexcept
|
||||
{
|
||||
static_assert(std::is_integral<Char>::value, "only integral types supported");
|
||||
return boost::spirit::char_encoding::ascii::isascii_(value) &&
|
||||
(value == comma || boost::spirit::char_encoding::ascii::isspace(value));
|
||||
}
|
||||
};
|
||||
constexpr const http_list_separator_ http_list_separator{};
|
||||
|
||||
std::string to_string(boost::iterator_range<const char*> source)
|
||||
{
|
||||
return {source.begin(), source.size()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add_first_field(std::string& str, const char* const name, const T& value)
|
||||
{
|
||||
str.append(name);
|
||||
str.push_back(equal_sign);
|
||||
boost::copy(value, std::back_inserter(str));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add_field(std::string& str, const char* const name, const T& value)
|
||||
{
|
||||
str.push_back(comma);
|
||||
add_first_field(str, name, value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
using quoted_result = boost::joined_range<
|
||||
const boost::joined_range<const boost::string_ref, const T>, const boost::string_ref
|
||||
>;
|
||||
|
||||
template<typename T>
|
||||
quoted_result<T> quoted(const T& arg)
|
||||
{
|
||||
return boost::range::join(boost::range::join(ceref(u8"\""), arg), ceref(u8"\""));
|
||||
}
|
||||
|
||||
//// Digest Authentication
|
||||
|
||||
template<typename Digest>
|
||||
typename std::result_of<Digest()>::type generate_a1(
|
||||
Digest digest, const http::login& creds, const boost::string_ref realm)
|
||||
{
|
||||
return digest(creds.username, u8":", realm, u8":", creds.password);
|
||||
}
|
||||
|
||||
template<typename Digest>
|
||||
typename std::result_of<Digest()>::type generate_a1(
|
||||
Digest digest, const http::http_client_auth::session& user)
|
||||
{
|
||||
return generate_a1(std::move(digest), user.credentials, user.server.realm);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void init_client_value(std::string& str,
|
||||
const boost::string_ref algorithm, const http::http_client_auth::session& user,
|
||||
const boost::string_ref uri, const T& response)
|
||||
{
|
||||
str.append(u8"Digest ");
|
||||
add_first_field(str, u8"algorithm", algorithm);
|
||||
add_field(str, u8"nonce", quoted(user.server.nonce));
|
||||
add_field(str, u8"realm", quoted(user.server.realm));
|
||||
add_field(str, u8"response", quoted(response));
|
||||
add_field(str, u8"uri", quoted(uri));
|
||||
add_field(str, u8"username", quoted(user.credentials.username));
|
||||
if (!user.server.opaque.empty())
|
||||
add_field(str, u8"opaque", quoted(user.server.opaque));
|
||||
}
|
||||
|
||||
//! Implements superseded algorithm specified in RFC 2069
|
||||
template<typename Digest>
|
||||
struct old_algorithm
|
||||
{
|
||||
explicit old_algorithm(Digest digest_) : digest(std::move(digest_)) {}
|
||||
|
||||
std::string operator()(const http::http_client_auth::session& user,
|
||||
const boost::string_ref method, const boost::string_ref uri) const
|
||||
{
|
||||
const auto response = digest(
|
||||
generate_a1(digest, user), u8":", user.server.nonce, u8":", digest(method, u8":", uri)
|
||||
);
|
||||
std::string out{};
|
||||
out.reserve(client_reserve_size);
|
||||
init_client_value(out, Digest::name, user, uri, response);
|
||||
return out;
|
||||
}
|
||||
private:
|
||||
Digest digest;
|
||||
};
|
||||
|
||||
//! Implements the `qop=auth` algorithm specified in RFC 2617
|
||||
template<typename Digest>
|
||||
struct auth_algorithm
|
||||
{
|
||||
explicit auth_algorithm(Digest digest_) : digest(std::move(digest_)) {}
|
||||
|
||||
std::string operator()(const http::http_client_auth::session& user,
|
||||
const boost::string_ref method, const boost::string_ref uri) const
|
||||
{
|
||||
namespace karma = boost::spirit::karma;
|
||||
using counter_type = decltype(user.counter);
|
||||
static_assert(
|
||||
std::numeric_limits<counter_type>::radix == 2, "unexpected radix for counter"
|
||||
);
|
||||
static_assert(
|
||||
std::numeric_limits<counter_type>::digits <= 32,
|
||||
"number of digits will cause underflow on padding below"
|
||||
);
|
||||
|
||||
std::string out{};
|
||||
out.reserve(client_reserve_size);
|
||||
|
||||
karma::generate(std::back_inserter(out), karma::hex(user.counter));
|
||||
out.insert(out.begin(), 8 - out.size(), zero); // zero left pad
|
||||
if (out.size() != 8)
|
||||
return {};
|
||||
|
||||
std::array<char, 8> nc{{}};
|
||||
boost::copy(out, nc.data());
|
||||
const auto response = digest(
|
||||
generate_a1(digest, user), u8":", user.server.nonce, u8":", nc, u8"::auth:", digest(method, u8":", uri)
|
||||
);
|
||||
out.clear();
|
||||
init_client_value(out, Digest::name, user, uri, response);
|
||||
add_field(out, u8"qop", ceref(u8"auth"));
|
||||
add_field(out, u8"nc", nc);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
Digest digest;
|
||||
};
|
||||
|
||||
//! Processes client "Authorization" and server "WWW-authenticate" HTTP fields
|
||||
struct auth_message
|
||||
{
|
||||
using iterator = const char*;
|
||||
enum status{ kFail = 0, kStale, kPass };
|
||||
|
||||
//! \return Status of the `response` field from the client
|
||||
static status verify(const boost::string_ref method, const boost::string_ref request,
|
||||
const http::http_server_auth::session& user)
|
||||
{
|
||||
const auto parsed = parse(request);
|
||||
if (parsed &&
|
||||
boost::equals(parsed->username, user.credentials.username) &&
|
||||
boost::fusion::any(digest_algorithms, has_valid_response{*parsed, user, method}))
|
||||
{
|
||||
if (boost::equals(parsed->nonce, user.nonce))
|
||||
{
|
||||
// RFC 2069 format does not verify nc value - allow just once
|
||||
if (user.counter == 1 || (!parsed->qop.empty() && parsed->counter() == user.counter))
|
||||
{
|
||||
return kPass;
|
||||
}
|
||||
}
|
||||
return kStale;
|
||||
}
|
||||
return kFail;
|
||||
}
|
||||
|
||||
//! \return Information needed to generate client authentication `response`s.
|
||||
static http::http_client_auth::session::keys extract(
|
||||
const http::http_response_info& response, const bool is_first)
|
||||
{
|
||||
using field = std::pair<std::string, std::string>;
|
||||
|
||||
server_parameters best{};
|
||||
|
||||
const std::list<field>& fields = response.m_header_info.m_etc_fields;
|
||||
auto current = fields.begin();
|
||||
const auto end = fields.end();
|
||||
while (true)
|
||||
{
|
||||
current = std::find_if(current, end, [] (const field& value) {
|
||||
return boost::equals(server_auth_field, value.first, ascii_iequal);
|
||||
});
|
||||
if (current == end)
|
||||
break;
|
||||
|
||||
const auto parsed = parse(current->second);
|
||||
if (parsed)
|
||||
{
|
||||
server_parameters local_best = parsed->algorithm.empty() ?
|
||||
server_parameters{*parsed, boost::fusion::find<md5_>(digest_algorithms)} :
|
||||
boost::fusion::iter_fold(digest_algorithms, server_parameters{}, matches_algorithm{*parsed});
|
||||
|
||||
if (local_best.index < best.index)
|
||||
best = std::move(local_best);
|
||||
}
|
||||
++current;
|
||||
}
|
||||
if (is_first || boost::equals(best.stale, ceref(u8"true"), ascii_iequal))
|
||||
return best.take();
|
||||
return {}; // authentication failed with bad user/pass
|
||||
}
|
||||
|
||||
private:
|
||||
explicit auth_message()
|
||||
: algorithm()
|
||||
, cnonce()
|
||||
, nc()
|
||||
, nonce()
|
||||
, qop()
|
||||
, realm()
|
||||
, response()
|
||||
, stale()
|
||||
, uri()
|
||||
, username() {
|
||||
}
|
||||
|
||||
static boost::optional<auth_message> parse(const boost::string_ref request)
|
||||
{
|
||||
struct parser
|
||||
{
|
||||
using field_parser = std::function<bool(const parser&, iterator&, iterator, auth_message&)>;
|
||||
|
||||
explicit parser() : field_table(), skip_whitespace(), header(), quoted_string(), token(), fields() {
|
||||
using namespace std::placeholders;
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
struct parse_nc
|
||||
{
|
||||
bool operator()(const parser&, iterator& current, const iterator end, auth_message& result) const
|
||||
{
|
||||
return qi::parse(
|
||||
current, end,
|
||||
(qi::raw[qi::uint_parser<std::uint32_t, 16, 8, 8>{}]),
|
||||
result.nc
|
||||
);
|
||||
}
|
||||
};
|
||||
struct parse_token
|
||||
{
|
||||
bool operator()(const parser& parse, iterator& current, const iterator end,
|
||||
boost::iterator_range<iterator>& result) const
|
||||
{
|
||||
return qi::parse(current, end, parse.token, result);
|
||||
}
|
||||
};
|
||||
struct parse_string
|
||||
{
|
||||
bool operator()(const parser& parse, iterator& current, const iterator end,
|
||||
boost::iterator_range<iterator>& result) const
|
||||
{
|
||||
return qi::parse(current, end, parse.quoted_string, result);
|
||||
}
|
||||
bool operator()(const parser& parse, iterator& current, const iterator end) const
|
||||
{
|
||||
return qi::parse(current, end, parse.quoted_string);
|
||||
}
|
||||
};
|
||||
struct parse_response
|
||||
{
|
||||
bool operator()(const parser&, iterator& current, const iterator end, auth_message& result) const
|
||||
{
|
||||
using byte = qi::uint_parser<std::uint8_t, 16, 2, 2>;
|
||||
return qi::parse(
|
||||
current, end,
|
||||
(qi::lit(quote) >> qi::raw[+(byte{})] >> qi::lit(quote)),
|
||||
result.response
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
field_table.add
|
||||
(u8"algorithm", std::bind(parse_token{}, _1, _2, _3, std::bind(&auth_message::algorithm, _4)))
|
||||
(u8"cnonce", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::cnonce, _4)))
|
||||
(u8"domain", std::bind(parse_string{}, _1, _2, _3)) // ignore field
|
||||
(u8"nc", parse_nc{})
|
||||
(u8"nonce", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::nonce, _4)))
|
||||
(u8"opaque", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::opaque, _4)))
|
||||
(u8"qop", std::bind(parse_token{}, _1, _2, _3, std::bind(&auth_message::qop, _4)))
|
||||
(u8"realm", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::realm, _4)))
|
||||
(u8"response", parse_response{})
|
||||
(u8"stale", std::bind(parse_token{}, _1, _2, _3, std::bind(&auth_message::stale, _4)))
|
||||
(u8"uri", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::uri, _4)))
|
||||
(u8"username", std::bind(parse_string{}, _1, _2, _3, std::bind(&auth_message::username, _4)));
|
||||
|
||||
skip_whitespace = *(&qi::ascii::char_ >> qi::ascii::space);
|
||||
header = skip_whitespace >> qi::ascii::no_case[u8"digest"] >> skip_whitespace;
|
||||
quoted_string = (qi::lit(quote) >> qi::raw[+(u8"\\\"" | (qi::ascii::char_ - quote))] >> qi::lit(quote));
|
||||
token =
|
||||
(!qi::lit(quote) >> qi::raw[+(&qi::ascii::char_ >> (qi::ascii::graph - qi::ascii::char_(u8"()<>@,;:\\\"/[]?={}")))]) |
|
||||
quoted_string;
|
||||
fields = field_table >> skip_whitespace >> equal_sign >> skip_whitespace;
|
||||
}
|
||||
|
||||
boost::optional<auth_message> operator()(const boost::string_ref request) const
|
||||
{
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
iterator current = request.begin();
|
||||
const iterator end = request.end();
|
||||
|
||||
if (!qi::parse(current, end, header))
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
auth_message info{};
|
||||
field_parser null_parser{};
|
||||
std::reference_wrapper<const field_parser> field = null_parser;
|
||||
|
||||
do // require at least one field; require field after `,` character
|
||||
{
|
||||
if (!qi::parse(current, end, fields, field) || !field(*this, current, end, info))
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
qi::parse(current, end, skip_whitespace);
|
||||
} while (qi::parse(current, end, qi::char_(comma) >> skip_whitespace));
|
||||
return boost::make_optional(current == end, info);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::spirit::qi::symbols<
|
||||
char, field_parser, boost::spirit::qi::tst<char, field_parser>, ascii_tolower_
|
||||
> field_table;
|
||||
boost::spirit::qi::rule<iterator> skip_whitespace;
|
||||
boost::spirit::qi::rule<iterator> header;
|
||||
boost::spirit::qi::rule<iterator, boost::iterator_range<iterator>()> quoted_string;
|
||||
boost::spirit::qi::rule<iterator, boost::iterator_range<iterator>()> token;
|
||||
boost::spirit::qi::rule<iterator, std::reference_wrapper<const field_parser>()> fields;
|
||||
}; // parser
|
||||
|
||||
static const parser parse_;
|
||||
return parse_(request);
|
||||
}
|
||||
|
||||
struct has_valid_response
|
||||
{
|
||||
template<typename Digest, typename Result>
|
||||
Result generate_old_response(Digest digest, const Result& key, const Result& auth) const
|
||||
{
|
||||
return digest(key, u8":", request.nonce, u8":", auth);
|
||||
}
|
||||
|
||||
template<typename Digest, typename Result>
|
||||
Result generate_new_response(Digest digest, const Result& key, const Result& auth) const
|
||||
{
|
||||
return digest(
|
||||
key, u8":", request.nonce, u8":", request.nc, u8":", request.cnonce, u8":", request.qop, u8":", auth
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Result>
|
||||
bool check(const Result& result) const
|
||||
{
|
||||
return boost::equals(request.response, result, ascii_iequal);
|
||||
}
|
||||
|
||||
template<typename Digest>
|
||||
bool operator()(const Digest& digest) const
|
||||
{
|
||||
if (boost::starts_with(request.algorithm, Digest::name, ascii_iequal) ||
|
||||
(request.algorithm.empty() && std::is_same<md5_, Digest>::value))
|
||||
{
|
||||
auto key = generate_a1(digest, user.credentials, auth_realm);
|
||||
if (boost::ends_with(request.algorithm, sess_algo, ascii_iequal))
|
||||
{
|
||||
key = digest(key, u8":", request.nonce, u8":", request.cnonce);
|
||||
}
|
||||
|
||||
auto auth = digest(method, u8":", request.uri);
|
||||
if (request.qop.empty())
|
||||
{
|
||||
return check(generate_old_response(std::move(digest), std::move(key), std::move(auth)));
|
||||
}
|
||||
else if (boost::equals(ceref(u8"auth"), request.qop, ascii_iequal))
|
||||
{
|
||||
return check(generate_new_response(std::move(digest), std::move(key), std::move(auth)));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const auth_message& request;
|
||||
const http::http_server_auth::session& user;
|
||||
const boost::string_ref method;
|
||||
};
|
||||
|
||||
boost::optional<std::uint32_t> counter() const
|
||||
{
|
||||
namespace qi = boost::spirit::qi;
|
||||
using hex = qi::uint_parser<std::uint32_t, 16>;
|
||||
std::uint32_t value = 0;
|
||||
const bool converted = qi::parse(nc.begin(), nc.end(), hex{}, value);
|
||||
return boost::make_optional(converted, value);
|
||||
}
|
||||
|
||||
struct server_parameters
|
||||
{
|
||||
server_parameters()
|
||||
: nonce(), opaque(), realm(), stale(), value_generator()
|
||||
, index(boost::fusion::size(digest_algorithms))
|
||||
{}
|
||||
|
||||
template<typename DigestIter>
|
||||
explicit server_parameters(const auth_message& request, const DigestIter& digest)
|
||||
: nonce(request.nonce)
|
||||
, opaque(request.opaque)
|
||||
, stale(request.stale)
|
||||
, realm(request.realm)
|
||||
, value_generator()
|
||||
, index(boost::fusion::distance(boost::fusion::begin(digest_algorithms), digest))
|
||||
{
|
||||
using digest_type = typename boost::fusion::result_of::value_of<DigestIter>::type;
|
||||
|
||||
// debug check internal state of the auth_message class
|
||||
assert(
|
||||
(std::is_same<digest_type, md5_>::value) ||
|
||||
boost::equals((*digest).name, request.algorithm, ascii_iequal)
|
||||
);
|
||||
if (request.qop.empty())
|
||||
value_generator = old_algorithm<digest_type>{*digest};
|
||||
else
|
||||
{
|
||||
for (auto elem = boost::make_split_iterator(request.qop, boost::token_finder(http_list_separator));
|
||||
!elem.eof();
|
||||
++elem)
|
||||
{
|
||||
if (boost::equals(ceref(u8"auth"), *elem, ascii_iequal))
|
||||
{
|
||||
value_generator = auth_algorithm<digest_type>{*digest};
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!value_generator) // no supported qop mode
|
||||
index = boost::fusion::size(digest_algorithms);
|
||||
}
|
||||
}
|
||||
|
||||
http::http_client_auth::session::keys take()
|
||||
{
|
||||
return {to_string(nonce), to_string(opaque), to_string(realm), std::move(value_generator)};
|
||||
}
|
||||
|
||||
boost::iterator_range<iterator> nonce;
|
||||
boost::iterator_range<iterator> opaque;
|
||||
boost::iterator_range<iterator> realm;
|
||||
boost::iterator_range<iterator> stale;
|
||||
http::http_client_auth::session::keys::algorithm value_generator;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
struct matches_algorithm
|
||||
{
|
||||
template<typename DigestIter>
|
||||
server_parameters operator()(server_parameters current, const DigestIter& digest) const
|
||||
{
|
||||
if (!current.value_generator)
|
||||
{
|
||||
if (boost::equals(response.algorithm, (*digest).name, ascii_iequal))
|
||||
{
|
||||
current = server_parameters{response, digest};
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
const auth_message& response;
|
||||
};
|
||||
|
||||
|
||||
boost::iterator_range<iterator> algorithm;
|
||||
boost::iterator_range<iterator> cnonce;
|
||||
boost::iterator_range<iterator> nc;
|
||||
boost::iterator_range<iterator> nonce;
|
||||
boost::iterator_range<iterator> opaque;
|
||||
boost::iterator_range<iterator> qop;
|
||||
boost::iterator_range<iterator> realm;
|
||||
boost::iterator_range<iterator> response;
|
||||
boost::iterator_range<iterator> stale;
|
||||
boost::iterator_range<iterator> uri;
|
||||
boost::iterator_range<iterator> username;
|
||||
}; // auth_message
|
||||
|
||||
struct add_challenge
|
||||
{
|
||||
template<typename Digest>
|
||||
void operator()(const Digest& digest) const
|
||||
{
|
||||
static constexpr const auto fvalue = ceref(u8"Digest qop=\"auth\"");
|
||||
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
{
|
||||
std::string out(fvalue);
|
||||
|
||||
const auto algorithm = boost::range::join(
|
||||
Digest::name, (i == 0 ? boost::string_ref{} : sess_algo)
|
||||
);
|
||||
add_field(out, u8"algorithm", algorithm);
|
||||
add_field(out, u8"realm", quoted(auth_realm));
|
||||
add_field(out, u8"nonce", quoted(nonce));
|
||||
add_field(out, u8"stale", is_stale ? ceref("true") : ceref("false"));
|
||||
|
||||
fields.push_back(std::make_pair(std::string(server_auth_field), std::move(out)));
|
||||
}
|
||||
}
|
||||
|
||||
const boost::string_ref nonce;
|
||||
std::list<std::pair<std::string, std::string>>& fields;
|
||||
const bool is_stale;
|
||||
};
|
||||
|
||||
http::http_response_info create_digest_response(const boost::string_ref nonce, const bool is_stale)
|
||||
{
|
||||
epee::net_utils::http::http_response_info rc{};
|
||||
rc.m_response_code = 401;
|
||||
rc.m_response_comment = u8"Unauthorized";
|
||||
rc.m_mime_tipe = u8"text/html";
|
||||
rc.m_body =
|
||||
u8"<html><head><title>Unauthorized Access</title></head><body><h1>401 Unauthorized</h1></body></html>";
|
||||
|
||||
boost::fusion::for_each(
|
||||
digest_algorithms, add_challenge{nonce, rc.m_additional_fields, is_stale}
|
||||
);
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
http_server_auth::http_server_auth(login credentials)
|
||||
: user(session{std::move(credentials)}) {
|
||||
}
|
||||
|
||||
boost::optional<http_response_info> http_server_auth::do_get_response(const http_request_info& request)
|
||||
{
|
||||
assert(user);
|
||||
using field = std::pair<std::string, std::string>;
|
||||
|
||||
const std::list<field>& fields = request.m_header_info.m_etc_fields;
|
||||
const auto auth = boost::find_if(fields, [] (const field& value) {
|
||||
return boost::equals(client_auth_field, value.first, ascii_iequal);
|
||||
});
|
||||
|
||||
bool is_stale = false;
|
||||
if (auth != fields.end())
|
||||
{
|
||||
++(user->counter);
|
||||
switch (auth_message::verify(request.m_http_method_str, auth->second, *user))
|
||||
{
|
||||
case auth_message::kPass:
|
||||
return boost::none;
|
||||
|
||||
case auth_message::kStale:
|
||||
is_stale = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case auth_message::kFail:
|
||||
break;
|
||||
}
|
||||
}
|
||||
user->counter = 0;
|
||||
{
|
||||
std::array<std::uint8_t, 16> rand_128bit{{}};
|
||||
crypto::rand(rand_128bit.size(), rand_128bit.data());
|
||||
user->nonce = string_encoding::base64_encode(rand_128bit.data(), rand_128bit.size());
|
||||
}
|
||||
return create_digest_response(user->nonce, is_stale);
|
||||
}
|
||||
|
||||
http_client_auth::http_client_auth(login credentials)
|
||||
: user(session{std::move(credentials)}) {
|
||||
}
|
||||
|
||||
http_client_auth::status http_client_auth::do_handle_401(const http_response_info& response)
|
||||
{
|
||||
assert(user);
|
||||
const bool first_auth = (user->counter == 0);
|
||||
user->server = auth_message::extract(response, first_auth);
|
||||
if (user->server.generator)
|
||||
{
|
||||
user->counter = 0;
|
||||
return kSuccess;
|
||||
}
|
||||
return first_auth ? kParseFailure : kBadPassword;
|
||||
}
|
||||
|
||||
boost::optional<std::pair<std::string, std::string>> http_client_auth::do_get_auth_field(
|
||||
const boost::string_ref method, const boost::string_ref uri)
|
||||
{
|
||||
assert(user);
|
||||
if (user->server.generator)
|
||||
{
|
||||
++(user->counter);
|
||||
return std::make_pair(std::string(client_auth_field), user->server.generator(*user, method, uri));
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
341
contrib/epee/src/mlog.cpp
Normal file
341
contrib/epee/src/mlog.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _MLOG_H_
|
||||
#define _MLOG_H_
|
||||
|
||||
#include <atomic>
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "logging"
|
||||
|
||||
#define MLOG_BASE_FORMAT "%datetime{%Y-%M-%d %H:%m:%s.%g}\t%thread\t%level\t%logger\t%loc\t%msg"
|
||||
|
||||
#define MLOG_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
|
||||
|
||||
using namespace epee;
|
||||
|
||||
static std::string generate_log_filename(const char *base)
|
||||
{
|
||||
std::string filename(base);
|
||||
char tmp[200];
|
||||
struct tm tm;
|
||||
time_t now = time(NULL);
|
||||
if
|
||||
#ifdef WIN32
|
||||
(!gmtime_s(&tm, &now))
|
||||
#else
|
||||
(!gmtime_r(&now, &tm))
|
||||
#endif
|
||||
strcpy(tmp, "unknown");
|
||||
else
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H-%M-%S", &tm);
|
||||
filename += "-";
|
||||
filename += tmp;
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::string mlog_get_default_log_path(const char *default_filename)
|
||||
{
|
||||
std::string process_name = epee::string_tools::get_current_module_name();
|
||||
std::string default_log_folder = epee::string_tools::get_current_module_folder();
|
||||
std::string default_log_file = process_name;
|
||||
std::string::size_type a = default_log_file.rfind('.');
|
||||
if ( a != std::string::npos )
|
||||
default_log_file.erase( a, default_log_file.size());
|
||||
if ( ! default_log_file.empty() )
|
||||
default_log_file += ".log";
|
||||
else
|
||||
default_log_file = default_filename;
|
||||
|
||||
return (boost::filesystem::path(default_log_folder) / boost::filesystem::path(default_log_file)).string();
|
||||
}
|
||||
|
||||
static void mlog_set_common_prefix()
|
||||
{
|
||||
static const char * const expected_filename = "contrib/epee/src/mlog.cpp";
|
||||
const char *path = __FILE__, *expected_ptr = strstr(path, expected_filename);
|
||||
if (!expected_ptr)
|
||||
return;
|
||||
el::Loggers::setFilenameCommonPrefix(std::string(path, expected_ptr - path));
|
||||
}
|
||||
|
||||
static const char *get_default_categories(int level)
|
||||
{
|
||||
const char *categories = "";
|
||||
switch (level)
|
||||
{
|
||||
case 0:
|
||||
categories = "*:WARNING,net:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO";
|
||||
break;
|
||||
case 1:
|
||||
categories = "*:WARNING,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO";
|
||||
break;
|
||||
case 2:
|
||||
categories = "*:DEBUG";
|
||||
break;
|
||||
case 3:
|
||||
categories = "*:TRACE";
|
||||
break;
|
||||
case 4:
|
||||
categories = "*:TRACE";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
void mlog_configure(const std::string &filename_base, bool console)
|
||||
{
|
||||
el::Configurations c;
|
||||
c.setGlobally(el::ConfigurationType::Filename, filename_base);
|
||||
c.setGlobally(el::ConfigurationType::ToFile, "true");
|
||||
const char *log_format = getenv("MONERO_LOG_FORMAT");
|
||||
if (!log_format)
|
||||
log_format = MLOG_BASE_FORMAT;
|
||||
c.setGlobally(el::ConfigurationType::Format, log_format);
|
||||
c.setGlobally(el::ConfigurationType::ToStandardOutput, console ? "true" : "false");
|
||||
c.setGlobally(el::ConfigurationType::MaxLogFileSize, "104850000"); // 100 MB - 7600 bytes
|
||||
el::Loggers::setDefaultConfigurations(c, true);
|
||||
|
||||
el::Loggers::addFlag(el::LoggingFlag::HierarchicalLogging);
|
||||
el::Loggers::addFlag(el::LoggingFlag::CreateLoggerAutomatically);
|
||||
el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
|
||||
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
|
||||
el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
|
||||
el::Helpers::installPreRollOutCallback([filename_base](const char *name, size_t){
|
||||
std::string rname = generate_log_filename(filename_base.c_str());
|
||||
rename(name, rname.c_str());
|
||||
});
|
||||
mlog_set_common_prefix();
|
||||
const char *monero_log = getenv("MONERO_LOGS");
|
||||
if (!monero_log)
|
||||
{
|
||||
monero_log = get_default_categories(0);
|
||||
}
|
||||
mlog_set_log(monero_log);
|
||||
}
|
||||
|
||||
void mlog_set_categories(const char *categories)
|
||||
{
|
||||
el::Loggers::setCategories(categories);
|
||||
MLOG_LOG("New log categories: " << categories);
|
||||
}
|
||||
|
||||
// maps epee style log level to new logging system
|
||||
void mlog_set_log_level(int level)
|
||||
{
|
||||
const char *categories = get_default_categories(level);
|
||||
el::Loggers::setCategories(categories);
|
||||
MLOG_LOG("New log categories: " << categories);
|
||||
}
|
||||
|
||||
void mlog_set_log(const char *log)
|
||||
{
|
||||
long level;
|
||||
char *ptr = NULL;
|
||||
|
||||
level = strtoll(log, &ptr, 10);
|
||||
if (ptr && *ptr)
|
||||
{
|
||||
// we can have a default level, eg, 2,foo:ERROR
|
||||
if (*ptr == ',') {
|
||||
std::string new_categories = std::string(get_default_categories(level)) + ptr;
|
||||
mlog_set_categories(new_categories.c_str());
|
||||
}
|
||||
else {
|
||||
mlog_set_categories(log);
|
||||
}
|
||||
}
|
||||
else if (level >= 0 && level <= 4)
|
||||
{
|
||||
mlog_set_log_level(level);
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR("Invalid numerical log level: " << log);
|
||||
}
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
bool is_stdout_a_tty()
|
||||
{
|
||||
static std::atomic<bool> initialized(false);
|
||||
static std::atomic<bool> is_a_tty(false);
|
||||
|
||||
if (!initialized.load(std::memory_order_acquire))
|
||||
{
|
||||
#if defined(WIN32)
|
||||
is_a_tty.store(0 != _isatty(_fileno(stdout)), std::memory_order_relaxed);
|
||||
#else
|
||||
is_a_tty.store(0 != isatty(fileno(stdout)), std::memory_order_relaxed);
|
||||
#endif
|
||||
initialized.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
return is_a_tty.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void set_console_color(int color, bool bright)
|
||||
{
|
||||
if (!is_stdout_a_tty())
|
||||
return;
|
||||
|
||||
switch(color)
|
||||
{
|
||||
case console_color_default:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE| (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;37m";
|
||||
else
|
||||
std::cout << "\033[0m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case console_color_white:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;37m";
|
||||
else
|
||||
std::cout << "\033[0;37m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case console_color_red:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;31m";
|
||||
else
|
||||
std::cout << "\033[0;31m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case console_color_green:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;32m";
|
||||
else
|
||||
std::cout << "\033[0;32m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case console_color_blue:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY);//(bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;34m";
|
||||
else
|
||||
std::cout << "\033[0;34m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case console_color_cyan:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;36m";
|
||||
else
|
||||
std::cout << "\033[0;36m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case console_color_magenta:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;35m";
|
||||
else
|
||||
std::cout << "\033[0;35m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case console_color_yellow:
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0));
|
||||
#else
|
||||
if(bright)
|
||||
std::cout << "\033[1;33m";
|
||||
else
|
||||
std::cout << "\033[0;33m";
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void reset_console_color() {
|
||||
if (!is_stdout_a_tty())
|
||||
return;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
#else
|
||||
std::cout << "\033[0m";
|
||||
std::cout.flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //_MLOG_H_
|
||||
223
contrib/epee/src/readline_buffer.cpp
Normal file
223
contrib/epee/src/readline_buffer.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "readline_buffer.h"
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
static void install_line_handler();
|
||||
static void remove_line_handler();
|
||||
|
||||
static boost::mutex sync_mutex;
|
||||
static rdln::linestatus line_stat;
|
||||
static char *the_line;
|
||||
|
||||
namespace
|
||||
{
|
||||
rdln::readline_buffer* current = NULL;
|
||||
}
|
||||
|
||||
rdln::suspend_readline::suspend_readline()
|
||||
: m_buffer(NULL), m_restart(false)
|
||||
{
|
||||
m_buffer = current;
|
||||
if(!m_buffer)
|
||||
return;
|
||||
m_restart = m_buffer->is_running();
|
||||
if(m_restart)
|
||||
m_buffer->stop();
|
||||
}
|
||||
|
||||
rdln::suspend_readline::~suspend_readline()
|
||||
{
|
||||
if(!m_buffer)
|
||||
return;
|
||||
if(m_restart)
|
||||
m_buffer->start();
|
||||
}
|
||||
|
||||
std::vector<std::string>& rdln::readline_buffer::completion_commands()
|
||||
{
|
||||
static std::vector<std::string> commands = {"exit"};
|
||||
return commands;
|
||||
}
|
||||
|
||||
rdln::readline_buffer::readline_buffer()
|
||||
: std::stringbuf(), m_cout_buf(NULL)
|
||||
{
|
||||
current = this;
|
||||
}
|
||||
|
||||
void rdln::readline_buffer::start()
|
||||
{
|
||||
if(m_cout_buf != NULL)
|
||||
return;
|
||||
m_cout_buf = std::cout.rdbuf();
|
||||
std::cout.rdbuf(this);
|
||||
install_line_handler();
|
||||
}
|
||||
|
||||
void rdln::readline_buffer::stop()
|
||||
{
|
||||
if(m_cout_buf == NULL)
|
||||
return;
|
||||
std::cout.rdbuf(m_cout_buf);
|
||||
m_cout_buf = NULL;
|
||||
remove_line_handler();
|
||||
}
|
||||
|
||||
rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
line_stat = rdln::partial;
|
||||
rl_callback_read_char();
|
||||
if (line_stat == rdln::full)
|
||||
{
|
||||
line = the_line;
|
||||
free(the_line);
|
||||
the_line = NULL;
|
||||
}
|
||||
return line_stat;
|
||||
}
|
||||
|
||||
void rdln::readline_buffer::set_prompt(const std::string& prompt)
|
||||
{
|
||||
if(m_cout_buf == NULL)
|
||||
return;
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
rl_set_prompt(prompt.c_str());
|
||||
rl_redisplay();
|
||||
}
|
||||
|
||||
void rdln::readline_buffer::add_completion(const std::string& command)
|
||||
{
|
||||
if(std::find(completion_commands().begin(), completion_commands().end(), command) != completion_commands().end())
|
||||
return;
|
||||
completion_commands().push_back(command);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& rdln::readline_buffer::get_completions()
|
||||
{
|
||||
return completion_commands();
|
||||
}
|
||||
|
||||
int rdln::readline_buffer::sync()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||
#if RL_READLINE_VERSION < 0x0700
|
||||
char lbuf[2] = {0,0};
|
||||
char *line = NULL;
|
||||
int end = 0, point = 0;
|
||||
#endif
|
||||
|
||||
if (rl_end || *rl_prompt)
|
||||
{
|
||||
#if RL_READLINE_VERSION >= 0x0700
|
||||
rl_clear_visible_line();
|
||||
#else
|
||||
line = rl_line_buffer;
|
||||
end = rl_end;
|
||||
point = rl_point;
|
||||
rl_line_buffer = lbuf;
|
||||
rl_end = 0;
|
||||
rl_point = 0;
|
||||
rl_save_prompt();
|
||||
rl_redisplay();
|
||||
#endif
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
m_cout_buf->sputc( this->sgetc() );
|
||||
}
|
||||
while ( this->snextc() != EOF );
|
||||
|
||||
#if RL_READLINE_VERSION < 0x0700
|
||||
if (end || *rl_prompt)
|
||||
{
|
||||
rl_restore_prompt();
|
||||
rl_line_buffer = line;
|
||||
rl_end = end;
|
||||
rl_point = point;
|
||||
}
|
||||
#endif
|
||||
rl_on_new_line();
|
||||
rl_redisplay();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_line(char* line)
|
||||
{
|
||||
bool exit = false;
|
||||
if (line)
|
||||
{
|
||||
line_stat = rdln::full;
|
||||
the_line = line;
|
||||
std::string test_line = line;
|
||||
boost::trim_right(test_line);
|
||||
if(!test_line.empty())
|
||||
{
|
||||
add_history(test_line.c_str());
|
||||
history_set_pos(history_length);
|
||||
if (test_line == "exit" || test_line == "q")
|
||||
exit = true;
|
||||
}
|
||||
} else
|
||||
/* EOF */
|
||||
{
|
||||
line_stat = rdln::empty;
|
||||
exit = true;
|
||||
}
|
||||
rl_done = 1;
|
||||
if (exit)
|
||||
rl_set_prompt("");
|
||||
return;
|
||||
}
|
||||
|
||||
static char* completion_matches(const char* text, int state)
|
||||
{
|
||||
static size_t list_index;
|
||||
static size_t len;
|
||||
|
||||
if(state == 0)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& completions = rdln::readline_buffer::get_completions();
|
||||
for(; list_index<completions.size(); )
|
||||
{
|
||||
const std::string& cmd = completions[list_index++];
|
||||
if(cmd.compare(0, len, text) == 0)
|
||||
{
|
||||
return strdup(cmd.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char** attempted_completion(const char* text, int start, int end)
|
||||
{
|
||||
rl_attempted_completion_over = 1;
|
||||
return rl_completion_matches(text, completion_matches);
|
||||
}
|
||||
|
||||
static void install_line_handler()
|
||||
{
|
||||
rl_attempted_completion_function = attempted_completion;
|
||||
rl_callback_handler_install("", handle_line);
|
||||
stifle_history(500);
|
||||
}
|
||||
|
||||
static void remove_line_handler()
|
||||
{
|
||||
rl_replace_line("", 0);
|
||||
rl_set_prompt("");
|
||||
rl_redisplay();
|
||||
rl_callback_handler_remove();
|
||||
}
|
||||
|
||||
61
contrib/epee/src/string_tools.cpp
Normal file
61
contrib/epee/src/string_tools.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "string_tools.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <arpa/inet.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace string_tools
|
||||
{
|
||||
std::string get_ip_string_from_int32(uint32_t ip)
|
||||
{
|
||||
in_addr adr;
|
||||
adr.s_addr = ip;
|
||||
const char* pbuf = inet_ntoa(adr);
|
||||
if(pbuf)
|
||||
return pbuf;
|
||||
else
|
||||
return "[failed]";
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str)
|
||||
{
|
||||
ip = inet_addr(ip_str.c_str());
|
||||
if(INADDR_NONE == ip)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
contrib/fuzz_testing/fuzz.sh
Executable file
21
contrib/fuzz_testing/fuzz.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
AFLFUZZ=$(which afl-fuzz)
|
||||
if ! test -x "$AFLFUZZ"
|
||||
then
|
||||
echo "afl-fuzz not found - install american-fuzzy-lop"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
type="$1"
|
||||
if test -z "$type"
|
||||
then
|
||||
echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction"
|
||||
exit 1
|
||||
fi
|
||||
case "$type" in
|
||||
block|transaction|signature|cold-outputs|cold-transaction) ;;
|
||||
*) echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction"; exit 1 ;;
|
||||
esac
|
||||
|
||||
afl-fuzz -i tests/data/fuzz/$type -m 150 -t 250 -o fuzz-out/$type build/fuzz/tests/fuzz/${type}_fuzz_tests
|
||||
@@ -1,14 +0,0 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (otshell CXX)
|
||||
|
||||
# Add executable
|
||||
|
||||
file(GLOB otshell_utils_sources # All files in directory:
|
||||
"*.h"
|
||||
"*.hpp"
|
||||
"*.cpp"
|
||||
)
|
||||
|
||||
add_library (otshell_utils ${otshell_utils_sources})
|
||||
set_target_properties (otshell_utils PROPERTIES OUTPUT_NAME "otshell_utils")
|
||||
#target_link_libraries (upnpc-static ${LDLIBS}) # to add used libs
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
This are some files also from OpenTransactions / otshell project,
|
||||
developed thanks to the awesome OpenTransaction project, organization and developers :)
|
||||
|
||||
Parts of code here was also developed thanks to the excellent Monero project,
|
||||
thanks to Monero project, organization and developers :)
|
||||
|
||||
[Some] files/code here (in external/otshell_utils) are under licence defined in
|
||||
src/doc/LICENCE-otshell.txt ;
|
||||
Others are from monero, with licence in src/doc/LICENCE-monero.txt ;
|
||||
|
||||
For me (rfree) the licence seem compatbile so no problem, personally (as author of many parts of the code,
|
||||
possibly not all) I do not worry who uses it how; I'am not a lawyer.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Please share :-) This licence can be used e.g. for parts of code that are usable in both open-source FOSS project
|
||||
Monero and Open Transactions, to share and develop both faster.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "ccolor.hpp"
|
||||
#include <cstdarg>
|
||||
|
||||
// from http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
|
||||
// from http://wiznet.gr/src/ccolor.zip
|
||||
// edited by rfree - as part of https://github.com/rfree/Open-Transactions/
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define snprintf c99_snprintf
|
||||
|
||||
inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
|
||||
int count = -1;
|
||||
if (size != 0)
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
inline int c99_snprintf(char* str, size_t size, const char* format, ...) {
|
||||
int count;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
#endif // _MSC_VER
|
||||
|
||||
#define CC_CONSOLE_COLOR_DEFAULT "\033[0m"
|
||||
#define CC_FORECOLOR(C) "\033[" #C "m"
|
||||
#define CC_BACKCOLOR(C) "\033[" #C "m"
|
||||
#define CC_ATTR(A) "\033[" #A "m"
|
||||
|
||||
namespace zkr
|
||||
{
|
||||
enum Color
|
||||
{
|
||||
Black,
|
||||
Red,
|
||||
Green,
|
||||
Yellow,
|
||||
Blue,
|
||||
Magenta,
|
||||
Cyan,
|
||||
White,
|
||||
Default = 9
|
||||
};
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
Reset,
|
||||
Bright,
|
||||
Dim,
|
||||
Underline,
|
||||
Blink,
|
||||
Reverse,
|
||||
Hidden
|
||||
};
|
||||
|
||||
char * cc::color(int attr, int fg, int bg)
|
||||
{
|
||||
static const int size = 20;
|
||||
static char command[size];
|
||||
|
||||
/* Command is the control command to the terminal */
|
||||
snprintf(command, size, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
const char *cc::console = CC_CONSOLE_COLOR_DEFAULT;
|
||||
const char *cc::underline = CC_ATTR(4);
|
||||
const char *cc::bold = CC_ATTR(1);
|
||||
|
||||
const char *cc::fore::black = CC_FORECOLOR(30);
|
||||
const char *cc::fore::blue = CC_FORECOLOR(34);
|
||||
const char *cc::fore::red = CC_FORECOLOR(31);
|
||||
const char *cc::fore::magenta = CC_FORECOLOR(35);
|
||||
const char *cc::fore::green = CC_FORECOLOR(92);
|
||||
const char *cc::fore::cyan = CC_FORECOLOR(36);
|
||||
const char *cc::fore::yellow = CC_FORECOLOR(33);
|
||||
const char *cc::fore::white = CC_FORECOLOR(37);
|
||||
const char *cc::fore::console = CC_FORECOLOR(39);
|
||||
|
||||
const char *cc::fore::lightblack = CC_FORECOLOR(90);
|
||||
const char *cc::fore::lightblue = CC_FORECOLOR(94);
|
||||
const char *cc::fore::lightred = CC_FORECOLOR(91);
|
||||
const char *cc::fore::lightmagenta = CC_FORECOLOR(95);
|
||||
const char *cc::fore::lightgreen = CC_FORECOLOR(92);
|
||||
const char *cc::fore::lightcyan = CC_FORECOLOR(96);
|
||||
const char *cc::fore::lightyellow = CC_FORECOLOR(93);
|
||||
const char *cc::fore::lightwhite = CC_FORECOLOR(97);
|
||||
|
||||
const char *cc::back::black = CC_BACKCOLOR(40);
|
||||
const char *cc::back::blue = CC_BACKCOLOR(44);
|
||||
const char *cc::back::red = CC_BACKCOLOR(41);
|
||||
const char *cc::back::magenta = CC_BACKCOLOR(45);
|
||||
const char *cc::back::green = CC_BACKCOLOR(42);
|
||||
const char *cc::back::cyan = CC_BACKCOLOR(46);
|
||||
const char *cc::back::yellow = CC_BACKCOLOR(43);
|
||||
const char *cc::back::white = CC_BACKCOLOR(47);
|
||||
const char *cc::back::console = CC_BACKCOLOR(49);
|
||||
|
||||
const char *cc::back::lightblack = CC_BACKCOLOR(100);
|
||||
const char *cc::back::lightblue = CC_BACKCOLOR(104);
|
||||
const char *cc::back::lightred = CC_BACKCOLOR(101);
|
||||
const char *cc::back::lightmagenta = CC_BACKCOLOR(105);
|
||||
const char *cc::back::lightgreen = CC_BACKCOLOR(102);
|
||||
const char *cc::back::lightcyan = CC_BACKCOLOR(106);
|
||||
const char *cc::back::lightyellow = CC_BACKCOLOR(103);
|
||||
const char *cc::back::lightwhite = CC_BACKCOLOR(107);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// ccolor.hpp
|
||||
|
||||
// from http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
|
||||
// from http://wiznet.gr/src/ccolor.zip
|
||||
// edited by rfree - as part of https://github.com/rfree/Open-Transactions/
|
||||
|
||||
#ifndef INCLUDE_OT_ccolor
|
||||
#define INCLUDE_OT_ccolor
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace zkr
|
||||
{
|
||||
class cc
|
||||
{
|
||||
public:
|
||||
|
||||
class fore
|
||||
{
|
||||
public:
|
||||
static const char *black;
|
||||
static const char *blue;
|
||||
static const char *red;
|
||||
static const char *magenta;
|
||||
static const char *green;
|
||||
static const char *cyan;
|
||||
static const char *yellow;
|
||||
static const char *white;
|
||||
static const char *console;
|
||||
|
||||
static const char *lightblack;
|
||||
static const char *lightblue;
|
||||
static const char *lightred;
|
||||
static const char *lightmagenta;
|
||||
static const char *lightgreen;
|
||||
static const char *lightcyan;
|
||||
static const char *lightyellow;
|
||||
static const char *lightwhite;
|
||||
};
|
||||
|
||||
class back
|
||||
{
|
||||
public:
|
||||
static const char *black;
|
||||
static const char *blue;
|
||||
static const char *red;
|
||||
static const char *magenta;
|
||||
static const char *green;
|
||||
static const char *cyan;
|
||||
static const char *yellow;
|
||||
static const char *white;
|
||||
static const char *console;
|
||||
|
||||
static const char *lightblack;
|
||||
static const char *lightblue;
|
||||
static const char *lightred;
|
||||
static const char *lightmagenta;
|
||||
static const char *lightgreen;
|
||||
static const char *lightcyan;
|
||||
static const char *lightyellow;
|
||||
static const char *lightwhite;
|
||||
};
|
||||
|
||||
static char *color(int attr, int fg, int bg);
|
||||
static const char *console;
|
||||
static const char *underline;
|
||||
static const char *bold;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/* See other files here for the LICENCE that applies here. */
|
||||
|
||||
|
||||
#ifndef INCLUDE_OT_NEWCLI_COMMON1
|
||||
#define INCLUDE_OT_NEWCLI_COMMON1
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
|
||||
|
||||
// list of thigs from libraries that we pull into namespace nOT::nNewcli
|
||||
// we might still need to copy/paste it in few places to make IDEs pick it up correctly
|
||||
#define INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 \
|
||||
using std::string; \
|
||||
using std::vector; \
|
||||
using std::vector; \
|
||||
using std::list; \
|
||||
using std::set; \
|
||||
using std::map; \
|
||||
using std::ostream; \
|
||||
using std::istream; \
|
||||
using std::cin; \
|
||||
using std::cerr; \
|
||||
using std::cout; \
|
||||
using std::cerr; \
|
||||
using std::endl; \
|
||||
using std::function; \
|
||||
using std::unique_ptr; \
|
||||
using std::shared_ptr; \
|
||||
using std::weak_ptr; \
|
||||
using std::enable_shared_from_this; \
|
||||
using boost::lock_guard; \
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/* See other files here for the LICENCE that applies here. */
|
||||
/* See header file .hpp for info */
|
||||
|
||||
#include "runoptions.hpp"
|
||||
|
||||
#include "lib_common1.hpp"
|
||||
|
||||
namespace nOT {
|
||||
|
||||
INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 // <=== namespaces
|
||||
|
||||
// (no debug - this is the default)
|
||||
// +nodebug (no debug)
|
||||
// +debug ...... --asdf
|
||||
// +debug +debugcerr .... --asfs
|
||||
// +debug +debugfile .... --asfs
|
||||
|
||||
cRunOptions::cRunOptions()
|
||||
: mRunMode(eRunModeCurrent), mDebug(false), mDebugSendToFile(false), mDebugSendToCerr(false)
|
||||
,mDoRunDebugshow(false)
|
||||
{ }
|
||||
|
||||
vector<string> cRunOptions::ExecuteRunoptionsAndRemoveThem(const vector<string> & args) {
|
||||
vector<string> arg_clear; // will store only the arguments that are not removed
|
||||
|
||||
for (auto arg : args) {
|
||||
bool thisIsRunoption=false;
|
||||
|
||||
if (arg.size()>0) {
|
||||
if (arg.at(0) == '+') thisIsRunoption=true;
|
||||
}
|
||||
|
||||
if (thisIsRunoption) Exec(arg); // ***
|
||||
if (! thisIsRunoption) arg_clear.push_back(arg);
|
||||
}
|
||||
|
||||
Normalize();
|
||||
|
||||
return arg_clear;
|
||||
}
|
||||
|
||||
void cRunOptions::Exec(const string & runoption) { // eg: Exec("+debug");
|
||||
if (runoption == "+nodebug") { mDebug=false; }
|
||||
else if (runoption == "+debug") { mDebug=true; }
|
||||
else if (runoption == "+debugcerr") { mDebug=true; mDebugSendToCerr=true; }
|
||||
else if (runoption == "+debugfile") { mDebug=true; mDebugSendToFile=true; }
|
||||
else if (runoption == "+demo") { mRunMode=eRunModeDemo; }
|
||||
else if (runoption == "+normal") { mRunMode=eRunModeNormal; }
|
||||
else if (runoption == "+current") { mRunMode=eRunModeCurrent; }
|
||||
else if (runoption == "+debugshow") { mDebug=true; mDebugSendToCerr=true; mDoRunDebugshow=true; }
|
||||
else {
|
||||
cerr << "Unknown runoption in Exec: '" << runoption << "'" << endl;
|
||||
throw std::runtime_error("Unknown runoption");
|
||||
}
|
||||
// cerr<<"debug="<<mDebug<<endl;
|
||||
}
|
||||
|
||||
void cRunOptions::Normalize() {
|
||||
if (mDebug) {
|
||||
if (!( mDebugSendToFile || mDebugSendToCerr )) mDebugSendToCerr=true; // if debug is on then send to something, e.g. to cerr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cRunOptions gRunOptions; // (extern)
|
||||
|
||||
} // namespace OT
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/* See other files here for the LICENCE that applies here. */
|
||||
/*
|
||||
Template for new files, replace word "template" and later delete this line here.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_OT_NEWCLI_runoptions_hpp
|
||||
#define INCLUDE_OT_NEWCLI_runoptions_hpp
|
||||
|
||||
#include "lib_common1.hpp"
|
||||
|
||||
namespace nOT {
|
||||
|
||||
INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 // <=== namespaces
|
||||
|
||||
/** Global options to run this program main() Eg used for developer's special options like +setdemo +setdebug.
|
||||
This is NOT for all the other options that are parsed and executed by program. */
|
||||
class cRunOptions {
|
||||
public:
|
||||
enum tRunMode { ///< Type of run mode - is this normal, or demonstration etc.
|
||||
eRunModeCurrent=1, ///< currently developed version
|
||||
eRunModeDemo, ///< best currently available Demo of something nice
|
||||
eRunModeNormal, ///< do the normal things that the program should do
|
||||
};
|
||||
|
||||
private:
|
||||
tRunMode mRunMode; ///< selected run mode
|
||||
|
||||
bool mDebug; // turn debug on, Eg: +debug without it probably nothing will be written to debug (maybe just error etc)
|
||||
bool mDebugSendToFile; // send to file, Eg: for +debugfile ; also turns on debug
|
||||
bool mDebugSendToCerr; // send to cerr, Eg: for +debugcerr ; also turns on debug
|
||||
// if debug is set but not any other DebugSend* then we will default to sending to debugcerr
|
||||
|
||||
bool mDoRunDebugshow;
|
||||
|
||||
public:
|
||||
tRunMode getTRunMode() const { return mRunMode; }
|
||||
bool getDebug() const { return mDebug; }
|
||||
bool getDebugSendToFile() const { return mDebugSendToFile; }
|
||||
bool getDebugSendToCerr() const { return mDebugSendToCerr; }
|
||||
bool getDoRunDebugshow() const { return mDoRunDebugshow; }
|
||||
|
||||
cRunOptions();
|
||||
|
||||
vector<string> ExecuteRunoptionsAndRemoveThem(const vector<string> & args);
|
||||
void Exec(const string & runoption); // eg: Exec("+debug");
|
||||
|
||||
void Normalize();
|
||||
};
|
||||
|
||||
extern cRunOptions gRunOptions;
|
||||
|
||||
|
||||
} // namespace nOT
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,806 +0,0 @@
|
||||
/// @file
|
||||
/// @author rfree (current maintainer in monero.cc project)
|
||||
/// @brief various general utils taken from (and relate to) otshell project, including loggiang/debug
|
||||
|
||||
/* See other files here for the LICENCE that applies here. */
|
||||
/* See header file .hpp for info */
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
#include "ccolor.hpp"
|
||||
|
||||
#include "lib_common1.hpp"
|
||||
|
||||
#include "runoptions.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined (WIN64)
|
||||
#define OS_TYPE_WINDOWS
|
||||
#elif defined(__unix__) || defined(__posix) || defined(__linux) || defined(__darwin) || defined(__APPLE__) || defined(__clang__)
|
||||
#define OS_TYPE_POSIX
|
||||
#else
|
||||
#warning "Compiler/OS platform is not recognized. Just assuming it will work as POSIX then"
|
||||
#define OS_TYPE_POSIX
|
||||
#endif
|
||||
|
||||
#if defined(OS_TYPE_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#elif defined(OS_TYPE_POSIX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#error "Compiler/OS platform detection failed - not supported"
|
||||
#endif
|
||||
|
||||
|
||||
namespace nOT {
|
||||
namespace nUtils {
|
||||
|
||||
INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 // <=== namespaces
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// Numerical values of the debug levels - see hpp
|
||||
const int _debug_level_nr_dbg3=20;
|
||||
const int _debug_level_nr_dbg2=30;
|
||||
const int _debug_level_nr_dbg1=40;
|
||||
const int _debug_level_nr_info=50;
|
||||
const int _debug_level_nr_note=60;
|
||||
const int _debug_level_nr_fact=75;
|
||||
const int _debug_level_nr_mark=80;
|
||||
const int _debug_level_nr_warn=90;
|
||||
const int _debug_level_nr_erro=100;
|
||||
|
||||
// ====================================================================
|
||||
|
||||
myexception::myexception(const char * what)
|
||||
: std::runtime_error(what)
|
||||
{ }
|
||||
|
||||
myexception::myexception(const std::string &what)
|
||||
: std::runtime_error(what)
|
||||
{ }
|
||||
|
||||
void myexception::Report() const {
|
||||
_erro("Error: " << what());
|
||||
}
|
||||
|
||||
//myexception::~myexception() { }
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// text trimming
|
||||
// http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
||||
std::string & ltrim(std::string &s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string & rtrim(std::string &s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string & trim(std::string &s) {
|
||||
return ltrim(rtrim(s));
|
||||
}
|
||||
|
||||
std::string get_current_time() {
|
||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||
time_t time_now = std::chrono::system_clock::to_time_t(now);
|
||||
std::chrono::high_resolution_clock::duration duration = now.time_since_epoch();
|
||||
int64_t micro = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
|
||||
|
||||
// std::localtime() - This function may not be thread-safe.
|
||||
#ifdef OS_TYPE_WINDOWS
|
||||
struct tm * tm_pointer = std::localtime( &time_now ); // thread-safe on mingw-w64 (thread local variable) and on MSVC btw
|
||||
// http://stackoverflow.com/questions/18551409/localtime-r-support-on-mingw
|
||||
// tm_pointer points to thread-local data, memory is owned/managed by the system/library
|
||||
#else
|
||||
// linux, freebsd, have this
|
||||
struct tm tm_object; // automatic storage duration http://en.cppreference.com/w/cpp/language/storage_duration
|
||||
struct tm * tm_pointer = & tm_object; // just point to our data
|
||||
auto x = localtime_r( &time_now , tm_pointer ); // modifies our own (this thread) data in tm_object, this is safe http://linux.die.net/man/3/localtime_r
|
||||
if (x != tm_pointer) return "(internal error in get_current_time)"; // redundant check in case of broken implementation of localtime_r
|
||||
#endif
|
||||
// tm_pointer now points to proper time data, and that memory is automatically managed
|
||||
if (!tm_pointer) return "(internal error in get_current_time - NULL)"; // redundant check in case of broken implementation of used library methods
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::setfill('0')
|
||||
<< std::setw(2) << tm_pointer->tm_year+1900
|
||||
<< '-' << std::setw(2) << tm_pointer->tm_mon+1
|
||||
<< '-' << std::setw(2) << tm_pointer->tm_mday
|
||||
<< ' ' << std::setw(2) << tm_pointer->tm_hour
|
||||
<< ':' << std::setw(2) << tm_pointer->tm_min
|
||||
<< ':' << std::setw(2) << tm_pointer->tm_sec
|
||||
<< '.' << std::setw(6) << (micro%1000000); // 6 because microseconds
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
cNullstream g_nullstream; // extern a stream that does nothing (eats/discards data)
|
||||
|
||||
boost::recursive_mutex gLoggerGuard; // extern
|
||||
std::atomic<int> gLoggerGuardDepth; // extern
|
||||
|
||||
std::atomic<int> & gLoggerGuardDepth_Get() {
|
||||
// TODO std::once would be nicer here
|
||||
|
||||
static bool once=0;
|
||||
|
||||
if (!once) { // initialize it once
|
||||
once=1;
|
||||
gLoggerGuardDepth=0;
|
||||
}
|
||||
|
||||
return gLoggerGuardDepth; // global, atomic counter
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================
|
||||
|
||||
namespace nDetail {
|
||||
|
||||
const char* DbgShortenCodeFileName(const char *s) {
|
||||
const char *p = s;
|
||||
const char *a = s;
|
||||
|
||||
bool inc=1;
|
||||
while (*p) {
|
||||
++p;
|
||||
if (inc && ('\0' != * p)) { a=p; inc=false; } // point to the current character (if valid) becasue previous one was slash
|
||||
if ((*p)=='/') { a=p; inc=true; } // point at current slash (but set inc to try to point to next character)
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// a workaround for MSVC compiler; e.g. see https://bugs.webkit.org/show_bug.cgi?format=multiple&id=125795
|
||||
#ifndef _MSC_VER
|
||||
template<typename T, typename ...Args>
|
||||
std::unique_ptr<T> make_unique( Args&& ...args )
|
||||
{
|
||||
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
|
||||
}
|
||||
#else
|
||||
using std::make_unique;
|
||||
#endif
|
||||
// ====================================================================
|
||||
|
||||
char cFilesystemUtils::GetDirSeparatorSys() {
|
||||
// TODO nicer os detection?
|
||||
#if defined(OS_TYPE_POSIX)
|
||||
return '/';
|
||||
#elif defined(OS_TYPE_WINDOWS)
|
||||
return '\\';
|
||||
#else
|
||||
#error "Do not know how to compile this for your platform."
|
||||
#endif
|
||||
}
|
||||
|
||||
char cFilesystemUtils::GetDirSeparatorInter() {
|
||||
return '/';
|
||||
}
|
||||
|
||||
string cFilesystemUtils::FileInternalToSystem(const std::string &name) {
|
||||
string ret;
|
||||
ret.resize(name.size());
|
||||
std::replace_copy(name.begin(), name.end(), ret.begin(),
|
||||
GetDirSeparatorInter() , GetDirSeparatorSys());
|
||||
return ret;
|
||||
}
|
||||
|
||||
string cFilesystemUtils::FileSystemToInternal(const std::string &name) {
|
||||
string ret;
|
||||
ret.reserve(name.size());
|
||||
std::replace_copy(name.begin(), name.end(), ret.begin(),
|
||||
GetDirSeparatorSys() , GetDirSeparatorInter());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool cFilesystemUtils::CreateDirTree(const std::string & dir, bool only_below) {
|
||||
const bool dbg=false;
|
||||
//struct stat st;
|
||||
const char dirchS = cFilesystemUtils::GetDirSeparatorSys();
|
||||
const char dirchI = cFilesystemUtils::GetDirSeparatorInter();
|
||||
std::istringstream iss(dir);
|
||||
string partI; // current par is in internal format (though it should not matter since it doesn't contain any slashes). eg "bar"
|
||||
string sofarS=""; // sofarS - the so far created dir part is in SYSTEM format. eg "foo/bar"
|
||||
if (dir.size()<1) return false; // illegal name
|
||||
// dir[0] is valid from here
|
||||
if ( only_below && ((dir[0]==dirchS) || (dir[0]==dirchI))) return false; // no jumping to top (on any os)
|
||||
|
||||
while (getline(iss,partI,dirchI)) { // get new component eg "bar" into part
|
||||
if (dbg) cout << '['<<partI<<']' << endl;
|
||||
sofarS += partI;
|
||||
if (partI.size()<1) return false; // bad format?
|
||||
if ((only_below) && (partI=="..")) return false; // trying to go up
|
||||
|
||||
if (dbg) cout << "test ["<<sofarS<<"]"<<endl;
|
||||
// TODO nicer os detection?
|
||||
#if defined(OS_TYPE_POSIX)
|
||||
struct stat st;
|
||||
bool exists = stat(sofarS.c_str() ,&st) == 0; // *
|
||||
if (exists) {
|
||||
if (! S_ISDIR(st.st_mode)) {
|
||||
// std::cerr << "This exists, but as a file: [" << sofar << "]" << (size_t)st.st_ino << endl;
|
||||
return false; // exists but is a file nor dir
|
||||
}
|
||||
}
|
||||
#elif defined(OS_TYPE_WINDOWS)
|
||||
DWORD dwAttrib = GetFileAttributesA(sofarS.c_str());
|
||||
bool exists = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
#else
|
||||
#error "Do not know how to compile this for your platform."
|
||||
#endif
|
||||
|
||||
if (!exists) {
|
||||
if (dbg) cout << "mkdir ["<<sofarS<<"]"<<endl;
|
||||
#if defined(OS_TYPE_POSIX)
|
||||
bool ok = 0== mkdir(sofarS.c_str(), 0700); // ***
|
||||
#elif defined(OS_TYPE_WINDOWS)
|
||||
bool ok = (bool) CreateDirectoryA(sofarS.c_str(), NULL); // TODO use -W() after conversion to unicode UTF16
|
||||
#else
|
||||
#error "Do not know how to compile this for your platform."
|
||||
#endif
|
||||
if (!ok) return false;
|
||||
}
|
||||
sofarS += dirchS;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// ====================================================================
|
||||
|
||||
namespace nDetail {
|
||||
|
||||
struct channel_use_info { ///< feedback information about using (e.g. opening) given debug channel - used internally by logging system
|
||||
/// TODO not yet used in code
|
||||
/// e.g. used to write into channel net/in/all that given message was a first logged message from never-before-logged thread or PID etc
|
||||
bool m_was_interesting; ///< anything interesting happened when using the channel?
|
||||
std::vector<std::string> m_extra_msg; ///< any additional messages about this channel use
|
||||
};
|
||||
|
||||
cDebugScopeGuard::cDebugScopeGuard() : mLevel(-1) {
|
||||
}
|
||||
|
||||
cDebugScopeGuard::~cDebugScopeGuard() {
|
||||
if (mLevel != -1) {
|
||||
gCurrentLogger.write_stream(mLevel,mChan) << mMsg << " ... end" << gCurrentLogger.endline() << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
void cDebugScopeGuard::Assign(const string &chan, const int level, const string &msg) {
|
||||
mChan=chan;
|
||||
mLevel=level;
|
||||
mMsg=msg;
|
||||
}
|
||||
|
||||
} // namespace nDetail
|
||||
|
||||
// ====================================================================
|
||||
|
||||
cLogger::cLogger() :
|
||||
mStream(NULL),
|
||||
mStreamBrokenDebug(NULL),
|
||||
mIsBroken(true), // before constructor finishes
|
||||
mLevel(_debug_level_nr_warn),
|
||||
mThread2Number_Biggest(0), // the CURRENT biggest value (no thread yet in map)
|
||||
mPid2Number_Biggest(0)
|
||||
{
|
||||
mStream = & std::cout;
|
||||
mStreamBrokenDebug = & std::cerr; // the backup stream
|
||||
*mStreamBrokenDebug << "Creating the logger system" << endl;
|
||||
mIsBroken=false; // ok, constr. succeeded, so string is not broken now
|
||||
|
||||
// this is here, because it could be using logging itself to log creation of first thread/PID etc
|
||||
Thread2Number( boost::this_thread::get_id() ); // convert current id to short number, useful to reserve a number so that main thread is usually called 1
|
||||
Pid2Number( getpid() ); // add this proces ID as first one
|
||||
}
|
||||
|
||||
cLogger::~cLogger() {
|
||||
for (auto pair : mChannels) {
|
||||
std::ofstream *ptr = pair.second;
|
||||
delete ptr;
|
||||
pair.second=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cLogger::SetStreamBroken() {
|
||||
SetStreamBroken("(no additional details about this problem)");
|
||||
}
|
||||
|
||||
void cLogger::SetStreamBroken(const std::string &msg) {
|
||||
_dbg_dbg("Stream is broken (msg: " << msg << ")");
|
||||
if (!mIsBroken) { // if not already marked as broken
|
||||
_dbg_dbg("(It was not broken before)");
|
||||
std::cerr << OT_CODE_STAMP << "WARNING: due to a problem in the debug/logging system itself ("<<msg<<") - we are switching back to fallback stream (e.g. cerr)" << std::endl;
|
||||
if (mStreamBrokenDebug == nullptr) {
|
||||
std::cerr << OT_CODE_STAMP << " ERROR: in addition, while reporting this problem, mStreamBrokenDebug stream is NULL: " << mStreamBrokenDebug << std::endl;
|
||||
} else {
|
||||
(*mStreamBrokenDebug) << OT_CODE_STAMP << "WARNING: due to debug stream problem ("<<msg<<") - switching back to fallback stream (e.g. cerr)" << std::endl;
|
||||
}
|
||||
mIsBroken = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream & cLogger::write_stream(int level) {
|
||||
return write_stream(level,"");
|
||||
}
|
||||
|
||||
std::ostream & cLogger::write_stream(int level, const std::string & channel ) {
|
||||
_dbg_dbg("level="<<level<<" channel="<<channel);
|
||||
if (level >= mLevel) {
|
||||
if (mStream) { // TODO now disabling mStream also disables writting to any channel
|
||||
_dbg_dbg("Selecting output...");
|
||||
ostream & output = SelectOutput(level,channel);
|
||||
_dbg_dbg("Selecting output... done, output=" << (void*)(&output));
|
||||
#if defined(OS_TYPE_WINDOWS)
|
||||
output << windows_stream(level);
|
||||
#endif
|
||||
output << icon(level) << ' ';
|
||||
boost::thread::id this_id = boost::this_thread::get_id();
|
||||
output << "{" << Thread2Number(this_id) << "}";
|
||||
auto nicePid = Pid2Number(getpid());
|
||||
if (nicePid>0) output << " {p" << nicePid << "}";
|
||||
output << ' ';
|
||||
return output; // <--- return
|
||||
} else _dbg_dbg("Not writting: No mStream");
|
||||
} else _dbg_dbg("Not writting: Too low level level="<<level<<" not >= mLevel="<<mLevel);
|
||||
return g_nullstream;
|
||||
}
|
||||
|
||||
std::string cLogger::GetLogBaseDir() const {
|
||||
return "log";
|
||||
}
|
||||
|
||||
void cLogger::OpenNewChannel(const std::string & channel) noexcept {
|
||||
try {
|
||||
_dbg_dbg("Openning channel for channel="<<channel);
|
||||
OpenNewChannel_(channel);
|
||||
}
|
||||
catch (const std::exception &except) {
|
||||
SetStreamBroken(OT_CODE_STAMP + " Got exception when opening debug channel: " + ToStr(except.what()));
|
||||
}
|
||||
catch (...) {
|
||||
SetStreamBroken(OT_CODE_STAMP + " Got not-standard exception when opening debug channel.");
|
||||
}
|
||||
}
|
||||
|
||||
void cLogger::OpenNewChannel_(const std::string & channel) { // channel=="net/sleep"
|
||||
_dbg_dbg("Openning channel for channel="<<channel);
|
||||
size_t last_split = channel.find_last_of(cFilesystemUtils::GetDirSeparatorInter());
|
||||
|
||||
string fname_system; // the full file name in system format
|
||||
|
||||
if (last_split==string::npos) { // The channel name has no directory, eg channel=="test"
|
||||
string dir = GetLogBaseDir();
|
||||
string basefile = channel + ".log";
|
||||
string fname = dir + cFilesystemUtils::GetDirSeparatorInter() + basefile;
|
||||
fname_system = cFilesystemUtils::FileInternalToSystem(fname); // <-
|
||||
}
|
||||
else { // there is a directory eg channel=="net/sleep"
|
||||
// net/sleep
|
||||
// ^----- last_split
|
||||
string dir = GetLogBaseDir() + cFilesystemUtils::GetDirSeparatorInter() + channel.substr(0, last_split);
|
||||
string basefile = channel.substr(last_split+1) + ".log";
|
||||
string fname = dir + cFilesystemUtils::GetDirSeparatorInter() + basefile;
|
||||
fname_system = cFilesystemUtils::FileInternalToSystem(fname); // <-
|
||||
bool dirok = cFilesystemUtils::CreateDirTree(dir);
|
||||
if (!dirok) { string err = "In logger failed to open directory (" + dir +") for channel (" + channel +")"; throw std::runtime_error(err); }
|
||||
}
|
||||
|
||||
_dbg_dbg("Openning fname_system="<<fname_system);
|
||||
std::ofstream * thefile = new std::ofstream( fname_system.c_str() ); // file system
|
||||
*thefile << "====== Log opened: " << fname_system << " (in " << ((void*)thefile) << ") ======" << endl;
|
||||
// cerr << "====== Log opened: " << fname_system << " (in " << ((void*)thefile) << ") ======" << endl;
|
||||
_dbg_dbg( "====== Log opened: " << fname_system << " (in " << ((void*)thefile) << ") ======" );
|
||||
mChannels.insert( std::pair<string,std::ofstream*>(channel , thefile ) ); // <- created the channel mapping
|
||||
}
|
||||
|
||||
std::ostream & cLogger::SelectOutput(int level, const std::string & channel) noexcept {
|
||||
try {
|
||||
if (mIsBroken) {
|
||||
_dbg_dbg("The stream is broken mIsBroken="<<mIsBroken<<" so will return backup stream");
|
||||
return *mStreamBrokenDebug;
|
||||
}
|
||||
if (channel=="") {
|
||||
_dbg_dbg("No channel given (channel="<<channel<<") so will return main stream");
|
||||
return *mStream;
|
||||
}
|
||||
|
||||
auto obj = mChannels.find(channel);
|
||||
if (obj == mChannels.end()) { // not found - need to make new channel
|
||||
_dbg_dbg("No stream openened for channel="<<channel<<" so will create it now");
|
||||
OpenNewChannel(channel); // <- create channel
|
||||
obj = mChannels.find(channel); // find again
|
||||
if (obj == mChannels.end()) { // still not found! something is wrong
|
||||
SetStreamBroken( OT_CODE_STAMP + " WARNING: can not get stream for channel="+ToStr(channel)+" level="+ToStr(channel) );
|
||||
return *mStreamBrokenDebug;
|
||||
}
|
||||
}
|
||||
auto the_stream_ptr = obj->second;
|
||||
_dbg_dbg("Found the stream file for channel="<<channel<<" as the_stream_ptr="<<the_stream_ptr);
|
||||
ASRT(the_stream_ptr);
|
||||
return *the_stream_ptr; // <--- RETURN
|
||||
}
|
||||
catch (std::exception &except) {
|
||||
SetStreamBroken( OT_CODE_STAMP + " Got exception: " + ToStr(except.what()) );
|
||||
_dbg_dbg("Exception! Returning broken stream");
|
||||
return *mStreamBrokenDebug;
|
||||
}
|
||||
catch (...) {
|
||||
SetStreamBroken( OT_CODE_STAMP + " Got not-standard exception.");
|
||||
_dbg_dbg("Exception! Returning broken stream");
|
||||
return *mStreamBrokenDebug;
|
||||
}
|
||||
|
||||
// dead code
|
||||
}
|
||||
|
||||
void cLogger::setOutStreamFile(const string &fname) { // switch to using this file
|
||||
_mark("WILL SWITCH DEBUG NOW to file: " << fname);
|
||||
mOutfile = make_unique<std::ofstream>(fname);
|
||||
mStream = & (*mOutfile);
|
||||
_mark("Started new debug, to file: " << fname);
|
||||
}
|
||||
|
||||
void cLogger::setOutStreamFromGlobalOptions() {
|
||||
if ( gRunOptions.getDebug() ) {
|
||||
if ( gRunOptions.getDebugSendToFile() ) {
|
||||
mOutfile = make_unique<std::ofstream> ("debuglog.txt");
|
||||
mStream = & (*mOutfile);
|
||||
}
|
||||
else if ( gRunOptions.getDebugSendToCerr() ) {
|
||||
mStream = & std::cerr;
|
||||
}
|
||||
else {
|
||||
mStream = & g_nullstream;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mStream = & g_nullstream;
|
||||
}
|
||||
}
|
||||
|
||||
void cLogger::setDebugLevel(int level) {
|
||||
bool note_before = (mLevel > level); // report the level change before or after the change? (on higher level)
|
||||
if (note_before) _note("Setting debug level to "<<level);
|
||||
mLevel = level;
|
||||
if (!note_before) _note("Setting debug level to "<<level);
|
||||
}
|
||||
|
||||
std::string cLogger::icon(int level) const {
|
||||
// TODO replan to avoid needles converting back and forth char*, string etc
|
||||
|
||||
using namespace zkr;
|
||||
#if defined(OS_TYPE_POSIX)
|
||||
if (level >= 100) return cc::back::lightred + ToStr(cc::fore::lightyellow) + ToStr("ERROR ") + ToStr(cc::fore::lightyellow) + " " ;
|
||||
if (level >= 90) return cc::back::lightyellow + ToStr(cc::fore::black) + ToStr("Warn ") + ToStr(cc::fore::red)+ " " ;
|
||||
if (level >= 80) return cc::back::lightmagenta + ToStr(cc::fore::black) + ToStr("MARK "); //+ zkr::cc::console + ToStr(cc::fore::lightmagenta)+ " ";
|
||||
if (level >= 75) return cc::back::lightyellow + ToStr(cc::fore::black) + ToStr("FACT ") + zkr::cc::console + ToStr(cc::fore::lightyellow)+ " ";
|
||||
if (level >= 70) return cc::fore::green + ToStr("Note ");
|
||||
if (level >= 50) return cc::fore::cyan + ToStr("info ");
|
||||
if (level >= 40) return cc::fore::lightwhite + ToStr("dbg ");
|
||||
if (level >= 30) return cc::fore::lightblue + ToStr("dbg ");
|
||||
if (level >= 20) return cc::fore::blue + ToStr("dbg ");
|
||||
|
||||
#elif defined(OS_TYPE_WINDOWS)
|
||||
if (level >= 100) return ToStr("ERROR ");
|
||||
if (level >= 90) return ToStr("Warn ");
|
||||
if (level >= 80) return ToStr("MARK ");
|
||||
if (level >= 75) return ToStr("FACT ");
|
||||
if (level >= 70) return ToStr("Note ");
|
||||
if (level >= 50) return ToStr("info ");
|
||||
if (level >= 40) return ToStr("dbg ");
|
||||
if (level >= 30) return ToStr("dbg ");
|
||||
if (level >= 20) return ToStr("dbg ");
|
||||
#endif
|
||||
|
||||
return " ";
|
||||
}
|
||||
|
||||
std::string cLogger::endline() const {
|
||||
#if defined(OS_TYPE_POSIX)
|
||||
return ToStr("") + zkr::cc::console + ToStr("\n"); // TODO replan to avoid needles converting back and forth char*, string etc
|
||||
#elif defined(OS_TYPE_WINDOWS)
|
||||
return ToStr("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
int cLogger::Thread2Number(const boost::thread::id id) {
|
||||
auto found = mThread2Number.find( id );
|
||||
if (found == mThread2Number.end()) { // new one
|
||||
mThread2Number_Biggest++;
|
||||
mThread2Number[id] = mThread2Number_Biggest;
|
||||
_info_c("dbg/main", "This is a new thread (used in debug), thread id="<<id); // can cause some recursion
|
||||
return mThread2Number_Biggest;
|
||||
} else {
|
||||
return mThread2Number[id];
|
||||
}
|
||||
}
|
||||
|
||||
int cLogger::Pid2Number(const t_anypid id) {
|
||||
auto found = mPid2Number.find( id );
|
||||
if (found == mPid2Number.end()) { // new one
|
||||
mPid2Number_Biggest++;
|
||||
mPid2Number[id] = mPid2Number_Biggest;
|
||||
_info_c("dbg/main", "This is a new process (used in debug), process pid="<<id); // can cause some recursion
|
||||
return mPid2Number_Biggest;
|
||||
} else {
|
||||
return mPid2Number[id];
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// object gCurrentLogger is defined later - in global namespace below
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// vector debug
|
||||
|
||||
void DisplayStringEndl(std::ostream & out, const std::string text) {
|
||||
out << text;
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
std::string SpaceFromEscape(const std::string &s) {
|
||||
std::ostringstream newStr;
|
||||
for(size_t i = 0; i < s.length();i++) {
|
||||
if(s[i] == '\\' && s[i+1] ==32)
|
||||
newStr<<"";
|
||||
else
|
||||
newStr<<s[i];
|
||||
}
|
||||
return newStr.str();
|
||||
}
|
||||
|
||||
std::string EscapeFromSpace(const std::string &s) {
|
||||
std::ostringstream newStr;
|
||||
for(size_t i = 0; i < s.length();i++) {
|
||||
if(s[i] == 32)
|
||||
newStr << "\\" << " ";
|
||||
else
|
||||
newStr << s[i];
|
||||
}
|
||||
return newStr.str();
|
||||
}
|
||||
|
||||
|
||||
std::string EscapeString(const std::string &s) {
|
||||
std::ostringstream newStr;
|
||||
for(size_t i = 0; i < s.length();i++) {
|
||||
if(s[i] >=32 && s[i] <= 126)
|
||||
newStr<<s[i];
|
||||
else
|
||||
newStr<<"\\"<< (int) s[i];
|
||||
}
|
||||
|
||||
return newStr.str();
|
||||
}
|
||||
|
||||
|
||||
bool CheckIfBegins(const std::string & beggining, const std::string & all) {
|
||||
if (all.compare(0, beggining.length(), beggining) == 0) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckIfEnds (std::string const & ending, std::string const & all){
|
||||
if (all.length() >= ending.length()) {
|
||||
return (0 == all.compare (all.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vector<string> WordsThatMatch(const std::string & sofar, const vector<string> & possib) {
|
||||
vector<string> ret;
|
||||
for ( auto rec : possib) { // check of possibilities
|
||||
if (CheckIfBegins(sofar,rec)) {
|
||||
rec = EscapeFromSpace(rec);
|
||||
ret.push_back(rec); // this record matches
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char GetLastChar(const std::string & str) { // TODO unicode?
|
||||
auto s = str.length();
|
||||
if (s==0) throw std::runtime_error("Getting last character of empty string (" + ToStr(s) + ")" + OT_CODE_STAMP);
|
||||
return str.at( s - 1);
|
||||
}
|
||||
|
||||
std::string GetLastCharIf(const std::string & str) { // TODO unicode?
|
||||
auto s = str.length();
|
||||
if (s==0) return ""; // empty string signalizes ther is nothing to be returned
|
||||
return std::string( 1 , str.at( s - 1) );
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// ASRT - assert. Name like ASSERT() was too long, and ASS() was just... no.
|
||||
// Use it like this: ASRT( x>y ); with the semicolon at end, a clever trick forces this syntax :)
|
||||
|
||||
void Assert(bool result, const std::string &stamp, const std::string &condition) {
|
||||
if (!result) {
|
||||
_erro("Assert failed at "+stamp+": ASSERT( " << condition << ")");
|
||||
throw std::runtime_error("Assert failed at "+stamp+": ASSERT( " + condition + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// advanced string
|
||||
|
||||
const std::string GetMultiline(string endLine) {
|
||||
std::string result(""); // Taken from OT_CLI_ReadUntilEOF
|
||||
while (true) {
|
||||
std::string input_line("");
|
||||
if (std::getline(std::cin, input_line, '\n'))
|
||||
{
|
||||
input_line += "\n";
|
||||
if (input_line[0] == '~')
|
||||
break;
|
||||
result += input_line;
|
||||
}
|
||||
if (std::cin.eof() )
|
||||
{
|
||||
std::cin.clear();
|
||||
break;
|
||||
}
|
||||
if (std::cin.fail() )
|
||||
{
|
||||
std::cin.clear();
|
||||
break;
|
||||
}
|
||||
if (std::cin.bad())
|
||||
{
|
||||
std::cin.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<string> SplitString(const string & str){
|
||||
std::istringstream iss(str);
|
||||
vector<string> vec { std::istream_iterator<string>{iss}, std::istream_iterator<string>{} };
|
||||
return vec;
|
||||
}
|
||||
|
||||
bool checkPrefix(const string & str, char prefix) {
|
||||
if (str.at(0) == prefix)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// operation on files
|
||||
|
||||
|
||||
#ifdef __unix
|
||||
|
||||
void cEnvUtils::GetTmpTextFile() {
|
||||
// TODO make this name configurable (depending on project)
|
||||
char filename[] = "/tmp/otshellutils_text.XXXXXX";
|
||||
fd = mkstemp(filename);
|
||||
if (fd == -1) {
|
||||
_erro("Can't create the file: " << filename);
|
||||
return;
|
||||
}
|
||||
mFilename = filename;
|
||||
}
|
||||
|
||||
void cEnvUtils::CloseFile() {
|
||||
close(fd);
|
||||
unlink( mFilename.c_str() );
|
||||
}
|
||||
|
||||
void cEnvUtils::OpenEditor() {
|
||||
char* editor = std::getenv("OT_EDITOR"); //TODO Read editor from configuration file
|
||||
if (editor == NULL)
|
||||
editor = std::getenv("VISUAL");
|
||||
if (editor == NULL)
|
||||
editor = std::getenv("EDITOR");
|
||||
|
||||
string command;
|
||||
if (editor != NULL)
|
||||
command = ToStr(editor) + " " + mFilename;
|
||||
else
|
||||
command = "/usr/bin/editor " + mFilename;
|
||||
_dbg3("Opening editor with command: " << command);
|
||||
if ( system( command.c_str() ) == -1 )
|
||||
_erro("Cannot execute system command: " << command);
|
||||
}
|
||||
|
||||
const string cEnvUtils::ReadFromTmpFile() {
|
||||
std::ifstream ifs(mFilename);
|
||||
string msg((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
return msg;
|
||||
}
|
||||
|
||||
const string cEnvUtils::Compose() {
|
||||
GetTmpTextFile();
|
||||
OpenEditor();
|
||||
string input = ReadFromTmpFile();
|
||||
CloseFile();
|
||||
return input;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const string cEnvUtils::ReadFromFile(const string path) {
|
||||
std::ifstream ifs(path);
|
||||
string msg((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
return msg;
|
||||
}
|
||||
|
||||
void hintingToTxt(std::fstream & file, string command, vector<string> &commands) {
|
||||
if(file.good()) {
|
||||
file<<command<<"~"<<endl;
|
||||
for (auto a: commands) {
|
||||
file <<a<< " ";
|
||||
file.flush();
|
||||
}
|
||||
file<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
string stringToColor(const string &hash) {
|
||||
// Generete vector with all possible light colors
|
||||
vector <string> lightColors;
|
||||
using namespace zkr;
|
||||
lightColors.push_back(cc::fore::lightblue);
|
||||
lightColors.push_back(cc::fore::lightred);
|
||||
lightColors.push_back(cc::fore::lightmagenta);
|
||||
lightColors.push_back(cc::fore::lightgreen);
|
||||
lightColors.push_back(cc::fore::lightcyan);
|
||||
lightColors.push_back(cc::fore::lightyellow);
|
||||
lightColors.push_back(cc::fore::lightwhite);
|
||||
|
||||
int sum=0;
|
||||
|
||||
for (auto ch : hash) sum+=ch;
|
||||
auto color = sum%(lightColors.size()-1);
|
||||
|
||||
return lightColors.at( color );
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// algorthms
|
||||
|
||||
|
||||
} // namespace nUtil
|
||||
|
||||
|
||||
} // namespace OT
|
||||
|
||||
// global namespace
|
||||
|
||||
const extern int _dbg_ignore = 0; // see description in .hpp
|
||||
|
||||
std::string GetObjectName() {
|
||||
//static std::string * name=nullptr;
|
||||
//if (!name) name = new std::string("(global)");
|
||||
return "";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
nOT::nUtils::cLogger gCurrentLogger;
|
||||
|
||||
@@ -1,532 +0,0 @@
|
||||
/// @file
|
||||
/// @author rfree (current maintainer in monero.cc project)
|
||||
/// @brief various general utils taken from (and relate to) otshell project, including loggiang/debug
|
||||
|
||||
/* See other files here for the LICENCE that applies here. */
|
||||
|
||||
#include "ccolor.hpp"
|
||||
#ifndef INCLUDE_OT_NEWCLI_UTILS
|
||||
#define INCLUDE_OT_NEWCLI_UTILS
|
||||
|
||||
#include "lib_common1.hpp"
|
||||
#ifdef __unix
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include"windows_stream.h"
|
||||
#endif
|
||||
|
||||
#ifndef CFG_WITH_TERMCOLORS
|
||||
//#error "You requested to turn off terminal colors (CFG_WITH_TERMCOLORS), however currently they are hardcoded (this option to turn them off is not yet implemented)."
|
||||
#endif
|
||||
|
||||
///Macros related to automatic deduction of class name etc;
|
||||
#define MAKE_CLASS_NAME(NAME) private: static std::string GetObjectName() { return #NAME; }
|
||||
#define MAKE_STRUCT_NAME(NAME) private: static std::string GetObjectName() { return #NAME; } public:
|
||||
|
||||
// define this to debug the debug system itself:
|
||||
// #define opt_debug_debug
|
||||
|
||||
#ifdef opt_debug_debug
|
||||
#define _dbg_dbg(X) do { std::cerr<<"_dbg_dbg: " << OT_CODE_STAMP << " {thread=" << boost::this_thread::get_id()<<"} " \
|
||||
<< " {pid="<<getpid()<<"} " << ": " << X << std::endl; } while(0)
|
||||
#else
|
||||
#define _dbg_dbg(X) do { } while(0)
|
||||
#endif
|
||||
|
||||
namespace nOT {
|
||||
|
||||
namespace nUtils {
|
||||
|
||||
/// @brief general based for my runtime errors
|
||||
class myexception : public std::runtime_error {
|
||||
public:
|
||||
myexception(const char * what);
|
||||
myexception(const std::string &what);
|
||||
//virtual ~myexception();
|
||||
virtual void Report() const;
|
||||
};
|
||||
|
||||
/// @macro Use this macro INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 as a shortcut for various using std::string etc.
|
||||
INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 // <=== namespaces
|
||||
|
||||
// ======================================================================================
|
||||
/// text trimming functions (they do mutate the passes string); they trim based on std::isspace. also return it's reference again
|
||||
/// http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
||||
std::string & trim(std::string &s); ///< trim text http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
||||
std::string & ltrim(std::string &s); ///< left trim
|
||||
std::string & rtrim(std::string &s); ///< right trim
|
||||
|
||||
// ======================================================================================
|
||||
|
||||
std::string get_current_time();
|
||||
|
||||
// string conversions
|
||||
template <class T>
|
||||
std::string ToStr(const T & obj) {
|
||||
std::ostringstream oss;
|
||||
oss << obj;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
struct cNullstream : std::ostream {
|
||||
cNullstream() : std::ios(0), std::ostream(0) {}
|
||||
};
|
||||
extern cNullstream g_nullstream; // a stream that does nothing (eats/discards data)
|
||||
// ========== debug ==========
|
||||
// _dbg_ignore is moved to global namespace (on purpose)
|
||||
|
||||
// TODO make _dbg_ignore thread-safe everywhere
|
||||
|
||||
extern boost::recursive_mutex gLoggerGuard; // the mutex guarding logging/debugging code e.g. protecting streams, files, etc
|
||||
|
||||
std::atomic<int> & gLoggerGuardDepth_Get(); // getter for the global singleton of counter (it guarantees initializing it to 0). This counter shows the current recursion (re-entrant) level of debug macros.
|
||||
|
||||
// TODO more debug of the debug system:
|
||||
// detect lock() error e.g. recursive limit
|
||||
// detect stream e.g. operator<< error
|
||||
|
||||
#define _debug_level(LEVEL,VAR) do { if (_dbg_ignore< LEVEL) { \
|
||||
_dbg_dbg("WRITE DEBUG: LEVEL="<<LEVEL<<" VAR: " << VAR ); \
|
||||
auto level=LEVEL; short int part=0; \
|
||||
try { \
|
||||
boost::lock_guard<boost::recursive_mutex> mutex_guard( nOT::nUtils::gLoggerGuard ); \
|
||||
part=1; \
|
||||
try { \
|
||||
++nOT::nUtils::gLoggerGuardDepth_Get(); \
|
||||
/* int counter = nOT::nUtils::gLoggerGuardDepth_Get(); if (counter!=1) gCurrentLogger.write_stream(100,"")<<"DEBUG-ERROR: recursion, counter="<<counter<<gCurrentLogger.endline(); */ \
|
||||
gCurrentLogger.write_stream(LEVEL,"") << nOT::nUtils::get_current_time() << ' ' << OT_CODE_STAMP << ' ' << VAR << gCurrentLogger.endline() << std::flush; \
|
||||
part=9; \
|
||||
} catch(...) { \
|
||||
gCurrentLogger.write_stream(std::max(level,90),"") << nOT::nUtils::get_current_time() << ' ' << OT_CODE_STAMP << ' ' << "(ERROR IN DEBUG)" << gCurrentLogger.endline(); \
|
||||
--nOT::nUtils::gLoggerGuardDepth_Get(); throw ; \
|
||||
} \
|
||||
--nOT::nUtils::gLoggerGuardDepth_Get(); \
|
||||
} catch(...) { if (part<8) gCurrentLogger.write_stream(100,"")<<"DEBUG-ERROR: problem in debug mechanism e.g. in locking." <<gCurrentLogger.endline(); throw ; } \
|
||||
} } while(0)
|
||||
|
||||
// info for code below: oss object is normal stack variable, using it does not need lock protection
|
||||
#define _debug_level_c(CHANNEL,LEVEL,VAR) do { if (_dbg_ignore< LEVEL) { \
|
||||
_dbg_dbg("WRITE DEBUG: LEVEL="<<LEVEL<<" CHANNEL="<<CHANNEL<<" VAR: " << VAR ); \
|
||||
auto level=LEVEL; short int part=0; \
|
||||
try { \
|
||||
boost::lock_guard<boost::recursive_mutex> mutex_guard( nOT::nUtils::gLoggerGuard ); \
|
||||
part=1; \
|
||||
try { \
|
||||
++nOT::nUtils::gLoggerGuardDepth_Get(); \
|
||||
std::ostringstream oss; \
|
||||
oss << nOT::nUtils::get_current_time() << ' ' << OT_CODE_STAMP << ' ' << VAR << gCurrentLogger.endline() << std::flush; \
|
||||
std::string as_string = oss.str(); \
|
||||
_dbg_dbg("START will write to log LEVEL="<<LEVEL<<" to CHANNEL="<<CHANNEL<<" as_string="<<as_string); \
|
||||
/* int counter = nOT::nUtils::gLoggerGuardDepth_Get(); if (counter!=1) gCurrentLogger.write_stream(100,"")<<"DEBUG-ERROR: recursion, counter="<<counter<<gCurrentLogger.endline(); */ \
|
||||
gCurrentLogger.write_stream(LEVEL,"" ) << as_string << gCurrentLogger.endline() << std::flush; \
|
||||
gCurrentLogger.write_stream(LEVEL,CHANNEL) << as_string << gCurrentLogger.endline() << std::flush; \
|
||||
_dbg_dbg("DONE will write to log LEVEL="<<LEVEL<<" to CHANNEL="<<CHANNEL<<" as_string="<<as_string); \
|
||||
part=9; \
|
||||
} catch(...) { \
|
||||
gCurrentLogger.write_stream(std::max(level,90),CHANNEL) << nOT::nUtils::get_current_time() << ' ' << OT_CODE_STAMP << ' ' << "(ERROR IN DEBUG)" << gCurrentLogger.endline(); \
|
||||
--nOT::nUtils::gLoggerGuardDepth_Get(); throw ; \
|
||||
} \
|
||||
--nOT::nUtils::gLoggerGuardDepth_Get(); \
|
||||
} catch(...) { if (part<8) gCurrentLogger.write_stream(100,CHANNEL)<<"DEBUG-ERROR: problem in debug mechanism e.g. in locking." <<gCurrentLogger.endline(); throw ; } \
|
||||
} } while(0)
|
||||
|
||||
// Numerical values of the debug levels - are defined here as const ints. Full name (with namespace) given for clarity.
|
||||
extern const int _debug_level_nr_dbg3;
|
||||
extern const int _debug_level_nr_dbg2;
|
||||
extern const int _debug_level_nr_dbg1;
|
||||
extern const int _debug_level_nr_info;
|
||||
extern const int _debug_level_nr_note;
|
||||
extern const int _debug_level_nr_fact;
|
||||
extern const int _debug_level_nr_mark;
|
||||
extern const int _debug_level_nr_warn;
|
||||
extern const int _debug_level_nr_erro;
|
||||
|
||||
#define _dbg3(VAR) _debug_level( nOT::nUtils::_debug_level_nr_dbg3,VAR) // details - most detailed
|
||||
#define _dbg2(VAR) _debug_level( nOT::nUtils::_debug_level_nr_dbg2,VAR) // details - a bit more important
|
||||
#define _dbg1(VAR) _debug_level( nOT::nUtils::_debug_level_nr_dbg1,VAR) // details - more important
|
||||
#define _info(VAR) _debug_level( nOT::nUtils::_debug_level_nr_info,VAR) // information
|
||||
#define _note(VAR) _debug_level( nOT::nUtils::_debug_level_nr_note,VAR) // more interesting information
|
||||
#define _fact(VAR) _debug_level( nOT::nUtils::_debug_level_nr_fact,VAR) // interesting events that could be interesting even for user, for logical/business things
|
||||
#define _mark(VAR) _debug_level( nOT::nUtils::_debug_level_nr_mark,VAR) // marked actions
|
||||
#define _warn(VAR) _debug_level( nOT::nUtils::_debug_level_nr_warn,VAR) // some problems
|
||||
#define _erro(VAR) _debug_level( nOT::nUtils::_debug_level_nr_erro,VAR) // errors
|
||||
|
||||
#define _dbg3_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_dbg3, VAR) // details - most detailed
|
||||
#define _dbg2_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_dbg2, VAR) // details - a bit more important
|
||||
#define _dbg1_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_dbg1, VAR) // details - more important
|
||||
#define _info_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_info, VAR) // information
|
||||
#define _note_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_note, VAR) // more interesting information
|
||||
#define _fact_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_fact, VAR) // interesting events that could be interesting even for user, for logical/business things
|
||||
#define _mark_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_mark, VAR) // marked actions
|
||||
#define _warn_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_warn, VAR) // some problems
|
||||
#define _erro_c(C,VAR) _debug_level_c(C, nOT::nUtils::_debug_level_nr_erro, VAR) // errors
|
||||
|
||||
// lock // because of VAR
|
||||
#define _scope_debug_level_c(CHANNEL,LEVEL,VAR) \
|
||||
std::ostringstream debug_detail_oss; \
|
||||
nOT::nUtils::gLoggerGuard.lock(); \
|
||||
debug_detail_oss << OT_CODE_STAMP << ' ' << VAR ; \
|
||||
nOT::nUtils::nDetail::cDebugScopeGuard debugScopeGuard; \
|
||||
if (_dbg_ignore<LEVEL) debugScopeGuard.Assign(CHANNEL,LEVEL, debug_detail_oss.str()); \
|
||||
if (_dbg_ignore<LEVEL) _debug_level_c(CHANNEL,LEVEL,debug_detail_oss.str() + " ... begin"); \
|
||||
nOT::nUtils::gLoggerGuard.unlock();
|
||||
#define _scope_debug_level(LEVEL,VAR) _scope_debug_level_c("",LEVEL,VAR)
|
||||
|
||||
#define _scope_dbg1(VAR) _scope_debug_level( _debug_level_nr_dbg3, VAR)
|
||||
#define _scope_dbg2(VAR) _scope_debug_level( _debug_level_nr_dbg2, VAR)
|
||||
#define _scope_dbg3(VAR) _scope_debug_level( _debug_level_nr_dbg1, VAR)
|
||||
#define _scope_info(VAR) _scope_debug_level( _debug_level_nr_info, VAR)
|
||||
#define _scope_note(VAR) _scope_debug_level( _debug_level_nr_note, VAR)
|
||||
#define _scope_fact(VAR) _scope_debug_level( _debug_level_nr_fact, VAR)
|
||||
#define _scope_mark(VAR) _scope_debug_level( _debug_level_nr_mark, VAR)
|
||||
#define _scope_warn(VAR) _scope_debug_level( _debug_level_nr_warn, VAR)
|
||||
#define _scope_erro(VAR) _scope_debug_level( _debug_level_nr_erro, VAR)
|
||||
|
||||
/***
|
||||
@brief do not use this namespace directly, it is implementation detail.
|
||||
*/
|
||||
namespace nDetail {
|
||||
|
||||
/***
|
||||
@brief a Debug scope-guard, to log a debug message when current scope is left. Do NOT use this directly,
|
||||
only use it via the macros like _scope_dbg1 etc.
|
||||
*/
|
||||
class cDebugScopeGuard {
|
||||
protected:
|
||||
string mMsg;
|
||||
int mLevel;
|
||||
string mChan;
|
||||
public:
|
||||
cDebugScopeGuard();
|
||||
~cDebugScopeGuard();
|
||||
void Assign(const string &chan, const int level, const string &msg);
|
||||
};
|
||||
|
||||
const char* DbgShortenCodeFileName(const char *s); ///< Returns a pointer to some part of the string that was given, skipping directory names, for log/debug
|
||||
|
||||
} // namespace nDetail
|
||||
|
||||
// ========== logger ==========
|
||||
|
||||
namespace nDetail {
|
||||
struct channel_use_info;
|
||||
} // namespace nDetail
|
||||
|
||||
/***
|
||||
@brief Class to write debug into. Used it by calling the debug macros _dbg1(...) _info(...) _erro(...) etc, NOT directly!
|
||||
@author rfree (maintainer)
|
||||
@thread this class is NOT thread safe and must used only by one thread at once (use it via ot_debug_macros like _info macro they do proper locking)
|
||||
*/
|
||||
class cLogger {
|
||||
public:
|
||||
cLogger();
|
||||
~cLogger();
|
||||
std::ostream & write_stream(int level); ///< starts a new message on given level (e.g. writes out the icon/tag) and returns stream to output to
|
||||
std::ostream & write_stream(int level, const std::string & channel); ///< the same but with name of the debug channel
|
||||
|
||||
void setOutStreamFromGlobalOptions(); // set debug level, file etc - according to global Options
|
||||
void setOutStreamFile(const std::string &fname); // switch to using this file
|
||||
void setDebugLevel(int level); // change the debug level e.g. to mute debug from now
|
||||
|
||||
std::string icon(int level) const; ///< returns "icon" for given debug level. It is text, might include color controll characters
|
||||
std::string endline() const; ///< returns string to be written at end of message
|
||||
|
||||
protected:
|
||||
typedef long int t_anypid; // a portable representation of PID. long int should cover all platforms
|
||||
|
||||
void SetStreamBroken(); ///< call in case of internal error in logger (e.g. can not open a file)
|
||||
void SetStreamBroken(const std::string &msg); ///< same but with error message
|
||||
|
||||
unique_ptr<std::ofstream> mOutfile;
|
||||
std::ostream * mStream; ///< pointing only! can point to our own mOutfile, or maye to global null stream
|
||||
std::ostream * mStreamBrokenDebug; ///< pointing only! this is a pointer to some stream that should be used when normal debugging is broken eg std::cerr
|
||||
bool mIsBroken; ///< is the debugging system broken (this should be set when internal problems occur and should cause fallback to std::cerr)
|
||||
|
||||
std::map< std::string , std::ofstream * > mChannels; // the ofstream objects are owned by this class
|
||||
|
||||
int mLevel; ///< current debug level
|
||||
|
||||
std::ostream & SelectOutput(int level, const std::string & channel) noexcept; ///< returns a proper stream for this level and channel (always usable string)
|
||||
void OpenNewChannel(const std::string & channel) noexcept; ///< tries to prepare this channel. does NOT guarantee to created mChannels[] entry!
|
||||
void OpenNewChannel_(const std::string & channel); ///< internal function, will throw in case of problems
|
||||
std::string GetLogBaseDir() const;
|
||||
|
||||
std::map< boost::thread::id , int > mThread2Number; ///< change long thread IDs into a short nice number to show
|
||||
int mThread2Number_Biggest; ///< current biggest value held there (biggest key) - works as growing-only counter basically
|
||||
int Thread2Number(const boost::thread::id id); ///< convert the system's thread id into a nice short our id; make one if new thread
|
||||
|
||||
std::map< t_anypid , int > mPid2Number; ///< change long proces PID into a short nice number to show
|
||||
int mPid2Number_Biggest; ///< current biggest value held there (biggest key) - works as growing-only counter basically
|
||||
int Pid2Number(const t_anypid id); ///< convert the system's PID id into a nice short our id; make one if new thread
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// vector debug
|
||||
|
||||
template <class T>
|
||||
std::string vectorToStr(const T & v) {
|
||||
std::ostringstream oss;
|
||||
for(auto rec: v) {
|
||||
oss << rec <<",";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DisplayVector(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") {
|
||||
std::copy( v.begin(), v.end(), std::ostream_iterator<T>(out, delim.c_str()) );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void EndlDisplayVector(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") {
|
||||
out << std::endl;
|
||||
DisplayVector(out,v,delim);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DisplayVectorEndl(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") {
|
||||
DisplayVector(out,v,delim);
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DbgDisplayVector(const std::vector<T> &v, const std::string &delim=" ") {
|
||||
std::cerr << "[";
|
||||
std::copy( v.begin(), v.end(), std::ostream_iterator<T>(std::cerr, delim.c_str()) );
|
||||
std::cerr << "]";
|
||||
}
|
||||
|
||||
string stringToColor(const string &hash);
|
||||
template <class T, class T2>
|
||||
void DisplayMap(std::ostream & out, const std::map<T, T2> &m, const std::string &delim=" ") {
|
||||
auto *no_color = zkr::cc::fore::console;
|
||||
for(auto var : m) {
|
||||
out << stringToColor(var.first) << var.first << delim << var.second << no_color << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T, class T2>
|
||||
void EndlDisplayMap(std::ostream & out, const std::map<T, T2> &m, const std::string &delim=" ") {
|
||||
out << endl;
|
||||
for(auto var : m) {
|
||||
out << var.first << delim << var.second << endl;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class T2>
|
||||
void DbgDisplayMap(const std::map<T, T2> &m, const std::string &delim=" ") {
|
||||
for(auto var : m) {
|
||||
std::cerr << var.first << delim << var.second << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void DbgDisplayVectorEndl(const std::vector<T> &v, const std::string &delim=" ") {
|
||||
DbgDisplayVector(v,delim);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void DisplayStringEndl(std::ostream & out, const std::string text);
|
||||
|
||||
bool CheckIfBegins(const std::string & beggining, const std::string & all);
|
||||
bool CheckIfEnds (std::string const & ending, std::string const & all);
|
||||
std::string SpaceFromEscape(const std::string &s);
|
||||
std::string EscapeFromSpace(const std::string &s);
|
||||
vector<string> WordsThatMatch(const std::string & sofar, const vector<string> & possib);
|
||||
char GetLastChar(const std::string & str);
|
||||
std::string GetLastCharIf(const std::string & str); // TODO unicode?
|
||||
std::string EscapeString(const std::string &s);
|
||||
|
||||
|
||||
template <class T>
|
||||
std::string DbgVector(const std::vector<T> &v, const std::string &delim="|") {
|
||||
std::ostringstream oss;
|
||||
oss << "[";
|
||||
bool first=true;
|
||||
for(auto vElement : v) { if (!first) oss<<delim; first=false; oss <<vElement ; }
|
||||
oss << "]";
|
||||
//std::copy( v.begin(), v.end(), std::ostream_iterator<T>(oss, delim.c_str()) );
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::ostream & operator<<(std::ostream & os, const map< T, vector<T> > & obj){
|
||||
os << "[";
|
||||
for(auto const & elem : obj) {
|
||||
os << " [" << elem.first << "=" << DbgVector(elem.second) << "] ";
|
||||
}
|
||||
os << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
template <class T, class T2>
|
||||
std::string DbgMap(const map<T, T2> & map) {
|
||||
std::ostringstream oss;
|
||||
oss << map;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// assert
|
||||
|
||||
// ASRT - assert. Name like ASSERT() was too long, and ASS() was just... no.
|
||||
// Use it like this: ASRT( x>y ); with the semicolon at end, a clever trick forces this syntax :)
|
||||
#define ASRT(x) do { if (!(x)) nOT::nUtils::Assert(false, OT_CODE_STAMP, #x); } while(0)
|
||||
|
||||
void Assert(bool result, const std::string &stamp, const std::string &condition);
|
||||
|
||||
// ====================================================================
|
||||
// advanced string
|
||||
|
||||
const std::string GetMultiline(string endLine = "~");
|
||||
vector<string> SplitString(const string & str);
|
||||
|
||||
bool checkPrefix(const string & str, char prefix = '^');
|
||||
|
||||
// ====================================================================
|
||||
// nUse utils
|
||||
|
||||
enum class eSubjectType {Account, Asset, User, Server, Unknown};
|
||||
|
||||
string SubjectType2String(const eSubjectType & type);
|
||||
eSubjectType String2SubjectType(const string & type);
|
||||
|
||||
// ====================================================================
|
||||
// operation on files
|
||||
|
||||
/// @brief tools related to filesystem
|
||||
/// @author rfree (maintainer)
|
||||
class cFilesystemUtils { // if we do not want to use boost in given project (or we could optionally write boost here later)
|
||||
public:
|
||||
static bool CreateDirTree(const std::string & dir, bool only_below=false);
|
||||
static char GetDirSeparatorSys(); /// < eg '/' or '\'
|
||||
static char GetDirSeparatorInter(); /// < internal is '/'
|
||||
static string FileInternalToSystem(const std::string &name); ///< converts from internal file name string to system file name string
|
||||
static string FileSystemToInternal(const std::string &name); ///< converts from system file name string to internal file name string
|
||||
};
|
||||
|
||||
|
||||
/// @brief utils to e.g. edit a file from console
|
||||
/// @author rfree (maintainer)
|
||||
class cEnvUtils {
|
||||
int fd;
|
||||
string mFilename;
|
||||
|
||||
void GetTmpTextFile();
|
||||
void CloseFile();
|
||||
void OpenEditor();
|
||||
const string ReadFromTmpFile();
|
||||
public:
|
||||
const string Compose();
|
||||
const string ReadFromFile(const string path);
|
||||
};
|
||||
void hintingToTxt(std::fstream & file, string command, vector<string> &commands);
|
||||
void generateQuestions (std::fstream & file, string command);
|
||||
void generateAnswers (std::fstream & file, string command, vector<string> &completions);
|
||||
|
||||
// ====================================================================
|
||||
|
||||
namespace nOper { // nOT::nUtils::nOper
|
||||
// cool shortcut operators, like vector + vecotr operator working same as string (appending)
|
||||
// isolated to namespace because it's unorthodox ide to implement this
|
||||
|
||||
using namespace std;
|
||||
|
||||
// TODO use && and move?
|
||||
template <class T>
|
||||
vector<T> operator+(const vector<T> &a, const vector<T> &b) {
|
||||
vector<T> ret = a;
|
||||
ret.insert( ret.end() , b.begin(), b.end() );
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
vector<T> operator+(const T &a, const vector<T> &b) {
|
||||
vector<T> ret(1,a);
|
||||
ret.insert( ret.end() , b.begin(), b.end() );
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
vector<T> operator+(const vector<T> &a, const T &b) {
|
||||
vector<T> b_vector(1,a);
|
||||
return a + b_vector;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
vector<T>& operator+=(vector<T> &a, const vector<T> &b) {
|
||||
a.insert( a.end() , b.begin(), b.end() );
|
||||
return a;
|
||||
}
|
||||
|
||||
// map
|
||||
template <class TK,class TV>
|
||||
map<TK,TV> operator+(const map<TK,TV> &a, const map<TK,TV> &b) {
|
||||
map<TK,TV> ret = a;
|
||||
for (const auto & elem : b) {
|
||||
ret.insert(elem);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
} // nOT::nUtils::nOper
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// Algorithms
|
||||
|
||||
// ====================================================================
|
||||
// ====================================================================
|
||||
|
||||
|
||||
/**
|
||||
@brief Special type that on creation will be initialized to have value INIT given as template argument.
|
||||
Might be usefull e.g. to express in the declaration of class what will be the default value of member variable
|
||||
See also http://www.boost.org/doc/libs/1_56_0/libs/utility/value_init.htm
|
||||
Probably not needed when using boost in your project.
|
||||
*/
|
||||
template <class T, T INIT>
|
||||
class value_init {
|
||||
private:
|
||||
T data;
|
||||
public:
|
||||
value_init();
|
||||
|
||||
T& operator=(const T& v) { data=v; return *this; }
|
||||
operator T const &() const { return data; }
|
||||
operator T&() { return data; }
|
||||
};
|
||||
|
||||
template <class T, T INIT>
|
||||
value_init<T, INIT>::value_init() : data(INIT) { }
|
||||
|
||||
} // namespace nUtils
|
||||
|
||||
} // namespace nOT
|
||||
|
||||
|
||||
// global namespace
|
||||
extern nOT::nUtils::cLogger gCurrentLogger; ///< The current main logger. Usually do not use it directly, instead use macros like _dbg1 etc
|
||||
|
||||
std::string GetObjectName(); ///< Method to return name of current object; To use in debug; Can be shadowed in your classes. (Might be not used currently)
|
||||
|
||||
const extern int _dbg_ignore; ///< the global _dbg_ignore, but local code (blocks, classes etc) you could shadow it in your code blocks,
|
||||
// to override debug compile-time setting for given block/class, e.g. to disable debug in one of your methods or increase it there.
|
||||
// Or to make it runtime by providing a class normal member and editing it in runtime
|
||||
|
||||
#define OT_CODE_STAMP ( nOT::nUtils::ToStr("[") + nOT::nUtils::nDetail::DbgShortenCodeFileName(__FILE__) + nOT::nUtils::ToStr("+") + nOT::nUtils::ToStr(__LINE__) + nOT::nUtils::ToStr(" ") + (GetObjectName()) + nOT::nUtils::ToStr("::") + nOT::nUtils::ToStr(__FUNCTION__) + nOT::nUtils::ToStr("]"))
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#if defined(_WIN32)
|
||||
#include "windows_stream.h"
|
||||
#include <windows.h>
|
||||
|
||||
windows_stream::windows_stream(unsigned int pLevel)
|
||||
:
|
||||
mLevel(pLevel)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream &stream, windows_stream const& object)
|
||||
{
|
||||
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (object.mLevel >= 100)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 90)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 80)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 75)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 70)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 50)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 40)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 30)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
return stream;
|
||||
}
|
||||
if (object.mLevel >= 20)
|
||||
{
|
||||
SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE);
|
||||
return stream;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef WINDOWS_STREAM_H
|
||||
#define WINDOWS_STREAM_H
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
class windows_stream
|
||||
{
|
||||
public:
|
||||
windows_stream(unsigned int pLevel);
|
||||
friend std::ostream& operator<<(std::ostream &stream, windows_stream const& object);
|
||||
private:
|
||||
unsigned int mLevel = 0;
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // WINDOWS_STREAM_H
|
||||
@@ -32,4 +32,5 @@ status
|
||||
stop_daemon
|
||||
stop_mining
|
||||
stop_save_graph
|
||||
sync_info
|
||||
unban
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
export LD_LIBRARY_PATH=${SNAP_LIBRARY_PATH}:${SNAP}/usr/lib/x86_64-linux-gnu
|
||||
export HOME=${SNAP_DATA}
|
||||
cd ${SNAP_DATA}
|
||||
|
||||
ARGS=
|
||||
if [ -e "${SNAP_DATA}/etc/monerod.conf" ]; then
|
||||
ARGS="--config-file ${SNAP_DATA}/etc/monerod.conf"
|
||||
fi
|
||||
|
||||
exec ${SNAP}/bin/monerod --detach $ARGS
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
exec tail -c +0 -F ${SNAP_DATA}/.bitmonero/bitmonero.log
|
||||
8
contrib/snap/monerod-wrapper
Executable file
8
contrib/snap/monerod-wrapper
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "$SNAP_USER_DATA/etc" ]; then
|
||||
mkdir $SNAP_USER_DATA/etc/
|
||||
cp -R $SNAP/etc/monerod.conf $SNAP_USER_DATA/etc/monerod.conf
|
||||
fi
|
||||
|
||||
exec "$SNAP/bin/monerod" "$@"
|
||||
9
contrib/snap/monerod.conf
Normal file
9
contrib/snap/monerod.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
# Configuration for monerod
|
||||
# Syntax: any command line option may be specified as 'clioptionname=value'.
|
||||
# See 'monerod --help' for all available options.
|
||||
|
||||
# Overrided by snap:
|
||||
# data-dir=/var/lib/monero
|
||||
# log-file=/var/log/monero/monero.log
|
||||
|
||||
log-level=0
|
||||
BIN
contrib/snap/setup/gui/icon.png
Normal file
BIN
contrib/snap/setup/gui/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -1,5 +1,5 @@
|
||||
name: monero
|
||||
version: 0 # TODO: change this to release version in CI builds
|
||||
version: 0.10.2-1
|
||||
summary: "Monero: the secure, private, untraceable cryptocurrency https://getmonero.org"
|
||||
description: |
|
||||
Monero is a private, secure, untraceable, decentralised digital currency.
|
||||
@@ -9,37 +9,28 @@ grade: devel
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
d:
|
||||
monerod:
|
||||
daemon: forking
|
||||
command: daemon.bash
|
||||
command: |
|
||||
monerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/monerod.conf
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
|
||||
log:
|
||||
command: log.bash
|
||||
|
||||
monero:
|
||||
command: wallet.bash
|
||||
monero-wallet-rpc:
|
||||
command: |
|
||||
monero-wallet-rpc --log-file ${SNAP_USER_DATA}
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- network-bind
|
||||
monero-wallet-cli:
|
||||
command: |
|
||||
monero-wallet-cli --log-file ${SNAP_USER_DATA}
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
|
||||
parts:
|
||||
wrapper:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage-packages:
|
||||
- rlwrap
|
||||
organize:
|
||||
contrib/snap/daemon.bash: daemon.bash
|
||||
contrib/snap/log.bash: log.bash
|
||||
contrib/snap/wallet.bash: wallet.bash
|
||||
snap:
|
||||
- daemon.bash
|
||||
- log.bash
|
||||
- wallet.bash
|
||||
- usr/bin/rlwrap
|
||||
|
||||
cmake-build:
|
||||
plugin: cmake
|
||||
configflags:
|
||||
@@ -51,7 +42,6 @@ parts:
|
||||
source: .
|
||||
build-packages:
|
||||
- gcc
|
||||
- cmake
|
||||
- pkg-config
|
||||
- libunbound-dev
|
||||
- libevent-dev
|
||||
@@ -68,6 +58,18 @@ parts:
|
||||
- libminiupnpc10
|
||||
- libunbound2
|
||||
- libunwind8
|
||||
snap:
|
||||
prime:
|
||||
- bin
|
||||
- usr/lib/
|
||||
- -usr/lib/gcc
|
||||
- -usr/share
|
||||
|
||||
dist-files:
|
||||
plugin: dump
|
||||
source: .
|
||||
organize:
|
||||
contrib/snap/monerod.conf: etc/monerod.conf
|
||||
contrib/snap/monerod-wrapper: bin/monerod-wrapper
|
||||
prime:
|
||||
- etc
|
||||
- bin
|
||||
- usr
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
export LD_LIBRARY_PATH=${SNAP_LIBRARY_PATH}:${SNAP}/usr/lib/x86_64-linux-gnu
|
||||
export HOME=${SNAP_USER_DATA}
|
||||
cd ${SNAP_USER_DATA}
|
||||
|
||||
exec ${SNAP}/usr/bin/rlwrap ${SNAP}/bin/monero-wallet-cli "$@"
|
||||
10
external/CMakeLists.txt
vendored
10
external/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -34,11 +34,12 @@
|
||||
# We always compile if we are building statically to reduce static dependency issues...
|
||||
# ...except for FreeBSD, because FreeBSD is a special case that doesn't play well with
|
||||
# others.
|
||||
|
||||
find_package(Miniupnpc QUIET)
|
||||
if(NOT IOS)
|
||||
find_package(Miniupnpc QUIET)
|
||||
endif()
|
||||
|
||||
# If we have the correct shared version and we're not building static, use it
|
||||
if(STATIC)
|
||||
if(STATIC OR IOS)
|
||||
set(USE_SHARED_MINIUPNPC false)
|
||||
elseif(MINIUPNP_FOUND AND MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(USE_SHARED_MINIUPNPC true)
|
||||
@@ -98,3 +99,4 @@ else()
|
||||
endif()
|
||||
|
||||
add_subdirectory(db_drivers)
|
||||
add_subdirectory(easylogging++)
|
||||
|
||||
55
external/boost/archive/portable_binary_archive.hpp
vendored
Normal file
55
external/boost/archive/portable_binary_archive.hpp
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef PORTABLE_BINARY_ARCHIVE_HPP
|
||||
#define PORTABLE_BINARY_ARCHIVE_HPP
|
||||
|
||||
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// MS compatible compilers support #pragma once
|
||||
#if defined(_MSC_VER)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
|
||||
#include <climits>
|
||||
#if CHAR_BIT != 8
|
||||
#error This code assumes an eight-bit byte.
|
||||
#endif
|
||||
|
||||
#include <boost/archive/basic_archive.hpp>
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
#include <boost/archive/impl/archive_serializer_map.ipp>
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
enum portable_binary_archive_flags {
|
||||
endian_big = 0x4000,
|
||||
endian_little = 0x8000
|
||||
};
|
||||
|
||||
//#if ( endian_big <= boost::archive::flags_last )
|
||||
//#error archive flags conflict
|
||||
//#endif
|
||||
|
||||
inline void
|
||||
reverse_bytes(signed char size, char *address){
|
||||
if (size <= 0)
|
||||
throw archive_exception(archive_exception::other_exception);
|
||||
char * first = address;
|
||||
char * last = first + size - 1;
|
||||
for(;first < last;++first, --last){
|
||||
char x = *last;
|
||||
*last = *first;
|
||||
*first = x;
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
#endif // PORTABLE_BINARY_ARCHIVE_HPP
|
||||
373
external/boost/archive/portable_binary_iarchive.hpp
vendored
Normal file
373
external/boost/archive/portable_binary_iarchive.hpp
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
#ifndef PORTABLE_BINARY_IARCHIVE_HPP
|
||||
#define PORTABLE_BINARY_IARCHIVE_HPP
|
||||
|
||||
// MS compatible compilers support #pragma once
|
||||
#if defined(_MSC_VER)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4244 )
|
||||
#endif
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// portable_binary_iarchive.hpp
|
||||
|
||||
// (C) Copyright 2002-7 Robert Ramey - http://www.rrsd.com .
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
#include <istream>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/item_version_type.hpp>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
#include <boost/archive/basic_binary_iprimitive.hpp>
|
||||
#include <boost/archive/detail/common_iarchive.hpp>
|
||||
#include <boost/archive/detail/register_archive.hpp>
|
||||
|
||||
#include <boost/archive/portable_binary_archive.hpp>
|
||||
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// exception to be thrown if integer read from archive doesn't fit
|
||||
// variable being loaded
|
||||
class portable_binary_iarchive_exception :
|
||||
public boost::archive::archive_exception
|
||||
{
|
||||
public:
|
||||
enum exception_code {
|
||||
incompatible_integer_size
|
||||
} m_exception_code ;
|
||||
portable_binary_iarchive_exception(exception_code c = incompatible_integer_size ) :
|
||||
boost::archive::archive_exception(boost::archive::archive_exception::other_exception),
|
||||
m_exception_code(c)
|
||||
{}
|
||||
virtual const char *what( ) const throw( )
|
||||
{
|
||||
const char *msg = "programmer error";
|
||||
switch(m_exception_code){
|
||||
case incompatible_integer_size:
|
||||
msg = "integer cannot be represented";
|
||||
break;
|
||||
default:
|
||||
msg = boost::archive::archive_exception::what();
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// "Portable" input binary archive. It addresses integer size and endienness so
|
||||
// that binary archives can be passed across systems. Note:floating point types
|
||||
// not addressed here
|
||||
class portable_binary_iarchive :
|
||||
public boost::archive::basic_binary_iprimitive<
|
||||
portable_binary_iarchive,
|
||||
std::istream::char_type,
|
||||
std::istream::traits_type
|
||||
>,
|
||||
public boost::archive::detail::common_iarchive<
|
||||
portable_binary_iarchive
|
||||
>
|
||||
{
|
||||
typedef boost::archive::basic_binary_iprimitive<
|
||||
portable_binary_iarchive,
|
||||
std::istream::char_type,
|
||||
std::istream::traits_type
|
||||
> primitive_base_t;
|
||||
typedef boost::archive::detail::common_iarchive<
|
||||
portable_binary_iarchive
|
||||
> archive_base_t;
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
#else
|
||||
friend archive_base_t;
|
||||
friend primitive_base_t; // since with override load below
|
||||
friend class boost::archive::detail::interface_iarchive<
|
||||
portable_binary_iarchive
|
||||
>;
|
||||
friend class boost::archive::load_access;
|
||||
protected:
|
||||
#endif
|
||||
unsigned int m_flags;
|
||||
void load_impl(boost::intmax_t & l, char maxsize);
|
||||
|
||||
// default fall through for any types not specified here
|
||||
template<class T>
|
||||
void load(T & t){
|
||||
boost::intmax_t l;
|
||||
load_impl(l, sizeof(T));
|
||||
// use cast to avoid compile time warning
|
||||
//t = static_cast< T >(l);
|
||||
t = T(l);
|
||||
}
|
||||
void load(boost::serialization::item_version_type & t){
|
||||
boost::intmax_t l;
|
||||
load_impl(l, sizeof(boost::serialization::item_version_type));
|
||||
// use cast to avoid compile time warning
|
||||
t = boost::serialization::item_version_type(l);
|
||||
}
|
||||
void load(boost::archive::version_type & t){
|
||||
boost::intmax_t l;
|
||||
load_impl(l, sizeof(boost::archive::version_type));
|
||||
// use cast to avoid compile time warning
|
||||
t = boost::archive::version_type(l);
|
||||
}
|
||||
void load(boost::archive::class_id_type & t){
|
||||
boost::intmax_t l;
|
||||
load_impl(l, sizeof(boost::archive::class_id_type));
|
||||
// use cast to avoid compile time warning
|
||||
t = boost::archive::class_id_type(static_cast<int>(l));
|
||||
}
|
||||
void load(std::string & t){
|
||||
this->primitive_base_t::load(t);
|
||||
}
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
void load(std::wstring & t){
|
||||
this->primitive_base_t::load(t);
|
||||
}
|
||||
#endif
|
||||
void load(float & t){
|
||||
this->primitive_base_t::load(t);
|
||||
// floats not supported
|
||||
//BOOST_STATIC_ASSERT(false);
|
||||
}
|
||||
void load(double & t){
|
||||
this->primitive_base_t::load(t);
|
||||
// doubles not supported
|
||||
//BOOST_STATIC_ASSERT(false);
|
||||
}
|
||||
void load(char & t){
|
||||
this->primitive_base_t::load(t);
|
||||
}
|
||||
void load(unsigned char & t){
|
||||
this->primitive_base_t::load(t);
|
||||
}
|
||||
typedef boost::archive::detail::common_iarchive<portable_binary_iarchive>
|
||||
detail_common_iarchive;
|
||||
#if BOOST_VERSION > 105800
|
||||
template<class T>
|
||||
void load_override(T & t){
|
||||
this->detail_common_iarchive::load_override(t);
|
||||
}
|
||||
void load_override(boost::archive::class_name_type & t);
|
||||
// binary files don't include the optional information
|
||||
void load_override(boost::archive::class_id_optional_type &){}
|
||||
#else
|
||||
template<class T>
|
||||
void load_override(T & t, int){
|
||||
this->detail_common_iarchive::load_override(t, 0);
|
||||
}
|
||||
void load_override(boost::archive::class_name_type & t, int);
|
||||
// binary files don't include the optional information
|
||||
void load_override(boost::archive::class_id_optional_type &, int){}
|
||||
#endif
|
||||
|
||||
void init(unsigned int flags);
|
||||
public:
|
||||
portable_binary_iarchive(std::istream & is, unsigned flags = 0) :
|
||||
primitive_base_t(
|
||||
* is.rdbuf(),
|
||||
0 != (flags & boost::archive::no_codecvt)
|
||||
),
|
||||
archive_base_t(flags),
|
||||
m_flags(0)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
|
||||
portable_binary_iarchive(
|
||||
std::basic_streambuf<
|
||||
std::istream::char_type,
|
||||
std::istream::traits_type
|
||||
> & bsb,
|
||||
unsigned int flags
|
||||
) :
|
||||
primitive_base_t(
|
||||
bsb,
|
||||
0 != (flags & boost::archive::no_codecvt)
|
||||
),
|
||||
archive_base_t(flags),
|
||||
m_flags(0)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
// required by export in boost version > 1.34
|
||||
#ifdef BOOST_SERIALIZATION_REGISTER_ARCHIVE
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(portable_binary_iarchive)
|
||||
#endif
|
||||
|
||||
// required by export in boost <= 1.34
|
||||
#define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES portable_binary_iarchive
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// portable_binary_iarchive.cpp
|
||||
|
||||
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/detail/endian.hpp>
|
||||
#include <boost/serialization/throw_exception.hpp>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
inline void
|
||||
portable_binary_iarchive::load_impl(boost::intmax_t & l, char maxsize){
|
||||
signed char size;
|
||||
l = 0;
|
||||
this->primitive_base_t::load(size);
|
||||
|
||||
if(0 == size){
|
||||
return;
|
||||
}
|
||||
|
||||
bool negative = (size < 0);
|
||||
if(negative)
|
||||
size = -size;
|
||||
|
||||
if(size > maxsize)
|
||||
boost::serialization::throw_exception(
|
||||
portable_binary_iarchive_exception()
|
||||
);
|
||||
|
||||
char * cptr = reinterpret_cast<char *>(& l);
|
||||
#ifdef BOOST_BIG_ENDIAN
|
||||
cptr += (sizeof(boost::intmax_t) - size);
|
||||
#endif
|
||||
this->primitive_base_t::load_binary(cptr, size);
|
||||
|
||||
#ifdef BOOST_BIG_ENDIAN
|
||||
if(m_flags & endian_little)
|
||||
#else
|
||||
if(m_flags & endian_big)
|
||||
#endif
|
||||
reverse_bytes(size, cptr);
|
||||
|
||||
if(negative)
|
||||
l = -l;
|
||||
}
|
||||
|
||||
#if BOOST_VERSION > 105800
|
||||
inline void
|
||||
portable_binary_iarchive::load_override(
|
||||
boost::archive::class_name_type & t
|
||||
){
|
||||
std::string cn;
|
||||
cn.reserve(BOOST_SERIALIZATION_MAX_KEY_SIZE);
|
||||
load_override(cn);
|
||||
if(cn.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE - 1))
|
||||
boost::serialization::throw_exception(
|
||||
boost::archive::archive_exception(
|
||||
boost::archive::archive_exception::invalid_class_name)
|
||||
);
|
||||
std::memcpy(t, cn.data(), cn.size());
|
||||
// borland tweak
|
||||
t.t[cn.size()] = '\0';
|
||||
}
|
||||
#else
|
||||
inline void
|
||||
portable_binary_iarchive::load_override(
|
||||
boost::archive::class_name_type & t, int
|
||||
){
|
||||
std::string cn;
|
||||
cn.reserve(BOOST_SERIALIZATION_MAX_KEY_SIZE);
|
||||
load_override(cn, 0);
|
||||
if(cn.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE - 1))
|
||||
boost::serialization::throw_exception(
|
||||
boost::archive::archive_exception(
|
||||
boost::archive::archive_exception::invalid_class_name)
|
||||
);
|
||||
std::memcpy(t, cn.data(), cn.size());
|
||||
// borland tweak
|
||||
t.t[cn.size()] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void
|
||||
portable_binary_iarchive::init(unsigned int flags){
|
||||
if(0 == (flags & boost::archive::no_header)){
|
||||
// read signature in an archive version independent manner
|
||||
std::string file_signature;
|
||||
* this >> file_signature;
|
||||
if(file_signature != boost::archive::BOOST_ARCHIVE_SIGNATURE())
|
||||
boost::serialization::throw_exception(
|
||||
boost::archive::archive_exception(
|
||||
boost::archive::archive_exception::invalid_signature
|
||||
)
|
||||
);
|
||||
// make sure the version of the reading archive library can
|
||||
// support the format of the archive being read
|
||||
boost::archive::library_version_type input_library_version;
|
||||
* this >> input_library_version;
|
||||
|
||||
// ignore archive version checking
|
||||
/*
|
||||
// extra little .t is to get around borland quirk
|
||||
if(boost::archive::BOOST_ARCHIVE_VERSION() < input_library_version)
|
||||
boost::serialization::throw_exception(
|
||||
boost::archive::archive_exception(
|
||||
boost::archive::archive_exception::unsupported_version
|
||||
)
|
||||
);
|
||||
*/
|
||||
|
||||
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205))
|
||||
this->set_library_version(input_library_version);
|
||||
//#else
|
||||
//#if ! BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
|
||||
//detail::
|
||||
//#endif
|
||||
boost::archive::detail::basic_iarchive::set_library_version(
|
||||
input_library_version
|
||||
);
|
||||
#endif
|
||||
}
|
||||
unsigned char x;
|
||||
load(x);
|
||||
m_flags = x << CHAR_BIT;
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
namespace boost {
|
||||
namespace archive {
|
||||
|
||||
namespace detail {
|
||||
template class archive_serializer_map<portable_binary_iarchive>;
|
||||
}
|
||||
|
||||
// template class basic_binary_iprimitive<
|
||||
// portable_binary_iarchive,
|
||||
// std::istream::char_type,
|
||||
// std::istream::traits_type
|
||||
//> ;
|
||||
|
||||
} // namespace archive
|
||||
} // namespace boost
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif // PORTABLE_BINARY_IARCHIVE_HPP
|
||||
320
external/boost/archive/portable_binary_oarchive.hpp
vendored
Normal file
320
external/boost/archive/portable_binary_oarchive.hpp
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
#ifndef PORTABLE_BINARY_OARCHIVE_HPP
|
||||
#define PORTABLE_BINARY_OARCHIVE_HPP
|
||||
|
||||
// MS compatible compilers support #pragma once
|
||||
#if defined(_MSC_VER)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4244 )
|
||||
#endif
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// portable_binary_oarchive.hpp
|
||||
|
||||
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
#include <ostream>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
#include <boost/archive/basic_binary_oprimitive.hpp>
|
||||
#include <boost/archive/detail/common_oarchive.hpp>
|
||||
#include <boost/archive/detail/register_archive.hpp>
|
||||
|
||||
#include <boost/archive/portable_binary_archive.hpp>
|
||||
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// exception to be thrown if integer read from archive doesn't fit
|
||||
// variable being loaded
|
||||
class portable_binary_oarchive_exception :
|
||||
public boost::archive::archive_exception
|
||||
{
|
||||
public:
|
||||
enum exception_code {
|
||||
invalid_flags
|
||||
} m_exception_code ;
|
||||
portable_binary_oarchive_exception(exception_code c = invalid_flags ) :
|
||||
boost::archive::archive_exception(boost::archive::archive_exception::other_exception),
|
||||
m_exception_code(c)
|
||||
{}
|
||||
virtual const char *what( ) const throw( )
|
||||
{
|
||||
const char *msg = "programmer error";
|
||||
switch(m_exception_code){
|
||||
case invalid_flags:
|
||||
msg = "cannot be both big and little endian";
|
||||
break;
|
||||
default:
|
||||
msg = boost::archive::archive_exception::what();
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// "Portable" output binary archive. This is a variation of the native binary
|
||||
// archive. it addresses integer size and endienness so that binary archives can
|
||||
// be passed across systems. Note:floating point types not addressed here
|
||||
|
||||
class portable_binary_oarchive :
|
||||
public boost::archive::basic_binary_oprimitive<
|
||||
portable_binary_oarchive,
|
||||
std::ostream::char_type,
|
||||
std::ostream::traits_type
|
||||
>,
|
||||
public boost::archive::detail::common_oarchive<
|
||||
portable_binary_oarchive
|
||||
>
|
||||
{
|
||||
typedef boost::archive::basic_binary_oprimitive<
|
||||
portable_binary_oarchive,
|
||||
std::ostream::char_type,
|
||||
std::ostream::traits_type
|
||||
> primitive_base_t;
|
||||
typedef boost::archive::detail::common_oarchive<
|
||||
portable_binary_oarchive
|
||||
> archive_base_t;
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
#else
|
||||
friend archive_base_t;
|
||||
friend primitive_base_t; // since with override save below
|
||||
friend class boost::archive::detail::interface_oarchive<
|
||||
portable_binary_oarchive
|
||||
>;
|
||||
friend class boost::archive::save_access;
|
||||
protected:
|
||||
#endif
|
||||
unsigned int m_flags;
|
||||
void save_impl(const boost::intmax_t l, const char maxsize);
|
||||
// add base class to the places considered when matching
|
||||
// save function to a specific set of arguments. Note, this didn't
|
||||
// work on my MSVC 7.0 system so we use the sure-fire method below
|
||||
// using archive_base_t::save;
|
||||
|
||||
// default fall through for any types not specified here
|
||||
template<class T>
|
||||
void save(const T & t){
|
||||
save_impl(t, sizeof(T));
|
||||
}
|
||||
void save(const std::string & t){
|
||||
this->primitive_base_t::save(t);
|
||||
}
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
void save(const std::wstring & t){
|
||||
this->primitive_base_t::save(t);
|
||||
}
|
||||
#endif
|
||||
void save(const float & t){
|
||||
this->primitive_base_t::save(t);
|
||||
// floats not supported
|
||||
//BOOST_STATIC_ASSERT(false);
|
||||
}
|
||||
void save(const double & t){
|
||||
this->primitive_base_t::save(t);
|
||||
// doubles not supported
|
||||
//BOOST_STATIC_ASSERT(false);
|
||||
}
|
||||
void save(const char & t){
|
||||
this->primitive_base_t::save(t);
|
||||
}
|
||||
void save(const unsigned char & t){
|
||||
this->primitive_base_t::save(t);
|
||||
}
|
||||
|
||||
// default processing - kick back to base class. Note the
|
||||
// extra stuff to get it passed borland compilers
|
||||
typedef boost::archive::detail::common_oarchive<portable_binary_oarchive>
|
||||
detail_common_oarchive;
|
||||
#if BOOST_VERSION > 105800
|
||||
template<class T>
|
||||
void save_override(T & t){
|
||||
this->detail_common_oarchive::save_override(t);
|
||||
}
|
||||
// explicitly convert to char * to avoid compile ambiguities
|
||||
void save_override(const boost::archive::class_name_type & t){
|
||||
const std::string s(t);
|
||||
* this << s;
|
||||
}
|
||||
// binary files don't include the optional information
|
||||
void save_override(
|
||||
const boost::archive::class_id_optional_type & /* t */
|
||||
){}
|
||||
#else
|
||||
template<class T>
|
||||
void save_override(T & t, int){
|
||||
this->detail_common_oarchive::save_override(t, 0);
|
||||
}
|
||||
// explicitly convert to char * to avoid compile ambiguities
|
||||
void save_override(const boost::archive::class_name_type & t, int){
|
||||
const std::string s(t);
|
||||
* this << s;
|
||||
}
|
||||
// binary files don't include the optional information
|
||||
void save_override(
|
||||
const boost::archive::class_id_optional_type & /* t */, int
|
||||
){}
|
||||
#endif
|
||||
|
||||
void init(unsigned int flags);
|
||||
public:
|
||||
portable_binary_oarchive(std::ostream & os, unsigned flags = 0) :
|
||||
primitive_base_t(
|
||||
* os.rdbuf(),
|
||||
0 != (flags & boost::archive::no_codecvt)
|
||||
),
|
||||
archive_base_t(flags),
|
||||
m_flags(flags & (endian_big | endian_little))
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
|
||||
portable_binary_oarchive(
|
||||
std::basic_streambuf<
|
||||
std::ostream::char_type,
|
||||
std::ostream::traits_type
|
||||
> & bsb,
|
||||
unsigned int flags
|
||||
) :
|
||||
primitive_base_t(
|
||||
bsb,
|
||||
0 != (flags & boost::archive::no_codecvt)
|
||||
),
|
||||
archive_base_t(flags),
|
||||
m_flags(0)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
// required by export in boost version > 1.34
|
||||
#ifdef BOOST_SERIALIZATION_REGISTER_ARCHIVE
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(portable_binary_oarchive)
|
||||
#endif
|
||||
|
||||
// required by export in boost <= 1.34
|
||||
#define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES portable_binary_oarchive
|
||||
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// portable_binary_oarchive.cpp
|
||||
|
||||
// (C) Copyright 2002-7 Robert Ramey - http://www.rrsd.com .
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
#include <ostream>
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
inline void
|
||||
portable_binary_oarchive::save_impl(
|
||||
const boost::intmax_t l,
|
||||
const char maxsize
|
||||
){
|
||||
signed char size = 0;
|
||||
|
||||
if(l == 0){
|
||||
this->primitive_base_t::save(size);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::intmax_t ll;
|
||||
bool negative = (l < 0);
|
||||
if(negative)
|
||||
ll = -l;
|
||||
else
|
||||
ll = l;
|
||||
|
||||
do{
|
||||
ll >>= CHAR_BIT;
|
||||
++size;
|
||||
}while(ll != 0);
|
||||
|
||||
this->primitive_base_t::save(
|
||||
static_cast<signed char>(negative ? -size : size)
|
||||
);
|
||||
|
||||
if(negative)
|
||||
ll = -l;
|
||||
else
|
||||
ll = l;
|
||||
char * cptr = reinterpret_cast<char *>(& ll);
|
||||
#ifdef BOOST_BIG_ENDIAN
|
||||
cptr += (sizeof(boost::intmax_t) - size);
|
||||
if(m_flags & endian_little)
|
||||
reverse_bytes(size, cptr);
|
||||
#else
|
||||
if(m_flags & endian_big)
|
||||
reverse_bytes(size, cptr);
|
||||
#endif
|
||||
this->primitive_base_t::save_binary(cptr, size);
|
||||
}
|
||||
|
||||
inline void
|
||||
portable_binary_oarchive::init(unsigned int flags) {
|
||||
if(m_flags == (endian_big | endian_little)){
|
||||
boost::serialization::throw_exception(
|
||||
portable_binary_oarchive_exception()
|
||||
);
|
||||
}
|
||||
if(0 == (flags & boost::archive::no_header)){
|
||||
// write signature in an archive version independent manner
|
||||
const std::string file_signature(
|
||||
boost::archive::BOOST_ARCHIVE_SIGNATURE()
|
||||
);
|
||||
* this << file_signature;
|
||||
// ignore archive version checking
|
||||
const boost::archive::library_version_type v{};
|
||||
/*
|
||||
// write library version
|
||||
const boost::archive::library_version_type v(
|
||||
boost::archive::BOOST_ARCHIVE_VERSION()
|
||||
);
|
||||
*/
|
||||
* this << v;
|
||||
}
|
||||
save(static_cast<unsigned char>(m_flags >> CHAR_BIT));
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
namespace boost {
|
||||
namespace archive {
|
||||
|
||||
namespace detail {
|
||||
template class archive_serializer_map<portable_binary_oarchive>;
|
||||
}
|
||||
|
||||
// template class basic_binary_oprimitive<
|
||||
// portable_binary_oarchive,
|
||||
// std::ostream::char_type,
|
||||
// std::ostream::traits_type
|
||||
// > ;
|
||||
|
||||
} // namespace archive
|
||||
} // namespace boost
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif // PORTABLE_BINARY_OARCHIVE_HPP
|
||||
2
external/db_drivers/CMakeLists.txt
vendored
2
external/db_drivers/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
# Copyright (c) 2014-2017, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user