├── .gitignore ├── .vscode └── settings.json ├── Pipfile ├── Pipfile.lock ├── README.md ├── index.html ├── index.js ├── quic_connection_sequence.jpg ├── quic_transport_server.py ├── sequence.drawio └── setup.cfg /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | certificate.key 3 | certificate.pem 4 | *.secret 5 | .DS_Store -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": ".venv/bin/python", 3 | "editor.formatOnSave": true, 4 | "python.linting.pycodestyleEnabled": true, 5 | "python.linting.pylintEnabled": true, 6 | "python.formatting.provider": "black", 7 | "notebook.kernelProviderAssociations": [] 8 | } 9 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | pycodestyle = "*" 8 | black = "*" 9 | flake8 = "*" 10 | cryptography = ">=3.2" 11 | 12 | [packages] 13 | aioquic = "*" 14 | 15 | [requires] 16 | python_version = "3.8" 17 | 18 | [pipenv] 19 | allow_prereleases = true 20 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "f01d3c613f9790b31c669c2399c59e1089e5b4f130a7cc199217da8a21c66b68" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "aioquic": { 20 | "hashes": [ 21 | "sha256:0a59cb078596087175b05929401645d49b0e0a687bc79bac236d9a7a73874b65", 22 | "sha256:1cbdc4ff1160ff82b3b1722e62a138c0fff41557449320768476af14d5b1eac3", 23 | "sha256:2cf057ea1af7639754e006fb98911b81b5d059f41f112b84557ec9492b22fec3", 24 | "sha256:2d603eefc960d0dee531e0e8d63b7c376816fab4beb7931fec24667641903899", 25 | "sha256:2ed04fa08d2d843166c264a90096a4fc61a75e26cc4198a6e7e9956d068c20b0", 26 | "sha256:2f66d52fb56f7b82b645231a957484dde379d626266c82d59d6db97bb31dd53a", 27 | "sha256:33e7ab651b77f7961b5521627aaa50c950e7da902102121deaf343e19ff9c60b", 28 | "sha256:4d826a7f63eefd625f26c767dd2e369b74e25dc1cb7b03edb73f67c27ccd6ff6", 29 | "sha256:637a25b7fd56084de89ccf34c905de29cd285b6a6679dcca7f52a7fef54a839d", 30 | "sha256:65cac12342aee15e8bd56cc8fccf9fe6dd05745383b68f39c7de4c6884a73a53", 31 | "sha256:6e024ce011d7400525814ec31ee83c9b29e4b26c243d8f3ad002fe391730d87c", 32 | "sha256:71e8fcbc7e210a19fb690aa31563ed97fbb2f8050904938697f4cd66f82d94c2", 33 | "sha256:7701db87ec94e11c9fb62e109886963072e2316667543f1c65ae1bed7319b1eb", 34 | "sha256:81200673a5219df55b29a7a6df5a2b4a430ab88154af7536e434d3b495d257c5", 35 | "sha256:866fe2540684e0b9515fc6ca72dd0f8e8994a5bae9f1a08ad2ea0db59a6b3143", 36 | "sha256:8cb2c06f0b12a84db0a05269d9ae912cc9a1284021a893f71de37d06367597a4", 37 | "sha256:95474e05759aa08a0f9e10d094c2c9fffd3344e30b02ae70600ccc753c3ecce9", 38 | "sha256:9be8e5a0f3772e184d35ad9c2e86d9c1dbd2b05c9e9875e2e2baf4dd0fd1fe1e", 39 | "sha256:ad7a870d27af0ea8a1709ef57fe1a346d01681e17d7d357b614a9375224f33d7", 40 | "sha256:aff622def5208e1d0dc986e92e3f39ec7c9381c6e834bd42eef2d426f280d30b", 41 | "sha256:b5cbb0433dcd301947f2d2d87e1cd1875fa458fa0f187436ff3cf3bf01d9e656", 42 | "sha256:c55798a741947b18d2d77de77c54de8963f92cba561afb89b175274dd8758784", 43 | "sha256:c73131f3a7c26bc93d10b07fdc5cb1db3d6293ee9e000c0908c44b7c0e7e6026", 44 | "sha256:ddb95d79b53a442dca36db8e56bc89d0e4f6835175e8c1439b5fad32e61d1e3d", 45 | "sha256:ea83c04b5a4898a6fbc6d7616cd92fc276d3cef487fe987e7482e466175b0195", 46 | "sha256:ed24fa120282eb9698c42e6afea9bbf68d11dddcf034e1a653d0427b29d120d0", 47 | "sha256:f045efcfc669e3e02af42aac60e46c4ed3a054b2694ae3c23c123c052dc2490e" 48 | ], 49 | "index": "pypi", 50 | "version": "==0.9.7" 51 | }, 52 | "certifi": { 53 | "hashes": [ 54 | "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd", 55 | "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4" 56 | ], 57 | "version": "==2020.11.8" 58 | }, 59 | "cffi": { 60 | "hashes": [ 61 | "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", 62 | "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", 63 | "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", 64 | "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", 65 | "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", 66 | "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", 67 | "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", 68 | "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", 69 | "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", 70 | "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", 71 | "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", 72 | "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", 73 | "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", 74 | "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", 75 | "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", 76 | "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", 77 | "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", 78 | "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", 79 | "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", 80 | "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", 81 | "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", 82 | "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", 83 | "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", 84 | "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", 85 | "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", 86 | "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", 87 | "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", 88 | "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", 89 | "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", 90 | "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", 91 | "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", 92 | "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", 93 | "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", 94 | "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" 95 | ], 96 | "version": "==1.14.4" 97 | }, 98 | "cryptography": { 99 | "hashes": [ 100 | "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538", 101 | "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f", 102 | "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77", 103 | "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b", 104 | "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33", 105 | "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e", 106 | "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb", 107 | "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e", 108 | "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7", 109 | "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297", 110 | "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d", 111 | "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7", 112 | "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b", 113 | "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7", 114 | "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4", 115 | "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8", 116 | "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b", 117 | "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851", 118 | "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13", 119 | "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b", 120 | "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3", 121 | "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df" 122 | ], 123 | "version": "==3.2.1" 124 | }, 125 | "pycparser": { 126 | "hashes": [ 127 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 128 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 129 | ], 130 | "version": "==2.20" 131 | }, 132 | "pylsqpack": { 133 | "hashes": [ 134 | "sha256:04336f883f310beed4f4f3bb4709879761a234d001fb21afcc6755a04043b842", 135 | "sha256:233138ba8b78827773422ebfb19ed53127e6d4f2dfbef23434bcc3a75b804b95", 136 | "sha256:25e323bf0cdc732b564648b2e22cef334b503c19848b6b10b0db3c1040178f48", 137 | "sha256:2e41aec759734f9e4941f712086a32bc03085802207ba45b30a43464b9a6eae5", 138 | "sha256:2fddda908f1e04797d004f099fa953bd446fdad8065139237003a627596880d9", 139 | "sha256:32a644315c61d5a73d5847481fe2507decc91500322c8ae5e6787b5a899786df", 140 | "sha256:363a8d6bbd64413962dae25f7353b3e3ba8a9dd9a30e0dd99e7a1e1846b4a779", 141 | "sha256:3902629861f974b6b88437bbd5cbf0e0f9e328f4c58069ac7626690435856e18", 142 | "sha256:3c84077a55a145170ec75ae5b3a869d460361761d798c59af864bedbe8d7b3de", 143 | "sha256:3eb576a1636bc37f93decbdf490d1b951518139efb8972f98d4601066e618d41", 144 | "sha256:42324c78e3bba95bb743f874e68b455965d3737de31affc2c253a6599577a5e5", 145 | "sha256:44f898f9f11d57c2f88a4f89177c402c093d91b004904273cc6a56f6efe0a764", 146 | "sha256:49feecf515875592081f96dcab42ddf1e50ee29f61c7ce79e1d0cb66c4591967", 147 | "sha256:4b0e4374431a9e846e5c43368026e6b4d77c55ef5775bd091ad36cced7a48f18", 148 | "sha256:4c59abe3d3ed691f422fcd86fb8c5aa34f6f852af131a8157fcdb46723ef50f8", 149 | "sha256:57b199d228160fb4d366a265935b2d9278012f5b0f05e227ca8b70f659a880c1", 150 | "sha256:614939a4e89885a47c8163695059ed667b8777b2f8943b42fd774b4c97b26698", 151 | "sha256:659363b95ecb29c69c3222f09a4694521b1dfaf453056bdea2d1fbf65985ba34", 152 | "sha256:660326112271bf5d0e5f44cc1f2e25d5e22987fb6aae3b1dd1922b3efe2ac1fd", 153 | "sha256:66074b1b1c9c761518b080fbd8593c73ef80f1444b1a1f792992badc6cd63430", 154 | "sha256:66e7efc810d7bd2dd03525c39789942c41cdabbf7fdd375b3c1a1aaf72b63b0f", 155 | "sha256:6bf2b6a5e3ae8eca38a9c003ab7c5fc4c3680e56380c2cbc84c08e61332d73b4", 156 | "sha256:6c1da92cc2fa225074355f564d794bf7d57005534b8984c680cc9a3b3ca1b217", 157 | "sha256:71e974b7005da6d416427e33b769e78a2ed5e5d41b3486714cd40c7cf9229f3c", 158 | "sha256:7cfd98932c7cb3a39d75e6ae4c8d4516128e4683591bc2adb54dddec52b34dc8", 159 | "sha256:7ea7bc40f94867a4da58c875d3cfdc13fe88a447e051d62087a7be6cbcee2d2f", 160 | "sha256:7ed46fc27c06d03564db2f11974f8ee58fb7026331fb79e2014f9a164f3ccda7", 161 | "sha256:87bcded74563457da4c321bbecf283b20d6dd00f5a2925828f41f6f85f7c0aa7", 162 | "sha256:89c067bd4be35d6055511f63f7d077053965dc41f35057baa3ddee1d972ae221", 163 | "sha256:8ff8a2749efd870e3a7893f4e4cca26d7660d4a3adf670fb08457f2feb0a7619", 164 | "sha256:9212e6f0cfe7e00ee13a5e60f863eaf123ca9f7ecbfaa3cbcc3be1864f280676", 165 | "sha256:9fd2ab3049529f3317fe88c3ab9041bd0af78421ac3a5f226f303a829b6a208b", 166 | "sha256:a440ca4b343947b605902d33607f292b2f4f76e466d631035e11fe372e6e456d", 167 | "sha256:a501b9f49ab864948c454469add9e63b909300c24503cf458f35019901dbcf76", 168 | "sha256:bbdc5e1523b31ee3da07adc39c1034eee26f84688bad5d75c86d1c5740e811d3", 169 | "sha256:c0654dac162a842610ffc5f0297b89aa3b63ef73d7ee6a9db944120e1a9a90f2", 170 | "sha256:ccb4181b30b9bc952b5e3adbf8c37b3fff8c80fae21f47a645e810717ed9f2c7", 171 | "sha256:db48081caf0818265fc3b94c1e7e6da81e33722017c75cf64f97bccdc2832b27", 172 | "sha256:de86c2c244fe7e0b19c876aa79e8c8edf956f5b019423e2002ea456afce0ef10", 173 | "sha256:e3b27f75c19f6cf453fef46a430fc632b0a627b055ed3d2b98233b0caca72467", 174 | "sha256:e64f758850d5f4dbe82c65c75f91832dd4eaacf5a884000fcd508490abb3b9a2", 175 | "sha256:ebab88ba7948ae8556dfbaccb92356dc75740da88c2742b3d17a4afa6ae280dd", 176 | "sha256:f6ed0e5975fee0701f0d2d7a01c2122da8e64130b7240de96bbc891449f91956", 177 | "sha256:fc497933814545f3c54e35a1b4ebd85a93c2a670832440a0469128c5f501c8fc" 178 | ], 179 | "version": "==0.3.11" 180 | }, 181 | "six": { 182 | "hashes": [ 183 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 184 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 185 | ], 186 | "version": "==1.15.0" 187 | } 188 | }, 189 | "develop": { 190 | "appdirs": { 191 | "hashes": [ 192 | "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", 193 | "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" 194 | ], 195 | "version": "==1.4.4" 196 | }, 197 | "black": { 198 | "hashes": [ 199 | "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea" 200 | ], 201 | "index": "pypi", 202 | "version": "==20.8b1" 203 | }, 204 | "cffi": { 205 | "hashes": [ 206 | "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", 207 | "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", 208 | "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", 209 | "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", 210 | "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", 211 | "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", 212 | "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", 213 | "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", 214 | "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", 215 | "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", 216 | "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", 217 | "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", 218 | "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", 219 | "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", 220 | "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", 221 | "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", 222 | "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", 223 | "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", 224 | "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", 225 | "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", 226 | "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", 227 | "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", 228 | "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", 229 | "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", 230 | "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", 231 | "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", 232 | "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", 233 | "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", 234 | "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", 235 | "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", 236 | "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", 237 | "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", 238 | "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", 239 | "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" 240 | ], 241 | "version": "==1.14.4" 242 | }, 243 | "click": { 244 | "hashes": [ 245 | "sha256:681c9380a24b22fec089c8e5ffe40aa16a0da79f248a26fe2481bfa8170bfcc1", 246 | "sha256:e4315a188403c0258bbc4a4e31863e48fc301c4e95b8007a8eeda0391158df13" 247 | ], 248 | "version": "==8.0.0a1" 249 | }, 250 | "cryptography": { 251 | "hashes": [ 252 | "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538", 253 | "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f", 254 | "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77", 255 | "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b", 256 | "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33", 257 | "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e", 258 | "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb", 259 | "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e", 260 | "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7", 261 | "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297", 262 | "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d", 263 | "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7", 264 | "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b", 265 | "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7", 266 | "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4", 267 | "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8", 268 | "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b", 269 | "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851", 270 | "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13", 271 | "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b", 272 | "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3", 273 | "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df" 274 | ], 275 | "version": "==3.2.1" 276 | }, 277 | "flake8": { 278 | "hashes": [ 279 | "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839", 280 | "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b" 281 | ], 282 | "index": "pypi", 283 | "version": "==3.8.4" 284 | }, 285 | "mccabe": { 286 | "hashes": [ 287 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", 288 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" 289 | ], 290 | "version": "==0.6.1" 291 | }, 292 | "mypy-extensions": { 293 | "hashes": [ 294 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 295 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 296 | ], 297 | "version": "==0.4.3" 298 | }, 299 | "pathspec": { 300 | "hashes": [ 301 | "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", 302 | "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" 303 | ], 304 | "version": "==0.8.1" 305 | }, 306 | "pycodestyle": { 307 | "hashes": [ 308 | "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367", 309 | "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e" 310 | ], 311 | "index": "pypi", 312 | "version": "==2.6.0" 313 | }, 314 | "pycparser": { 315 | "hashes": [ 316 | "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", 317 | "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" 318 | ], 319 | "version": "==2.20" 320 | }, 321 | "pyflakes": { 322 | "hashes": [ 323 | "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92", 324 | "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8" 325 | ], 326 | "version": "==2.2.0" 327 | }, 328 | "regex": { 329 | "hashes": [ 330 | "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538", 331 | "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4", 332 | "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc", 333 | "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa", 334 | "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444", 335 | "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1", 336 | "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af", 337 | "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8", 338 | "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9", 339 | "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88", 340 | "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba", 341 | "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364", 342 | "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e", 343 | "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7", 344 | "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0", 345 | "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31", 346 | "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683", 347 | "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee", 348 | "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b", 349 | "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884", 350 | "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c", 351 | "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e", 352 | "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562", 353 | "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85", 354 | "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c", 355 | "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6", 356 | "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d", 357 | "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b", 358 | "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70", 359 | "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b", 360 | "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b", 361 | "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f", 362 | "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0", 363 | "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5", 364 | "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5", 365 | "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f", 366 | "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e", 367 | "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512", 368 | "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d", 369 | "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917", 370 | "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f" 371 | ], 372 | "version": "==2020.11.13" 373 | }, 374 | "six": { 375 | "hashes": [ 376 | "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", 377 | "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" 378 | ], 379 | "version": "==1.15.0" 380 | }, 381 | "toml": { 382 | "hashes": [ 383 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 384 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 385 | ], 386 | "version": "==0.10.2" 387 | }, 388 | "typed-ast": { 389 | "hashes": [ 390 | "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", 391 | "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", 392 | "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d", 393 | "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", 394 | "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", 395 | "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", 396 | "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c", 397 | "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", 398 | "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", 399 | "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", 400 | "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", 401 | "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", 402 | "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", 403 | "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d", 404 | "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", 405 | "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", 406 | "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c", 407 | "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", 408 | "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395", 409 | "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", 410 | "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", 411 | "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", 412 | "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", 413 | "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", 414 | "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072", 415 | "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298", 416 | "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91", 417 | "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", 418 | "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f", 419 | "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" 420 | ], 421 | "version": "==1.4.1" 422 | }, 423 | "typing-extensions": { 424 | "hashes": [ 425 | "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918", 426 | "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c", 427 | "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f" 428 | ], 429 | "version": "==3.7.4.3" 430 | } 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quicTransport_mouse_point_share 2 | 3 | ## prepare 4 | 5 | - DownloadGoogle Chrome(M85~) 6 | - Get origin trial key 7 | - Register QuicTransport Trials. [All Trials](https://developers.chrome.com/origintrials/#/trials/active) 8 | - Copy token. 9 | - Use Trials Token in `index.html`. 10 | - ``` 11 | 15 | ``` 16 | - Generate a certificate and a private key 17 | - ``` 18 | openssl req -newkey rsa:2048 -nodes -keyout certificate.key \ 19 | -x509 -out certificate.pem -subj '/CN=Test Certificate' \ 20 | -addext "subjectAltName = DNS:localhost" 21 | ``` 22 | - Compute the fingerprint of the certificate 23 | - ``` 24 | openssl x509 -pubkey -noout -in certificate.pem | 25 | openssl rsa -pubin -outform der | 26 | openssl dgst -sha256 -binary | base64 27 | ``` 28 | - Copy fingerprint. 29 | - Open Google Chrome 30 | - ``` 31 | open -a "Google Chrome" --args --origin-to-force-quic-on=localhost:4433 --ignore-certificate-errors-spki-list="" 32 | ``` 33 | 34 | ### install 35 | 36 | `pipenv install` 37 | 38 | ## run 39 | 40 | `pipenv shell` 41 | `python quic_transport_server.py certificate.pem certificate.key` 42 | `python -m http.server 8000` 43 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | QuicTransport client 4 | 5 | 6 | 10 | 11 | 12 | 13 |
14 |
15 |

