Compare commits
810 Commits
v7.2.2
...
feature/se
Author | SHA1 | Date | |
---|---|---|---|
|
bdee582203 | ||
|
4ef04b8339 | ||
|
e581f29b42 | ||
|
a42f115f79 | ||
|
5ce1a596cf | ||
|
21db7b6c5b | ||
|
e15a2900e7 | ||
|
140a21c8b3 | ||
|
6d0c568aaa | ||
|
c96abcef1c | ||
|
4a9b0b9dfd | ||
|
8837d5e784 | ||
|
242c945400 | ||
|
feab4dee0f | ||
|
8175829b4b | ||
|
4c66a7561e | ||
|
111475e65c | ||
|
45061b0b14 | ||
|
1bb847a51c | ||
|
ce9feeafdf | ||
|
415f0b3e6d | ||
|
94431756ff | ||
|
5f6c54bb90 | ||
|
f994a41845 | ||
|
f3760318b7 | ||
|
c2362e6875 | ||
|
d91b24723d | ||
|
2d28b7d4ff | ||
|
86d3fc8621 | ||
|
422c7ff855 | ||
|
1c7ccbae12 | ||
|
ed2a81f115 | ||
|
7ed8ac208a | ||
|
aa12098cb5 | ||
|
5d4bb90703 | ||
|
fad9f89846 | ||
|
527308a049 | ||
|
68b318ab97 | ||
|
65bae2736d | ||
|
a923caec0b | ||
|
4d7332c4ee | ||
|
4f3f1f3e4c | ||
|
2a954b5b5b | ||
|
b96b3b099f | ||
|
bb31612ebe | ||
|
d2c5ab1cc4 | ||
|
a01584ad9d | ||
|
9651f3823d | ||
|
0544cdedeb | ||
|
df0239ae68 | ||
|
c8bf2a0d82 | ||
|
4d96804b22 | ||
|
ce9db42c23 | ||
|
a844dbc587 | ||
|
28952cb0b0 | ||
|
fe29579755 | ||
|
b816f1fbda | ||
|
1320e4ddaf | ||
|
f4a7277d61 | ||
|
34d7b18c85 | ||
|
d72d516a92 | ||
|
f6c482c65d | ||
|
dec8a2b9ab | ||
|
a5bc39be55 | ||
|
c62ad5f466 | ||
|
effa115ed2 | ||
|
c992cb4e42 | ||
|
b9504fcd44 | ||
|
299bcd4b92 | ||
|
f56098dd4c | ||
|
e0187b2d8e | ||
|
31682f5f2d | ||
|
221087ffff | ||
|
c7fc4f0f8e | ||
|
2eece1d11a | ||
|
5ba05212ec | ||
|
9e457871b4 | ||
|
b5481262fb | ||
|
98e98f083e | ||
|
d60777b9cc | ||
|
8b5e42fe84 | ||
|
d89d152ad7 | ||
|
47a3736b24 | ||
|
1cd7cf340a | ||
|
3a25a05d9c | ||
|
d2acfd5d1f | ||
|
9dfcd8ea69 | ||
|
ee65f95fe3 | ||
|
b9cc6d7e23 | ||
|
1e97e5e536 | ||
|
440a1058b3 | ||
|
ff489515be | ||
|
536a502b60 | ||
|
db0ff4ecd1 | ||
|
e4aed56d72 | ||
|
1427a97dd9 | ||
|
d7318f97e6 | ||
|
d1a4cab134 | ||
|
8e7d310439 | ||
|
9347664622 | ||
|
4e240e4992 | ||
|
626e190d91 | ||
|
1933da7044 | ||
|
494f408320 | ||
|
299afc1425 | ||
|
0679b6399f | ||
|
862f8ea2d4 | ||
|
cae016564e | ||
|
e223f8fac2 | ||
|
c86fa8ad3b | ||
|
ba4cf75e0f | ||
|
9f98628709 | ||
|
0b2d816320 | ||
|
8b1c4ff081 | ||
|
fde0b717d3 | ||
|
228cdca250 | ||
|
18386ae66f | ||
|
5c5ea6dec1 | ||
|
2e1657167f | ||
|
c91a0d2a35 | ||
|
d465511812 | ||
|
6b98694caa | ||
|
d82e05f72d | ||
|
48622a24db | ||
|
94a274ced4 | ||
|
a7977cf1a5 | ||
|
3fffd2ed0b | ||
|
a0d5f37402 | ||
|
1b11ef006a | ||
|
155bbfa984 | ||
|
89aae8b344 | ||
|
28a0ba4768 | ||
|
708969c126 | ||
|
cc492bf1a3 | ||
|
901c21e499 | ||
|
16c6f08e2d | ||
|
6e9f27d63c | ||
|
5b282ce3b4 | ||
|
c7b2446164 | ||
|
0e43c618a5 | ||
|
af6100b90f | ||
|
a4cd248368 | ||
|
6e52723c8c | ||
|
a3ad92b9d9 | ||
|
b07827790f | ||
|
85e00a195c | ||
|
081dd2c4bb | ||
|
bbfa76a2c9 | ||
|
16a060131a | ||
|
6dabc68d29 | ||
|
ac0593bfb3 | ||
|
ac3e9eab25 | ||
|
6de426a574 | ||
|
c3a619f114 | ||
|
128545cc2b | ||
|
8152898c4e | ||
|
852bf452b6 | ||
|
b38e80f846 | ||
|
a383ac10d9 | ||
|
2c32f5c593 | ||
|
41cbee2cd2 | ||
|
1f8944852a | ||
|
95dd03b298 | ||
|
a0cfaff528 | ||
|
d6542383ed | ||
|
afed387bcf | ||
|
313949f087 | ||
|
e5c8e2e7f4 | ||
|
845bbc5208 | ||
|
7a26ff4de8 | ||
|
a1f3c40a2d | ||
|
1fdbc2bc22 | ||
|
0f4def2338 | ||
|
7939f7ad50 | ||
|
8bfc3c5ea6 | ||
|
bf46f3fe8f | ||
|
55141aa875 | ||
|
4e4792d6dc | ||
|
2aca019d84 | ||
|
864249b62d | ||
|
d1fb34694c | ||
|
d1fc31b894 | ||
|
f6bf2531bb | ||
|
681390f22f | ||
|
0ee675e554 | ||
|
7e1a60e61d | ||
|
4cd11fdbc7 | ||
|
05c7a26e3a | ||
|
6762978ddf | ||
|
658650cf24 | ||
|
8a662b35e1 | ||
|
3cd7c0194f | ||
|
05f29639e5 | ||
|
5c18ffdae2 | ||
|
d3cee46e93 | ||
|
94c589f696 | ||
|
490fbf4cb5 | ||
|
d46ce7eb63 | ||
|
169e225ccd | ||
|
ceb0c602c9 | ||
|
95722e3bbb | ||
|
1cde26771a | ||
|
cd3c9d879c | ||
|
398c4fbf99 | ||
|
e7b4a985b4 | ||
|
6f76fea188 | ||
|
f6b8e7f234 | ||
|
041fa3e340 | ||
|
408ee41990 | ||
|
ed4be773a2 | ||
|
fcdb57f31d | ||
|
47b3368f78 | ||
|
20ce498d23 | ||
|
354c9b412e | ||
|
1c08cedd8a | ||
|
e2121d809e | ||
|
9c1065bc1b | ||
|
27136bbce8 | ||
|
c3238b7e02 | ||
|
b11640b477 | ||
|
2453f5b717 | ||
|
65c5c5f894 | ||
|
64d3c99f99 | ||
|
6c0890594b | ||
|
fb271953f7 | ||
|
7080c5679f | ||
|
427db5bd59 | ||
|
c09eac49c9 | ||
|
ae6f87eb42 | ||
|
82b3c5e2f3 | ||
|
e41ba279e9 | ||
|
c259c918ac | ||
|
2f7438f0d5 | ||
|
37a7b362d8 | ||
|
c0f098a578 | ||
|
21404c23dd | ||
|
eeefc9cf4b | ||
|
24b2475b11 | ||
|
2defe6f597 | ||
|
f9dc460325 | ||
|
30b83b5ff0 | ||
|
003afc8b56 | ||
|
95a97a197a | ||
|
eccd8b3c0e | ||
|
a43046c921 | ||
|
b360fb9ca0 | ||
|
0bf185e143 | ||
|
da3d134be0 | ||
|
b4c4746d43 | ||
|
fdd1ad9b17 | ||
|
1be8d9d46f | ||
|
51799353a6 | ||
|
3ad13a592d | ||
|
55934918ff | ||
|
ab93e4f168 | ||
|
e1ad0b0889 | ||
|
cbe3e7617c | ||
|
94c8966e86 | ||
|
d973a062c2 | ||
|
ba41dbc69a | ||
|
96380dd462 | ||
|
61bd765784 | ||
|
4a0f06193b | ||
|
826917ef17 | ||
|
4e1dbbbecf | ||
|
b5b0de2083 | ||
|
a95fcbbdbf | ||
|
7a73ec7c06 | ||
|
0c1f2252a1 | ||
|
98a397696c | ||
|
225b7d7db7 | ||
|
f968d4c333 | ||
|
59e15be524 | ||
|
ccabe93ae8 | ||
|
56def6def4 | ||
|
3b1a1efed2 | ||
|
185869e628 | ||
|
108f6238e3 | ||
|
d3e5a63fa2 | ||
|
0847e60d2a | ||
|
ac60ec4320 | ||
|
93debc00dc | ||
|
ff75846d2d | ||
|
53c767140d | ||
|
839a747ce8 | ||
|
f78a3f88ff | ||
|
142987259c | ||
|
c8d41f987f | ||
|
d139dd88e8 | ||
|
7898a5f4eb | ||
|
53efbf3ca9 | ||
|
b6e5ff2f3d | ||
|
ae1386a1d7 | ||
|
2f730303c2 | ||
|
e98ec9ec75 | ||
|
ffecef901a | ||
|
5c13cbb08f | ||
|
64cfbe9514 | ||
|
5cc21c87fb | ||
|
505e0c79d9 | ||
|
ca9d59c1c1 | ||
|
8319dbb56a | ||
|
b1b6697c37 | ||
|
280716394d | ||
|
5795f72eab | ||
|
7e16c8959b | ||
|
dfc188a24d | ||
|
d18bae0c95 | ||
|
747746cba1 | ||
|
5b73edec8c | ||
|
3750781bce | ||
|
e646e53dac | ||
|
6b8aa43ec0 | ||
|
e8a20c7e8a | ||
|
0423ed01a6 | ||
|
4a600c2611 | ||
|
e5faa23d4f | ||
|
b2f9c219b1 | ||
|
77d65760f0 | ||
|
98d0460af0 | ||
|
de8d93341c | ||
|
0b6a773087 | ||
|
dc1aa676c4 | ||
|
5ae9cc1cd7 | ||
|
f84bc53c8d | ||
|
b26e9d0338 | ||
|
dbd62b8622 | ||
|
20c80352bf | ||
|
9d70fb2b86 | ||
|
71aad26d44 | ||
|
3a1918eb2f | ||
|
a1709c07d9 | ||
|
b8c1176c79 | ||
|
03b5a57474 | ||
|
f58cf4826a | ||
|
d050cc5e13 | ||
|
6ef88b6303 | ||
|
3e15840b14 | ||
|
0d147cbd94 | ||
|
be93f7480a | ||
|
2e5f24f1f8 | ||
|
23cf4bd59b | ||
|
051c34bc5d | ||
|
9623ceb4d5 | ||
|
e1a7395880 | ||
|
51aeeca024 | ||
|
076e8bf6a3 | ||
|
73c5b9b847 | ||
|
f4f3eed78d | ||
|
89909c15bc | ||
|
78b3d7ff2d | ||
|
012193c74e | ||
|
539abe5151 | ||
|
7e5aba140e | ||
|
6b933391e5 | ||
|
1e2a5ee21d | ||
|
225a5ef808 | ||
|
396d0d9bdc | ||
|
88c8fb74bb | ||
|
fd902c7a58 | ||
|
06cbebe22e | ||
|
ba4a9e1586 | ||
|
285386e47f | ||
|
c65fec7271 | ||
|
879a4b38aa | ||
|
13c87e38ed | ||
|
718154cfb4 | ||
|
26de9b9714 | ||
|
3365facf9f | ||
|
8a4826164b | ||
|
d6eabae4f0 | ||
|
6bd81bb92e | ||
|
126a91dfec | ||
|
51fa147b99 | ||
|
6160877167 | ||
|
717f049579 | ||
|
f71331056c | ||
|
c131ff2662 | ||
|
616447e01d | ||
|
8c1d66bcf3 | ||
|
bea580b906 | ||
|
c513e02b24 | ||
|
90d71deb0f | ||
|
fc0776303a | ||
|
bb0c6f9a8a | ||
|
dae21e7681 | ||
|
d28437ecc0 | ||
|
7fec24af67 | ||
|
0de3637569 | ||
|
f94c7cef59 | ||
|
7734d63b1b | ||
|
f894504761 | ||
|
7aa9b4ee64 | ||
|
a12250dc16 | ||
|
d8fbe1a63e | ||
|
91e1760719 | ||
|
02c8a62e7d | ||
|
0c9bcfb8ac | ||
|
bd4c5037c7 | ||
|
ccaaedf38f | ||
|
751f294164 | ||
|
e2acbe8499 | ||
|
aba880a6b3 | ||
|
616e8da0a5 | ||
|
a220774a3b | ||
|
4fc8224264 | ||
|
66dae5840c | ||
|
89b9e6e531 | ||
|
fc4623381a | ||
|
1023e925f6 | ||
|
5d65365751 | ||
|
ee64a6ec7e | ||
|
9bc09105d7 | ||
|
4b96632a69 | ||
|
22a806ca6f | ||
|
d8dc977fc1 | ||
|
6d900b8ffb | ||
|
5a2c070898 | ||
|
58f17ddb09 | ||
|
47c9786bab | ||
|
e5edbeacb4 | ||
|
964fb20df9 | ||
|
309ed80446 | ||
|
01f2eb6615 | ||
|
3a55c7aaba | ||
|
243f41bf28 | ||
|
934b28f5b6 | ||
|
edfc03bed2 | ||
|
59ce71b64d | ||
|
d473a7dc22 | ||
|
efb063d600 | ||
|
12fe55905c | ||
|
aed831c075 | ||
|
5ad15fad8b | ||
|
a7d328896c | ||
|
1274a151d0 | ||
|
d93d639345 | ||
|
e0d9a16985 | ||
|
7f1070dde6 | ||
|
7f1e70329c | ||
|
186c8fbb62 | ||
|
c935be6a49 | ||
|
4ee502fa1a | ||
|
084805b248 | ||
|
eaebd258c0 | ||
|
2843a20814 | ||
|
08a56726a8 | ||
|
7cad8654e5 | ||
|
841cfe37dd | ||
|
849a41293f | ||
|
5b17edb3f9 | ||
|
9f2047dad6 | ||
|
c01c53c5c7 | ||
|
27bf1684cb | ||
|
be2aee3354 | ||
|
5f42a07d0d | ||
|
8a94c945b7 | ||
|
7740028291 | ||
|
7369e9c233 | ||
|
8c66825a78 | ||
|
a56f8272a9 | ||
|
e846ca392f | ||
|
f9ec89cf7a | ||
|
b935bc526a | ||
|
97617ced4a | ||
|
d575c7c2a9 | ||
|
99a3bbc4f9 | ||
|
80226cb7d3 | ||
|
6189e0cd50 | ||
|
2254421ead | ||
|
4934f5846b | ||
|
c8c1aabf20 | ||
|
93b901a286 | ||
|
518a445074 | ||
|
080a6db657 | ||
|
d49b1bd78a | ||
|
bd96050d84 | ||
|
2a90ad9e53 | ||
|
16758293ff | ||
|
e965322a98 | ||
|
fcf5c41b43 | ||
|
88adbf0ca2 | ||
|
3df142db7a | ||
|
f90fc4bfa2 | ||
|
dc1f9fb243 | ||
|
7c30c8aa07 | ||
|
b1d13105e7 | ||
|
287537b34a | ||
|
fe04014e1c | ||
|
094b5834b7 | ||
|
1eb98cc74f | ||
|
232aa069d2 | ||
|
a69408fa25 | ||
|
75011d0b4e | ||
|
28ae70ed20 | ||
|
2727d39fa4 | ||
|
467f99b3bb | ||
|
d53c9c5ecf | ||
|
48c19b4f3c | ||
|
16e5b08a0f | ||
|
636a69e9e1 | ||
|
45d40dc159 | ||
|
88abb79a96 | ||
|
1e1d5c3f7d | ||
|
95e9faff95 | ||
|
979ff60a6b | ||
|
ea2e8f0787 | ||
|
3893c12054 | ||
|
8ad47a315b | ||
|
3b576c3047 | ||
|
4d83dab4f3 | ||
|
28a7ec4f35 | ||
|
b5aae88a0b | ||
|
bee97237d9 | ||
|
8c8e950455 | ||
|
ad8b344298 | ||
|
6d310d417a | ||
|
9dca893ce7 | ||
|
e3444e666b | ||
|
e37e69311b | ||
|
6918f863b1 | ||
|
9ee05bf591 | ||
|
e15700235e | ||
|
1c7c07e128 | ||
|
4fbc4e3be9 | ||
|
e251c81d43 | ||
|
f30a5074ab | ||
|
f6ae490723 | ||
|
7f96c43d6f | ||
|
52260a63fb | ||
|
82b528ee30 | ||
|
a443bbdf80 | ||
|
26ee46b246 | ||
|
cf37816602 | ||
|
b8087f6c48 | ||
|
28cbe8fbeb | ||
|
28210ee31d | ||
|
0caf875399 | ||
|
323684efff | ||
|
678ee0615d | ||
|
6c889def37 | ||
|
93586deb6f | ||
|
b6b9ffd15c | ||
|
1189b5f693 | ||
|
1c2b6d59da | ||
|
eacc28fedf | ||
|
5c85ee1214 | ||
|
7df7453365 | ||
|
3d8297247e | ||
|
662f66e501 | ||
|
9131cb4790 | ||
|
3b616676c6 | ||
|
cce759b8dd | ||
|
98b6c9b89e | ||
|
5370201df8 | ||
|
419c395966 | ||
|
2962ce9a0f | ||
|
c96398aa0c | ||
|
e68ce1d680 | ||
|
d34f10b4ea | ||
|
7e2c1f274b | ||
|
9fe3811c45 | ||
|
b74bccee0a | ||
|
a2d170f415 | ||
|
03f762db86 | ||
|
aea859af52 | ||
|
f61fd7b7f1 | ||
|
5682129b1d | ||
|
c3431f19bf | ||
|
65b11cb968 | ||
|
f4f60d38b8 | ||
|
4337345103 | ||
|
52f460f66d | ||
|
d486c72e02 | ||
|
bdfc55b951 | ||
|
b0f6026c23 | ||
|
b2aca491b6 | ||
|
401fc39879 | ||
|
d4b0839328 | ||
|
37c64841ff | ||
|
8f8dd076ff | ||
|
51fcf65424 | ||
|
56b19fa2b0 | ||
|
fe38dab405 | ||
|
6cb2aaab65 | ||
|
c604c4591f | ||
|
f0f54434cb | ||
|
f9de85c257 | ||
|
44f817646e | ||
|
91786779f8 | ||
|
27d0aed2c9 | ||
|
7767c96a9e | ||
|
3388bb50e1 | ||
|
1554c587b3 | ||
|
ce70e73a34 | ||
|
804ec9246f | ||
|
f029321664 | ||
|
d41b7f64e4 | ||
|
0366d1afb9 | ||
|
4ef3073ca4 | ||
|
68a53aa884 | ||
|
2358b3ff26 | ||
|
00ed1d2817 | ||
|
5b6fdb6526 | ||
|
fe700d1e7b | ||
|
eac611ab1e | ||
|
0635313566 | ||
|
663299c91e | ||
|
523a6e989a | ||
|
13f4aee5ee | ||
|
bbc0e2106c | ||
|
eb6ee52aaa | ||
|
80e330d4c3 | ||
|
a3adc49d8c | ||
|
9c6eeed0f8 | ||
|
705e9a93f8 | ||
|
572a217050 | ||
|
d58798e36c | ||
|
e98634a277 | ||
|
f1f08eced0 | ||
|
6c2da9f0e4 | ||
|
e158635f57 | ||
|
5a241e77da | ||
|
68e397ab34 | ||
|
4c78b94cd8 | ||
|
3a9cc9b079 | ||
|
6ff8c6e7f3 | ||
|
6f90425154 | ||
|
49ec9b1d9e | ||
|
a0e35ad644 | ||
|
b91dc77d6f | ||
|
b462b5a5c8 | ||
|
b5e7fb20b6 | ||
|
9d245add9c | ||
|
ded03ed743 | ||
|
6cc260c04e | ||
|
5b4354a6f3 | ||
|
34de36fe01 | ||
|
08c2cdbf1d | ||
|
dedbeb3eab | ||
|
d88bf16500 | ||
|
ad9c8318a7 | ||
|
f2778c0729 | ||
|
03ca73658c | ||
|
1da5f6c30c | ||
|
bee8a99a34 | ||
|
f5efd41dc1 | ||
|
c202f8cf1d | ||
|
0c226c7629 | ||
|
a9e772f330 | ||
|
86cc76388e | ||
|
0f4e9af172 | ||
|
3a1352c8ec | ||
|
2c86fd947f | ||
|
927484a71f | ||
|
88adb8f5ef | ||
|
98e7f5cb22 | ||
|
67e5957064 | ||
|
8c3473a91a | ||
|
1c775cb759 | ||
|
c4054d4984 | ||
|
76e2f9f3ac | ||
|
41a40b8b9f | ||
|
6b8694bfbf | ||
|
2d696b6806 | ||
|
709a5ec89a | ||
|
932bb732e0 | ||
|
dd4e29542c | ||
|
726e66ca66 | ||
|
474fd70ec7 | ||
|
5074dbc3c6 | ||
|
eb54e7f1ae | ||
|
8983dd97a1 | ||
|
7eaea28970 | ||
|
907605c59c | ||
|
58921592c8 | ||
|
b9c49c38ed | ||
|
76c97027c8 | ||
|
5db3620f49 | ||
|
a2e6fa0b16 | ||
|
1d359f0fc4 | ||
|
885d245afb | ||
|
75d01c0c11 | ||
|
ea219e3ddd | ||
|
e9cd54b2f4 | ||
|
a8b6573f96 | ||
|
4e158c8ba7 | ||
|
121c84a2d1 | ||
|
bfb76de9ab | ||
|
2434605c06 | ||
|
a0f15bfb56 | ||
|
7fabd14a63 | ||
|
6b4d2aeb07 | ||
|
5ab61b46b5 | ||
|
39c9691d70 | ||
|
d00960b33f | ||
|
4a5cfac2ea | ||
|
7e1d21239f | ||
|
1a8b870a9e | ||
|
3e150db493 | ||
|
1cf8b7e952 | ||
|
ea75432f12 | ||
|
85370dfd21 | ||
|
8a0afef825 | ||
|
76f196206b | ||
|
bf3e8195f7 | ||
|
bce3071a12 | ||
|
911f684e4d | ||
|
49bc156a56 | ||
|
791c3701d7 | ||
|
372af54e46 | ||
|
20c8953e5b | ||
|
2f9ad54bae | ||
|
57c22cddb8 | ||
|
a5026849a3 | ||
|
60dc765178 | ||
|
5e1c150024 | ||
|
0fd06bb592 | ||
|
9641c8cf49 | ||
|
4ca31be4a2 | ||
|
667f18cbfe | ||
|
4df5050760 | ||
|
f50881a72f | ||
|
b80696af00 | ||
|
3cb2f6dcf7 | ||
|
b1e2c4ce72 | ||
|
89ff9dd5ac | ||
|
8b95b173cd | ||
|
80a877ddab | ||
|
e892b21872 | ||
|
c344913ae8 | ||
|
3eef8fba27 | ||
|
d34e47f716 | ||
|
9bfba28d01 | ||
|
cc43357fb4 | ||
|
bce5ef2dca | ||
|
3021ac4b95 | ||
|
385e80d185 | ||
|
bd1c8873d0 | ||
|
6ac3bdb94a | ||
|
e964a0a1f0 | ||
|
97255fbd62 | ||
|
d5041f64be | ||
|
64f649d1f9 | ||
|
097c7e5397 | ||
|
c6adc00eac | ||
|
b1710bfa31 | ||
|
0e52c42970 | ||
|
2b136b2981 | ||
|
b95e5e36dc | ||
|
1bc5bc7f1c | ||
|
946d7015a2 | ||
|
4adf5720f0 | ||
|
973a3f03c3 | ||
|
06177afd6a | ||
|
e5937638d4 | ||
|
7c4f14f941 | ||
|
ead54d6c37 | ||
|
b749f3c724 | ||
|
d279aecb87 | ||
|
67de0fc8da | ||
|
8ed2399517 | ||
|
cf340011e2 | ||
|
ec2ad37860 | ||
|
3443e82812 | ||
|
63138507d6 | ||
|
b2eb07db14 | ||
|
379a845166 | ||
|
266cf93584 | ||
|
0ee71e9a09 | ||
|
ea07afcc0b | ||
|
43cd6d34ca | ||
|
3b67032adb | ||
|
2d46a0605b | ||
|
ba54664748 | ||
|
a79f4c10a1 | ||
|
bd04b28b9e | ||
|
cbadecab33 | ||
|
8c079787f0 | ||
|
62528e6a0b | ||
|
49bf8bd830 | ||
|
c64bc20bb5 | ||
|
54da891f79 | ||
|
e847716076 | ||
|
3a68bbd1b2 | ||
|
9cb1d03411 | ||
|
4fed156b90 | ||
|
de8bcd36e8 | ||
|
135cfe3238 | ||
|
6dbfe28427 | ||
|
2b203c4616 | ||
|
f12e655cf8 | ||
|
cf0045a483 | ||
|
9c81eeace0 | ||
|
5b333f91f6 | ||
|
912d926260 | ||
|
a8dfd640a7 | ||
|
390044b716 | ||
|
8ac36e6ee5 | ||
|
208c693088 | ||
|
eae2f7d113 | ||
|
45f92115f9 | ||
|
42f3adc7a2 | ||
|
71b40c6d6c | ||
|
af12089e7a | ||
|
33677c4b2b | ||
|
376c8c2e00 | ||
|
8232e9e8ce | ||
|
436bf8deb5 | ||
|
c858a1c9e5 |
17
.github/workflows/ccpp.yml
vendored
17
.github/workflows/ccpp.yml
vendored
@@ -1,7 +1,8 @@
|
||||
name: C/C++ CI
|
||||
name: unittest
|
||||
|
||||
on: [push]
|
||||
|
||||
# fake comment to trigger an action 1
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -16,16 +17,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: install redis
|
||||
run: brew install redis
|
||||
|
||||
- name: start redis server
|
||||
run: brew services start redis
|
||||
|
||||
- name: make test
|
||||
run: make test
|
||||
|
||||
# We don't need to have redis running anymore, as we have our fake limited one
|
||||
# - name: install redis
|
||||
# run: brew install redis
|
||||
#
|
||||
# - name: start redis server
|
||||
# run: brew services start redis
|
||||
|
||||
# # Windows does not work yet, I'm stuck at getting CMake to run + finding vcpkg
|
||||
# win:
|
||||
# runs-on: windows-2016
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,7 @@
|
||||
build
|
||||
*.pyc
|
||||
venv
|
||||
ixsnake/ixsnake/.certs/
|
||||
site/
|
||||
ws/.certs/
|
||||
ws/.srl
|
||||
|
19
CMake/FindJsonCpp.cmake
Normal file
19
CMake/FindJsonCpp.cmake
Normal file
@@ -0,0 +1,19 @@
|
||||
# Find package structure taken from libcurl
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(JSONCPP_INCLUDE_DIRS json/json.h)
|
||||
find_library(JSONCPP_LIBRARY jsoncpp)
|
||||
|
||||
find_package_handle_standard_args(JSONCPP
|
||||
FOUND_VAR
|
||||
JSONCPP_FOUND
|
||||
REQUIRED_VARS
|
||||
JSONCPP_LIBRARY
|
||||
JSONCPP_INCLUDE_DIRS
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find jsoncpp"
|
||||
)
|
||||
|
||||
set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIRS})
|
||||
set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY})
|
@@ -107,28 +107,30 @@ elseif (WIN32)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/windows/IXSetThreadName_windows.cpp)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/freebsd/IXSetThreadName_freebsd.cpp)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
else()
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSelectInterruptEventFd.cpp)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptEventFd.h)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(USE_MBED_TLS TRUE)
|
||||
endif()
|
||||
option(USE_TLS "Enable TLS support" FALSE)
|
||||
|
||||
if (USE_TLS)
|
||||
if (WIN32)
|
||||
option(USE_MBED_TLS "Use Mbed TLS" ON)
|
||||
else()
|
||||
option(USE_MBED_TLS "Use Mbed TLS" OFF)
|
||||
endif()
|
||||
option(USE_OPEN_SSL "Use OpenSSL" OFF)
|
||||
|
||||
if (USE_MBED_TLS)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketMbedTLS.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketMbedTLS.cpp)
|
||||
elseif (APPLE AND NOT USE_OPEN_SSL)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
|
||||
elseif (WIN32)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketSChannel.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketSChannel.cpp)
|
||||
else()
|
||||
set(USE_OPEN_SSL TRUE)
|
||||
set(USE_OPEN_SSL ON)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketOpenSSL.cpp)
|
||||
endif()
|
||||
@@ -145,19 +147,15 @@ if (USE_TLS)
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_MBED_TLS)
|
||||
elseif (USE_OPEN_SSL)
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
|
||||
elseif (APPLE)
|
||||
elseif (WIN32)
|
||||
else()
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE AND USE_TLS AND NOT USE_MBED_TLS)
|
||||
if (APPLE AND USE_TLS AND NOT USE_MBED_TLS AND NOT USE_OPEN_SSL)
|
||||
target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(ixwebsocket wsock32 ws2_32)
|
||||
target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
@@ -174,7 +172,9 @@ if (USE_TLS AND USE_OPEN_SSL)
|
||||
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/local/opt/openssl/include)
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
add_definitions(${OPENSSL_DEFINITIONS})
|
||||
message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
@@ -182,6 +182,7 @@ if (USE_TLS AND USE_OPEN_SSL)
|
||||
endif()
|
||||
|
||||
if (USE_TLS AND USE_MBED_TLS)
|
||||
# FIXME I'm not too sure that this USE_VENDORED_THIRD_PARTY thing works
|
||||
if (USE_VENDORED_THIRD_PARTY)
|
||||
set (ENABLE_PROGRAMS OFF)
|
||||
add_subdirectory(third_party/mbedtls)
|
||||
@@ -200,13 +201,13 @@ if (ZLIB_FOUND)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(ixwebsocket ${ZLIB_LIBRARIES})
|
||||
else()
|
||||
add_subdirectory(third_party/zlib)
|
||||
include_directories(third_party/zlib ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib)
|
||||
add_subdirectory(third_party/zlib)
|
||||
target_link_libraries(ixwebsocket zlibstatic)
|
||||
endif()
|
||||
|
||||
set( IXWEBSOCKET_INCLUDE_DIRS
|
||||
.
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
@@ -231,6 +232,7 @@ if (USE_WS OR USE_TEST)
|
||||
add_subdirectory(ixsentry)
|
||||
|
||||
add_subdirectory(third_party/spdlog spdlog)
|
||||
add_subdirectory(third_party/sentry-native sentry-native)
|
||||
|
||||
if (USE_WS)
|
||||
add_subdirectory(ws)
|
||||
|
@@ -1 +0,0 @@
|
||||
7.2.1
|
34
Dockerfile
34
Dockerfile
@@ -1,34 +0,0 @@
|
||||
FROM alpine as build
|
||||
|
||||
RUN apk add --no-cache gcc g++ musl-dev linux-headers cmake openssl-dev
|
||||
RUN apk add --no-cache make
|
||||
RUN apk add --no-cache zlib-dev
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
RUN chown -R app:app /opt
|
||||
RUN chown -R app:app /usr/local
|
||||
|
||||
# There is a bug in CMake where we cannot build from the root top folder
|
||||
# So we build from /opt
|
||||
COPY --chown=app:app . /opt
|
||||
WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
|
||||
FROM alpine as runtime
|
||||
|
||||
RUN apk add --no-cache libstdc++
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
||||
CMD ["--help"]
|
1
Dockerfile
Symbolic link
1
Dockerfile
Symbolic link
@@ -0,0 +1 @@
|
||||
docker/Dockerfile.centos
|
44
README.md
44
README.md
@@ -1,13 +1,47 @@
|
||||
## Hello world
|
||||
|
||||

|
||||

|
||||
|
||||
IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use and support everything you'll likely need for websocket dev (SSL, deflate compression, compiles on most platforms, etc...). HTTP client and server code is also available, but it hasn't received as much testing.
|
||||
|
||||
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android).
|
||||
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Two important design goals are simplicity and correctness.
|
||||
|
||||
Interested ? Go read the [docs](https://machinezone.github.io/IXWebSocket/) ! If things don't work as expected, please create an issue in github, or even better a pull request if you know how to fix your problem.
|
||||
```cpp
|
||||
// Required on Windows
|
||||
ix::initNetSystem();
|
||||
|
||||
IXWebSocket is actively being developed, check out the [changelog](CHANGELOG.md) to know what's cooking. If you are looking for a real time messaging service (the chat-like 'server' your websocket code will talk to) with many features such as history, backed by Redis, look at [cobra](https://github.com/machinezone/cobra).
|
||||
// Our websocket object
|
||||
ix::WebSocket webSocket;
|
||||
|
||||
IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/IXWebSocket/autobahn/index.html). Some tests are still failing in the server code.
|
||||
std::string url("ws://localhost:8080/");
|
||||
webSocket.setUrl(url);
|
||||
|
||||
// Setup a callback to be fired (in a background thread, watch out for race conditions !)
|
||||
// when a message or an event (open, close, error) is received
|
||||
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
{
|
||||
if (msg->type == ix::WebSocketMessageType::Message)
|
||||
{
|
||||
std::cout << msg->str << std::endl;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Now that our callback is setup, we can start our background thread and receive messages
|
||||
webSocket.start();
|
||||
|
||||
// Send a message to the server (default to TEXT mode)
|
||||
webSocket.send("hello world");
|
||||
```
|
||||
|
||||
Interested? Go read the [docs](https://machinezone.github.io/IXWebSocket/)! If things don't work as expected, please create an issue on GitHub, or even better a pull request if you know how to fix your problem.
|
||||
|
||||
IXWebSocket is actively being developed, check out the [changelog](https://machinezone.github.io/IXWebSocket/CHANGELOG/) to know what's cooking. If you are looking for a real time messaging service (the chat-like 'server' your websocket code will talk to) with many features such as history, backed by Redis, look at [cobra](https://github.com/machinezone/cobra).
|
||||
|
||||
IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code.
|
||||
|
||||
## Users
|
||||
|
||||
If your company or project is using this library, feel free to open an issue or PR to amend this list.
|
||||
|
||||
- [Machine Zone](https://www.mz.com)
|
||||
|
@@ -1,43 +1,67 @@
|
||||
version: "3"
|
||||
services:
|
||||
snake:
|
||||
image: bsergean/ws:build
|
||||
entrypoint: ws snake --port 8765 --host 0.0.0.0 --redis_hosts redis1
|
||||
ports:
|
||||
- "8765:8765"
|
||||
networks:
|
||||
- ws-net
|
||||
depends_on:
|
||||
- redis1
|
||||
# snake:
|
||||
# image: bsergean/ws:build
|
||||
# entrypoint: ws snake --port 8767 --host 0.0.0.0 --redis_hosts redis1
|
||||
# ports:
|
||||
# - "8767:8767"
|
||||
# networks:
|
||||
# - ws-net
|
||||
# depends_on:
|
||||
# - redis1
|
||||
|
||||
ws:
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
# proxy:
|
||||
# image: bsergean/ws:build
|
||||
# entrypoint: strace ws proxy_server --remote_host 'wss://cobra.addsrv.com' --host 0.0.0.0 --port 8765 -v
|
||||
# ports:
|
||||
# - "8765:8765"
|
||||
# networks:
|
||||
# - ws-net
|
||||
|
||||
#pyproxy:
|
||||
# image: bsergean/ws_proxy:build
|
||||
# entrypoint: /usr/bin/ws_proxy.py --remote_url 'wss://cobra.addsrv.com' --host 0.0.0.0 --port 8765
|
||||
# ports:
|
||||
# - "8765:8765"
|
||||
# networks:
|
||||
# - ws-net
|
||||
|
||||
# # ws:
|
||||
# # security_opt:
|
||||
# # - seccomp:unconfined
|
||||
# # cap_add:
|
||||
# # - SYS_PTRACE
|
||||
# # stdin_open: true
|
||||
# # tty: true
|
||||
# # image: bsergean/ws:build
|
||||
# # entrypoint: sh
|
||||
# # networks:
|
||||
# # - ws-net
|
||||
# # depends_on:
|
||||
# # - redis1
|
||||
# #
|
||||
# # redis1:
|
||||
# # image: redis:alpine
|
||||
# # networks:
|
||||
# # - ws-net
|
||||
# #
|
||||
# # statsd:
|
||||
# # image: jaconel/statsd
|
||||
# # ports:
|
||||
# # - "8125:8125"
|
||||
# # environment:
|
||||
# # - STATSD_DUMP_MSG=true
|
||||
# # - GRAPHITE_HOST=127.0.0.1
|
||||
# # networks:
|
||||
# # - ws-net
|
||||
|
||||
compile:
|
||||
image: alpine
|
||||
entrypoint: sh
|
||||
stdin_open: true
|
||||
tty: true
|
||||
image: bsergean/ws:build
|
||||
entrypoint: bash
|
||||
networks:
|
||||
- ws-net
|
||||
depends_on:
|
||||
- redis1
|
||||
|
||||
redis1:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
- ws-net
|
||||
|
||||
statsd:
|
||||
image: jaconel/statsd
|
||||
ports:
|
||||
- "8125:8125"
|
||||
environment:
|
||||
- STATSD_DUMP_MSG=true
|
||||
- GRAPHITE_HOST=127.0.0.1
|
||||
networks:
|
||||
- ws-net
|
||||
volumes:
|
||||
- /Users/bsergeant/src/foss:/home/bsergean/src/foss
|
||||
|
||||
networks:
|
||||
ws-net:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM alpine as build
|
||||
FROM alpine:3.11 as build
|
||||
|
||||
RUN apk add --no-cache gcc g++ musl-dev linux-headers cmake openssl-dev
|
||||
RUN apk add --no-cache make
|
||||
@@ -15,20 +15,25 @@ WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
FROM alpine as runtime
|
||||
FROM alpine:3.11 as runtime
|
||||
|
||||
RUN apk add --no-cache libstdc++
|
||||
RUN apk add --no-cache strace
|
||||
RUN apk add --no-cache gdb
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Copy source code for gcc
|
||||
COPY --chown=app:app --from=build /opt /opt
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
||||
CMD ["--help"]
|
||||
|
35
docker/Dockerfile.centos
Normal file
35
docker/Dockerfile.centos
Normal file
@@ -0,0 +1,35 @@
|
||||
FROM centos:8 as build
|
||||
|
||||
RUN yum install -y gcc-c++ make cmake zlib-devel openssl-devel redhat-rpm-config
|
||||
|
||||
RUN groupadd app && useradd -g app app
|
||||
RUN chown -R app:app /opt
|
||||
RUN chown -R app:app /usr/local
|
||||
|
||||
# There is a bug in CMake where we cannot build from the root top folder
|
||||
# So we build from /opt
|
||||
COPY --chown=app:app . /opt
|
||||
WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
FROM centos:8 as runtime
|
||||
|
||||
RUN yum install -y gdb strace
|
||||
|
||||
RUN groupadd app && useradd -g app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Copy source code for gcc
|
||||
COPY --chown=app:app --from=build /opt /opt
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
@@ -1,5 +1,280 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
All changes to this project will be documented in this file.
|
||||
|
||||
## [8.1.8] - 2020-03-02
|
||||
|
||||
(websocket server) fix regression with disabling zlib extension on the server side. If a client does not support this extension the server will handle it fine. We still need to figure out how to disable the option.
|
||||
|
||||
## [8.1.7] - 2020-02-26
|
||||
|
||||
(websocket) traffic tracker received bytes is message size while it should be wire size
|
||||
|
||||
## [8.1.6] - 2020-02-26
|
||||
|
||||
(ws_connect) display sent/received bytes statistics on exit
|
||||
|
||||
## [8.1.5] - 2020-02-23
|
||||
|
||||
(server) give thread name to some usual worker threads / unittest is broken !!
|
||||
|
||||
## [8.1.4] - 2020-02-22
|
||||
|
||||
(websocket server) fix regression from 8.1.2, where per-deflate message compression was always disabled
|
||||
|
||||
## [8.1.3] - 2020-02-21
|
||||
|
||||
(client + server) Fix #155 / http header parser should treat the space(s) after the : delimiter as optional. Fixing this bug made us discover that websocket sub-protocols are not properly serialiazed, but start with a ,
|
||||
|
||||
## [8.1.2] - 2020-02-18
|
||||
|
||||
(WebSocketServer) add option to disable deflate compression, exposed with the -x option to ws echo_server
|
||||
|
||||
## [8.1.1] - 2020-02-18
|
||||
|
||||
(ws cobra to statsd and sentry sender) exit if no messages are received for one minute, which is a sign that something goes wrong on the server side. That should be changed to be configurable in the future
|
||||
|
||||
## [8.1.0] - 2020-02-13
|
||||
|
||||
(http client + sentry minidump upload) Multipart stream closing boundary is invalid + mark some options as mandatory in the command line tools
|
||||
|
||||
## [8.0.7] - 2020-02-12
|
||||
|
||||
(build) remove the unused subtree which was causing some way of installing to break
|
||||
|
||||
## [8.0.6] - 2020-01-31
|
||||
|
||||
(snake) add an option to disable answering pongs as response to pings, to test cobra client behavior with hanged connections
|
||||
|
||||
## [8.0.5] - 2020-01-31
|
||||
|
||||
(IXCobraConnection) set a ping timeout of 90 seconds. If no pong messages are received as responses to ping for a while, give up and close the connection
|
||||
|
||||
## [8.0.4] - 2020-01-31
|
||||
|
||||
(cobra to sentry) remove noisy logging
|
||||
|
||||
## [8.0.3] - 2020-01-30
|
||||
|
||||
(ixcobra) check if we are authenticated in publishNext before trying to publish a message
|
||||
|
||||
## [8.0.2] - 2020-01-28
|
||||
|
||||
Extract severity level when emitting messages to sentry
|
||||
|
||||
## [8.0.1] - 2020-01-28
|
||||
|
||||
Fix bug #151 - If a socket connection is interrupted, calling stop() on the IXWebSocket object blocks until the next retry
|
||||
|
||||
## [8.0.0] - 2020-01-26
|
||||
|
||||
(SocketServer) add ability to bind on an ipv6 address
|
||||
|
||||
## [7.9.6] - 2020-01-22
|
||||
|
||||
(ws) add a dnslookup sub-command, to get the ip address of a remote host
|
||||
|
||||
## [7.9.5] - 2020-01-14
|
||||
|
||||
(windows) fix #144, get rid of stubbed/un-implemented windows schannel ssl backend
|
||||
|
||||
## [7.9.4] - 2020-01-12
|
||||
|
||||
(openssl + mbedssl) fix #140, can send large files with ws send over ssl / still broken with apple ssl
|
||||
|
||||
## [7.9.3] - 2020-01-10
|
||||
|
||||
(apple ssl) model write method after the OpenSSL one for consistency
|
||||
|
||||
## [7.9.2] - 2020-01-06
|
||||
|
||||
(apple ssl) unify read and write ssl utility code
|
||||
|
||||
## [7.9.1] - 2020-01-06
|
||||
|
||||
(websocket client) better error propagation when errors are detected while sending data
|
||||
(ws send) detect failures to send big files, terminate in those cases and report error
|
||||
|
||||
## [7.9.0] - 2020-01-04
|
||||
|
||||
(ws send) add option (-x) to disable per message deflate compression
|
||||
|
||||
## [7.8.9] - 2020-01-04
|
||||
|
||||
(ws send + receive) handle all message types (ping + pong + fragment) / investigate #140
|
||||
|
||||
## [7.8.8] - 2019-12-28
|
||||
|
||||
(mbedtls) fix related to private key file parsing and initialization
|
||||
|
||||
## [7.8.6] - 2019-12-28
|
||||
|
||||
(ws cobra to sentry/statsd) fix for handling null events properly for empty queues + use queue to send data to statsd
|
||||
|
||||
## [7.8.5] - 2019-12-28
|
||||
|
||||
(ws cobra to sentry) handle null events for empty queues
|
||||
|
||||
## [7.8.4] - 2019-12-27
|
||||
|
||||
(ws cobra to sentry) game is picked in a fair manner, so that all games get the same share of sent events
|
||||
|
||||
## [7.8.3] - 2019-12-27
|
||||
|
||||
(ws cobra to sentry) refactor queue related code into a class
|
||||
|
||||
## [7.8.2] - 2019-12-25
|
||||
|
||||
(ws cobra to sentry) bound the queue size used to hold up cobra messages before they are sent to sentry. Default queue size is a 100 messages. Without such limit the program runs out of memory when a subscriber receive a lot of messages that cannot make it to sentry
|
||||
|
||||
## [7.8.1] - 2019-12-25
|
||||
|
||||
(ws client) use correct compilation defines so that spdlog is not used as a header only library (reduce binary size and increase compilation speed)
|
||||
|
||||
## [7.8.0] - 2019-12-24
|
||||
|
||||
(ws client) all commands use spdlog instead of std::cerr or std::cout for logging
|
||||
|
||||
## [7.6.5] - 2019-12-24
|
||||
|
||||
(cobra client) send a websocket ping every 30s to keep the connection opened
|
||||
|
||||
## [7.6.4] - 2019-12-22
|
||||
|
||||
(client) error handling, quote url in error case when failing to parse one
|
||||
(ws) ws_cobra_publish: register callbacks before connecting
|
||||
(doc) mention mbedtls in supported ssl server backend
|
||||
|
||||
## [7.6.3] - 2019-12-20
|
||||
|
||||
(tls) add a simple description of the TLS configuration routine for debugging
|
||||
|
||||
## [7.6.2] - 2019-12-20
|
||||
|
||||
(mbedtls) correct support for using own certificate and private key
|
||||
|
||||
## [7.6.1] - 2019-12-20
|
||||
|
||||
(ws commands) in websocket proxy, disable automatic reconnections + in Dockerfile, use alpine 3.11
|
||||
|
||||
## [7.6.0] - 2019-12-19
|
||||
|
||||
(cobra) Add TLS options to all cobra commands and classes. Add example to the doc.
|
||||
|
||||
## [7.5.8] - 2019-12-18
|
||||
|
||||
(cobra-to-sentry) capture application version from device field
|
||||
|
||||
## [7.5.7] - 2019-12-18
|
||||
|
||||
(tls) Experimental TLS server support with mbedtls (windows) + process cert tlsoption (client + server)
|
||||
|
||||
## [7.5.6] - 2019-12-18
|
||||
|
||||
(tls servers) Make it clear that apple ssl and mbedtls backends do not support SSL in server mode
|
||||
|
||||
## [7.5.5] - 2019-12-17
|
||||
|
||||
(tls options client) TLSOptions struct _validated member should be initialized to false
|
||||
|
||||
## [7.5.4] - 2019-12-16
|
||||
|
||||
(websocket client) improve the error message when connecting to a non websocket server
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
Connection error: Got bad status connecting to example.com:443, status: 200, HTTP Status line: HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
Connection error: Expecting status 101 (Switching Protocol), got 200 status connecting to example.com:443, HTTP Status line: HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
## [7.5.3] - 2019-12-12
|
||||
|
||||
(server) attempt at fixing #131 by using blocking writes in server mode
|
||||
|
||||
## [7.5.2] - 2019-12-11
|
||||
|
||||
(ws) cobra to sentry - created events with sentry tags based on tags present in the cobra messages
|
||||
|
||||
## [7.5.1] - 2019-12-06
|
||||
|
||||
(mac) convert SSL errors to utf8
|
||||
|
||||
## [7.5.0] - 2019-12-05
|
||||
|
||||
- (ws) cobra to sentry. Handle Error 429 Too Many Requests and politely wait before sending more data to sentry.
|
||||
|
||||
In the example below sentry we are sending data too fast, sentry asks us to slow down which we do. Notice how the sent count stop increasing, while we are waiting for 41 seconds.
|
||||
|
||||
```
|
||||
[2019-12-05 15:50:33.759] [info] messages received 2449 sent 3
|
||||
[2019-12-05 15:50:34.759] [info] messages received 5533 sent 7
|
||||
[2019-12-05 15:50:35.759] [info] messages received 8612 sent 11
|
||||
[2019-12-05 15:50:36.759] [info] messages received 11562 sent 15
|
||||
[2019-12-05 15:50:37.759] [info] messages received 14410 sent 19
|
||||
[2019-12-05 15:50:38.759] [info] messages received 17236 sent 23
|
||||
[2019-12-05 15:50:39.282] [error] Error sending data to sentry: 429
|
||||
[2019-12-05 15:50:39.282] [error] Body: {"exception":[{"stacktrace":{"frames":[{"filename":"WorldScene.lua","function":"WorldScene.lua:1935","lineno":1958},{"filename":"WorldScene.lua","function":"onUpdate_WorldCam","lineno":1921},{"filename":"WorldMapTile.lua","function":"__index","lineno":239}]},"value":"noisytypes: Attempt to call nil(nil,2224139838)!"}],"platform":"python","sdk":{"name":"ws","version":"1.0.0"},"tags":[["game","niso"],["userid","107638363"],["environment","live"]],"timestamp":"2019-12-05T23:50:39Z"}
|
||||
|
||||
[2019-12-05 15:50:39.282] [error] Response: {"error_name":"rate_limit","error":"Creation of this event was denied due to rate limiting"}
|
||||
[2019-12-05 15:50:39.282] [warning] Error 429 - Too Many Requests. ws will sleep and retry after 41 seconds
|
||||
[2019-12-05 15:50:39.760] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:40.760] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:41.760] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:42.761] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:43.762] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:44.763] [info] messages received 18839 sent 25
|
||||
[2019-12-05 15:50:45.768] [info] messages received 18839 sent 25
|
||||
```
|
||||
|
||||
## [7.4.5] - 2019-12-03
|
||||
|
||||
- (ws) #125 / fix build problem when jsoncpp is not installed locally
|
||||
|
||||
## [7.4.4] - 2019-12-03
|
||||
|
||||
- (ws) #125 / cmake detects an already installed jsoncpp and will try to use this one if present
|
||||
|
||||
## [7.4.3] - 2019-12-03
|
||||
|
||||
- (http client) use std::unordered_map instead of std::map for HttpParameters and HttpFormDataParameters class aliases
|
||||
|
||||
## [7.4.2] - 2019-12-02
|
||||
|
||||
- (client) internal IXDNSLookup class requires a valid cancellation request function callback to be passed in
|
||||
|
||||
## [7.4.1] - 2019-12-02
|
||||
|
||||
- (client) fix an overflow in the exponential back off code
|
||||
|
||||
## [7.4.0] - 2019-11-25
|
||||
|
||||
- (http client) Add support for multipart HTTP POST upload
|
||||
- (ixsentry) Add support for uploading a minidump to sentry
|
||||
|
||||
## [7.3.5] - 2019-11-20
|
||||
|
||||
- On Darwin SSL, add ability to skip peer verification.
|
||||
|
||||
## [7.3.4] - 2019-11-20
|
||||
|
||||
- 32-bits compile fix, courtesy of @fcojavmc
|
||||
|
||||
## [7.3.1] - 2019-11-16
|
||||
|
||||
- ws proxy_server / remote server close not forwarded to the client
|
||||
|
||||
## [7.3.0] - 2019-11-15
|
||||
|
||||
- New ws command: `ws proxy_server`.
|
||||
|
||||
## [7.2.2] - 2019-11-01
|
||||
|
||||
- Tag a release + minor reformating.
|
||||
|
||||
## [7.2.1] - 2019-10-26
|
||||
|
||||
|
@@ -23,6 +23,16 @@ Options for building:
|
||||
|
||||
If you are on Windows, look at the [appveyor](https://github.com/machinezone/IXWebSocket/blob/master/appveyor.yml) file that has instructions for building dependencies.
|
||||
|
||||
It is also possible to externally include the project, so that everything is fetched over the wire when you build like so:
|
||||
|
||||
```
|
||||
ExternalProject_Add(
|
||||
IXWebSocket
|
||||
GIT_REPOSITORY https://github.com/machinezone/IXWebSocket.git
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### vcpkg
|
||||
|
||||
It is possible to get IXWebSocket through Microsoft [vcpkg](https://github.com/microsoft/vcpkg).
|
||||
@@ -33,11 +43,16 @@ vcpkg install ixwebsocket
|
||||
|
||||
### Conan
|
||||
|
||||
Support for building with conan was contributed by Olivia Zoe (thanks !). The package name to reference is `IXWebSocket/5.0.0@LunarWatcher/stable`. The package is in the process to be published to the official conan package repo, but in the meantime, it can be accessed by adding a new remote
|
||||
[  ](https://bintray.com/conan/conan-center/ixwebsocket%3A_/_latestVersion)
|
||||
|
||||
```
|
||||
conan remote add remote_name_here https://api.bintray.com/conan/oliviazoe0/conan-packages
|
||||
```
|
||||
Conan is currently supported through a recipe in [Conan Center](https://github.com/conan-io/conan-center-index/tree/master/recipes/ixwebsocket) ([Bintray entry](https://bintray.com/conan/conan-center/ixwebsocket%3A_)).
|
||||
|
||||
Package reference
|
||||
|
||||
* Conan 1.21.0 and up: `ixwebsocket/7.9.2`
|
||||
* Earlier versions: `ixwebsocket/7.9.2@_/_`
|
||||
|
||||
Note that the version listed here might not be the latest one. See Bintray or the recipe itself for the latest version. If you're migrating from the previous, custom Bintray remote, note that the package reference _has_ to be lower-case.
|
||||
|
||||
### Docker
|
||||
|
||||
|
81
docs/cobra.md
Normal file
81
docs/cobra.md
Normal file
@@ -0,0 +1,81 @@
|
||||
## General
|
||||
|
||||
[cobra](https://github.com/machinezone/cobra) is a real time messaging server. The `ws` utility can run a cobra server (named snake), and has client to publish and subscribe to a cobra server.
|
||||
|
||||
Bring up 3 terminals and run a server, a publisher and a subscriber in each one. As you publish data you should see it being received by the subscriber. You can run `redis-cli MONITOR` too to see how redis is being used.
|
||||
|
||||
### Server
|
||||
|
||||
You will need to have a redis server running locally. To run the server:
|
||||
|
||||
```bash
|
||||
$ cd <ixwebsocket-top-level-folder>/ixsnake/ixsnake
|
||||
$ ws snake
|
||||
{
|
||||
"apps": {
|
||||
"FC2F10139A2BAc53BB72D9db967b024f": {
|
||||
"roles": {
|
||||
"_sub": {
|
||||
"secret": "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba"
|
||||
},
|
||||
"_pub": {
|
||||
"secret": "1c04DB8fFe76A4EeFE3E318C72d771db"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redis host: 127.0.0.1
|
||||
redis password:
|
||||
redis port: 6379
|
||||
```
|
||||
|
||||
### Publisher
|
||||
|
||||
```bash
|
||||
$ cd <ixwebsocket-top-level-folder>/ws
|
||||
$ ws cobra_publish --appkey FC2F10139A2BAc53BB72D9db967b024f --endpoint ws://127.0.0.1:8008 --rolename _pub --rolesecret 1c04DB8fFe76A4EeFE3E318C72d771db test_channel cobraMetricsSample.json
|
||||
[2019-11-27 09:06:12.980] [info] Publisher connected
|
||||
[2019-11-27 09:06:12.980] [info] Connection: Upgrade
|
||||
[2019-11-27 09:06:12.980] [info] Sec-WebSocket-Accept: zTtQKMKbvwjdivURplYXwCVUCWM=
|
||||
[2019-11-27 09:06:12.980] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
||||
[2019-11-27 09:06:12.980] [info] Server: ixwebsocket/7.4.0 macos ssl/DarwinSSL zlib 1.2.11
|
||||
[2019-11-27 09:06:12.980] [info] Upgrade: websocket
|
||||
[2019-11-27 09:06:12.982] [info] Publisher authenticated
|
||||
[2019-11-27 09:06:12.982] [info] Published msg 3
|
||||
[2019-11-27 09:06:12.982] [info] Published message id 3 acked
|
||||
```
|
||||
|
||||
### Subscriber
|
||||
|
||||
```bash
|
||||
$ ws cobra_subscribe --appkey FC2F10139A2BAc53BB72D9db967b024f --endpoint ws://127.0.0.1:8008 --rolename _pub --rolesecret 1c04DB8fFe76A4EeFE3E318C72d771db test_channel
|
||||
#messages 0 msg/s 0
|
||||
[2019-11-27 09:07:39.341] [info] Subscriber connected
|
||||
[2019-11-27 09:07:39.341] [info] Connection: Upgrade
|
||||
[2019-11-27 09:07:39.341] [info] Sec-WebSocket-Accept: 9vkQWofz49qMCUlTSptCCwHWm+Q=
|
||||
[2019-11-27 09:07:39.341] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
||||
[2019-11-27 09:07:39.341] [info] Server: ixwebsocket/7.4.0 macos ssl/DarwinSSL zlib 1.2.11
|
||||
[2019-11-27 09:07:39.341] [info] Upgrade: websocket
|
||||
[2019-11-27 09:07:39.342] [info] Subscriber authenticated
|
||||
[2019-11-27 09:07:39.345] [info] Subscriber: subscribed to channel test_channel
|
||||
#messages 0 msg/s 0
|
||||
#messages 0 msg/s 0
|
||||
#messages 0 msg/s 0
|
||||
{"baz":123,"foo":"bar"}
|
||||
|
||||
#messages 1 msg/s 1
|
||||
#messages 1 msg/s 0
|
||||
#messages 1 msg/s 0
|
||||
{"baz":123,"foo":"bar"}
|
||||
|
||||
{"baz":123,"foo":"bar"}
|
||||
|
||||
#messages 3 msg/s 2
|
||||
#messages 3 msg/s 0
|
||||
{"baz":123,"foo":"bar"}
|
||||
|
||||
#messages 4 msg/s 1
|
||||
^C
|
||||
```
|
@@ -24,13 +24,13 @@ Large frames are broken up into smaller chunks or messages to avoid filling up t
|
||||
|
||||
The library has an interactive tool which is handy for testing compatibility ith other libraries. We have tested our client against Python, Erlang, Node.js, and C++ websocket server libraries.
|
||||
|
||||
The unittest tries to be comprehensive, and has been running on multiple platoform, with different sanitizers such as thread sanitizer to catch data races or the undefined behavior sanitizer.
|
||||
The unittest tries to be comprehensive, and has been running on multiple platforms, with different sanitizers such as a thread sanitizer to catch data races or the undefined behavior sanitizer.
|
||||
|
||||
The regression test is running after each commit on travis.
|
||||
|
||||
## Limitations
|
||||
|
||||
* On Windows TLS is not setup yet to validate certificates.
|
||||
* On Windows and Android certificate validation needs to be setup so that SocketTLSOptions.caFile point to a pem file, such as the one distributed by Firefox. Unless that setup is done connecting to a wss endpoint will display an error. On Windows with mbedtls the message will contain `error in handshake : X509 - Certificate verification failed, e.g. CRL, CA or signature check failed`.
|
||||
* There is no convenient way to embed a ca cert.
|
||||
* Automatic reconnection works at the TCP socket level, and will detect remote end disconnects. However, if the device/computer network become unreachable (by turning off wifi), it is quite hard to reliably and timely detect it at the socket level using `recv` and `send` error codes. [Here](https://stackoverflow.com/questions/14782143/linux-socket-how-to-detect-disconnected-network-in-a-client-program) is a good discussion on the subject. This behavior is consistent with other runtimes such as node.js. One way to detect a disconnected device with low level C code is to do a name resolution with DNS but this can be expensive. Mobile devices have good and reliable API to do that.
|
||||
* The server code is using select to detect incoming data, and creates one OS thread per connection. This is not as scalable as strategies using epoll or kqueue.
|
||||
|
@@ -9,14 +9,15 @@
|
||||
* Linux
|
||||
* Android
|
||||
* Windows
|
||||
* FreeBSD
|
||||
|
||||
## Example code
|
||||
|
||||
```
|
||||
# Required on Windows
|
||||
```cpp
|
||||
// Required on Windows
|
||||
ix::initNetSystem();
|
||||
|
||||
# Our websocket object
|
||||
// Our websocket object
|
||||
ix::WebSocket webSocket;
|
||||
|
||||
std::string url("ws://localhost:8080/");
|
||||
@@ -39,8 +40,12 @@ webSocket.start();
|
||||
webSocket.send("hello world");
|
||||
```
|
||||
|
||||
## Why another library ?
|
||||
## Why another library?
|
||||
|
||||
There are 2 main reasons that explain why IXWebSocket got written. First, we needed a C++ cross-platform client library, which should have few dependencies. What looked like the most solid one, [websocketpp](https://github.com/zaphoyd/websocketpp) did depend on boost and this was not an option for us. Secondly, there were other available libraries with fewer dependencies (C ones), but they required calling an explicit poll routine periodically to know if a client had received data from a server, which was not elegant.
|
||||
|
||||
We started by solving those 2 problems, then we added server websocket code, then an HTTP client, and finally a very simple HTTP server.
|
||||
|
||||
## Contributing
|
||||
|
||||
IXWebSocket is developed on [GitHub](https://github.com/machinezone/IXWebSocket). We'd love to hear about how you use it; opening up an issue on GitHub is ok for that. If things don't work as expected, please create an issue on GitHub, or even better a pull request if you know how to fix your problem.
|
||||
|
@@ -6,7 +6,7 @@ The [*ws*](https://github.com/machinezone/IXWebSocket/tree/master/ws) folder cou
|
||||
|
||||
To use the network system on Windows, you need to initialize it once with *WSAStartup()* and clean it up with *WSACleanup()*. We have helpers for that which you can use, see below. This init would typically take place in your main function.
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <ixwebsocket/IXNetSystem.h>
|
||||
|
||||
int main()
|
||||
@@ -22,12 +22,12 @@ int main()
|
||||
|
||||
## WebSocket client API
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
|
||||
...
|
||||
|
||||
# Our websocket object
|
||||
// Our websocket object
|
||||
ix::WebSocket webSocket;
|
||||
|
||||
std::string url("ws://localhost:8080/");
|
||||
@@ -82,9 +82,9 @@ If the connection was closed and sending failed, the return value will be set to
|
||||
|
||||
### Open and Close notifications
|
||||
|
||||
The onMessage event will be fired when the connection is opened or closed. This is similar to the [Javascript browser API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), which has `open` and `close` events notification that can be registered with the browser `addEventListener`.
|
||||
The onMessage event will be fired when the connection is opened or closed. This is similar to the [JavaScript browser API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), which has `open` and `close` events notification that can be registered with the browser `addEventListener`.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
{
|
||||
if (msg->type == ix::WebSocketMessageType::Open)
|
||||
@@ -115,7 +115,7 @@ webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
|
||||
A message will be fired when there is an error with the connection. The message type will be `ix::WebSocketMessageType::Error`. Multiple fields will be available on the event to describe the error.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
{
|
||||
if (msg->type == ix::WebSocketMessageType::Error)
|
||||
@@ -140,7 +140,7 @@ webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
|
||||
The url can be set and queried after a websocket object has been created. You will have to call `stop` and `start` if you want to disconnect and connect to that new url.
|
||||
|
||||
```
|
||||
```cpp
|
||||
std::string url("wss://example.com");
|
||||
websocket.configure(url);
|
||||
```
|
||||
@@ -149,7 +149,7 @@ websocket.configure(url);
|
||||
|
||||
Ping/pong messages are used to implement keep-alive. 2 message types exists to identify ping and pong messages. Note that when a ping message is received, a pong is instantly send back as requested by the WebSocket spec.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
{
|
||||
if (msg->type == ix::WebSocketMessageType::Ping ||
|
||||
@@ -163,7 +163,7 @@ webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
|
||||
|
||||
A ping message can be sent to the server, with an optional data string.
|
||||
|
||||
```
|
||||
```cpp
|
||||
websocket.ping("ping data, optional (empty string is ok): limited to 125 bytes long");
|
||||
```
|
||||
|
||||
@@ -173,7 +173,7 @@ You can configure an optional heart beat / keep-alive, sent every 45 seconds
|
||||
when there is no any traffic to make sure that load balancers do not kill an
|
||||
idle connection.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setHeartBeatPeriod(45);
|
||||
```
|
||||
|
||||
@@ -181,7 +181,7 @@ webSocket.setHeartBeatPeriod(45);
|
||||
|
||||
You can set extra HTTP headers to be sent during the WebSocket handshake.
|
||||
|
||||
```
|
||||
```cpp
|
||||
WebSocketHttpHeaders headers;
|
||||
headers["foo"] = "bar";
|
||||
webSocket.setExtraHeaders(headers);
|
||||
@@ -191,14 +191,14 @@ webSocket.setExtraHeaders(headers);
|
||||
|
||||
You can specify subprotocols to be set during the WebSocket handshake. For more info you can refer to [this doc](https://hpbn.co/websocket/#subprotocol-negotiation).
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.addSubprotocol("appProtocol-v1");
|
||||
webSocket.addSubprotocol("appProtocol-v2");
|
||||
```
|
||||
|
||||
The protocol that the server did accept is available in the open info `protocol` field.
|
||||
|
||||
```
|
||||
```cpp
|
||||
std::cout << "protocol: " << msg->openInfo.protocol << std::endl;
|
||||
```
|
||||
|
||||
@@ -206,7 +206,7 @@ std::cout << "protocol: " << msg->openInfo.protocol << std::endl;
|
||||
|
||||
Automatic reconnection kicks in when the connection is disconnected without the user consent. This feature is on by default and can be turned off.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.enableAutomaticReconnection(); // turn on
|
||||
webSocket.disableAutomaticReconnection(); // turn off
|
||||
bool enabled = webSocket.isAutomaticReconnectionEnabled(); // query state
|
||||
@@ -239,7 +239,7 @@ Wait time(ms): 10000
|
||||
|
||||
The waiting time is capped by default at 10s between 2 attempts, but that value can be changed and queried.
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setMaxWaitBetweenReconnectionRetries(5 * 1000); // 5000ms = 5s
|
||||
uint32_t m = webSocket.getMaxWaitBetweenReconnectionRetries();
|
||||
```
|
||||
@@ -253,7 +253,7 @@ Then, secure sockets are automatically used when connecting to a `wss://*` url.
|
||||
Additional TLS options can be configured by passing a `ix::SocketTLSOptions` instance to the
|
||||
`setTLSOptions` on `ix::WebSocket` (or `ix::WebSocketServer` or `ix::HttpServer`)
|
||||
|
||||
```
|
||||
```cpp
|
||||
webSocket.setTLSOptions({
|
||||
.certFile = "path/to/cert/file.pem",
|
||||
.keyFile = "path/to/key/file.pem",
|
||||
@@ -279,7 +279,7 @@ For a server, specifying `caFile` implies that:
|
||||
|
||||
## WebSocket server API
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <ixwebsocket/IXWebSocketServer.h>
|
||||
|
||||
...
|
||||
@@ -344,7 +344,7 @@ server.wait();
|
||||
|
||||
## HTTP client API
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <ixwebsocket/IXHttpClient.h>
|
||||
|
||||
...
|
||||
@@ -427,7 +427,7 @@ bool ok = httpClient.performRequest(args, [](const HttpResponsePtr& response)
|
||||
|
||||
## HTTP server API
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <ixwebsocket/IXHttpServer.h>
|
||||
|
||||
ix::HttpServer server(port, hostname);
|
||||
@@ -445,7 +445,7 @@ server.wait();
|
||||
|
||||
If you want to handle how requests are processed, implement the setOnConnectionCallback callback, which takes an HttpRequestPtr as input, and returns an HttpResponsePtr. You can look at HttpServer::setDefaultConnectionCallback for a slightly more advanced callback example.
|
||||
|
||||
```
|
||||
```cpp
|
||||
setOnConnectionCallback(
|
||||
[this](HttpRequestPtr request,
|
||||
std::shared_ptr<ConnectionState> /*connectionState*/) -> HttpResponsePtr
|
||||
|
134
docs/ws.md
134
docs/ws.md
@@ -195,6 +195,15 @@ Server: Python/3.7 websockets/8.0.2
|
||||
Upgrade: websocket
|
||||
```
|
||||
|
||||
## Websocket proxy
|
||||
|
||||
```
|
||||
ws proxy_server --remote_host ws://127.0.0.1:9000 -v
|
||||
Listening on 127.0.0.1:8008
|
||||
```
|
||||
|
||||
If you connect to ws://127.0.0.1:8008, the proxy will connect to ws://127.0.0.1:9000 and pass all traffic to this server.
|
||||
|
||||
## File transfer
|
||||
|
||||
```
|
||||
@@ -234,6 +243,127 @@ Options:
|
||||
--transfer-timeout INT Transfer timeout
|
||||
```
|
||||
|
||||
## Cobra Client
|
||||
## Cobra client and server
|
||||
|
||||
[cobra](https://github.com/machinezone/cobra) is a real time messenging server. ws has sub-command to interacti with cobra.
|
||||
[cobra](https://github.com/machinezone/cobra) is a real time messenging server. ws has several sub-command to interact with cobra. There is also a minimal cobra compatible server named snake available.
|
||||
|
||||
Below are examples on running a snake server and clients with TLS enabled (the server only works with the OpenSSL and the Mbed TLS backend for now).
|
||||
|
||||
First, generate certificates.
|
||||
|
||||
```
|
||||
$ cd /path/to/IXWebSocket
|
||||
$ cd ixsnake/ixsnake
|
||||
$ bash ../../ws/generate_certs.sh
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
.....+++
|
||||
.................+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/trusted-ca-key.pem
|
||||
generated ./.certs/trusted-ca-crt.pem
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
..+++
|
||||
.......................................+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/trusted-server-key.pem
|
||||
Signature ok
|
||||
subject=/O=machinezone/O=IXWebSocket/CN=trusted-server
|
||||
Getting CA Private Key
|
||||
generated ./.certs/trusted-server-crt.pem
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
...................................+++
|
||||
..................................................+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/trusted-client-key.pem
|
||||
Signature ok
|
||||
subject=/O=machinezone/O=IXWebSocket/CN=trusted-client
|
||||
Getting CA Private Key
|
||||
generated ./.certs/trusted-client-crt.pem
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
..............+++
|
||||
.......................................+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/untrusted-ca-key.pem
|
||||
generated ./.certs/untrusted-ca-crt.pem
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
..........+++
|
||||
................................................+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/untrusted-client-key.pem
|
||||
Signature ok
|
||||
subject=/O=machinezone/O=IXWebSocket/CN=untrusted-client
|
||||
Getting CA Private Key
|
||||
generated ./.certs/untrusted-client-crt.pem
|
||||
Generating RSA private key, 2048 bit long modulus
|
||||
.....................................................................................+++
|
||||
...........+++
|
||||
e is 65537 (0x10001)
|
||||
generated ./.certs/selfsigned-client-key.pem
|
||||
Signature ok
|
||||
subject=/O=machinezone/O=IXWebSocket/CN=selfsigned-client
|
||||
Getting Private key
|
||||
generated ./.certs/selfsigned-client-crt.pem
|
||||
```
|
||||
|
||||
Now run the snake server.
|
||||
|
||||
```
|
||||
$ export certs=.certs
|
||||
$ ws snake --tls --port 8765 --cert-file ${certs}/trusted-server-crt.pem --key-file ${certs}/trusted-server-key.pem --ca-file ${certs}/trusted-ca-crt.pem
|
||||
{
|
||||
"apps": {
|
||||
"FC2F10139A2BAc53BB72D9db967b024f": {
|
||||
"roles": {
|
||||
"_sub": {
|
||||
"secret": "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba"
|
||||
},
|
||||
"_pub": {
|
||||
"secret": "1c04DB8fFe76A4EeFE3E318C72d771db"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redis host: 127.0.0.1
|
||||
redis password:
|
||||
redis port: 6379
|
||||
```
|
||||
|
||||
As a new connection comes in, such output should be printed
|
||||
|
||||
```
|
||||
[2019-12-19 20:27:19.724] [info] New connection
|
||||
id: 0
|
||||
Uri: /v2?appkey=_health
|
||||
Headers:
|
||||
Connection: Upgrade
|
||||
Host: 127.0.0.1:8765
|
||||
Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
||||
Sec-WebSocket-Key: d747B0fE61Db73f7Eh47c0==
|
||||
Sec-WebSocket-Protocol: json
|
||||
Sec-WebSocket-Version: 13
|
||||
Upgrade: websocket
|
||||
User-Agent: ixwebsocket/7.5.8 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11
|
||||
```
|
||||
|
||||
To connect and publish a message, do:
|
||||
|
||||
```
|
||||
$ export certs=.certs
|
||||
$ cd /path/to/ws/folder
|
||||
$ ls cobraMetricsSample.json
|
||||
cobraMetricsSample.json
|
||||
$ ws cobra_publish --endpoint wss://127.0.0.1:8765 --appkey FC2F10139A2BAc53BB72D9db967b024f --rolename _pub --rolesecret 1c04DB8fFe76A4EeFE3E318C72d771db --channel foo --cert-file ${certs}/trusted-client-crt.pem --key-file ${certs}/trusted-client-key.pem --ca-file ${certs}/trusted-ca-crt.pem cobraMetricsSample.json
|
||||
[2019-12-19 20:46:42.656] [info] Publisher connected
|
||||
[2019-12-19 20:46:42.657] [info] Connection: Upgrade
|
||||
[2019-12-19 20:46:42.657] [info] Sec-WebSocket-Accept: rs99IFThoBrhSg+k8G4ixH9yaq4=
|
||||
[2019-12-19 20:46:42.657] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
||||
[2019-12-19 20:46:42.657] [info] Server: ixwebsocket/7.5.8 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11
|
||||
[2019-12-19 20:46:42.657] [info] Upgrade: websocket
|
||||
[2019-12-19 20:46:42.658] [info] Publisher authenticated
|
||||
[2019-12-19 20:46:42.658] [info] Published msg 3
|
||||
[2019-12-19 20:46:42.659] [info] Published message id 3 acked
|
||||
```
|
||||
|
||||
To use OpenSSL on macOS, compile with `make ws_openssl`. First you will have to install OpenSSL libraries, which can be done with Homebrew. Use `make ws_mbedtls` accordingly to use MbedTLS.
|
||||
|
@@ -20,11 +20,16 @@ add_library(ixcobra STATIC
|
||||
${IXCOBRA_HEADERS}
|
||||
)
|
||||
|
||||
find_package(JsonCpp)
|
||||
if (NOT JSONCPP_FOUND)
|
||||
set(JSONCPP_INCLUDE_DIRS ../third_party/jsoncpp)
|
||||
endif()
|
||||
|
||||
set(IXCOBRA_INCLUDE_DIRS
|
||||
.
|
||||
..
|
||||
../ixcore
|
||||
../ixcrypto
|
||||
../third_party)
|
||||
${JSONCPP_INCLUDE_DIRS})
|
||||
|
||||
target_include_directories( ixcobra PUBLIC ${IXCOBRA_INCLUDE_DIRS} )
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "IXCobraConnection.h"
|
||||
#include <ixcrypto/IXHMac.h>
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
@@ -14,6 +15,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace ix
|
||||
@@ -22,6 +24,7 @@ namespace ix
|
||||
PublishTrackerCallback CobraConnection::_publishTrackerCallback = nullptr;
|
||||
constexpr size_t CobraConnection::kQueueMaxSize;
|
||||
constexpr CobraConnection::MsgId CobraConnection::kInvalidMsgId;
|
||||
constexpr int CobraConnection::kPingIntervalSecs;
|
||||
|
||||
CobraConnection::CobraConnection() :
|
||||
_webSocket(new WebSocket()),
|
||||
@@ -226,6 +229,10 @@ namespace ix
|
||||
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
|
||||
invokeErrorCallback(ss.str(), std::string());
|
||||
}
|
||||
else if (msg->type == ix::WebSocketMessageType::Pong)
|
||||
{
|
||||
invokeEventCallback(ix::CobraConnection_EventType_Pong);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -243,7 +250,8 @@ namespace ix
|
||||
const std::string& endpoint,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions)
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions,
|
||||
const SocketTLSOptions& socketTLSOptions)
|
||||
{
|
||||
_roleName = rolename;
|
||||
_roleSecret = rolesecret;
|
||||
@@ -256,6 +264,16 @@ namespace ix
|
||||
std::string url = ss.str();
|
||||
_webSocket->setUrl(url);
|
||||
_webSocket->setPerMessageDeflateOptions(webSocketPerMessageDeflateOptions);
|
||||
_webSocket->setTLSOptions(socketTLSOptions);
|
||||
|
||||
// Send a websocket ping every N seconds (N = 30) now
|
||||
// This should keep the connection open and prevent some load balancers such as
|
||||
// the Amazon one from shutting it down
|
||||
_webSocket->setPingInterval(kPingIntervalSecs);
|
||||
|
||||
// If we don't receive a pong back, declare loss after 3 * N seconds
|
||||
// (will be 90s now), and close and restart the connection
|
||||
_webSocket->setPingTimeout(3 * kPingIntervalSecs);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -496,7 +514,7 @@ namespace ix
|
||||
if (_messageQueue.empty()) return true;
|
||||
|
||||
auto&& msg = _messageQueue.back();
|
||||
if (!publishMessage(msg))
|
||||
if (!_authenticated || !publishMessage(msg))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
|
||||
#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
|
||||
#include <jsoncpp/json/json.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -20,6 +20,7 @@
|
||||
namespace ix
|
||||
{
|
||||
class WebSocket;
|
||||
struct SocketTLSOptions;
|
||||
|
||||
enum CobraConnectionEventType
|
||||
{
|
||||
@@ -29,7 +30,8 @@ namespace ix
|
||||
CobraConnection_EventType_Closed = 3,
|
||||
CobraConnection_EventType_Subscribed = 4,
|
||||
CobraConnection_EventType_UnSubscribed = 5,
|
||||
CobraConnection_EventType_Published = 6
|
||||
CobraConnection_EventType_Published = 6,
|
||||
CobraConnection_EventType_Pong = 7
|
||||
};
|
||||
|
||||
enum CobraConnectionPublishMode
|
||||
@@ -62,7 +64,8 @@ namespace ix
|
||||
const std::string& endpoint,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions);
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions,
|
||||
const SocketTLSOptions& socketTLSOptions);
|
||||
|
||||
/// Set the traffic tracker callback
|
||||
static void setTrafficTrackerCallback(const TrafficTrackerCallback& callback);
|
||||
@@ -213,6 +216,9 @@ namespace ix
|
||||
|
||||
// Each pdu sent should have an incremental unique id
|
||||
std::atomic<uint64_t> _id;
|
||||
|
||||
// Frequency at which we send a websocket ping to the backing cobra connection
|
||||
static constexpr int kPingIntervalSecs = 30;
|
||||
};
|
||||
|
||||
} // namespace ix
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "IXCobraMetricsPublisher.h"
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
@@ -31,14 +32,15 @@ namespace ix
|
||||
const std::string& channel,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
bool enablePerMessageDeflate)
|
||||
bool enablePerMessageDeflate,
|
||||
const SocketTLSOptions& socketTLSOptions)
|
||||
{
|
||||
// Configure the satori connection and start its publish background thread
|
||||
_cobra_metrics_theaded_publisher.start();
|
||||
|
||||
_cobra_metrics_theaded_publisher.configure(appkey, endpoint, channel,
|
||||
rolename, rolesecret,
|
||||
enablePerMessageDeflate);
|
||||
enablePerMessageDeflate, socketTLSOptions);
|
||||
}
|
||||
|
||||
Json::Value& CobraMetricsPublisher::getGenericAttributes()
|
||||
|
@@ -9,12 +9,14 @@
|
||||
#include "IXCobraMetricsThreadedPublisher.h"
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <jsoncpp/json/json.h>
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
struct SocketTLSOptions;
|
||||
|
||||
class CobraMetricsPublisher
|
||||
{
|
||||
public:
|
||||
@@ -43,7 +45,8 @@ namespace ix
|
||||
const std::string& channel,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
bool enablePerMessageDeflate);
|
||||
bool enablePerMessageDeflate,
|
||||
const SocketTLSOptions& socketTLSOptions);
|
||||
|
||||
/// Setter for the list of blacklisted metrics ids.
|
||||
/// That list is sorted internally for fast lookups
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "IXCobraMetricsThreadedPublisher.h"
|
||||
#include <ixwebsocket/IXSetThreadName.h>
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
#include <ixcore/utils/IXCoreLogger.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -13,6 +14,7 @@
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace ix
|
||||
@@ -63,6 +65,10 @@ namespace ix
|
||||
{
|
||||
ss << "Published message " << msgId << " acked";
|
||||
}
|
||||
else if (eventType == ix::CobraConnection_EventType_Pong)
|
||||
{
|
||||
ss << "Received websocket pong";
|
||||
}
|
||||
|
||||
ix::IXCoreLogger::Log(ss.str().c_str());
|
||||
});
|
||||
@@ -91,14 +97,17 @@ namespace ix
|
||||
const std::string& channel,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
bool enablePerMessageDeflate)
|
||||
bool enablePerMessageDeflate,
|
||||
const SocketTLSOptions& socketTLSOptions)
|
||||
{
|
||||
_channel = channel;
|
||||
|
||||
ix::IXCoreLogger::Log(socketTLSOptions.getDescription().c_str());
|
||||
|
||||
ix::WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(enablePerMessageDeflate);
|
||||
_cobra_connection.configure(appkey, endpoint,
|
||||
rolename, rolesecret,
|
||||
webSocketPerMessageDeflateOptions);
|
||||
webSocketPerMessageDeflateOptions, socketTLSOptions);
|
||||
}
|
||||
|
||||
void CobraMetricsThreadedPublisher::pushMessage(MessageKind messageKind)
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#include "IXCobraConnection.h"
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <jsoncpp/json/json.h>
|
||||
#include <json/json.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace ix
|
||||
{
|
||||
struct SocketTLSOptions;
|
||||
|
||||
class CobraMetricsThreadedPublisher
|
||||
{
|
||||
public:
|
||||
@@ -30,7 +32,8 @@ namespace ix
|
||||
const std::string& channel,
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
bool enablePerMessageDeflate);
|
||||
bool enablePerMessageDeflate,
|
||||
const SocketTLSOptions& socketTLSOptions);
|
||||
|
||||
/// Start the worker thread, used for background publishing
|
||||
void start();
|
||||
|
@@ -16,10 +16,15 @@ add_library(ixsentry STATIC
|
||||
${IXSENTRY_HEADERS}
|
||||
)
|
||||
|
||||
find_package(JsonCpp)
|
||||
if (NOT JSONCPP_FOUND)
|
||||
set(JSONCPP_INCLUDE_DIRS ../third_party/jsoncpp)
|
||||
endif()
|
||||
|
||||
set(IXSENTRY_INCLUDE_DIRS
|
||||
.
|
||||
..
|
||||
../third_party
|
||||
../third_party/spdlog/include)
|
||||
../ixcore
|
||||
${JSONCPP_INCLUDE_DIRS})
|
||||
|
||||
target_include_directories( ixsentry PUBLIC ${IXSENTRY_INCLUDE_DIRS} )
|
||||
|
@@ -8,8 +8,11 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <ixwebsocket/IXWebSocketVersion.h>
|
||||
#include <ixcore/utils/IXCoreLogger.h>
|
||||
|
||||
|
||||
namespace ix
|
||||
@@ -18,6 +21,7 @@ namespace ix
|
||||
: _dsn(dsn)
|
||||
, _validDsn(false)
|
||||
, _luaFrameRegex("\t([^/]+):([0-9]+): in function ['<]([^/]+)['>]")
|
||||
, _httpClient(std::make_shared<HttpClient>(true))
|
||||
{
|
||||
const std::regex dsnRegex("(http[s]?)://([^:]+):([^@]+)@([^/]+)/([0-9]+)");
|
||||
std::smatch group;
|
||||
@@ -117,26 +121,6 @@ namespace ix
|
||||
{
|
||||
Json::Value payload;
|
||||
|
||||
payload["platform"] = "python";
|
||||
payload["sdk"]["name"] = "ws";
|
||||
payload["sdk"]["version"] = "1.0.0";
|
||||
payload["timestamp"] = SentryClient::getIso8601();
|
||||
|
||||
bool isNoisyTypes = msg["id"].asString() == "game_noisytypes_id";
|
||||
|
||||
std::string stackTraceFieldName = isNoisyTypes ? "traceback" : "stack";
|
||||
std::string stack(msg["data"][stackTraceFieldName].asString());
|
||||
|
||||
Json::Value exception;
|
||||
exception["stacktrace"]["frames"] = parseLuaStackTrace(stack);
|
||||
exception["value"] = isNoisyTypes ? parseExceptionName(stack) : msg["data"]["message"];
|
||||
|
||||
payload["exception"].append(exception);
|
||||
|
||||
Json::Value extra;
|
||||
extra["cobra_event"] = msg;
|
||||
extra["cobra_event"] = msg;
|
||||
|
||||
//
|
||||
// "tags": [
|
||||
// [
|
||||
@@ -145,8 +129,72 @@ namespace ix
|
||||
// ],
|
||||
// ]
|
||||
//
|
||||
Json::Value tags;
|
||||
Json::Value tags(Json::arrayValue);
|
||||
|
||||
payload["platform"] = "python";
|
||||
payload["sdk"]["name"] = "ws";
|
||||
payload["sdk"]["version"] = IX_WEBSOCKET_VERSION;
|
||||
payload["timestamp"] = SentryClient::getIso8601();
|
||||
|
||||
bool isNoisyTypes = msg["id"].asString() == "game_noisytypes_id";
|
||||
|
||||
std::string stackTraceFieldName = isNoisyTypes ? "traceback" : "stack";
|
||||
std::string stack;
|
||||
std::string message;
|
||||
|
||||
if (isNoisyTypes)
|
||||
{
|
||||
stack = msg["data"][stackTraceFieldName].asString();
|
||||
message = parseExceptionName(stack);
|
||||
}
|
||||
else // logging
|
||||
{
|
||||
if (msg["data"].isMember("info"))
|
||||
{
|
||||
stack = msg["data"]["info"][stackTraceFieldName].asString();
|
||||
message = msg["data"]["info"]["message"].asString();
|
||||
|
||||
if (msg["data"].isMember("tags"))
|
||||
{
|
||||
auto members = msg["data"]["tags"].getMemberNames();
|
||||
|
||||
for (auto member : members)
|
||||
{
|
||||
Json::Value tag;
|
||||
tag.append(member);
|
||||
tag.append(msg["data"]["tags"][member]);
|
||||
tags.append(tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg["data"]["info"].isMember("level_str"))
|
||||
{
|
||||
// https://docs.sentry.io/enriching-error-data/context/?platform=python#setting-the-level
|
||||
std::string level = msg["data"]["info"]["level_str"].asString();
|
||||
if (level == "critical")
|
||||
{
|
||||
level = "fatal";
|
||||
}
|
||||
payload["level"] = level;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stack = msg["data"][stackTraceFieldName].asString();
|
||||
message = msg["data"]["message"].asString();
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value exception;
|
||||
exception["stacktrace"]["frames"] = parseLuaStackTrace(stack);
|
||||
exception["value"] = message;
|
||||
|
||||
payload["exception"].append(exception);
|
||||
|
||||
Json::Value extra;
|
||||
extra["cobra_event"] = msg;
|
||||
|
||||
// Builtin tags
|
||||
Json::Value gameTag;
|
||||
gameTag.append("game");
|
||||
gameTag.append(msg["device"]["game"]);
|
||||
@@ -162,6 +210,11 @@ namespace ix
|
||||
environmentTag.append(msg["device"]["environment"]);
|
||||
tags.append(environmentTag);
|
||||
|
||||
Json::Value clientVersionTag;
|
||||
clientVersionTag.append("client_version");
|
||||
clientVersionTag.append(msg["device"]["app_version"]);
|
||||
tags.append(clientVersionTag);
|
||||
|
||||
payload["tags"] = tags;
|
||||
|
||||
return _jsonWriter.write(payload);
|
||||
@@ -169,39 +222,63 @@ namespace ix
|
||||
|
||||
std::pair<HttpResponsePtr, std::string> SentryClient::send(const Json::Value& msg, bool verbose)
|
||||
{
|
||||
auto args = _httpClient.createRequest();
|
||||
auto args = _httpClient->createRequest();
|
||||
args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
|
||||
args->connectTimeout = 60;
|
||||
args->transferTimeout = 5 * 60;
|
||||
args->followRedirects = true;
|
||||
args->verbose = verbose;
|
||||
args->logger = [](const std::string& msg) { spdlog::info("request logger: {}", msg); };
|
||||
args->logger = [](const std::string& msg) { ix::IXCoreLogger::Log(msg.c_str()); };
|
||||
|
||||
std::string body = computePayload(msg);
|
||||
HttpResponsePtr response = _httpClient.post(_url, body, args);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
for (auto it : response->headers)
|
||||
{
|
||||
spdlog::info("{}: {}", it.first, it.second);
|
||||
}
|
||||
|
||||
spdlog::info("Upload size: {}", response->uploadSize);
|
||||
spdlog::info("Download size: {}", response->downloadSize);
|
||||
|
||||
spdlog::info("Status: {}", response->statusCode);
|
||||
if (response->errorCode != HttpErrorCode::Ok)
|
||||
{
|
||||
spdlog::info("error message: {}", response->errorMsg);
|
||||
}
|
||||
|
||||
if (response->headers["Content-Type"] != "application/octet-stream")
|
||||
{
|
||||
spdlog::info("payload: {}", response->payload);
|
||||
}
|
||||
}
|
||||
HttpResponsePtr response = _httpClient->post(_url, body, args);
|
||||
|
||||
return std::make_pair(response, body);
|
||||
}
|
||||
|
||||
// https://sentry.io/api/12345/minidump?sentry_key=abcdefgh");
|
||||
std::string SentryClient::computeUrl(const std::string& project, const std::string& key)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "https://sentry.io/api/"
|
||||
<< project
|
||||
<< "/minidump?sentry_key="
|
||||
<< key;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//
|
||||
// curl -v -X POST -F upload_file_minidump=@ws/crash.dmp 'https://sentry.io/api/123456/minidump?sentry_key=12344567890'
|
||||
//
|
||||
void SentryClient::uploadMinidump(
|
||||
const std::string& sentryMetadata,
|
||||
const std::string& minidumpBytes,
|
||||
const std::string& project,
|
||||
const std::string& key,
|
||||
bool verbose,
|
||||
const OnResponseCallback& onResponseCallback)
|
||||
{
|
||||
std::string multipartBoundary = _httpClient->generateMultipartBoundary();
|
||||
|
||||
auto args = _httpClient->createRequest();
|
||||
args->verb = HttpClient::kPost;
|
||||
args->connectTimeout = 60;
|
||||
args->transferTimeout = 5 * 60;
|
||||
args->followRedirects = true;
|
||||
args->verbose = verbose;
|
||||
args->multipartBoundary = multipartBoundary;
|
||||
args->logger = [](const std::string& msg) { ix::IXCoreLogger::Log(msg.c_str()); };
|
||||
|
||||
HttpFormDataParameters httpFormDataParameters;
|
||||
httpFormDataParameters["upload_file_minidump"] = minidumpBytes;
|
||||
|
||||
HttpParameters httpParameters;
|
||||
httpParameters["sentry"] = sentryMetadata;
|
||||
|
||||
args->url = computeUrl(project, key);
|
||||
args->body = _httpClient->serializeHttpFormDataParameters(multipartBoundary, httpFormDataParameters, httpParameters);
|
||||
|
||||
_httpClient->performRequest(args, onResponseCallback);
|
||||
}
|
||||
} // namespace ix
|
||||
|
@@ -8,8 +8,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <ixwebsocket/IXHttpClient.h>
|
||||
#include <jsoncpp/json/json.h>
|
||||
#include <json/json.h>
|
||||
#include <regex>
|
||||
#include <memory>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@@ -23,12 +24,24 @@ namespace ix
|
||||
|
||||
Json::Value parseLuaStackTrace(const std::string& stack);
|
||||
|
||||
void uploadMinidump(
|
||||
const std::string& sentryMetadata,
|
||||
const std::string& minidumpBytes,
|
||||
const std::string& project,
|
||||
const std::string& key,
|
||||
bool verbose,
|
||||
const OnResponseCallback& onResponseCallback);
|
||||
|
||||
private:
|
||||
int64_t getTimestamp();
|
||||
std::string computeAuthHeader();
|
||||
std::string getIso8601();
|
||||
std::string computePayload(const Json::Value& msg);
|
||||
|
||||
std::string computeUrl(const std::string& project, const std::string& key);
|
||||
|
||||
void displayReponse(HttpResponsePtr response);
|
||||
|
||||
std::string _dsn;
|
||||
bool _validDsn;
|
||||
std::string _url;
|
||||
@@ -41,7 +54,7 @@ namespace ix
|
||||
|
||||
std::regex _luaFrameRegex;
|
||||
|
||||
HttpClient _httpClient;
|
||||
std::shared_ptr<HttpClient> _httpClient;
|
||||
};
|
||||
|
||||
} // namespace ix
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
|
||||
namespace snake
|
||||
{
|
||||
@@ -26,8 +27,12 @@ namespace snake
|
||||
// AppKeys
|
||||
nlohmann::json apps;
|
||||
|
||||
// TLS options
|
||||
ix::SocketTLSOptions socketTLSOptions;
|
||||
|
||||
// Misc
|
||||
bool verbose;
|
||||
bool disablePong;
|
||||
};
|
||||
|
||||
bool isAppKeyValid(const AppConfig& appConfig, std::string appkey);
|
||||
|
@@ -29,8 +29,13 @@ namespace ix
|
||||
return false;
|
||||
}
|
||||
|
||||
CancellationRequest cancellationRequest = []() -> bool
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
std::string errMsg;
|
||||
return _socket->connect(hostname, port, errMsg, nullptr);
|
||||
return _socket->connect(hostname, port, errMsg, cancellationRequest);
|
||||
}
|
||||
|
||||
void RedisClient::stop()
|
||||
|
@@ -17,8 +17,8 @@
|
||||
|
||||
namespace ix
|
||||
{
|
||||
RedisServer::RedisServer(int port, const std::string& host, int backlog, size_t maxConnections)
|
||||
: SocketServer(port, host, backlog, maxConnections)
|
||||
RedisServer::RedisServer(int port, const std::string& host, int backlog, size_t maxConnections, int addressFamily)
|
||||
: SocketServer(port, host, backlog, maxConnections, addressFamily)
|
||||
, _connectedClientsCount(0)
|
||||
, _stopHandlingConnections(false)
|
||||
{
|
||||
|
@@ -25,7 +25,8 @@ namespace ix
|
||||
RedisServer(int port = SocketServer::kDefaultPort,
|
||||
const std::string& host = SocketServer::kDefaultHost,
|
||||
int backlog = SocketServer::kDefaultTcpBacklog,
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections);
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections,
|
||||
int addressFamily = SocketServer::kDefaultAddressFamily);
|
||||
virtual ~RedisServer();
|
||||
virtual void stop() final;
|
||||
|
||||
|
@@ -20,6 +20,7 @@ namespace snake
|
||||
{
|
||||
return _nonce;
|
||||
}
|
||||
|
||||
void setNonce(const std::string& nonce)
|
||||
{
|
||||
_nonce = nonce;
|
||||
|
@@ -20,7 +20,16 @@ namespace snake
|
||||
: _appConfig(appConfig)
|
||||
, _server(appConfig.port, appConfig.hostname)
|
||||
{
|
||||
;
|
||||
_server.setTLSOptions(appConfig.socketTLSOptions);
|
||||
|
||||
if (appConfig.disablePong)
|
||||
{
|
||||
_server.disablePong();
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Listening on " << appConfig.hostname << ":" << appConfig.port;
|
||||
ix::IXCoreLogger::Log(ss.str().c_str());
|
||||
}
|
||||
|
||||
//
|
||||
|
@@ -61,7 +61,7 @@ namespace ix
|
||||
errMsg = "no error";
|
||||
|
||||
// Maybe a cancellation request got in before the background thread terminated ?
|
||||
if (isCancellationRequested && isCancellationRequested())
|
||||
if (isCancellationRequested())
|
||||
{
|
||||
errMsg = "cancellation requested";
|
||||
return nullptr;
|
||||
@@ -107,7 +107,7 @@ namespace ix
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(_wait));
|
||||
|
||||
// Were we cancelled ?
|
||||
if (isCancellationRequested && isCancellationRequested())
|
||||
if (isCancellationRequested())
|
||||
{
|
||||
errMsg = "cancellation requested";
|
||||
return nullptr;
|
||||
@@ -115,7 +115,7 @@ namespace ix
|
||||
}
|
||||
|
||||
// Maybe a cancellation request got in before the bg terminated ?
|
||||
if (isCancellationRequested && isCancellationRequested())
|
||||
if (isCancellationRequested())
|
||||
{
|
||||
errMsg = "cancellation requested";
|
||||
return nullptr;
|
||||
|
@@ -13,7 +13,7 @@ namespace ix
|
||||
uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count,
|
||||
uint32_t maxWaitBetweenReconnectionRetries)
|
||||
{
|
||||
uint32_t wait_time = std::pow(2, retry_count) * 100;
|
||||
uint32_t wait_time = (retry_count < 26) ? (std::pow(2, retry_count) * 100) : 0;
|
||||
|
||||
if (wait_time > maxWaitBetweenReconnectionRetries || wait_time == 0)
|
||||
{
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "IXProgressCallback.h"
|
||||
#include "IXWebSocketHttpHeaders.h"
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@@ -65,7 +66,8 @@ namespace ix
|
||||
};
|
||||
|
||||
using HttpResponsePtr = std::shared_ptr<HttpResponse>;
|
||||
using HttpParameters = std::map<std::string, std::string>;
|
||||
using HttpParameters = std::unordered_map<std::string, std::string>;
|
||||
using HttpFormDataParameters = std::unordered_map<std::string, std::string>;
|
||||
using Logger = std::function<void(const std::string&)>;
|
||||
using OnResponseCallback = std::function<void(const HttpResponsePtr&)>;
|
||||
|
||||
@@ -75,6 +77,7 @@ namespace ix
|
||||
std::string verb;
|
||||
WebSocketHttpHeaders extraHeaders;
|
||||
std::string body;
|
||||
std::string multipartBoundary;
|
||||
int connectTimeout;
|
||||
int transferTimeout;
|
||||
bool followRedirects;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <zlib.h>
|
||||
@@ -198,8 +199,16 @@ namespace ix
|
||||
// Set default Content-Type if unspecified
|
||||
if (args->extraHeaders.find("Content-Type") == args->extraHeaders.end())
|
||||
{
|
||||
ss << "Content-Type: application/x-www-form-urlencoded"
|
||||
<< "\r\n";
|
||||
if (args->multipartBoundary.empty())
|
||||
{
|
||||
ss << "Content-Type: application/x-www-form-urlencoded"
|
||||
<< "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "Content-Type: multipart/form-data; boundary=" << args->multipartBoundary
|
||||
<< "\r\n";
|
||||
}
|
||||
}
|
||||
ss << "\r\n";
|
||||
ss << body;
|
||||
@@ -597,6 +606,53 @@ namespace ix
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string HttpClient::serializeHttpFormDataParameters(
|
||||
const std::string& multipartBoundary,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
const HttpParameters& httpParameters)
|
||||
{
|
||||
//
|
||||
// --AaB03x
|
||||
// Content-Disposition: form-data; name="submit-name"
|
||||
|
||||
// Larry
|
||||
// --AaB03x
|
||||
// Content-Disposition: form-data; name="foo.txt"; filename="file1.txt"
|
||||
// Content-Type: text/plain
|
||||
|
||||
// ... contents of file1.txt ...
|
||||
// --AaB03x--
|
||||
//
|
||||
std::stringstream ss;
|
||||
|
||||
for (auto&& it : httpFormDataParameters)
|
||||
{
|
||||
ss << "--" << multipartBoundary << "\r\n"
|
||||
<< "Content-Disposition:"
|
||||
<< " form-data; name=\"" << it.first << "\";"
|
||||
<< " filename=\"" << it.first << "\""
|
||||
<< "\r\n"
|
||||
<< "Content-Type: application/octet-stream"
|
||||
<< "\r\n"
|
||||
<< "\r\n"
|
||||
<< it.second << "\r\n";
|
||||
}
|
||||
|
||||
for (auto&& it : httpParameters)
|
||||
{
|
||||
ss << "--" << multipartBoundary << "\r\n"
|
||||
<< "Content-Disposition:"
|
||||
<< " form-data; name=\"" << it.first << "\";"
|
||||
<< "\r\n"
|
||||
<< "\r\n"
|
||||
<< it.second << "\r\n";
|
||||
}
|
||||
|
||||
ss << "--" << multipartBoundary << "--\r\n";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool HttpClient::gzipInflate(const std::string& in, std::string& out)
|
||||
{
|
||||
z_stream inflateState;
|
||||
@@ -649,4 +705,16 @@ namespace ix
|
||||
args->logger(msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::string HttpClient::generateMultipartBoundary()
|
||||
{
|
||||
std::string str("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
static std::random_device rd;
|
||||
static std::mt19937 generator(rd());
|
||||
|
||||
std::shuffle(str.begin(), str.end(), generator);
|
||||
|
||||
return str;
|
||||
}
|
||||
} // namespace ix
|
||||
|
@@ -64,6 +64,13 @@ namespace ix
|
||||
|
||||
std::string serializeHttpParameters(const HttpParameters& httpParameters);
|
||||
|
||||
std::string serializeHttpFormDataParameters(
|
||||
const std::string& multipartBoundary,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
const HttpParameters& httpParameters = HttpParameters());
|
||||
|
||||
std::string generateMultipartBoundary();
|
||||
|
||||
std::string urlEncode(const std::string& value);
|
||||
|
||||
const static std::string kPost;
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include "IXSocketConnect.h"
|
||||
#include "IXUserAgent.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
@@ -43,8 +42,9 @@ namespace
|
||||
|
||||
namespace ix
|
||||
{
|
||||
HttpServer::HttpServer(int port, const std::string& host, int backlog, size_t maxConnections)
|
||||
: SocketServer(port, host, backlog, maxConnections)
|
||||
HttpServer::HttpServer(
|
||||
int port, const std::string& host, int backlog, size_t maxConnections, int addressFamily)
|
||||
: SocketServer(port, host, backlog, maxConnections, addressFamily)
|
||||
, _connectedClientsCount(0)
|
||||
{
|
||||
setDefaultConnectionCallback();
|
||||
|
@@ -28,7 +28,8 @@ namespace ix
|
||||
HttpServer(int port = SocketServer::kDefaultPort,
|
||||
const std::string& host = SocketServer::kDefaultHost,
|
||||
int backlog = SocketServer::kDefaultTcpBacklog,
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections);
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections,
|
||||
int addressFamily = SocketServer::kDefaultAddressFamily);
|
||||
virtual ~HttpServer();
|
||||
virtual void stop() final;
|
||||
|
||||
|
@@ -7,9 +7,9 @@
|
||||
#include "IXSelectInterruptFactory.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <ixwebsocket/IXSelectInterruptPipe.h>
|
||||
#include "IXSelectInterruptPipe.h"
|
||||
#else
|
||||
#include <ixwebsocket/IXSelectInterrupt.h>
|
||||
#include "IXSelectInterrupt.h"
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
|
@@ -54,14 +54,17 @@ namespace ix
|
||||
// to ::poll does fix that.
|
||||
//
|
||||
// However poll isn't as portable as select and has bugs on Windows, so we
|
||||
// should write a shim to fallback to select on those platforms. See
|
||||
// have a shim to fallback to select on those platforms. See
|
||||
// https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
||||
//
|
||||
nfds_t nfds = 1;
|
||||
struct pollfd fds[2];
|
||||
memset(fds, 0, sizeof(fds));
|
||||
|
||||
fds[0].fd = sockfd;
|
||||
fds[0].events = (readyToRead) ? POLLIN : POLLOUT;
|
||||
|
||||
// this is ignored by poll, but our select based poll wrapper on Windows needs it
|
||||
fds[0].events |= POLLERR;
|
||||
|
||||
// File descriptor used to interrupt select when needed
|
||||
@@ -132,6 +135,11 @@ namespace ix
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (sockfd != -1 && (fds[0].revents & POLLERR || fds[0].revents & POLLHUP ||
|
||||
fds[0].revents & POLLNVAL))
|
||||
{
|
||||
pollResult = PollResultType::Error;
|
||||
}
|
||||
|
||||
return pollResult;
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ namespace ix
|
||||
virtual void close();
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length);
|
||||
virtual ssize_t send(const std::string& buffer);
|
||||
ssize_t send(const std::string& buffer);
|
||||
virtual ssize_t recv(void* buffer, size_t length);
|
||||
|
||||
// Blocking and cancellable versions, working with socket that can be set
|
||||
|
@@ -24,9 +24,47 @@
|
||||
|
||||
#include <Security/SecureTransport.h>
|
||||
|
||||
namespace
|
||||
namespace ix
|
||||
{
|
||||
OSStatus read_from_socket(SSLConnectionRef connection, void* data, size_t* len)
|
||||
SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd)
|
||||
: Socket(fd)
|
||||
, _sslContext(nullptr)
|
||||
, _tlsOptions(tlsOptions)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
SocketAppleSSL::~SocketAppleSSL()
|
||||
{
|
||||
SocketAppleSSL::close();
|
||||
}
|
||||
|
||||
std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status)
|
||||
{
|
||||
std::string errMsg("Unknown SSL error.");
|
||||
|
||||
CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
|
||||
if (error)
|
||||
{
|
||||
CFStringRef message = CFErrorCopyDescription(error);
|
||||
if (message)
|
||||
{
|
||||
char localBuffer[128];
|
||||
Boolean success;
|
||||
success = CFStringGetCString(message, localBuffer, 128, kCFStringEncodingUTF8);
|
||||
if (success)
|
||||
{
|
||||
errMsg = localBuffer;
|
||||
}
|
||||
CFRelease(message);
|
||||
}
|
||||
CFRelease(error);
|
||||
}
|
||||
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
OSStatus SocketAppleSSL::readFromSocket(SSLConnectionRef connection, void* data, size_t* len)
|
||||
{
|
||||
int fd = (int) (long) connection;
|
||||
if (fd < 0) return errSSLInternal;
|
||||
@@ -42,11 +80,15 @@ namespace
|
||||
{
|
||||
*len = (size_t) status;
|
||||
if (requested_sz > *len)
|
||||
{
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
else if (0 == status)
|
||||
else if (status == 0)
|
||||
{
|
||||
*len = 0;
|
||||
return errSSLClosedGraceful;
|
||||
@@ -58,7 +100,8 @@ namespace
|
||||
{
|
||||
case ENOENT: return errSSLClosedGraceful;
|
||||
|
||||
case EAGAIN: return errSSLWouldBlock;
|
||||
case EAGAIN: return errSSLWouldBlock; // EWOULDBLOCK is a define for EAGAIN on osx
|
||||
case EINPROGRESS: return errSSLWouldBlock;
|
||||
|
||||
case ECONNRESET: return errSSLClosedAbort;
|
||||
|
||||
@@ -67,7 +110,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus write_to_socket(SSLConnectionRef connection, const void* data, size_t* len)
|
||||
OSStatus SocketAppleSSL::writeToSocket(SSLConnectionRef connection,
|
||||
const void* data,
|
||||
size_t* len)
|
||||
{
|
||||
int fd = (int) (long) connection;
|
||||
if (fd < 0) return errSSLInternal;
|
||||
@@ -82,11 +127,15 @@ namespace
|
||||
{
|
||||
*len = (size_t) status;
|
||||
if (to_write_sz > *len)
|
||||
{
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
else if (0 == status)
|
||||
else if (status == 0)
|
||||
{
|
||||
*len = 0;
|
||||
return errSSLClosedGraceful;
|
||||
@@ -94,58 +143,25 @@ namespace
|
||||
else
|
||||
{
|
||||
*len = 0;
|
||||
if (EAGAIN == errno)
|
||||
switch (errno)
|
||||
{
|
||||
return errSSLWouldBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return errSecIO;
|
||||
case ENOENT: return errSSLClosedGraceful;
|
||||
|
||||
case EAGAIN: return errSSLWouldBlock; // EWOULDBLOCK is a define for EAGAIN on osx
|
||||
case EINPROGRESS: return errSSLWouldBlock;
|
||||
|
||||
case ECONNRESET: return errSSLClosedAbort;
|
||||
|
||||
default: return errSecIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string getSSLErrorDescription(OSStatus status)
|
||||
|
||||
bool SocketAppleSSL::accept(std::string& errMsg)
|
||||
{
|
||||
std::string errMsg("Unknown SSL error.");
|
||||
|
||||
CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
|
||||
if (error)
|
||||
{
|
||||
CFStringRef message = CFErrorCopyDescription(error);
|
||||
if (message)
|
||||
{
|
||||
char localBuffer[128];
|
||||
Boolean success;
|
||||
success =
|
||||
CFStringGetCString(message, localBuffer, 128, CFStringGetSystemEncoding());
|
||||
if (success)
|
||||
{
|
||||
errMsg = localBuffer;
|
||||
}
|
||||
CFRelease(message);
|
||||
}
|
||||
CFRelease(error);
|
||||
}
|
||||
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace ix
|
||||
{
|
||||
SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd)
|
||||
: Socket(fd)
|
||||
, _sslContext(nullptr)
|
||||
, _tlsOptions(tlsOptions)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
SocketAppleSSL::~SocketAppleSSL()
|
||||
{
|
||||
SocketAppleSSL::close();
|
||||
errMsg = "TLS not supported yet in server mode with apple ssl backend";
|
||||
return false;
|
||||
}
|
||||
|
||||
// No wait support
|
||||
@@ -163,18 +179,41 @@ namespace ix
|
||||
|
||||
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||
|
||||
SSLSetIOFuncs(_sslContext, read_from_socket, write_to_socket);
|
||||
SSLSetIOFuncs(
|
||||
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
|
||||
SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
|
||||
SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
|
||||
SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
|
||||
|
||||
do
|
||||
if (_tlsOptions.isPeerVerifyDisabled())
|
||||
{
|
||||
status = SSLHandshake(_sslContext);
|
||||
} while (errSSLWouldBlock == status || errSSLServerAuthCompleted == status);
|
||||
Boolean option(1);
|
||||
SSLSetSessionOption(_sslContext, kSSLSessionOptionBreakOnServerAuth, option);
|
||||
|
||||
do
|
||||
{
|
||||
status = SSLHandshake(_sslContext);
|
||||
} while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
|
||||
|
||||
if (status == errSSLServerAuthCompleted)
|
||||
{
|
||||
// proceed with the handshake
|
||||
do
|
||||
{
|
||||
status = SSLHandshake(_sslContext);
|
||||
} while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
status = SSLHandshake(_sslContext);
|
||||
} while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
if (noErr != status)
|
||||
if (status != noErr)
|
||||
{
|
||||
errMsg = getSSLErrorDescription(status);
|
||||
close();
|
||||
@@ -199,32 +238,38 @@ namespace ix
|
||||
|
||||
ssize_t SocketAppleSSL::send(char* buf, size_t nbyte)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
OSStatus status;
|
||||
do
|
||||
OSStatus status = errSSLWouldBlock;
|
||||
while (status == errSSLWouldBlock)
|
||||
{
|
||||
size_t processed = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
status = SSLWrite(_sslContext, buf, nbyte, &processed);
|
||||
ret += processed;
|
||||
buf += processed;
|
||||
nbyte -= processed;
|
||||
} while (nbyte > 0 && errSSLWouldBlock == status);
|
||||
|
||||
if (ret == 0 && errSSLClosedAbort != status) ret = -1;
|
||||
return ret;
|
||||
}
|
||||
if (processed > 0) return (ssize_t) processed;
|
||||
|
||||
ssize_t SocketAppleSSL::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
// The connection was reset, inform the caller that this
|
||||
// Socket should close
|
||||
if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify ||
|
||||
status == errSSLClosedAbort)
|
||||
{
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == errSSLWouldBlock)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// No wait support
|
||||
ssize_t SocketAppleSSL::recv(void* buf, size_t nbyte)
|
||||
{
|
||||
OSStatus status = errSSLWouldBlock;
|
||||
while (errSSLWouldBlock == status)
|
||||
while (status == errSSLWouldBlock)
|
||||
{
|
||||
size_t processed = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
@@ -21,6 +21,8 @@ namespace ix
|
||||
SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd = -1);
|
||||
~SocketAppleSSL();
|
||||
|
||||
virtual bool accept(std::string& errMsg) final;
|
||||
|
||||
virtual bool connect(const std::string& host,
|
||||
int port,
|
||||
std::string& errMsg,
|
||||
@@ -28,10 +30,13 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
static std::string getSSLErrorDescription(OSStatus status);
|
||||
static OSStatus writeToSocket(SSLConnectionRef connection, const void* data, size_t* len);
|
||||
static OSStatus readFromSocket(SSLConnectionRef connection, void* data, size_t* len);
|
||||
|
||||
SSLContextRef _sslContext;
|
||||
mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
|
||||
|
||||
|
@@ -9,18 +9,16 @@
|
||||
#ifdef IXWEBSOCKET_USE_TLS
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_MBED_TLS
|
||||
#include <ixwebsocket/IXSocketMbedTLS.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <ixwebsocket/IXSocketSChannel.h>
|
||||
#include "IXSocketMbedTLS.h"
|
||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||
#include <ixwebsocket/IXSocketOpenSSL.h>
|
||||
#include "IXSocketOpenSSL.h"
|
||||
#elif __APPLE__
|
||||
#include <ixwebsocket/IXSocketAppleSSL.h>
|
||||
#include "IXSocketAppleSSL.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
#include "IXSocket.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +29,7 @@ namespace ix
|
||||
std::string& errorMsg,
|
||||
const SocketTLSOptions& tlsOptions)
|
||||
{
|
||||
(void) tlsOptions;
|
||||
errorMsg.clear();
|
||||
std::shared_ptr<Socket> socket;
|
||||
|
||||
@@ -45,8 +44,6 @@ namespace ix
|
||||
socket = std::make_shared<SocketMbedTLS>(tlsOptions, fd);
|
||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||
socket = std::make_shared<SocketOpenSSL>(tlsOptions, fd);
|
||||
#elif defined(_WIN32)
|
||||
socket = std::make_shared<SocketSChannel>(tlsOptions, fd);
|
||||
#elif defined(__APPLE__)
|
||||
socket = std::make_shared<SocketAppleSSL>(tlsOptions, fd);
|
||||
#endif
|
||||
|
@@ -38,9 +38,11 @@ namespace ix
|
||||
mbedtls_ctr_drbg_init(&_ctr_drbg);
|
||||
mbedtls_entropy_init(&_entropy);
|
||||
mbedtls_x509_crt_init(&_cacert);
|
||||
mbedtls_x509_crt_init(&_cert);
|
||||
mbedtls_pk_init(&_pkey);
|
||||
}
|
||||
|
||||
bool SocketMbedTLS::init(const std::string& host, std::string& errMsg)
|
||||
bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg)
|
||||
{
|
||||
initMBedTLS();
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
@@ -58,7 +60,7 @@ namespace ix
|
||||
}
|
||||
|
||||
if (mbedtls_ssl_config_defaults(&_conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
(isClient) ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT) != 0)
|
||||
{
|
||||
@@ -68,13 +70,32 @@ namespace ix
|
||||
|
||||
mbedtls_ssl_conf_rng(&_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
|
||||
|
||||
if (_tlsOptions.hasCertAndKey())
|
||||
{
|
||||
if (mbedtls_x509_crt_parse_file(&_cert, _tlsOptions.certFile.c_str()) < 0)
|
||||
{
|
||||
errMsg = "Cannot parse cert file '" + _tlsOptions.certFile + "'";
|
||||
return false;
|
||||
}
|
||||
if (mbedtls_pk_parse_keyfile(&_pkey, _tlsOptions.keyFile.c_str(), "") < 0)
|
||||
{
|
||||
errMsg = "Cannot parse key file '" + _tlsOptions.keyFile + "'";
|
||||
return false;
|
||||
}
|
||||
if (mbedtls_ssl_conf_own_cert(&_conf, &_cert, &_pkey) < 0)
|
||||
{
|
||||
errMsg = "Problem configuring cert '" + _tlsOptions.certFile + "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_tlsOptions.isPeerVerifyDisabled())
|
||||
{
|
||||
mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL);
|
||||
mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
|
||||
// FIXME: should we call mbedtls_ssl_conf_verify ?
|
||||
|
||||
@@ -87,7 +108,8 @@ namespace ix
|
||||
errMsg = "Cannot parse CA file '" + _tlsOptions.caFile + "'";
|
||||
return false;
|
||||
}
|
||||
mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL);
|
||||
}
|
||||
|
||||
if (mbedtls_ssl_setup(&_ssl, &_conf) != 0)
|
||||
@@ -96,7 +118,7 @@ namespace ix
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
|
||||
if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
|
||||
{
|
||||
errMsg = "SNI setup failed";
|
||||
return false;
|
||||
@@ -105,6 +127,50 @@ namespace ix
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketMbedTLS::accept(std::string& errMsg)
|
||||
{
|
||||
bool isClient = false;
|
||||
bool initialized = init(std::string(), isClient, errMsg);
|
||||
if (!initialized)
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&_ssl, &_sockfd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
int res;
|
||||
do
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
res = mbedtls_ssl_handshake(&_ssl);
|
||||
} while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
char buf[256];
|
||||
mbedtls_strerror(res, buf, sizeof(buf));
|
||||
|
||||
errMsg = "error in handshake : ";
|
||||
errMsg += buf;
|
||||
|
||||
if (res == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
|
||||
{
|
||||
char verifyBuf[512];
|
||||
uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
|
||||
|
||||
mbedtls_x509_crt_verify_info(verifyBuf, sizeof(verifyBuf), " ! ", flags);
|
||||
errMsg += " : ";
|
||||
errMsg += verifyBuf;
|
||||
}
|
||||
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketMbedTLS::connect(const std::string& host,
|
||||
int port,
|
||||
std::string& errMsg,
|
||||
@@ -116,7 +182,8 @@ namespace ix
|
||||
if (_sockfd == -1) return false;
|
||||
}
|
||||
|
||||
bool initialized = init(host, errMsg);
|
||||
bool isClient = true;
|
||||
bool initialized = init(host, isClient, errMsg);
|
||||
if (!initialized)
|
||||
{
|
||||
close();
|
||||
@@ -156,41 +223,30 @@ namespace ix
|
||||
mbedtls_ctr_drbg_free(&_ctr_drbg);
|
||||
mbedtls_entropy_free(&_entropy);
|
||||
mbedtls_x509_crt_free(&_cacert);
|
||||
mbedtls_x509_crt_free(&_cert);
|
||||
|
||||
Socket::close();
|
||||
}
|
||||
|
||||
ssize_t SocketMbedTLS::send(char* buf, size_t nbyte)
|
||||
{
|
||||
ssize_t sent = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
while (nbyte > 0)
|
||||
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
nbyte -= res;
|
||||
sent += res;
|
||||
}
|
||||
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t SocketMbedTLS::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
}
|
||||
|
||||
ssize_t SocketMbedTLS::recv(void* buf, size_t nbyte)
|
||||
|
@@ -26,6 +26,8 @@ namespace ix
|
||||
SocketMbedTLS(const SocketTLSOptions& tlsOptions, int fd = -1);
|
||||
~SocketMbedTLS();
|
||||
|
||||
virtual bool accept(std::string& errMsg) final;
|
||||
|
||||
virtual bool connect(const std::string& host,
|
||||
int port,
|
||||
std::string& errMsg,
|
||||
@@ -33,7 +35,6 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
@@ -42,11 +43,13 @@ namespace ix
|
||||
mbedtls_entropy_context _entropy;
|
||||
mbedtls_ctr_drbg_context _ctr_drbg;
|
||||
mbedtls_x509_crt _cacert;
|
||||
mbedtls_x509_crt _cert;
|
||||
mbedtls_pk_context _pkey;
|
||||
|
||||
std::mutex _mutex;
|
||||
SocketTLSOptions _tlsOptions;
|
||||
|
||||
bool init(const std::string& host, std::string& errMsg);
|
||||
bool init(const std::string& host, bool isClient, std::string& errMsg);
|
||||
void initMBedTLS();
|
||||
};
|
||||
|
||||
|
@@ -11,8 +11,14 @@
|
||||
#include "IXSocketConnect.h"
|
||||
#include <cassert>
|
||||
#include <errno.h>
|
||||
#ifdef _WIN32
|
||||
#include <Shlwapi.h>
|
||||
#else
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#include <openssl/x509v3.h>
|
||||
#endif
|
||||
#define socketerrno errno
|
||||
|
||||
namespace ix
|
||||
@@ -136,7 +142,11 @@ namespace ix
|
||||
*/
|
||||
bool SocketOpenSSL::checkHost(const std::string& host, const char* pattern)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return PathMatchSpecA(host.c_str(), pattern);
|
||||
#else
|
||||
return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl,
|
||||
@@ -593,42 +603,30 @@ namespace ix
|
||||
|
||||
ssize_t SocketOpenSSL::send(char* buf, size_t nbyte)
|
||||
{
|
||||
ssize_t sent = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
while (nbyte > 0)
|
||||
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
ssize_t write_result = SSL_write(_ssl_connection, buf + sent, (int) nbyte);
|
||||
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
||||
|
||||
if (reason == SSL_ERROR_NONE)
|
||||
{
|
||||
nbyte -= write_result;
|
||||
sent += write_result;
|
||||
}
|
||||
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t SocketOpenSSL::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
ERR_clear_error();
|
||||
ssize_t write_result = SSL_write(_ssl_connection, buf, (int) nbyte);
|
||||
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
||||
|
||||
if (reason == SSL_ERROR_NONE)
|
||||
{
|
||||
return write_result;
|
||||
}
|
||||
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t SocketOpenSSL::recv(void* buf, size_t nbyte)
|
||||
|
@@ -33,7 +33,6 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
|
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* IXSocketSChannel.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*
|
||||
* See https://docs.microsoft.com/en-us/windows/desktop/WinSock/using-secure-socket-extensions
|
||||
*
|
||||
* https://github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/netds/winsock/securesocket/stcpclient/tcpclient.c
|
||||
*
|
||||
* This is the right example to look at:
|
||||
* https://www.codeproject.com/Articles/1000189/A-Working-TCP-Client-and-Server-With-SSL
|
||||
*/
|
||||
#include "IXSocketSChannel.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#include <basetsd.h>
|
||||
#include <io.h>
|
||||
#include <schannel.h>
|
||||
#include <ws2def.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <mstcpip.h>
|
||||
#include <ntdsapi.h>
|
||||
#include <rpc.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define RECV_DATA_BUF_SIZE 256
|
||||
|
||||
// Link with ws2_32.lib
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
// link with fwpuclnt.lib for Winsock secure socket extensions
|
||||
#pragma comment(lib, "fwpuclnt.lib")
|
||||
|
||||
// link with ntdsapi.lib for DsMakeSpn function
|
||||
#pragma comment(lib, "ntdsapi.lib")
|
||||
|
||||
// The following function assumes that Winsock
|
||||
// has already been initialized
|
||||
|
||||
|
||||
#else
|
||||
#error("This file should only be built on Windows")
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
{
|
||||
SocketSChannel::SocketSChannel()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
SocketSChannel::~SocketSChannel()
|
||||
{
|
||||
}
|
||||
|
||||
bool SocketSChannel::connect(const std::string& host, int port, std::string& errMsg)
|
||||
{
|
||||
return Socket::connect(host, port, errMsg, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void SocketSChannel::secureSocket()
|
||||
{
|
||||
// there will be a lot to do here ...
|
||||
}
|
||||
|
||||
void SocketSChannel::close()
|
||||
{
|
||||
Socket::close();
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::send(char* buf, size_t nbyte)
|
||||
{
|
||||
return Socket::send(buf, nbyte);
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::send(const std::string& buffer)
|
||||
{
|
||||
return Socket::send(buffer);
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::recv(void* buf, size_t nbyte)
|
||||
{
|
||||
return Socket::recv(buf, nbyte);
|
||||
}
|
||||
|
||||
} // namespace ix
|
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* IXSocketSChannel.h
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IXSocket.h"
|
||||
|
||||
namespace ix
|
||||
{
|
||||
class SocketSChannel final : public Socket
|
||||
{
|
||||
public:
|
||||
SocketSChannel();
|
||||
~SocketSChannel();
|
||||
|
||||
virtual bool connect(const std::string& host, int port, std::string& errMsg) final;
|
||||
virtual void close() final;
|
||||
|
||||
// The important override
|
||||
virtual void secureSocket() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace ix
|
@@ -7,12 +7,13 @@
|
||||
#include "IXSocketServer.h"
|
||||
|
||||
#include "IXNetSystem.h"
|
||||
#include "IXSetThreadName.h"
|
||||
#include "IXSocket.h"
|
||||
#include "IXSocketConnect.h"
|
||||
#include "IXSocketFactory.h"
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace ix
|
||||
@@ -21,15 +22,15 @@ namespace ix
|
||||
const std::string SocketServer::kDefaultHost("127.0.0.1");
|
||||
const int SocketServer::kDefaultTcpBacklog(5);
|
||||
const size_t SocketServer::kDefaultMaxConnections(32);
|
||||
const int SocketServer::kDefaultAddressFamily(AF_INET);
|
||||
|
||||
SocketServer::SocketServer(int port,
|
||||
const std::string& host,
|
||||
int backlog,
|
||||
size_t maxConnections)
|
||||
SocketServer::SocketServer(
|
||||
int port, const std::string& host, int backlog, size_t maxConnections, int addressFamily)
|
||||
: _port(port)
|
||||
, _host(host)
|
||||
, _backlog(backlog)
|
||||
, _maxConnections(maxConnections)
|
||||
, _addressFamily(addressFamily)
|
||||
, _serverFd(-1)
|
||||
, _stop(false)
|
||||
, _stopGc(false)
|
||||
@@ -45,21 +46,26 @@ namespace ix
|
||||
void SocketServer::logError(const std::string& str)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_logMutex);
|
||||
std::cerr << str << std::endl;
|
||||
fprintf(stderr, "%s\n", str.c_str());
|
||||
}
|
||||
|
||||
void SocketServer::logInfo(const std::string& str)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_logMutex);
|
||||
std::cout << str << std::endl;
|
||||
fprintf(stdout, "%s\n", str.c_str());
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> SocketServer::listen()
|
||||
{
|
||||
struct sockaddr_in server; // server address information
|
||||
if (_addressFamily != AF_INET && _addressFamily != AF_INET6)
|
||||
{
|
||||
std::string errMsg("SocketServer::listen() AF_INET and AF_INET6 are currently "
|
||||
"the only supported address families");
|
||||
return std::make_pair(false, errMsg);
|
||||
}
|
||||
|
||||
// Get a socket for accepting connections.
|
||||
if ((_serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
if ((_serverFd = socket(_addressFamily, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error creating socket): " << strerror(Socket::getErrno());
|
||||
@@ -79,27 +85,63 @@ namespace ix
|
||||
return std::make_pair(false, ss.str());
|
||||
}
|
||||
|
||||
// Bind the socket to the server address.
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons(_port);
|
||||
|
||||
// Using INADDR_ANY trigger a pop-up box as binding to any address is detected
|
||||
// by the osx firewall. We need to codesign the binary with a self-signed cert
|
||||
// to allow that, but this is a bit of a pain. (this is what node or python would do).
|
||||
//
|
||||
// Using INADDR_LOOPBACK also does not work ... while it should.
|
||||
// We default to 127.0.0.1 (localhost)
|
||||
//
|
||||
server.sin_addr.s_addr = inet_addr(_host.c_str());
|
||||
|
||||
if (bind(_serverFd, (struct sockaddr*) &server, sizeof(server)) < 0)
|
||||
if (_addressFamily == AF_INET)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error calling bind "
|
||||
<< "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
|
||||
struct sockaddr_in server;
|
||||
server.sin_family = _addressFamily;
|
||||
server.sin_port = htons(_port);
|
||||
|
||||
Socket::closeSocket(_serverFd);
|
||||
return std::make_pair(false, ss.str());
|
||||
if (inet_pton(_addressFamily, _host.c_str(), &server.sin_addr.s_addr) <= 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error calling inet_pton "
|
||||
<< "at address " << _host << ":" << _port << " : "
|
||||
<< strerror(Socket::getErrno());
|
||||
|
||||
Socket::closeSocket(_serverFd);
|
||||
return std::make_pair(false, ss.str());
|
||||
}
|
||||
|
||||
// Bind the socket to the server address.
|
||||
if (bind(_serverFd, (struct sockaddr*) &server, sizeof(server)) < 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error calling bind "
|
||||
<< "at address " << _host << ":" << _port << " : "
|
||||
<< strerror(Socket::getErrno());
|
||||
|
||||
Socket::closeSocket(_serverFd);
|
||||
return std::make_pair(false, ss.str());
|
||||
}
|
||||
}
|
||||
else // AF_INET6
|
||||
{
|
||||
struct sockaddr_in6 server;
|
||||
server.sin6_family = _addressFamily;
|
||||
server.sin6_port = htons(_port);
|
||||
|
||||
if (inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error calling inet_pton "
|
||||
<< "at address " << _host << ":" << _port << " : "
|
||||
<< strerror(Socket::getErrno());
|
||||
|
||||
Socket::closeSocket(_serverFd);
|
||||
return std::make_pair(false, ss.str());
|
||||
}
|
||||
|
||||
// Bind the socket to the server address.
|
||||
if (bind(_serverFd, (struct sockaddr*) &server, sizeof(server)) < 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SocketServer::listen() error calling bind "
|
||||
<< "at address " << _host << ":" << _port << " : "
|
||||
<< strerror(Socket::getErrno());
|
||||
|
||||
Socket::closeSocket(_serverFd);
|
||||
return std::make_pair(false, ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -206,6 +248,8 @@ namespace ix
|
||||
// Set the socket to non blocking mode, so that accept calls are not blocking
|
||||
SocketConnect::configure(_serverFd);
|
||||
|
||||
setThreadName("SocketServer::listen");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_stop) return;
|
||||
@@ -306,6 +350,8 @@ namespace ix
|
||||
|
||||
void SocketServer::runGC()
|
||||
{
|
||||
setThreadName("SocketServer::GC");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Garbage collection to shutdown/join threads for closed connections.
|
||||
|
@@ -36,7 +36,8 @@ namespace ix
|
||||
SocketServer(int port = SocketServer::kDefaultPort,
|
||||
const std::string& host = SocketServer::kDefaultHost,
|
||||
int backlog = SocketServer::kDefaultTcpBacklog,
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections);
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections,
|
||||
int addressFamily = SocketServer::kDefaultAddressFamily);
|
||||
virtual ~SocketServer();
|
||||
virtual void stop();
|
||||
|
||||
@@ -49,6 +50,7 @@ namespace ix
|
||||
const static std::string kDefaultHost;
|
||||
const static int kDefaultTcpBacklog;
|
||||
const static size_t kDefaultMaxConnections;
|
||||
const static int kDefaultAddressFamily;
|
||||
|
||||
void start();
|
||||
std::pair<bool, std::string> listen();
|
||||
@@ -69,6 +71,7 @@ namespace ix
|
||||
std::string _host;
|
||||
int _backlog;
|
||||
size_t _maxConnections;
|
||||
int _addressFamily;
|
||||
|
||||
// socket for accepting connections
|
||||
int _serverFd;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@@ -71,4 +72,16 @@ namespace ix
|
||||
{
|
||||
return _errMsg;
|
||||
}
|
||||
|
||||
std::string SocketTLSOptions::getDescription() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "TLS Options:" << std::endl;
|
||||
ss << " certFile = " << certFile << std::endl;
|
||||
ss << " keyFile = " << keyFile << std::endl;
|
||||
ss << " caFile = " << caFile << std::endl;
|
||||
ss << " ciphers = " << ciphers << std::endl;
|
||||
ss << " ciphers = " << ciphers << std::endl;
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace ix
|
||||
|
@@ -43,8 +43,10 @@ namespace ix
|
||||
|
||||
const std::string& getErrorMsg() const;
|
||||
|
||||
std::string getDescription() const;
|
||||
|
||||
private:
|
||||
mutable std::string _errMsg;
|
||||
mutable bool _validated;
|
||||
mutable bool _validated = false;
|
||||
};
|
||||
} // namespace ix
|
||||
|
@@ -134,6 +134,13 @@ namespace ix
|
||||
_enablePong = false;
|
||||
}
|
||||
|
||||
void WebSocket::enablePerMessageDeflate()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_configMutex);
|
||||
WebSocketPerMessageDeflateOptions perMessageDeflateOptions(true);
|
||||
_perMessageDeflateOptions = perMessageDeflateOptions;
|
||||
}
|
||||
|
||||
void WebSocket::disablePerMessageDeflate()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_configMutex);
|
||||
@@ -169,6 +176,7 @@ namespace ix
|
||||
// wait until working thread will exit
|
||||
// it will exit after close operation is finished
|
||||
_stop = true;
|
||||
_sleepCondition.notify_one();
|
||||
_thread.join();
|
||||
_stop = false;
|
||||
}
|
||||
@@ -190,9 +198,19 @@ namespace ix
|
||||
auto subProtocols = getSubProtocols();
|
||||
if (!subProtocols.empty())
|
||||
{
|
||||
//
|
||||
// Sub Protocol strings are comma separated.
|
||||
// Python code to do that is:
|
||||
// >>> ','.join(['json', 'msgpack'])
|
||||
// 'json,msgpack'
|
||||
//
|
||||
int i = 0;
|
||||
for (auto subProtocol : subProtocols)
|
||||
{
|
||||
subProtocolsHeader += ",";
|
||||
if (i++ != 0)
|
||||
{
|
||||
subProtocolsHeader += ",";
|
||||
}
|
||||
subProtocolsHeader += subProtocol;
|
||||
}
|
||||
headers["Sec-WebSocket-Protocol"] = subProtocolsHeader;
|
||||
@@ -282,8 +300,13 @@ namespace ix
|
||||
// Only sleep if we are retrying
|
||||
if (duration.count() > 0)
|
||||
{
|
||||
// to do: make sleeping conditional
|
||||
std::this_thread::sleep_for(duration);
|
||||
std::unique_lock<std::mutex> lock(_sleepMutex);
|
||||
_sleepCondition.wait_for(lock, duration);
|
||||
}
|
||||
|
||||
if (_stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Try to connect synchronously
|
||||
@@ -389,7 +412,7 @@ namespace ix
|
||||
WebSocketCloseInfo(),
|
||||
binary));
|
||||
|
||||
WebSocket::invokeTrafficTrackerCallback(msg.size(), true);
|
||||
WebSocket::invokeTrafficTrackerCallback(wireSize, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "IXWebSocketSendInfo.h"
|
||||
#include "IXWebSocketTransport.h"
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -56,6 +57,7 @@ namespace ix
|
||||
void setPingTimeout(int pingTimeoutSecs);
|
||||
void enablePong();
|
||||
void disablePong();
|
||||
void enablePerMessageDeflate();
|
||||
void disablePerMessageDeflate();
|
||||
void addSubProtocol(const std::string& subProtocol);
|
||||
|
||||
@@ -70,7 +72,7 @@ namespace ix
|
||||
WebSocketInitResult connect(int timeoutSecs);
|
||||
void run();
|
||||
|
||||
// send is in binary mode by default
|
||||
// send is in text mode by default
|
||||
WebSocketSendInfo send(const std::string& data,
|
||||
bool binary = false,
|
||||
const OnProgressCallback& onProgressCallback = nullptr);
|
||||
@@ -140,6 +142,10 @@ namespace ix
|
||||
static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries;
|
||||
uint32_t _maxWaitBetweenReconnectionRetries;
|
||||
|
||||
// Make the sleeping in the automatic reconnection cancellable
|
||||
std::mutex _sleepMutex;
|
||||
std::condition_variable _sleepCondition;
|
||||
|
||||
std::atomic<int> _handshakeTimeoutSecs;
|
||||
static const int kDefaultHandShakeTimeoutSecs;
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "IXUserAgent.h"
|
||||
#include "libwshandshake.hpp"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
@@ -178,8 +179,8 @@ namespace ix
|
||||
if (status != 101)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Got bad status connecting to " << host << ":" << port << ", status: " << status
|
||||
<< ", HTTP Status line: " << line;
|
||||
ss << "Expecting status 101 (Switching Protocol), got " << status
|
||||
<< " status connecting to " << host << ":" << port << ", HTTP Status line: " << line;
|
||||
return WebSocketInitResult(false, status, ss.str());
|
||||
}
|
||||
|
||||
@@ -335,7 +336,7 @@ namespace ix
|
||||
std::string header = headers["sec-websocket-extensions"];
|
||||
WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(header);
|
||||
|
||||
// If the client has requested that extension, enable it.
|
||||
// If the client has requested that extension,
|
||||
if (webSocketPerMessageDeflateOptions.enabled())
|
||||
{
|
||||
_enablePerMessageDeflate = true;
|
||||
|
@@ -66,12 +66,23 @@ namespace ix
|
||||
{
|
||||
line[i] = '\0';
|
||||
std::string lineStr(line);
|
||||
// colon is ':', colon+1 is ' ', colon+2 is the start of the value.
|
||||
// colon is ':', usually colon+1 is ' ', and colon+2 is the start of the value.
|
||||
// some webservers do not put a space after the colon character, so
|
||||
// the start of the value might be farther than colon+2.
|
||||
// The spec says that space after the : should be discarded.
|
||||
// i is end of string (\0), i-colon is length of string minus key;
|
||||
// subtract 1 for '\0', 1 for '\n', 1 for '\r',
|
||||
// 1 for the ' ' after the ':', and total is -4
|
||||
// since we use an std::string later on and don't account for '\0',
|
||||
// plus the optional first space, total is -2
|
||||
int start = colon + 1;
|
||||
while (lineStr[start] == ' ')
|
||||
{
|
||||
start++;
|
||||
}
|
||||
|
||||
std::string name(lineStr.substr(0, colon));
|
||||
std::string value(lineStr.substr(colon + 2, i - colon - 4));
|
||||
std::string value(lineStr.substr(start, lineStr.size() - start - 2));
|
||||
|
||||
headers[name] = value;
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "IXWebSocketServer.h"
|
||||
|
||||
#include "IXNetSystem.h"
|
||||
#include "IXSetThreadName.h"
|
||||
#include "IXSocketConnect.h"
|
||||
#include "IXWebSocket.h"
|
||||
#include "IXWebSocketTransport.h"
|
||||
@@ -23,10 +24,12 @@ namespace ix
|
||||
const std::string& host,
|
||||
int backlog,
|
||||
size_t maxConnections,
|
||||
int handshakeTimeoutSecs)
|
||||
: SocketServer(port, host, backlog, maxConnections)
|
||||
int handshakeTimeoutSecs,
|
||||
int addressFamily)
|
||||
: SocketServer(port, host, backlog, maxConnections, addressFamily)
|
||||
, _handshakeTimeoutSecs(handshakeTimeoutSecs)
|
||||
, _enablePong(kDefaultEnablePong)
|
||||
, _enablePerMessageDeflate(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -58,6 +61,11 @@ namespace ix
|
||||
_enablePong = false;
|
||||
}
|
||||
|
||||
void WebSocketServer::disablePerMessageDeflate()
|
||||
{
|
||||
_enablePerMessageDeflate = false;
|
||||
}
|
||||
|
||||
void WebSocketServer::setOnConnectionCallback(const OnConnectionCallback& callback)
|
||||
{
|
||||
_onConnectionCallback = callback;
|
||||
@@ -66,15 +74,21 @@ namespace ix
|
||||
void WebSocketServer::handleConnection(std::shared_ptr<Socket> socket,
|
||||
std::shared_ptr<ConnectionState> connectionState)
|
||||
{
|
||||
setThreadName("WebSocketServer::" + connectionState->getId());
|
||||
|
||||
auto webSocket = std::make_shared<WebSocket>();
|
||||
_onConnectionCallback(webSocket, connectionState);
|
||||
|
||||
webSocket->disableAutomaticReconnection();
|
||||
|
||||
if (_enablePong)
|
||||
{
|
||||
webSocket->enablePong();
|
||||
}
|
||||
else
|
||||
{
|
||||
webSocket->disablePong();
|
||||
}
|
||||
|
||||
// Add this client to our client set
|
||||
{
|
||||
@@ -106,7 +120,6 @@ namespace ix
|
||||
}
|
||||
}
|
||||
|
||||
logInfo("WebSocketServer::handleConnection() done");
|
||||
connectionState->setTerminated();
|
||||
}
|
||||
|
||||
|
@@ -29,29 +29,33 @@ namespace ix
|
||||
const std::string& host = SocketServer::kDefaultHost,
|
||||
int backlog = SocketServer::kDefaultTcpBacklog,
|
||||
size_t maxConnections = SocketServer::kDefaultMaxConnections,
|
||||
int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs);
|
||||
int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs,
|
||||
int addressFamily = SocketServer::kDefaultAddressFamily);
|
||||
virtual ~WebSocketServer();
|
||||
virtual void stop() final;
|
||||
|
||||
void enablePong();
|
||||
void disablePong();
|
||||
void disablePerMessageDeflate();
|
||||
|
||||
void setOnConnectionCallback(const OnConnectionCallback& callback);
|
||||
|
||||
// Get all the connected clients
|
||||
std::set<std::shared_ptr<WebSocket>> getClients();
|
||||
|
||||
const static int kDefaultHandShakeTimeoutSecs;
|
||||
|
||||
private:
|
||||
// Member variables
|
||||
int _handshakeTimeoutSecs;
|
||||
bool _enablePong;
|
||||
bool _enablePerMessageDeflate;
|
||||
|
||||
OnConnectionCallback _onConnectionCallback;
|
||||
|
||||
std::mutex _clientsMutex;
|
||||
std::set<std::shared_ptr<WebSocket>> _clients;
|
||||
|
||||
const static int kDefaultHandShakeTimeoutSecs;
|
||||
const static bool kDefaultEnablePong;
|
||||
|
||||
// Methods
|
||||
|
@@ -77,6 +77,7 @@ namespace ix
|
||||
|
||||
WebSocketTransport::WebSocketTransport()
|
||||
: _useMask(true)
|
||||
, _blockingSend(false)
|
||||
, _compressedMessage(false)
|
||||
, _readyState(ReadyState::CLOSED)
|
||||
, _closeCode(WebSocketCloseConstants::kInternalErrorCode)
|
||||
@@ -143,7 +144,9 @@ namespace ix
|
||||
|
||||
if (!UrlParser::parse(url, protocol, host, path, query, port))
|
||||
{
|
||||
return WebSocketInitResult(false, 0, std::string("Could not parse URL ") + url);
|
||||
std::stringstream ss;
|
||||
ss << "Could not parse url: '" << url << "'";
|
||||
return WebSocketInitResult(false, 0, ss.str());
|
||||
}
|
||||
|
||||
std::string errorMsg;
|
||||
@@ -178,6 +181,7 @@ namespace ix
|
||||
|
||||
// Server should not mask the data it sends to the client
|
||||
_useMask = false;
|
||||
_blockingSend = true;
|
||||
|
||||
_socket = socket;
|
||||
|
||||
@@ -339,48 +343,16 @@ namespace ix
|
||||
// there can be a lot of it for large messages.
|
||||
if (pollResult == PollResultType::SendRequest)
|
||||
{
|
||||
while (!isSendBufferEmpty() && !_requestInitCancellation)
|
||||
if (!flushSendBuffer())
|
||||
{
|
||||
// Wait with a 10ms timeout until the socket is ready to write.
|
||||
// This way we are not busy looping
|
||||
PollResultType result = _socket->isReadyToWrite(10);
|
||||
|
||||
if (result == PollResultType::Error)
|
||||
{
|
||||
closeSocket();
|
||||
setReadyState(ReadyState::CLOSED);
|
||||
break;
|
||||
}
|
||||
else if (result == PollResultType::ReadyForWrite)
|
||||
{
|
||||
sendOnSocket();
|
||||
}
|
||||
return PollResult::CannotFlushSendBuffer;
|
||||
}
|
||||
}
|
||||
else if (pollResult == PollResultType::ReadyForRead)
|
||||
{
|
||||
while (true)
|
||||
if (!receiveFromSocket())
|
||||
{
|
||||
ssize_t ret = _socket->recv((char*) &_readbuf[0], _readbuf.size());
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ret <= 0)
|
||||
{
|
||||
// if there are received data pending to be processed, then delay the abnormal
|
||||
// closure to after dispatch (other close code/reason could be read from the
|
||||
// buffer)
|
||||
|
||||
closeSocket();
|
||||
|
||||
return PollResult::AbnormalClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rxbuf.insert(_rxbuf.end(), _readbuf.begin(), _readbuf.begin() + ret);
|
||||
}
|
||||
return PollResult::AbnormalClose;
|
||||
}
|
||||
}
|
||||
else if (pollResult == PollResultType::Error)
|
||||
@@ -543,7 +515,7 @@ namespace ix
|
||||
}
|
||||
|
||||
// Prevent integer overflow in the next conditional
|
||||
const uint64_t maxFrameSize(1 << 63);
|
||||
const uint64_t maxFrameSize(1ULL << 63);
|
||||
if (ws.N > maxFrameSize)
|
||||
{
|
||||
return;
|
||||
@@ -748,7 +720,7 @@ namespace ix
|
||||
|
||||
// if an abnormal closure was raised in poll, and nothing else triggered a CLOSED state in
|
||||
// the received and processed data then close the connection
|
||||
if (pollResult == PollResult::AbnormalClose)
|
||||
if (pollResult != PollResult::Succeeded)
|
||||
{
|
||||
_rxbuf.clear();
|
||||
|
||||
@@ -874,10 +846,12 @@ namespace ix
|
||||
_txbuf.reserve(wireSize);
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Common case for most message. No fragmentation required.
|
||||
if (wireSize < kChunkSize)
|
||||
{
|
||||
sendFragment(type, true, message_begin, message_end, compress);
|
||||
success = sendFragment(type, true, message_begin, message_end, compress);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -913,7 +887,10 @@ namespace ix
|
||||
}
|
||||
|
||||
// Send message
|
||||
sendFragment(opcodeType, fin, begin, end, compress);
|
||||
if (!sendFragment(opcodeType, fin, begin, end, compress))
|
||||
{
|
||||
return WebSocketSendInfo(false);
|
||||
}
|
||||
|
||||
if (onProgressCallback && !onProgressCallback((int) i, (int) steps))
|
||||
{
|
||||
@@ -928,12 +905,18 @@ namespace ix
|
||||
if (!isSendBufferEmpty())
|
||||
{
|
||||
_socket->wakeUpFromPoll(Socket::kSendRequest);
|
||||
|
||||
// FIXME: we should have a timeout when sending large messages: see #131
|
||||
if (_blockingSend && !flushSendBuffer())
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return WebSocketSendInfo(true, compressionError, payloadSize, wireSize);
|
||||
return WebSocketSendInfo(success, compressionError, payloadSize, wireSize);
|
||||
}
|
||||
|
||||
void WebSocketTransport::sendFragment(wsheader_type::opcode_type type,
|
||||
bool WebSocketTransport::sendFragment(wsheader_type::opcode_type type,
|
||||
bool fin,
|
||||
std::string::const_iterator message_begin,
|
||||
std::string::const_iterator message_end,
|
||||
@@ -1018,7 +1001,7 @@ namespace ix
|
||||
appendToSendBuffer(header, message_begin, message_end, message_size, masking_key);
|
||||
|
||||
// Now actually send this data
|
||||
sendOnSocket();
|
||||
return sendOnSocket();
|
||||
}
|
||||
|
||||
WebSocketSendInfo WebSocketTransport::sendPing(const std::string& message)
|
||||
@@ -1051,19 +1034,17 @@ namespace ix
|
||||
wsheader_type::TEXT_FRAME, message, _enablePerMessageDeflate, onProgressCallback);
|
||||
}
|
||||
|
||||
ssize_t WebSocketTransport::send()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||
return _socket->send((char*) &_txbuf[0], _txbuf.size());
|
||||
}
|
||||
|
||||
void WebSocketTransport::sendOnSocket()
|
||||
bool WebSocketTransport::sendOnSocket()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_txbufMutex);
|
||||
|
||||
while (_txbuf.size())
|
||||
{
|
||||
ssize_t ret = send();
|
||||
ssize_t ret = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||
ret = _socket->send((char*) &_txbuf[0], _txbuf.size());
|
||||
}
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
@@ -1073,13 +1054,43 @@ namespace ix
|
||||
{
|
||||
closeSocket();
|
||||
setReadyState(ReadyState::CLOSED);
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_txbuf.erase(_txbuf.begin(), _txbuf.begin() + ret);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketTransport::receiveFromSocket()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ssize_t ret = _socket->recv((char*) &_readbuf[0], _readbuf.size());
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ret <= 0)
|
||||
{
|
||||
// if there are received data pending to be processed, then delay the abnormal
|
||||
// closure to after dispatch (other close code/reason could be read from the
|
||||
// buffer)
|
||||
|
||||
closeSocket();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rxbuf.insert(_rxbuf.end(), _readbuf.begin(), _readbuf.begin() + ret);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketTransport::sendCloseFrame(uint16_t code, const std::string& reason)
|
||||
@@ -1168,4 +1179,30 @@ namespace ix
|
||||
return _txbuf.size();
|
||||
}
|
||||
|
||||
bool WebSocketTransport::flushSendBuffer()
|
||||
{
|
||||
while (!isSendBufferEmpty() && !_requestInitCancellation)
|
||||
{
|
||||
// Wait with a 10ms timeout until the socket is ready to write.
|
||||
// This way we are not busy looping
|
||||
PollResultType result = _socket->isReadyToWrite(10);
|
||||
|
||||
if (result == PollResultType::Error)
|
||||
{
|
||||
closeSocket();
|
||||
setReadyState(ReadyState::CLOSED);
|
||||
return false;
|
||||
}
|
||||
else if (result == PollResultType::ReadyForWrite)
|
||||
{
|
||||
if (!sendOnSocket())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ix
|
||||
|
@@ -61,7 +61,8 @@ namespace ix
|
||||
enum class PollResult
|
||||
{
|
||||
Succeeded,
|
||||
AbnormalClose
|
||||
AbnormalClose,
|
||||
CannotFlushSendBuffer
|
||||
};
|
||||
|
||||
using OnMessageCallback =
|
||||
@@ -98,7 +99,6 @@ namespace ix
|
||||
bool remote = false);
|
||||
|
||||
void closeSocket();
|
||||
ssize_t send();
|
||||
|
||||
ReadyState getReadyState() const;
|
||||
void setReadyState(ReadyState readyState);
|
||||
@@ -135,6 +135,10 @@ namespace ix
|
||||
// client should mask but server should not
|
||||
std::atomic<bool> _useMask;
|
||||
|
||||
// Tells whether we should flush the send buffer before
|
||||
// saying that a send is complete. This is the mode for server code.
|
||||
std::atomic<bool> _blockingSend;
|
||||
|
||||
// Buffer for reading from our socket. That buffer is never resized.
|
||||
std::vector<uint8_t> _readbuf;
|
||||
|
||||
@@ -238,13 +242,16 @@ namespace ix
|
||||
size_t closeWireSize,
|
||||
bool remote);
|
||||
|
||||
void sendOnSocket();
|
||||
bool flushSendBuffer();
|
||||
bool sendOnSocket();
|
||||
bool receiveFromSocket();
|
||||
|
||||
WebSocketSendInfo sendData(wsheader_type::opcode_type type,
|
||||
const std::string& message,
|
||||
bool compress,
|
||||
const OnProgressCallback& onProgressCallback = nullptr);
|
||||
|
||||
void sendFragment(wsheader_type::opcode_type type,
|
||||
bool sendFragment(wsheader_type::opcode_type type,
|
||||
bool fin,
|
||||
std::string::const_iterator begin,
|
||||
std::string::const_iterator end,
|
||||
|
@@ -6,4 +6,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IX_WEBSOCKET_VERSION "7.1.0"
|
||||
#define IX_WEBSOCKET_VERSION "8.1.7"
|
||||
|
13
makefile
13
makefile
@@ -30,7 +30,7 @@ uninstall:
|
||||
xargs rm -fv < build/install_manifest.txt
|
||||
|
||||
tag:
|
||||
git tag v"`cat DOCKER_VERSION`"
|
||||
git tag v"`sh tools/extract_version.sh`"
|
||||
|
||||
xcode:
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 -GXcode && open ixwebsocket.xcodeproj
|
||||
@@ -40,12 +40,18 @@ xcode_openssl:
|
||||
|
||||
.PHONY: docker
|
||||
|
||||
NAME := bsergean/ws
|
||||
TAG := $(shell cat DOCKER_VERSION)
|
||||
NAME := ${DOCKER_REPO}/ws
|
||||
TAG := $(shell sh tools/extract_version.sh)
|
||||
IMG := ${NAME}:${TAG}
|
||||
LATEST := ${NAME}:latest
|
||||
BUILD := ${NAME}:build
|
||||
|
||||
print_version:
|
||||
@echo 'IXWebSocket version =>' ${TAG}
|
||||
|
||||
set_version:
|
||||
sh tools/update_version.sh ${VERSION}
|
||||
|
||||
docker_test:
|
||||
docker build -f docker/Dockerfile.debian -t bsergean/ixwebsocket_test:build .
|
||||
|
||||
@@ -57,6 +63,7 @@ docker:
|
||||
docker_push:
|
||||
docker tag ${IMG} ${LATEST}
|
||||
docker push ${LATEST}
|
||||
docker push ${IMG}
|
||||
|
||||
run:
|
||||
docker run --cap-add sys_ptrace --entrypoint=sh -it bsergean/ws:build
|
||||
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ALL_BUILD
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD:
|
||||
echo ""
|
||||
echo Build\ all\ projects
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ALL_BUILD
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD:
|
||||
echo ""
|
||||
echo Build\ all\ projects
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ALL_BUILD
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD:
|
||||
echo ""
|
||||
echo Build\ all\ projects
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ALL_BUILD
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ALL_BUILD:
|
||||
echo ""
|
||||
echo Build\ all\ projects
|
18
sentry-native/CMakeScripts/ReRunCMake.make
Normal file
18
sentry-native/CMakeScripts/ReRunCMake.make
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
|
||||
TARGETS:=
|
||||
empty:=
|
||||
space:= $(empty) $(empty)
|
||||
spaceplus:= $(empty)\ $(empty)
|
||||
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Applications/CMake.app/Contents/share/cmake-3.12/Modules/CMakeASMInformation.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Applications/CMake.app/Contents/share/cmake-3.12/Modules/Compiler/AppleClang-ASM.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Applications/CMake.app/Contents/share/cmake-3.12/Modules/Compiler/Clang-ASM.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Applications/CMake.app/Contents/share/cmake-3.12/Modules/Compiler/Clang.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Applications/CMake.app/Contents/share/cmake-3.12/Modules/Platform/Apple-clang.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Users/bsergeant/src/foss/IXWebSocket/CMakeFiles/3.12.3/CMakeASMCompiler.cmake))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Users/bsergeant/src/foss/IXWebSocket/third_party/sentry-native/CMakeLists.txt))
|
||||
TARGETS += $(subst $(space),$(spaceplus),$(wildcard /Users/bsergeant/src/foss/IXWebSocket/third_party/sentry-native/src/CMakeLists.txt))
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/CMakeFiles/cmake.check_cache: $(TARGETS)
|
||||
/Applications/CMake.app/Contents/bin/cmake -H/Users/bsergeant/src/foss/IXWebSocket -B/Users/bsergeant/src/foss/IXWebSocket
|
139
sentry-native/CMakeScripts/XCODE_DEPEND_HELPER.make
Normal file
139
sentry-native/CMakeScripts/XCODE_DEPEND_HELPER.make
Normal file
@@ -0,0 +1,139 @@
|
||||
# DO NOT EDIT
|
||||
# This makefile makes sure all linkable targets are
|
||||
# up-to-date with anything they link to
|
||||
default:
|
||||
echo "Do not invoke directly"
|
||||
|
||||
# Rules to remove targets that are older than anything to which they
|
||||
# link. This forces Xcode to relink the targets from scratch. It
|
||||
# does not seem to check these dependencies itself.
|
||||
PostBuild.example.Debug:
|
||||
PostBuild.sentry.Debug: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/example:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example
|
||||
|
||||
|
||||
PostBuild.example_crashpad.Debug:
|
||||
PostBuild.sentry.Debug: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad
|
||||
|
||||
|
||||
PostBuild.sentry.Debug:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
|
||||
|
||||
PostBuild.sentry_test_integration.Debug:
|
||||
PostBuild.sentry.Debug: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration
|
||||
|
||||
|
||||
PostBuild.sentry_test_unit.Debug:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_unit:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_unit
|
||||
|
||||
|
||||
PostBuild.example.Release:
|
||||
PostBuild.sentry.Release: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/example:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example
|
||||
|
||||
|
||||
PostBuild.example_crashpad.Release:
|
||||
PostBuild.sentry.Release: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/example_crashpad
|
||||
|
||||
|
||||
PostBuild.sentry.Release:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
|
||||
|
||||
PostBuild.sentry_test_integration.Release:
|
||||
PostBuild.sentry.Release: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_integration
|
||||
|
||||
|
||||
PostBuild.sentry_test_unit.Release:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_unit:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/sentry_test_unit
|
||||
|
||||
|
||||
PostBuild.example.MinSizeRel:
|
||||
PostBuild.sentry.MinSizeRel: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example
|
||||
|
||||
|
||||
PostBuild.example_crashpad.MinSizeRel:
|
||||
PostBuild.sentry.MinSizeRel: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example_crashpad
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example_crashpad:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/example_crashpad
|
||||
|
||||
|
||||
PostBuild.sentry.MinSizeRel:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a
|
||||
|
||||
|
||||
PostBuild.sentry_test_integration.MinSizeRel:
|
||||
PostBuild.sentry.MinSizeRel: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/sentry_test_integration
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/sentry_test_integration:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/sentry_test_integration
|
||||
|
||||
|
||||
PostBuild.sentry_test_unit.MinSizeRel:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/sentry_test_unit:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/sentry_test_unit
|
||||
|
||||
|
||||
PostBuild.example.RelWithDebInfo:
|
||||
PostBuild.sentry.RelWithDebInfo: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example
|
||||
|
||||
|
||||
PostBuild.example_crashpad.RelWithDebInfo:
|
||||
PostBuild.sentry.RelWithDebInfo: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example_crashpad
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example_crashpad:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/example_crashpad
|
||||
|
||||
|
||||
PostBuild.sentry.RelWithDebInfo:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a
|
||||
|
||||
|
||||
PostBuild.sentry_test_integration.RelWithDebInfo:
|
||||
PostBuild.sentry.RelWithDebInfo: /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/sentry_test_integration
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/sentry_test_integration:\
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/sentry_test_integration
|
||||
|
||||
|
||||
PostBuild.sentry_test_unit.RelWithDebInfo:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/sentry_test_unit:
|
||||
/bin/rm -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/sentry_test_unit
|
||||
|
||||
|
||||
|
||||
|
||||
# For each target create a dummy ruleso the target does not have to exist
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a:
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a:
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ZERO_CHECK
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK:
|
||||
echo ""
|
||||
make -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeScripts/ReRunCMake.make
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ZERO_CHECK
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK:
|
||||
echo ""
|
||||
make -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeScripts/ReRunCMake.make
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ZERO_CHECK
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK:
|
||||
echo ""
|
||||
make -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeScripts/ReRunCMake.make
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for ZERO_CHECK
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK
|
||||
|
||||
|
||||
/Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeFiles/ZERO_CHECK:
|
||||
echo ""
|
||||
make -f /Users/bsergeant/src/foss/IXWebSocket/sentry-native/CMakeScripts/ReRunCMake.make
|
@@ -0,0 +1,9 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for install
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
install_buildpart_0
|
||||
|
||||
|
||||
install_buildpart_0:
|
||||
/Applications/CMake.app/Contents/bin/cmake -DBUILD_TYPE=$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -P cmake_install.cmake
|
@@ -0,0 +1,9 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for install
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
install_buildpart_0
|
||||
|
||||
|
||||
install_buildpart_0:
|
||||
/Applications/CMake.app/Contents/bin/cmake -DBUILD_TYPE=$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -P cmake_install.cmake
|
@@ -0,0 +1,9 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for install
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
install_buildpart_0
|
||||
|
||||
|
||||
install_buildpart_0:
|
||||
/Applications/CMake.app/Contents/bin/cmake -DBUILD_TYPE=$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -P cmake_install.cmake
|
@@ -0,0 +1,9 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for install
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
install_buildpart_0
|
||||
|
||||
|
||||
install_buildpart_0:
|
||||
/Applications/CMake.app/Contents/bin/cmake -DBUILD_TYPE=$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) -P cmake_install.cmake
|
10
sentry-native/CMakeScripts/sentry_postBuildPhase.makeDebug
Normal file
10
sentry-native/CMakeScripts/sentry_postBuildPhase.makeDebug
Normal file
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for sentry
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
sentry_buildpart_0
|
||||
|
||||
|
||||
sentry_buildpart_0:
|
||||
echo "Creating symlinks"
|
||||
/Applications/CMake.app/Contents/bin/cmake -E cmake_symlink_library /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for sentry
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
sentry_buildpart_0
|
||||
|
||||
|
||||
sentry_buildpart_0:
|
||||
echo "Creating symlinks"
|
||||
/Applications/CMake.app/Contents/bin/cmake -E cmake_symlink_library /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.dylib
|
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for sentry
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
sentry_buildpart_0
|
||||
|
||||
|
||||
sentry_buildpart_0:
|
||||
echo "Creating symlinks"
|
||||
/Applications/CMake.app/Contents/bin/cmake -E cmake_symlink_library /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.dylib
|
10
sentry-native/CMakeScripts/sentry_postBuildPhase.makeRelease
Normal file
10
sentry-native/CMakeScripts/sentry_postBuildPhase.makeRelease
Normal file
@@ -0,0 +1,10 @@
|
||||
# Generated by CMake, DO NOT EDIT
|
||||
# Custom rules for sentry
|
||||
.SUFFIXES:
|
||||
all: \
|
||||
sentry_buildpart_0
|
||||
|
||||
|
||||
sentry_buildpart_0:
|
||||
echo "Creating symlinks"
|
||||
/Applications/CMake.app/Contents/bin/cmake -E cmake_symlink_library /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib /Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.dylib
|
1944
sentry-native/Sentry-Native.xcodeproj/project.pbxproj
Normal file
1944
sentry-native/Sentry-Native.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildSystemType</key>
|
||||
<string>Original</string>
|
||||
</dict>
|
||||
</plist>
|
84
sentry-native/cmake_install.cmake
Normal file
84
sentry-native/cmake_install.cmake
Normal file
@@ -0,0 +1,84 @@
|
||||
# Install script for directory: /Users/bsergeant/src/foss/IXWebSocket/third_party/sentry-native
|
||||
|
||||
# Set the install prefix
|
||||
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||
endif()
|
||||
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Set the install configuration name.
|
||||
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
|
||||
if(BUILD_TYPE)
|
||||
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
|
||||
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_CONFIG_NAME "Release")
|
||||
endif()
|
||||
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
|
||||
endif()
|
||||
|
||||
# Set the component getting installed.
|
||||
if(NOT CMAKE_INSTALL_COMPONENT)
|
||||
if(COMPONENT)
|
||||
message(STATUS "Install component: \"${COMPONENT}\"")
|
||||
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_COMPONENT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Is this installation the result of a crosscompile?
|
||||
if(NOT DEFINED CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
||||
endif()
|
||||
|
||||
if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xUnspecifiedx" OR NOT CMAKE_INSTALL_COMPONENT)
|
||||
if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Dd][Ee][Bb][Uu][Gg])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a")
|
||||
if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a" AND
|
||||
NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
execute_process(COMMAND "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
endif()
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a")
|
||||
if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a" AND
|
||||
NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
execute_process(COMMAND "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
endif()
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Mm][Ii][Nn][Ss][Ii][Zz][Ee][Rr][Ee][Ll])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a")
|
||||
if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a" AND
|
||||
NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
execute_process(COMMAND "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
endif()
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ww][Ii][Tt][Hh][Dd][Ee][Bb][Ii][Nn][Ff][Oo])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a")
|
||||
if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a" AND
|
||||
NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
execute_process(COMMAND "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsentry.a")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xUnspecifiedx" OR NOT CMAKE_INSTALL_COMPONENT)
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include" TYPE FILE FILES "/Users/bsergeant/src/foss/IXWebSocket/third_party/sentry-native/include/sentry.h")
|
||||
endif()
|
||||
|
||||
if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xUnspecifiedx" OR NOT CMAKE_INSTALL_COMPONENT)
|
||||
if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Dd][Ee][Bb][Uu][Gg])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE FILE FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a.dSYM")
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE FILE FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/libsentry.a.dSYM")
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Mm][Ii][Nn][Ss][Ii][Zz][Ee][Rr][Ee][Ll])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE FILE FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/MinSizeRel/libsentry.a.dSYM")
|
||||
elseif("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ww][Ii][Tt][Hh][Dd][Ee][Bb][Ii][Nn][Ff][Oo])$")
|
||||
file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE FILE FILES "/Users/bsergeant/src/foss/IXWebSocket/sentry-native/RelWithDebInfo/libsentry.a.dSYM")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCAL_ONLY)
|
||||
# Include the install script for each subdirectory.
|
||||
include("/Users/bsergeant/src/foss/IXWebSocket/sentry-native/src/cmake_install.cmake")
|
||||
|
||||
endif()
|
||||
|
34
sentry-native/src/cmake_install.cmake
Normal file
34
sentry-native/src/cmake_install.cmake
Normal file
@@ -0,0 +1,34 @@
|
||||
# Install script for directory: /Users/bsergeant/src/foss/IXWebSocket/third_party/sentry-native/src
|
||||
|
||||
# Set the install prefix
|
||||
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||
endif()
|
||||
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Set the install configuration name.
|
||||
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
|
||||
if(BUILD_TYPE)
|
||||
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
|
||||
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_CONFIG_NAME "Release")
|
||||
endif()
|
||||
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
|
||||
endif()
|
||||
|
||||
# Set the component getting installed.
|
||||
if(NOT CMAKE_INSTALL_COMPONENT)
|
||||
if(COMPONENT)
|
||||
message(STATUS "Install component: \"${COMPONENT}\"")
|
||||
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_COMPONENT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Is this installation the result of a crosscompile?
|
||||
if(NOT DEFINED CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
||||
endif()
|
||||
|
@@ -23,13 +23,22 @@ include_directories(
|
||||
../ws
|
||||
)
|
||||
|
||||
add_definitions(-DSPDLOG_COMPILED_LIB=1)
|
||||
|
||||
find_package(JsonCpp)
|
||||
if (NOT JSONCPP_FOUND)
|
||||
include_directories(../third_party/jsoncpp)
|
||||
set(JSONCPP_SOURCES ../third_party/jsoncpp/jsoncpp.cpp)
|
||||
endif()
|
||||
|
||||
# Shared sources
|
||||
set (SOURCES
|
||||
${JSONCPP_SOURCES}
|
||||
|
||||
test_runner.cpp
|
||||
IXTest.cpp
|
||||
IXGetFreePort.cpp
|
||||
../third_party/msgpack11/msgpack11.cpp
|
||||
../third_party/jsoncpp/jsoncpp.cpp
|
||||
|
||||
IXSocketTest.cpp
|
||||
IXSocketConnectTest.cpp
|
||||
@@ -46,12 +55,12 @@ set (SOURCES
|
||||
IXDNSLookupTest.cpp
|
||||
IXWebSocketSubProtocolTest.cpp
|
||||
IXSentryClientTest.cpp
|
||||
IXWebSocketChatTest.cpp
|
||||
)
|
||||
|
||||
# Some unittest don't work on windows yet
|
||||
if (UNIX)
|
||||
list(APPEND SOURCES
|
||||
IXWebSocketChatTest.cpp
|
||||
IXWebSocketCloseTest.cpp
|
||||
)
|
||||
endif()
|
||||
@@ -79,6 +88,11 @@ if (APPLE AND USE_TLS)
|
||||
target_link_libraries(ixwebsocket_unittest "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
if (JSONCPP_FOUND)
|
||||
target_include_directories(ixwebsocket_unittest PUBLIC ${JSONCPP_INCLUDE_DIRS})
|
||||
target_link_libraries(ixwebsocket_unittest ${JSONCPP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(ixwebsocket_unittest ixsnake)
|
||||
target_link_libraries(ixwebsocket_unittest ixcobra)
|
||||
target_link_libraries(ixwebsocket_unittest ixwebsocket)
|
||||
@@ -86,4 +100,6 @@ target_link_libraries(ixwebsocket_unittest ixcrypto)
|
||||
target_link_libraries(ixwebsocket_unittest ixcore)
|
||||
target_link_libraries(ixwebsocket_unittest ixsentry)
|
||||
|
||||
target_link_libraries(ixwebsocket_unittest spdlog)
|
||||
|
||||
install(TARGETS ixwebsocket_unittest DESTINATION bin)
|
||||
|
@@ -34,12 +34,10 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
class SatoriChat
|
||||
class CobraChat
|
||||
{
|
||||
public:
|
||||
SatoriChat(const std::string& user,
|
||||
const std::string& session,
|
||||
const std::string& endpoint);
|
||||
CobraChat(const std::string& user, const std::string& session, const std::string& endpoint);
|
||||
|
||||
void subscribe(const std::string& channel);
|
||||
void start();
|
||||
@@ -72,9 +70,9 @@ namespace
|
||||
std::mutex _logMutex;
|
||||
};
|
||||
|
||||
SatoriChat::SatoriChat(const std::string& user,
|
||||
const std::string& session,
|
||||
const std::string& endpoint)
|
||||
CobraChat::CobraChat(const std::string& user,
|
||||
const std::string& session,
|
||||
const std::string& endpoint)
|
||||
: _user(user)
|
||||
, _session(session)
|
||||
, _endpoint(endpoint)
|
||||
@@ -83,34 +81,34 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void SatoriChat::start()
|
||||
void CobraChat::start()
|
||||
{
|
||||
_thread = std::thread(&SatoriChat::run, this);
|
||||
_thread = std::thread(&CobraChat::run, this);
|
||||
}
|
||||
|
||||
void SatoriChat::stop()
|
||||
void CobraChat::stop()
|
||||
{
|
||||
_stop = true;
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
bool SatoriChat::isReady() const
|
||||
bool CobraChat::isReady() const
|
||||
{
|
||||
return _connectedAndSubscribed;
|
||||
}
|
||||
|
||||
size_t SatoriChat::getReceivedMessagesCount() const
|
||||
size_t CobraChat::getReceivedMessagesCount() const
|
||||
{
|
||||
return _receivedQueue.size();
|
||||
}
|
||||
|
||||
bool SatoriChat::hasPendingMessages() const
|
||||
bool CobraChat::hasPendingMessages() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_queue_mutex);
|
||||
return !_publish_queue.empty();
|
||||
}
|
||||
|
||||
Json::Value SatoriChat::popMessage()
|
||||
Json::Value CobraChat::popMessage()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_queue_mutex);
|
||||
auto msg = _publish_queue.front();
|
||||
@@ -121,7 +119,7 @@ namespace
|
||||
//
|
||||
// Callback to handle received messages, that are printed on the console
|
||||
//
|
||||
void SatoriChat::subscribe(const std::string& channel)
|
||||
void CobraChat::subscribe(const std::string& channel)
|
||||
{
|
||||
std::string filter;
|
||||
_conn.subscribe(channel, filter, [this](const Json::Value& msg) {
|
||||
@@ -151,7 +149,7 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
void SatoriChat::sendMessage(const std::string& text)
|
||||
void CobraChat::sendMessage(const std::string& text)
|
||||
{
|
||||
Json::Value msg;
|
||||
msg["user"] = _user;
|
||||
@@ -166,16 +164,21 @@ namespace
|
||||
// Do satori communication on a background thread, where we can have
|
||||
// something like an event loop that publish, poll and receive data
|
||||
//
|
||||
void SatoriChat::run()
|
||||
void CobraChat::run()
|
||||
{
|
||||
// "chat" conf
|
||||
std::string appkey("FC2F10139A2BAc53BB72D9db967b024f");
|
||||
std::string channel = _session;
|
||||
std::string role = "_sub";
|
||||
std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba";
|
||||
SocketTLSOptions socketTLSOptions;
|
||||
|
||||
_conn.configure(
|
||||
appkey, _endpoint, role, secret, ix::WebSocketPerMessageDeflateOptions(true));
|
||||
_conn.configure(appkey,
|
||||
_endpoint,
|
||||
role,
|
||||
secret,
|
||||
ix::WebSocketPerMessageDeflateOptions(true),
|
||||
socketTLSOptions);
|
||||
_conn.connect();
|
||||
|
||||
_conn.setEventCallback([this, channel](ix::CobraConnectionEventType eventType,
|
||||
@@ -280,8 +283,8 @@ TEST_CASE("Cobra_chat", "[cobra_chat]")
|
||||
ss << "ws://localhost:" << port;
|
||||
std::string endpoint = ss.str();
|
||||
|
||||
SatoriChat chatA("jean", session, endpoint);
|
||||
SatoriChat chatB("paul", session, endpoint);
|
||||
CobraChat chatA("jean", session, endpoint);
|
||||
CobraChat chatB("paul", session, endpoint);
|
||||
|
||||
chatA.start();
|
||||
chatB.start();
|
||||
|
@@ -62,11 +62,14 @@ namespace
|
||||
gMessageCount = 0;
|
||||
|
||||
ix::CobraConnection conn;
|
||||
SocketTLSOptions socketTLSOptions;
|
||||
|
||||
conn.configure(APPKEY,
|
||||
endpoint,
|
||||
SUBSCRIBER_ROLE,
|
||||
SUBSCRIBER_SECRET,
|
||||
ix::WebSocketPerMessageDeflateOptions(true));
|
||||
ix::WebSocketPerMessageDeflateOptions(true),
|
||||
socketTLSOptions);
|
||||
conn.connect();
|
||||
|
||||
conn.setEventCallback([&conn](ix::CobraConnectionEventType eventType,
|
||||
@@ -202,9 +205,15 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
|
||||
|
||||
ix::CobraMetricsPublisher cobraMetricsPublisher;
|
||||
|
||||
SocketTLSOptions socketTLSOptions;
|
||||
bool perMessageDeflate = true;
|
||||
cobraMetricsPublisher.configure(
|
||||
APPKEY, endpoint, CHANNEL, PUBLISHER_ROLE, PUBLISHER_SECRET, perMessageDeflate);
|
||||
cobraMetricsPublisher.configure(APPKEY,
|
||||
endpoint,
|
||||
CHANNEL,
|
||||
PUBLISHER_ROLE,
|
||||
PUBLISHER_SECRET,
|
||||
perMessageDeflate,
|
||||
socketTLSOptions);
|
||||
cobraMetricsPublisher.setSession(uuid4());
|
||||
cobraMetricsPublisher.enable(true); // disabled by default, needs to be enabled to be active
|
||||
|
||||
|
@@ -59,10 +59,14 @@ TEST_CASE("http server", "[httpd]")
|
||||
|
||||
REQUIRE(response->errorCode == HttpErrorCode::Ok);
|
||||
REQUIRE(response->statusCode == 200);
|
||||
REQUIRE(response->headers["Accept-Encoding"] == "gzip");
|
||||
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("http server redirection", "[httpd_redirect]")
|
||||
{
|
||||
SECTION("Connect to a local HTTP server, with redirection enabled")
|
||||
{
|
||||
int port = getFreePort();
|
||||
|
@@ -8,9 +8,8 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
#include <ixsentry/IXSentryClient.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace ix;
|
||||
|
||||
@@ -21,7 +20,9 @@ namespace ix
|
||||
SECTION("Attempt to index nil")
|
||||
{
|
||||
SentryClient sentryClient("");
|
||||
std::string stack = "Attempt to index nil[overlay]!\nstack traceback:\n\tfoo.lua:2661: in function 'getFoo'\n\tfoo.lua:1666: in function 'onUpdate'\n\tfoo.lua:1751: in function <foo.lua:1728>";
|
||||
std::string stack = "Attempt to index nil[overlay]!\nstack traceback:\n\tfoo.lua:2661: "
|
||||
"in function 'getFoo'\n\tfoo.lua:1666: in function "
|
||||
"'onUpdate'\n\tfoo.lua:1751: in function <foo.lua:1728>";
|
||||
auto frames = sentryClient.parseLuaStackTrace(stack);
|
||||
|
||||
REQUIRE(frames.size() == 3);
|
||||
@@ -30,7 +31,8 @@ namespace ix
|
||||
SECTION("Attempt to perform nil")
|
||||
{
|
||||
SentryClient sentryClient("");
|
||||
std::string stack = "Attempt to perform nil - 1572111278.299\nstack traceback:\n\tfoo.lua:57: in function <foo.lua:53>";
|
||||
std::string stack = "Attempt to perform nil - 1572111278.299\nstack "
|
||||
"traceback:\n\tfoo.lua:57: in function <foo.lua:53>";
|
||||
auto frames = sentryClient.parseLuaStackTrace(stack);
|
||||
|
||||
REQUIRE(frames.size() == 1);
|
||||
|
11
test/compatibility/node/echo_server.js
Normal file
11
test/compatibility/node/echo_server.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const WebSocket = require('ws');
|
||||
|
||||
const wss = new WebSocket.Server({ port: 8080 });
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('received: %s', message);
|
||||
});
|
||||
|
||||
ws.send('something');
|
||||
});
|
11
test/compatibility/node/echo_server_permessagedeflate.js
Normal file
11
test/compatibility/node/echo_server_permessagedeflate.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const WebSocket = require('ws');
|
||||
|
||||
const wss = new WebSocket.Server({ port: 8080, perMessageDeflate: true });
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('received: %s', message);
|
||||
});
|
||||
|
||||
ws.send('something');
|
||||
});
|
File diff suppressed because one or more lines are too long
36
test/compatibility/python/websocket-client/ws_send.py
Normal file
36
test/compatibility/python/websocket-client/ws_send.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from websocket import *
|
||||
|
||||
import random
|
||||
import string
|
||||
import ssl
|
||||
|
||||
def randomString(stringLength=10):
|
||||
"""Generate a random string of fixed length """
|
||||
letters = string.ascii_lowercase
|
||||
return ''.join(random.choice(letters) for i in range(stringLength))
|
||||
|
||||
st = randomString(32768)
|
||||
|
||||
with open('generated_file', 'w') as f:
|
||||
f.write(st)
|
||||
|
||||
ws = create_connection("wss://echo.websocket.org/",
|
||||
sslopt={"cert_reqs": ssl.CERT_NONE})
|
||||
|
||||
print("Sending")
|
||||
|
||||
frame = ABNF.create_frame(st, ABNF.OPCODE_TEXT, 0)
|
||||
ws.send_frame(frame)
|
||||
cont_frame = ABNF.create_frame(st, ABNF.OPCODE_CONT, 0)
|
||||
ws.send_frame(cont_frame)
|
||||
cont_frame = ABNF.create_frame(st, ABNF.OPCODE_CONT, 1)
|
||||
ws.send_frame(cont_frame)
|
||||
|
||||
print("Sent")
|
||||
print("Receiving...")
|
||||
result = ws.recv()
|
||||
if st+st+st == result:
|
||||
print("Received ")
|
||||
else:
|
||||
print("Error")
|
||||
ws.close()
|
1
test/compatibility/python/websockets/DOCKER_VERSION
Normal file
1
test/compatibility/python/websockets/DOCKER_VERSION
Normal file
@@ -0,0 +1 @@
|
||||
0.0.1
|
17
test/compatibility/python/websockets/Dockerfile
Normal file
17
test/compatibility/python/websockets/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM python:3.8.0-alpine3.10
|
||||
|
||||
RUN pip install websockets
|
||||
|
||||
COPY vendor/protocol.py /usr/local/lib/python3.8/site-packages/websockets/protocol.py
|
||||
|
||||
COPY *.py /usr/bin/
|
||||
COPY entrypoint.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/*.py
|
||||
|
||||
RUN mkdir /certs
|
||||
COPY *.pem /certs/
|
||||
|
||||
WORKDIR /certs
|
||||
|
||||
EXPOSE 8765 8766
|
||||
CMD ["sh", "/usr/bin/entrypoint.sh"]
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user