QuicTransport client

16 |
17 |

Establish QuicTransport connection

18 | 26 | 35 |
36 | 37 | 43 | 49 |
50 |
51 | 57 |
58 | 64 |
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // "Connect" button handler. 2 | async function prepareConnection() { 3 | let url = document.getElementById("url").value; 4 | var transport = new WebTransport(url); 5 | console.log(`initializing WebTransport Instance`); 6 | transport.closed 7 | .then(() => { 8 | console.log(`The QUIC connection to ${url} closed gracefully`); 9 | }) 10 | .catch((error) => { 11 | console.error(`the QUIC connection to ${url} closed due to ${error}`); 12 | }); 13 | await transport.ready; 14 | console.log("startReceivingDatagram"); 15 | startReceivingDatagram(transport); 16 | console.log("startReceivingStream"); 17 | startReceivingStream(transport); 18 | globalThis.currentTransport = transport; 19 | globalThis.streamNumber = 1; 20 | } 21 | let prev_mouse_point_x = null; 22 | let prev_mouse_point_y = null; 23 | 24 | async function startReceivingDatagram(transport) { 25 | const reader = transport.datagramReadable.getReader(); 26 | while (true) { 27 | const { value, done } = await reader.read(); 28 | let result = new TextDecoder("ascii").decode(value); 29 | // result = "mouse_point=x,y" 30 | if (result.startsWith("mouse_point=")) { 31 | const index = result.indexOf("="); 32 | const [mouse_point_x, mouse_point_y] = result.slice(index + 1).split(","); 33 | const myPics = document.getElementById("myPics"); 34 | const context = myPics.getContext("2d"); 35 | if (prev_mouse_point_x && prev_mouse_point_y) { 36 | drawLine( 37 | context, 38 | prev_mouse_point_x, 39 | prev_mouse_point_y, 40 | mouse_point_x, 41 | mouse_point_y 42 | ); 43 | } 44 | prev_mouse_point_x = mouse_point_x; 45 | prev_mouse_point_y = mouse_point_y; 46 | } 47 | if (done) { 48 | break; 49 | } 50 | } 51 | } 52 | 53 | async function startReceivingStream(transport) { 54 | let reader = transport.incomingUnidirectionalStreams.getReader(); 55 | while (true) { 56 | let result = await reader.read(); 57 | if (result.done) { 58 | console.log("Done accepting unidirectional streams!"); 59 | return; 60 | } 61 | let stream = result.value; 62 | let number = globalThis.streamNumber++; 63 | readDataFromStream(stream, number); 64 | } 65 | } 66 | 67 | async function readDataFromStream(stream, number) { 68 | let decoder = new TextDecoderStream("utf-8"); 69 | let reader = stream.readable.pipeThrough(decoder).getReader(); 70 | while (true) { 71 | let result = await reader.read(); 72 | if (result.done) { 73 | console.log("Stream #" + number + " closed"); 74 | return; 75 | } 76 | if (result.value.startsWith("quic_transport_id=")) { 77 | const index = result.value.indexOf("="); 78 | document.getElementById("QuicTransportID").value = result.value.slice( 79 | index + 1 80 | ); 81 | } else if (result.value.startsWith("joined")) { 82 | const index = result.value.indexOf("="); 83 | document.getElementById("OtherQuicTransportID").value += 84 | result.value.slice(index + 1) + "\n"; 85 | } 86 | } 87 | } 88 | 89 | async function sendMousePointDatagram() { 90 | let QuicTransportID = document.getElementById("QuicTransportID").value; 91 | QuicTransportID = new TextEncoder().encode(QuicTransportID); 92 | const transport = globalThis.currentTransport; 93 | mouse_point_share(); 94 | } 95 | let isDrawing = false; 96 | function drawLine(context, x1, y1, x2, y2) { 97 | context.beginPath(); 98 | context.strokeStyle = "black"; 99 | context.lineWidth = 1; 100 | context.moveTo(x1, y1); 101 | context.lineTo(x2, y2); 102 | context.stroke(); 103 | context.closePath(); 104 | } 105 | 106 | var timeoutId; 107 | function mouse_point_share() { 108 | const myPics = document.getElementById("myPics"); 109 | const context = myPics.getContext("2d"); 110 | myPics.addEventListener("mousedown", (e) => { 111 | x = e.offsetX; 112 | y = e.offsetY; 113 | isDrawing = true; 114 | }); 115 | 116 | myPics.addEventListener("mousemove", (e) => { 117 | if (timeoutId) return; 118 | // Prevent from very high frequency sending. 119 | timeoutId = setTimeout(function () { 120 | timeoutId = 0; 121 | 122 | if (isDrawing === true) { 123 | drawLine(context, x, y, e.offsetX, e.offsetY); 124 | x = e.offsetX; 125 | y = e.offsetY; 126 | const text = `mouse_point=${e.offsetX},${e.offsetY}`; 127 | const encoded_text = new TextEncoder().encode(text); 128 | 129 | if (globalThis.writer) { 130 | writer.write(encoded_text); 131 | } else { 132 | const ws = globalThis.currentTransport.datagramWritable; 133 | const writer = ws.getWriter(); 134 | globalThis.writer = writer; 135 | writer.write(encoded_text); 136 | } 137 | } 138 | }, 10); 139 | }); 140 | 141 | window.addEventListener("mouseup", (e) => { 142 | if (isDrawing === true) { 143 | drawLine(context, x, y, e.offsetX, e.offsetY); 144 | x = 0; 145 | y = 0; 146 | isDrawing = false; 147 | } 148 | }); 149 | } 150 | -------------------------------------------------------------------------------- /quic_connection_sequence.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuki-uchida/quicTransport_mouse_point_share/5b8106ed75a1ad76b0128950e16df57733978fab/quic_connection_sequence.jpg -------------------------------------------------------------------------------- /quic_transport_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | """ 17 | An example QuicTransport server based on the aioquic library. 18 | Processes incoming streams and datagrams, and 19 | replies with the ASCII-encoded length of the data sent in bytes. 20 | Example use: 21 | python3 quic_transport_server.py certificate.pem certificate.key 22 | Example use from JavaScript: 23 | let transport = new QuicTransport("quic-transport://localhost:4433/counter"); 24 | await transport.ready; 25 | let stream = await transport.createBidirectionalStream(); 26 | let encoder = new TextEncoder(); 27 | let writer = stream.writable.getWriter(); 28 | await writer.write(encoder.encode("Hello, world!")) 29 | writer.close(); 30 | console.log(await new Response(stream.readable).text()); 31 | This will output "13" (the length of "Hello, world!") into the console. 32 | """ 33 | 34 | # ---- Dependencies ---- 35 | # 36 | # This server only depends on Python standard library and aioquic. See 37 | # https://github.com/aiortc/aioquic for instructions on how to install 38 | # aioquic. 39 | # 40 | # ---- Certificates ---- 41 | # 42 | # QUIC always operates using TLS, meaning that running a QuicTransport server 43 | # requires a valid TLS certificate. The easiest way to do this is to get a 44 | # certificate from a real publicly trusted CA like . 45 | # https://developers.google.com/web/fundamentals/security/encrypt-in-transit/enable-https 46 | # contains a detailed explanation of how to achieve that. 47 | # 48 | # As an alternative, Chromium can be instructed to trust a self-signed 49 | # certificate using command-line flags. Here are step-by-step instructions on 50 | # how to do that: 51 | # 52 | # 1. Generate a certificate and a private key: 53 | # openssl req -newkey rsa:2048 -nodes -keyout certificate.key \ 54 | # -x509 -out certificate.pem -subj '/CN=Test Certificate' \ 55 | # -addext "subjectAltName = DNS:localhost" 56 | # 57 | # 2. Compute the fingerprint of the certificate: 58 | # openssl x509 -pubkey -noout -in certificate.pem | 59 | # openssl rsa -pubin -outform der | 60 | # openssl dgst -sha256 -binary | base64 61 | # The result should be a base64-encoded blob that looks like this: 62 | # "Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck=" 63 | # 64 | # 3. Pass a flag to Chromium indicating what host and port should be allowed 65 | # to use the self-signed certificate. For instance, if the host is 66 | # localhost, and the port is 4433, the flag would be: 67 | # --origin-to-force-quic-on=localhost:4433 68 | # 69 | # 4. Pass a flag to Chromium indicating which certificate needs to be trusted. 70 | # For the example above, that flag would be: 71 | # --ignore-certificate-errors-spki-list=Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck= 72 | # 73 | # See https://www.chromium.org/developers/how-tos/run-chromium-with-flags for 74 | # details on how to run Chromium with flags. 75 | 76 | # open -a "Google Chrome" --args --origin-to-force-quic-on=localhost:4433 --ignore-certificate-errors-spki-list="ks9+B0hyVs6hwrZh3alG5XBKVGbAIrSnRWPSsdYXXFw=" 77 | 78 | 79 | import uuid 80 | from aioquic.tls import SessionTicket 81 | from aioquic.quic.events import ( 82 | StreamDataReceived, 83 | StreamReset, 84 | DatagramFrameReceived, 85 | QuicEvent, 86 | ) 87 | from aioquic.quic.connection import QuicConnection, END_STATES 88 | from aioquic.quic.configuration import QuicConfiguration 89 | from aioquic.asyncio import QuicConnectionProtocol, serve 90 | from typing import Dict, Optional 91 | from collections import defaultdict 92 | import urllib.parse 93 | import struct 94 | import os 95 | import io 96 | import asyncio 97 | import argparse 98 | import sys 99 | 100 | 101 | # Additional 102 | 103 | BIND_ADDRESS = "::1" 104 | BIND_PORT = 4433 105 | 106 | connections_list = {} 107 | 108 | 109 | def addConnections(new_connection, new_protocol) -> None: 110 | print(f"quic_transport_server addConnections{connections_list}") 111 | new_quic_transport_id = str(uuid.uuid4()) 112 | # 入室情報を他の人に教えてあげる(streamで) 113 | for quic_transport_id, connection_dict in connections_list.items(): 114 | response_id = connection_dict["connection"].get_next_available_stream_id( 115 | is_unidirectional=True 116 | ) 117 | payload = str(f"joined={new_quic_transport_id}").encode("ascii") 118 | connection_dict["connection"].send_stream_data(response_id, payload, True) 119 | # connection_dict["protocol"].transmit() 120 | 121 | connections_list[new_quic_transport_id] = { 122 | "connection": new_connection, 123 | "protocol": new_protocol, 124 | } 125 | # 自分のQuicTransportIDを教えてあげる(streamで) 126 | response_id = new_connection.get_next_available_stream_id(is_unidirectional=True) 127 | payload = str(f"quic_transport_id={new_quic_transport_id}").encode("ascii") 128 | new_connection.send_stream_data(response_id, payload, True) 129 | new_protocol.transmit() 130 | for quic_transport_id, connection_dict in connections_list.items(): 131 | # if new_connection == connection_dict["connection"]: 132 | # continue 133 | if new_quic_transport_id == quic_transport_id: 134 | continue 135 | response_id = new_connection.get_next_available_stream_id( 136 | is_unidirectional=True 137 | ) 138 | payload = str(f"joined={quic_transport_id}").encode("ascii") 139 | new_connection.send_stream_data(response_id, payload, True) 140 | new_protocol.transmit() 141 | return new_quic_transport_id 142 | 143 | 144 | def removeConnections(connection, protocol) -> None: 145 | connections_list.remove({"connection": connection, "protocol": protocol}) 146 | print( 147 | f"quic_transport_server removeConnections removed :{connection},{protocol}, remain: {connections_list} " 148 | ) 149 | # TODO:// 抜けたことを知らせる処理をかく 150 | 151 | 152 | # QUIC uses two lowest bits of the stream ID to indicate whether the stream is: 153 | # (a) unidirectional or bidirectional, 154 | # (b) initiated by the client or by the server. 155 | # See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-2.1 for 156 | # more details. 157 | 158 | # ストリームのIDをみると、タイプがわかる 159 | # 0x0: クライアント開始&双方向 160 | # 0x1: サーバー起動&双方向 161 | # 0x2: クライアント開始&単方向 162 | # 0x3: サーバー起動&単方向 163 | 164 | 165 | def is_client_bidi_stream(stream_id): 166 | return stream_id % 4 == 0 167 | 168 | 169 | # CounterHandler implements a really simple protocol: 170 | # - For every incoming bidirectional stream, it counts bytes it receives on 171 | # that stream until the stream is closed, and then replies with that byte 172 | # count on the same stream. 173 | # - For every incoming unidirectional stream, it counts bytes it receives on 174 | # that stream until the stream is closed, and then replies with that byte 175 | # count on a new unidirectional stream. 176 | # - For every incoming datagram, it sends a datagram with the length of 177 | # datagram that was just received. 178 | 179 | 180 | class sendDataHandler: 181 | def __init__(self, protocol, connection) -> None: 182 | self.protocol = protocol 183 | self.connection = connection 184 | self.counters = defaultdict(str) 185 | self.quic_transport_id = addConnections(self.connection, self.protocol) 186 | 187 | def removeFromConnections(self) -> None: 188 | removeConnections(self.connection, self.proto) 189 | 190 | def quic_event_received(self, event: QuicEvent) -> None: 191 | if isinstance(event, DatagramFrameReceived): 192 | payload = event.data 193 | # self.connection.send_datagram_frame(payload) 194 | for quic_transport_id, connection_dict in connections_list.items(): 195 | if self.quic_transport_id == quic_transport_id: 196 | continue 197 | connection_dict["connection"].send_datagram_frame(payload) 198 | connection_dict["protocol"].transmit() 199 | 200 | 201 | # QuicTransportProtocol handles the beginning of a QuicTransport connection: it 202 | # parses the incoming URL, and routes the transport events to a relevant 203 | # handler (in this example, CounterHandler). It does that by waiting for a 204 | # client indication (a special stream with protocol headers), and buffering all 205 | # unrelated events until the client indication can be fully processed. 206 | 207 | 208 | class QuicTransportProtocol(QuicConnectionProtocol): 209 | def __init__(self, *args, **kwargs) -> None: 210 | super().__init__(*args, **kwargs) 211 | self.pending_events = [] 212 | self.handler = None 213 | self.client_indication_data = b"" 214 | 215 | # QuicConnectionProtocolクラスのtをオーバーライドしてる 216 | # quicを経由したデータ送信は全てここを通る?少なくともclient indicationはここを経由する 217 | 218 | def quic_event_received(self, event: QuicEvent) -> None: 219 | try: 220 | print( 221 | "quic_server_transport_server#QuicTransportProtocol#quic_event_received ============================================================================================================================================" 222 | ) 223 | if self.is_closing_or_closed(): 224 | self.handler.removeFromConnections() 225 | return 226 | # If the handler is available, that means the connection has been 227 | # established and the client has been processed. 228 | if self.handler is not None: 229 | print( 230 | "quic_server_transport_server#QuicTransportProtocol#quic_event_received handler is already available!!" 231 | ) 232 | self.handler.quic_event_received(event) 233 | return 234 | # stream_id=2 => クライアントサイド開始&単方向 235 | if isinstance(event, StreamDataReceived) and event.stream_id == 2: 236 | # print(f'event.data : {event.data}') 237 | # print(f'event.end_stream : {event.end_stream}') 238 | self.client_indication_data += event.data 239 | # streamが終了している場合には開始する処理が走る。すでに開始している場合には何もせず? 240 | if event.end_stream: 241 | # client_indicationを処理して、アクセスしてきたpathによって処理を変える。 242 | # self.handlerにCounter handlerのようなものが入っていないといけない? 243 | self.process_client_indication() 244 | # print(self.is_closing_or_closed()) 245 | if self.is_closing_or_closed(): 246 | return 247 | # Pass all buffered events into the handler now that it's 248 | # available. 249 | # print(self.pending_events) 250 | for e in self.pending_events: 251 | self.handler.quic_event_received(e) 252 | self.pending_events.clear() 253 | else: 254 | # We have received some application data before we have the 255 | # request URL available, which is possible since there is no 256 | # ordering guarantee on data between different QUIC streams. 257 | # Buffer the data for now. 258 | self.pending_events.append(event) 259 | 260 | except Exception as e: 261 | print(e) 262 | self.handler = None 263 | self.close() 264 | # print('quic_event_received() ended') 265 | 266 | # Client indication follows a "key-length-value" format, where key and 267 | # length are 16-bit integers. See 268 | # https://tools.ietf.org/html/draft-vvv-webtransport-quic-01#section-3.2 269 | 270 | def parse_client_indication(self, bs): 271 | while True: 272 | prefix = bs.read(4) 273 | if len(prefix) == 0: 274 | return # End-of-stream reached. 275 | if len(prefix) != 4: 276 | raise Exception("Truncated key-length tag") 277 | # Cの構造体のデータとpython bytesオブジェクトの変換でstructは使用される 278 | key, length = struct.unpack("!HH", prefix) 279 | value = bs.read(length) 280 | if len(value) != length: 281 | raise Exception("Truncated value") 282 | yield (key, value) 283 | 284 | def process_client_indication(self) -> None: 285 | """ 286 | ProtocolNegotiated/HandshakeCompletedのeventが送られてきた後に送られるClient_indicationを処理する。 287 | stream_idが2(クライアント開始・単方向)で、handlerがまだ渡されていない(開始していないstreamである)場合にこの関数が呼ばれる。 288 | (その時はend_stream=Trueで、self.is_closing_or_closed()がFalseになっているはず) 289 | new QuicTransport(url);の段階で、clientの情報が送られてくる。その情報はまず`quic_event_received()` で処理される 290 | """ 291 | KEY_ORIGIN = 0 292 | KEY_PATH = 1 293 | indication = dict( 294 | self.parse_client_indication(io.BytesIO(self.client_indication_data)) 295 | ) 296 | 297 | origin = urllib.parse.urlparse(indication[KEY_ORIGIN].decode()) 298 | path = urllib.parse.urlparse(indication[KEY_PATH]).decode() 299 | # Verify that the origin host is allowed to talk to this server. This 300 | # is similar to the CORS (Cross-Origin Resource Sharing) mechanism in 301 | # HTTP. See . 302 | if origin.hostname != "localhost": 303 | raise Exception("Wrong origin specified") 304 | # Dispatch the incoming connection based on the path specified in the 305 | # URL. 306 | if path.path == "/mouse_point_share": 307 | self.handler = sendDataHandler(self, self._quic) 308 | print("handler attached!!!!!!!") 309 | else: 310 | raise Exception("Unknown path") 311 | 312 | def is_closing_or_closed(self) -> bool: 313 | return self._quic._close_pending or self._quic._state in END_STATES 314 | 315 | 316 | if __name__ == "__main__": 317 | parser = argparse.ArgumentParser() 318 | parser.add_argument("certificate") 319 | parser.add_argument("key") 320 | args = parser.parse_args() 321 | # Quicのsetting 322 | configuration = QuicConfiguration( 323 | # Identifies the protocol used. The origin trial uses the protocol 324 | # described in draft-vvv-webtransport-quic-01, hence the ALPN value. 325 | # See https://tools.ietf.org/html/draft-vvv-webtransport-quic-01#section-3.1 326 | alpn_protocols=["wq-vvv-01"], 327 | is_client=False, 328 | idle_timeout=30000, 329 | # Note that this is just an upper limit; the real maximum datagram size 330 | # available depends on the MTU of the path. See 331 | # . 332 | max_datagram_frame_size=1500, 333 | ) 334 | # Quicの鍵読み込み。 335 | configuration.load_cert_chain(args.certificate, args.key) 336 | 337 | loop = asyncio.get_event_loop() 338 | # 完了するまで続ける 339 | print("running quic server") 340 | loop.run_until_complete( 341 | serve( 342 | BIND_ADDRESS, 343 | BIND_PORT, 344 | configuration=configuration, 345 | create_protocol=QuicTransportProtocol, 346 | ) 347 | ) 348 | loop.run_forever() 349 | -------------------------------------------------------------------------------- /sequence.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = E501 3 | 4 | [pep8] 5 | ignore = E501 --------------------------------------------------------------------------------