protocol-quic 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/ext/ngtcp2/AUTHORS +44 -0
  4. data/ext/ngtcp2/CMakeLists.txt +431 -0
  5. data/ext/ngtcp2/CMakeOptions.txt +17 -0
  6. data/ext/ngtcp2/COPYING +22 -0
  7. data/ext/ngtcp2/ChangeLog +0 -0
  8. data/ext/ngtcp2/Makefile.am +60 -0
  9. data/ext/ngtcp2/NEWS +0 -0
  10. data/ext/ngtcp2/README +1 -0
  11. data/ext/ngtcp2/README.rst +258 -0
  12. data/ext/ngtcp2/ci/build_boringssl.sh +10 -0
  13. data/ext/ngtcp2/ci/build_nghttp3.sh +9 -0
  14. data/ext/ngtcp2/ci/build_openssl1.sh +8 -0
  15. data/ext/ngtcp2/ci/build_openssl1_cross.sh +9 -0
  16. data/ext/ngtcp2/ci/build_openssl3.sh +8 -0
  17. data/ext/ngtcp2/ci/build_picotls.sh +26 -0
  18. data/ext/ngtcp2/ci/build_wolfssl.sh +9 -0
  19. data/ext/ngtcp2/ci/gen-certificate.sh +8 -0
  20. data/ext/ngtcp2/cmake/ExtractValidFlags.cmake +31 -0
  21. data/ext/ngtcp2/cmake/FindCUnit.cmake +40 -0
  22. data/ext/ngtcp2/cmake/FindJemalloc.cmake +40 -0
  23. data/ext/ngtcp2/cmake/FindLibev.cmake +38 -0
  24. data/ext/ngtcp2/cmake/FindLibnghttp3.cmake +41 -0
  25. data/ext/ngtcp2/cmake/Findwolfssl.cmake +41 -0
  26. data/ext/ngtcp2/cmake/Version.cmake +11 -0
  27. data/ext/ngtcp2/cmakeconfig.h.in +36 -0
  28. data/ext/ngtcp2/configure.ac +755 -0
  29. data/ext/ngtcp2/crypto/CMakeLists.txt +56 -0
  30. data/ext/ngtcp2/crypto/Makefile.am +49 -0
  31. data/ext/ngtcp2/crypto/boringssl/CMakeLists.txt +64 -0
  32. data/ext/ngtcp2/crypto/boringssl/Makefile.am +39 -0
  33. data/ext/ngtcp2/crypto/boringssl/boringssl.c +630 -0
  34. data/ext/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in +33 -0
  35. data/ext/ngtcp2/crypto/gnutls/CMakeLists.txt +86 -0
  36. data/ext/ngtcp2/crypto/gnutls/Makefile.am +43 -0
  37. data/ext/ngtcp2/crypto/gnutls/gnutls.c +644 -0
  38. data/ext/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in +33 -0
  39. data/ext/ngtcp2/crypto/includes/CMakeLists.txt +56 -0
  40. data/ext/ngtcp2/crypto/includes/Makefile.am +45 -0
  41. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +893 -0
  42. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h +104 -0
  43. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_gnutls.h +107 -0
  44. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h +132 -0
  45. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h +246 -0
  46. data/ext/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h +106 -0
  47. data/ext/ngtcp2/crypto/openssl/CMakeLists.txt +86 -0
  48. data/ext/ngtcp2/crypto/openssl/Makefile.am +43 -0
  49. data/ext/ngtcp2/crypto/openssl/libngtcp2_crypto_openssl.pc.in +33 -0
  50. data/ext/ngtcp2/crypto/openssl/openssl.c +807 -0
  51. data/ext/ngtcp2/crypto/picotls/CMakeLists.txt +65 -0
  52. data/ext/ngtcp2/crypto/picotls/Makefile.am +39 -0
  53. data/ext/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in +33 -0
  54. data/ext/ngtcp2/crypto/picotls/picotls.c +707 -0
  55. data/ext/ngtcp2/crypto/shared.c +1431 -0
  56. data/ext/ngtcp2/crypto/shared.h +350 -0
  57. data/ext/ngtcp2/crypto/wolfssl/CMakeLists.txt +84 -0
  58. data/ext/ngtcp2/crypto/wolfssl/Makefile.am +43 -0
  59. data/ext/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in +33 -0
  60. data/ext/ngtcp2/crypto/wolfssl/wolfssl.c +534 -0
  61. data/ext/ngtcp2/doc/Makefile.am +65 -0
  62. data/ext/ngtcp2/doc/make.bat +35 -0
  63. data/ext/ngtcp2/doc/mkapiref.py +356 -0
  64. data/ext/ngtcp2/doc/source/conf.py.in +94 -0
  65. data/ext/ngtcp2/doc/source/index.rst +22 -0
  66. data/ext/ngtcp2/doc/source/programmers-guide.rst +476 -0
  67. data/ext/ngtcp2/docker/Dockerfile +39 -0
  68. data/ext/ngtcp2/examples/CMakeLists.txt +361 -0
  69. data/ext/ngtcp2/examples/Makefile.am +228 -0
  70. data/ext/ngtcp2/examples/client.cc +3049 -0
  71. data/ext/ngtcp2/examples/client.h +192 -0
  72. data/ext/ngtcp2/examples/client_base.cc +202 -0
  73. data/ext/ngtcp2/examples/client_base.h +213 -0
  74. data/ext/ngtcp2/examples/debug.cc +298 -0
  75. data/ext/ngtcp2/examples/debug.h +124 -0
  76. data/ext/ngtcp2/examples/examplestest.cc +84 -0
  77. data/ext/ngtcp2/examples/gtlssimpleclient.c +720 -0
  78. data/ext/ngtcp2/examples/h09client.cc +2601 -0
  79. data/ext/ngtcp2/examples/h09client.h +196 -0
  80. data/ext/ngtcp2/examples/h09server.cc +3024 -0
  81. data/ext/ngtcp2/examples/h09server.h +237 -0
  82. data/ext/ngtcp2/examples/http.cc +138 -0
  83. data/ext/ngtcp2/examples/http.h +44 -0
  84. data/ext/ngtcp2/examples/network.h +80 -0
  85. data/ext/ngtcp2/examples/server.cc +3731 -0
  86. data/ext/ngtcp2/examples/server.h +256 -0
  87. data/ext/ngtcp2/examples/server_base.cc +58 -0
  88. data/ext/ngtcp2/examples/server_base.h +195 -0
  89. data/ext/ngtcp2/examples/shared.cc +385 -0
  90. data/ext/ngtcp2/examples/shared.h +96 -0
  91. data/ext/ngtcp2/examples/simpleclient.c +683 -0
  92. data/ext/ngtcp2/examples/template.h +71 -0
  93. data/ext/ngtcp2/examples/tests/README.rst +60 -0
  94. data/ext/ngtcp2/examples/tests/__init__.py +0 -0
  95. data/ext/ngtcp2/examples/tests/config.ini.in +32 -0
  96. data/ext/ngtcp2/examples/tests/conftest.py +28 -0
  97. data/ext/ngtcp2/examples/tests/ngtcp2test/__init__.py +6 -0
  98. data/ext/ngtcp2/examples/tests/ngtcp2test/certs.py +476 -0
  99. data/ext/ngtcp2/examples/tests/ngtcp2test/client.py +187 -0
  100. data/ext/ngtcp2/examples/tests/ngtcp2test/env.py +191 -0
  101. data/ext/ngtcp2/examples/tests/ngtcp2test/log.py +101 -0
  102. data/ext/ngtcp2/examples/tests/ngtcp2test/server.py +137 -0
  103. data/ext/ngtcp2/examples/tests/ngtcp2test/tls.py +983 -0
  104. data/ext/ngtcp2/examples/tests/test_01_handshake.py +30 -0
  105. data/ext/ngtcp2/examples/tests/test_02_resume.py +46 -0
  106. data/ext/ngtcp2/examples/tests/test_03_earlydata.py +56 -0
  107. data/ext/ngtcp2/examples/tests/test_04_clientcert.py +57 -0
  108. data/ext/ngtcp2/examples/tests/test_05_ciphers.py +46 -0
  109. data/ext/ngtcp2/examples/tls_client_context.h +52 -0
  110. data/ext/ngtcp2/examples/tls_client_context_boringssl.cc +126 -0
  111. data/ext/ngtcp2/examples/tls_client_context_boringssl.h +49 -0
  112. data/ext/ngtcp2/examples/tls_client_context_gnutls.cc +74 -0
  113. data/ext/ngtcp2/examples/tls_client_context_gnutls.h +50 -0
  114. data/ext/ngtcp2/examples/tls_client_context_openssl.cc +137 -0
  115. data/ext/ngtcp2/examples/tls_client_context_openssl.h +49 -0
  116. data/ext/ngtcp2/examples/tls_client_context_picotls.cc +158 -0
  117. data/ext/ngtcp2/examples/tls_client_context_picotls.h +53 -0
  118. data/ext/ngtcp2/examples/tls_client_context_wolfssl.cc +177 -0
  119. data/ext/ngtcp2/examples/tls_client_context_wolfssl.h +51 -0
  120. data/ext/ngtcp2/examples/tls_client_session.h +52 -0
  121. data/ext/ngtcp2/examples/tls_client_session_boringssl.cc +110 -0
  122. data/ext/ngtcp2/examples/tls_client_session_boringssl.h +52 -0
  123. data/ext/ngtcp2/examples/tls_client_session_gnutls.cc +190 -0
  124. data/ext/ngtcp2/examples/tls_client_session_gnutls.h +52 -0
  125. data/ext/ngtcp2/examples/tls_client_session_openssl.cc +113 -0
  126. data/ext/ngtcp2/examples/tls_client_session_openssl.h +52 -0
  127. data/ext/ngtcp2/examples/tls_client_session_picotls.cc +147 -0
  128. data/ext/ngtcp2/examples/tls_client_session_picotls.h +52 -0
  129. data/ext/ngtcp2/examples/tls_client_session_wolfssl.cc +160 -0
  130. data/ext/ngtcp2/examples/tls_client_session_wolfssl.h +52 -0
  131. data/ext/ngtcp2/examples/tls_server_context.h +52 -0
  132. data/ext/ngtcp2/examples/tls_server_context_boringssl.cc +257 -0
  133. data/ext/ngtcp2/examples/tls_server_context_boringssl.h +54 -0
  134. data/ext/ngtcp2/examples/tls_server_context_gnutls.cc +99 -0
  135. data/ext/ngtcp2/examples/tls_server_context_gnutls.h +59 -0
  136. data/ext/ngtcp2/examples/tls_server_context_openssl.cc +338 -0
  137. data/ext/ngtcp2/examples/tls_server_context_openssl.h +54 -0
  138. data/ext/ngtcp2/examples/tls_server_context_picotls.cc +321 -0
  139. data/ext/ngtcp2/examples/tls_server_context_picotls.h +58 -0
  140. data/ext/ngtcp2/examples/tls_server_context_wolfssl.cc +284 -0
  141. data/ext/ngtcp2/examples/tls_server_context_wolfssl.h +55 -0
  142. data/ext/ngtcp2/examples/tls_server_session.h +52 -0
  143. data/ext/ngtcp2/examples/tls_server_session_boringssl.cc +84 -0
  144. data/ext/ngtcp2/examples/tls_server_session_boringssl.h +47 -0
  145. data/ext/ngtcp2/examples/tls_server_session_gnutls.cc +155 -0
  146. data/ext/ngtcp2/examples/tls_server_session_gnutls.h +46 -0
  147. data/ext/ngtcp2/examples/tls_server_session_openssl.cc +54 -0
  148. data/ext/ngtcp2/examples/tls_server_session_openssl.h +47 -0
  149. data/ext/ngtcp2/examples/tls_server_session_picotls.cc +70 -0
  150. data/ext/ngtcp2/examples/tls_server_session_picotls.h +47 -0
  151. data/ext/ngtcp2/examples/tls_server_session_wolfssl.cc +55 -0
  152. data/ext/ngtcp2/examples/tls_server_session_wolfssl.h +47 -0
  153. data/ext/ngtcp2/examples/tls_session_base_gnutls.cc +87 -0
  154. data/ext/ngtcp2/examples/tls_session_base_gnutls.h +51 -0
  155. data/ext/ngtcp2/examples/tls_session_base_openssl.cc +54 -0
  156. data/ext/ngtcp2/examples/tls_session_base_openssl.h +52 -0
  157. data/ext/ngtcp2/examples/tls_session_base_picotls.cc +56 -0
  158. data/ext/ngtcp2/examples/tls_session_base_picotls.h +54 -0
  159. data/ext/ngtcp2/examples/tls_session_base_wolfssl.cc +54 -0
  160. data/ext/ngtcp2/examples/tls_session_base_wolfssl.h +54 -0
  161. data/ext/ngtcp2/examples/tls_shared_picotls.cc +59 -0
  162. data/ext/ngtcp2/examples/tls_shared_picotls.h +36 -0
  163. data/ext/ngtcp2/examples/util.cc +646 -0
  164. data/ext/ngtcp2/examples/util.h +361 -0
  165. data/ext/ngtcp2/examples/util_gnutls.cc +136 -0
  166. data/ext/ngtcp2/examples/util_openssl.cc +131 -0
  167. data/ext/ngtcp2/examples/util_test.cc +237 -0
  168. data/ext/ngtcp2/examples/util_test.h +45 -0
  169. data/ext/ngtcp2/examples/util_wolfssl.cc +130 -0
  170. data/ext/ngtcp2/fuzz/corpus/decode_frame/ack +0 -0
  171. data/ext/ngtcp2/fuzz/corpus/decode_frame/ack_ecn +0 -0
  172. data/ext/ngtcp2/fuzz/corpus/decode_frame/connection_close +0 -0
  173. data/ext/ngtcp2/fuzz/corpus/decode_frame/crypto +1 -0
  174. data/ext/ngtcp2/fuzz/corpus/decode_frame/data_blocked +1 -0
  175. data/ext/ngtcp2/fuzz/corpus/decode_frame/datagram +1 -0
  176. data/ext/ngtcp2/fuzz/corpus/decode_frame/datagram_len +1 -0
  177. data/ext/ngtcp2/fuzz/corpus/decode_frame/max_data +1 -0
  178. data/ext/ngtcp2/fuzz/corpus/decode_frame/max_stream_data +0 -0
  179. data/ext/ngtcp2/fuzz/corpus/decode_frame/max_streams +0 -0
  180. data/ext/ngtcp2/fuzz/corpus/decode_frame/new_connection_id +1 -0
  181. data/ext/ngtcp2/fuzz/corpus/decode_frame/new_token +1 -0
  182. data/ext/ngtcp2/fuzz/corpus/decode_frame/path_challenge +1 -0
  183. data/ext/ngtcp2/fuzz/corpus/decode_frame/path_response +1 -0
  184. data/ext/ngtcp2/fuzz/corpus/decode_frame/reset_stream +0 -0
  185. data/ext/ngtcp2/fuzz/corpus/decode_frame/retire_connection_id +1 -0
  186. data/ext/ngtcp2/fuzz/corpus/decode_frame/stop_sending +0 -0
  187. data/ext/ngtcp2/fuzz/corpus/decode_frame/stream +0 -0
  188. data/ext/ngtcp2/fuzz/corpus/decode_frame/stream_data_blocked +0 -0
  189. data/ext/ngtcp2/fuzz/corpus/decode_frame/stream_len +0 -0
  190. data/ext/ngtcp2/fuzz/corpus/decode_frame/streams_blocked +0 -0
  191. data/ext/ngtcp2/fuzz/corpus/ksl/random +0 -0
  192. data/ext/ngtcp2/fuzz/decode_frame.cc +25 -0
  193. data/ext/ngtcp2/fuzz/ksl.cc +77 -0
  194. data/ext/ngtcp2/interop/Dockerfile +39 -0
  195. data/ext/ngtcp2/interop/run_endpoint.sh +93 -0
  196. data/ext/ngtcp2/lib/CMakeLists.txt +110 -0
  197. data/ext/ngtcp2/lib/Makefile.am +122 -0
  198. data/ext/ngtcp2/lib/includes/CMakeLists.txt +4 -0
  199. data/ext/ngtcp2/lib/includes/Makefile.am +25 -0
  200. data/ext/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +5843 -0
  201. data/ext/ngtcp2/lib/includes/ngtcp2/version.h.in +51 -0
  202. data/ext/ngtcp2/lib/libngtcp2.pc.in +33 -0
  203. data/ext/ngtcp2/lib/ngtcp2_acktr.c +335 -0
  204. data/ext/ngtcp2/lib/ngtcp2_acktr.h +221 -0
  205. data/ext/ngtcp2/lib/ngtcp2_addr.c +117 -0
  206. data/ext/ngtcp2/lib/ngtcp2_addr.h +69 -0
  207. data/ext/ngtcp2/lib/ngtcp2_balloc.c +90 -0
  208. data/ext/ngtcp2/lib/ngtcp2_balloc.h +91 -0
  209. data/ext/ngtcp2/lib/ngtcp2_bbr.c +693 -0
  210. data/ext/ngtcp2/lib/ngtcp2_bbr.h +157 -0
  211. data/ext/ngtcp2/lib/ngtcp2_bbr2.c +1490 -0
  212. data/ext/ngtcp2/lib/ngtcp2_bbr2.h +149 -0
  213. data/ext/ngtcp2/lib/ngtcp2_buf.c +56 -0
  214. data/ext/ngtcp2/lib/ngtcp2_buf.h +108 -0
  215. data/ext/ngtcp2/lib/ngtcp2_cc.c +616 -0
  216. data/ext/ngtcp2/lib/ngtcp2_cc.h +422 -0
  217. data/ext/ngtcp2/lib/ngtcp2_cid.c +147 -0
  218. data/ext/ngtcp2/lib/ngtcp2_cid.h +175 -0
  219. data/ext/ngtcp2/lib/ngtcp2_conn.c +13731 -0
  220. data/ext/ngtcp2/lib/ngtcp2_conn.h +1119 -0
  221. data/ext/ngtcp2/lib/ngtcp2_conn_stat.h +131 -0
  222. data/ext/ngtcp2/lib/ngtcp2_conv.c +291 -0
  223. data/ext/ngtcp2/lib/ngtcp2_conv.h +208 -0
  224. data/ext/ngtcp2/lib/ngtcp2_crypto.c +895 -0
  225. data/ext/ngtcp2/lib/ngtcp2_crypto.h +148 -0
  226. data/ext/ngtcp2/lib/ngtcp2_err.c +154 -0
  227. data/ext/ngtcp2/lib/ngtcp2_err.h +34 -0
  228. data/ext/ngtcp2/lib/ngtcp2_gaptr.c +167 -0
  229. data/ext/ngtcp2/lib/ngtcp2_gaptr.h +98 -0
  230. data/ext/ngtcp2/lib/ngtcp2_idtr.c +79 -0
  231. data/ext/ngtcp2/lib/ngtcp2_idtr.h +89 -0
  232. data/ext/ngtcp2/lib/ngtcp2_ksl.c +819 -0
  233. data/ext/ngtcp2/lib/ngtcp2_ksl.h +345 -0
  234. data/ext/ngtcp2/lib/ngtcp2_log.c +822 -0
  235. data/ext/ngtcp2/lib/ngtcp2_log.h +123 -0
  236. data/ext/ngtcp2/lib/ngtcp2_macro.h +58 -0
  237. data/ext/ngtcp2/lib/ngtcp2_map.c +336 -0
  238. data/ext/ngtcp2/lib/ngtcp2_map.h +136 -0
  239. data/ext/ngtcp2/lib/ngtcp2_mem.c +113 -0
  240. data/ext/ngtcp2/lib/ngtcp2_mem.h +72 -0
  241. data/ext/ngtcp2/lib/ngtcp2_net.h +136 -0
  242. data/ext/ngtcp2/lib/ngtcp2_objalloc.c +40 -0
  243. data/ext/ngtcp2/lib/ngtcp2_objalloc.h +140 -0
  244. data/ext/ngtcp2/lib/ngtcp2_opl.c +46 -0
  245. data/ext/ngtcp2/lib/ngtcp2_opl.h +65 -0
  246. data/ext/ngtcp2/lib/ngtcp2_path.c +77 -0
  247. data/ext/ngtcp2/lib/ngtcp2_path.h +49 -0
  248. data/ext/ngtcp2/lib/ngtcp2_pkt.c +2527 -0
  249. data/ext/ngtcp2/lib/ngtcp2_pkt.h +1235 -0
  250. data/ext/ngtcp2/lib/ngtcp2_pmtud.c +160 -0
  251. data/ext/ngtcp2/lib/ngtcp2_pmtud.h +123 -0
  252. data/ext/ngtcp2/lib/ngtcp2_ppe.c +230 -0
  253. data/ext/ngtcp2/lib/ngtcp2_ppe.h +153 -0
  254. data/ext/ngtcp2/lib/ngtcp2_pq.c +164 -0
  255. data/ext/ngtcp2/lib/ngtcp2_pq.h +126 -0
  256. data/ext/ngtcp2/lib/ngtcp2_pv.c +172 -0
  257. data/ext/ngtcp2/lib/ngtcp2_pv.h +194 -0
  258. data/ext/ngtcp2/lib/ngtcp2_qlog.c +1219 -0
  259. data/ext/ngtcp2/lib/ngtcp2_qlog.h +161 -0
  260. data/ext/ngtcp2/lib/ngtcp2_range.c +61 -0
  261. data/ext/ngtcp2/lib/ngtcp2_range.h +80 -0
  262. data/ext/ngtcp2/lib/ngtcp2_rcvry.h +40 -0
  263. data/ext/ngtcp2/lib/ngtcp2_ringbuf.c +121 -0
  264. data/ext/ngtcp2/lib/ngtcp2_ringbuf.h +132 -0
  265. data/ext/ngtcp2/lib/ngtcp2_rob.c +319 -0
  266. data/ext/ngtcp2/lib/ngtcp2_rob.h +197 -0
  267. data/ext/ngtcp2/lib/ngtcp2_rst.c +138 -0
  268. data/ext/ngtcp2/lib/ngtcp2_rst.h +86 -0
  269. data/ext/ngtcp2/lib/ngtcp2_rtb.c +1676 -0
  270. data/ext/ngtcp2/lib/ngtcp2_rtb.h +468 -0
  271. data/ext/ngtcp2/lib/ngtcp2_str.c +233 -0
  272. data/ext/ngtcp2/lib/ngtcp2_str.h +94 -0
  273. data/ext/ngtcp2/lib/ngtcp2_strm.c +698 -0
  274. data/ext/ngtcp2/lib/ngtcp2_strm.h +310 -0
  275. data/ext/ngtcp2/lib/ngtcp2_unreachable.c +71 -0
  276. data/ext/ngtcp2/lib/ngtcp2_unreachable.h +46 -0
  277. data/ext/ngtcp2/lib/ngtcp2_vec.c +243 -0
  278. data/ext/ngtcp2/lib/ngtcp2_vec.h +120 -0
  279. data/ext/ngtcp2/lib/ngtcp2_version.c +39 -0
  280. data/ext/ngtcp2/lib/ngtcp2_window_filter.c +99 -0
  281. data/ext/ngtcp2/lib/ngtcp2_window_filter.h +65 -0
  282. data/ext/ngtcp2/m4/ax_check_compile_flag.m4 +74 -0
  283. data/ext/ngtcp2/m4/ax_cxx_compile_stdcxx.m4 +1009 -0
  284. data/ext/ngtcp2/tests/CMakeLists.txt +68 -0
  285. data/ext/ngtcp2/tests/Makefile.am +94 -0
  286. data/ext/ngtcp2/tests/main.c +358 -0
  287. data/ext/ngtcp2/tests/ngtcp2_acktr_test.c +367 -0
  288. data/ext/ngtcp2/tests/ngtcp2_acktr_test.h +37 -0
  289. data/ext/ngtcp2/tests/ngtcp2_conn_test.c +9821 -0
  290. data/ext/ngtcp2/tests/ngtcp2_conn_test.h +104 -0
  291. data/ext/ngtcp2/tests/ngtcp2_conv_test.c +430 -0
  292. data/ext/ngtcp2/tests/ngtcp2_conv_test.h +46 -0
  293. data/ext/ngtcp2/tests/ngtcp2_crypto_test.c +667 -0
  294. data/ext/ngtcp2/tests/ngtcp2_crypto_test.h +35 -0
  295. data/ext/ngtcp2/tests/ngtcp2_gaptr_test.c +127 -0
  296. data/ext/ngtcp2/tests/ngtcp2_gaptr_test.h +36 -0
  297. data/ext/ngtcp2/tests/ngtcp2_idtr_test.c +79 -0
  298. data/ext/ngtcp2/tests/ngtcp2_idtr_test.h +34 -0
  299. data/ext/ngtcp2/tests/ngtcp2_ksl_test.c +502 -0
  300. data/ext/ngtcp2/tests/ngtcp2_ksl_test.h +39 -0
  301. data/ext/ngtcp2/tests/ngtcp2_map_test.c +206 -0
  302. data/ext/ngtcp2/tests/ngtcp2_map_test.h +38 -0
  303. data/ext/ngtcp2/tests/ngtcp2_pkt_test.c +1645 -0
  304. data/ext/ngtcp2/tests/ngtcp2_pkt_test.h +68 -0
  305. data/ext/ngtcp2/tests/ngtcp2_pmtud_test.c +153 -0
  306. data/ext/ngtcp2/tests/ngtcp2_pmtud_test.h +34 -0
  307. data/ext/ngtcp2/tests/ngtcp2_pv_test.c +129 -0
  308. data/ext/ngtcp2/tests/ngtcp2_pv_test.h +35 -0
  309. data/ext/ngtcp2/tests/ngtcp2_range_test.c +105 -0
  310. data/ext/ngtcp2/tests/ngtcp2_range_test.h +36 -0
  311. data/ext/ngtcp2/tests/ngtcp2_ringbuf_test.c +91 -0
  312. data/ext/ngtcp2/tests/ngtcp2_ringbuf_test.h +35 -0
  313. data/ext/ngtcp2/tests/ngtcp2_rob_test.c +552 -0
  314. data/ext/ngtcp2/tests/ngtcp2_rob_test.h +37 -0
  315. data/ext/ngtcp2/tests/ngtcp2_rtb_test.c +470 -0
  316. data/ext/ngtcp2/tests/ngtcp2_rtb_test.h +38 -0
  317. data/ext/ngtcp2/tests/ngtcp2_str_test.c +96 -0
  318. data/ext/ngtcp2/tests/ngtcp2_str_test.h +36 -0
  319. data/ext/ngtcp2/tests/ngtcp2_strm_test.c +575 -0
  320. data/ext/ngtcp2/tests/ngtcp2_strm_test.h +36 -0
  321. data/ext/ngtcp2/tests/ngtcp2_test_helper.c +404 -0
  322. data/ext/ngtcp2/tests/ngtcp2_test_helper.h +191 -0
  323. data/ext/ngtcp2/tests/ngtcp2_vec_test.c +426 -0
  324. data/ext/ngtcp2/tests/ngtcp2_vec_test.h +36 -0
  325. data/ext/ngtcp2/third-party/CMakeLists.txt +34 -0
  326. data/ext/ngtcp2/third-party/Makefile.am +31 -0
  327. data/ext/ngtcp2/third-party/http-parser/AUTHORS +68 -0
  328. data/ext/ngtcp2/third-party/http-parser/LICENSE-MIT +23 -0
  329. data/ext/ngtcp2/third-party/http-parser/Makefile +157 -0
  330. data/ext/ngtcp2/third-party/http-parser/README.md +246 -0
  331. data/ext/ngtcp2/third-party/http-parser/bench.c +111 -0
  332. data/ext/ngtcp2/third-party/http-parser/contrib/parsertrace.c +160 -0
  333. data/ext/ngtcp2/third-party/http-parser/contrib/url_parser.c +47 -0
  334. data/ext/ngtcp2/third-party/http-parser/http_parser.c +2419 -0
  335. data/ext/ngtcp2/third-party/http-parser/http_parser.gyp +111 -0
  336. data/ext/ngtcp2/third-party/http-parser/http_parser.h +431 -0
  337. data/ext/ngtcp2/third-party/http-parser/test.c +4411 -0
  338. data/lib/protocol/quic/version.rb +10 -0
  339. data/lib/protocol/quic.rb +9 -0
  340. data/license.md +21 -0
  341. data.tar.gz.sig +1 -0
  342. metadata +424 -0
  343. metadata.gz.sig +1 -0
@@ -0,0 +1,3024 @@
1
+ /*
2
+ * ngtcp2
3
+ *
4
+ * Copyright (c) 2017 ngtcp2 contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining
7
+ * a copy of this software and associated documentation files (the
8
+ * "Software"), to deal in the Software without restriction, including
9
+ * without limitation the rights to use, copy, modify, merge, publish,
10
+ * distribute, sublicense, and/or sell copies of the Software, and to
11
+ * permit persons to whom the Software is furnished to do so, subject to
12
+ * the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be
15
+ * included in all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ */
25
+ #include <chrono>
26
+ #include <cstdlib>
27
+ #include <cassert>
28
+ #include <cstring>
29
+ #include <iostream>
30
+ #include <algorithm>
31
+ #include <memory>
32
+ #include <fstream>
33
+ #include <iomanip>
34
+
35
+ #include <unistd.h>
36
+ #include <getopt.h>
37
+ #include <sys/types.h>
38
+ #include <sys/socket.h>
39
+ #include <netdb.h>
40
+ #include <sys/stat.h>
41
+ #include <fcntl.h>
42
+ #include <sys/mman.h>
43
+ #include <netinet/udp.h>
44
+ #include <net/if.h>
45
+
46
+ #include <http-parser/http_parser.h>
47
+
48
+ #include "h09server.h"
49
+ #include "network.h"
50
+ #include "debug.h"
51
+ #include "util.h"
52
+ #include "shared.h"
53
+ #include "http.h"
54
+ #include "template.h"
55
+
56
+ using namespace ngtcp2;
57
+ using namespace std::literals;
58
+
59
+ namespace {
60
+ constexpr size_t NGTCP2_SV_SCIDLEN = 18;
61
+ } // namespace
62
+
63
+ namespace {
64
+ constexpr size_t max_preferred_versionslen = 4;
65
+ } // namespace
66
+
67
+ namespace {
68
+ auto randgen = util::make_mt19937();
69
+ } // namespace
70
+
71
+ Config config{};
72
+
73
+ Stream::Stream(int64_t stream_id, Handler *handler)
74
+ : stream_id(stream_id), handler(handler), eos(false) {
75
+ nghttp3_buf_init(&respbuf);
76
+ htp.data = this;
77
+ http_parser_init(&htp, HTTP_REQUEST);
78
+ }
79
+
80
+ namespace {
81
+ constexpr auto NGTCP2_SERVER = "ngtcp2 server"sv;
82
+ } // namespace
83
+
84
+ namespace {
85
+ std::string make_status_body(unsigned int status_code) {
86
+ auto status_string = util::format_uint(status_code);
87
+ auto reason_phrase = http::get_reason_phrase(status_code);
88
+
89
+ std::string body;
90
+ body = "<html><head><title>";
91
+ body += status_string;
92
+ body += ' ';
93
+ body += reason_phrase;
94
+ body += "</title></head><body><h1>";
95
+ body += status_string;
96
+ body += ' ';
97
+ body += reason_phrase;
98
+ body += "</h1><hr><address>";
99
+ body += NGTCP2_SERVER;
100
+ body += " at port ";
101
+ body += util::format_uint(config.port);
102
+ body += "</address>";
103
+ body += "</body></html>";
104
+ return body;
105
+ }
106
+ } // namespace
107
+
108
+ struct Request {
109
+ std::string path;
110
+ };
111
+
112
+ namespace {
113
+ Request request_path(const std::string_view &uri) {
114
+ http_parser_url u;
115
+ Request req;
116
+
117
+ http_parser_url_init(&u);
118
+
119
+ if (auto rv = http_parser_parse_url(uri.data(), uri.size(),
120
+ /* is_connect = */ 0, &u);
121
+ rv != 0) {
122
+ return req;
123
+ }
124
+
125
+ if (u.field_set & (1 << UF_PATH)) {
126
+ req.path = std::string(uri.data() + u.field_data[UF_PATH].off,
127
+ u.field_data[UF_PATH].len);
128
+ if (req.path.find('%') != std::string::npos) {
129
+ req.path = util::percent_decode(std::begin(req.path), std::end(req.path));
130
+ }
131
+ if (!req.path.empty() && req.path.back() == '/') {
132
+ req.path += "index.html";
133
+ }
134
+ } else {
135
+ req.path = "/index.html";
136
+ }
137
+
138
+ req.path = util::normalize_path(req.path);
139
+ if (req.path == "/") {
140
+ req.path = "/index.html";
141
+ }
142
+
143
+ return req;
144
+ }
145
+ } // namespace
146
+
147
+ enum FileEntryFlag {
148
+ FILE_ENTRY_TYPE_DIR = 0x1,
149
+ };
150
+
151
+ struct FileEntry {
152
+ uint64_t len;
153
+ void *map;
154
+ int fd;
155
+ uint8_t flags;
156
+ };
157
+
158
+ namespace {
159
+ std::unordered_map<std::string, FileEntry> file_cache;
160
+ } // namespace
161
+
162
+ std::pair<FileEntry, int> Stream::open_file(const std::string &path) {
163
+ auto it = file_cache.find(path);
164
+ if (it != std::end(file_cache)) {
165
+ return {(*it).second, 0};
166
+ }
167
+
168
+ auto fd = open(path.c_str(), O_RDONLY);
169
+ if (fd == -1) {
170
+ return {{}, -1};
171
+ }
172
+
173
+ struct stat st {};
174
+ if (fstat(fd, &st) != 0) {
175
+ close(fd);
176
+ return {{}, -1};
177
+ }
178
+
179
+ FileEntry fe{};
180
+ if (st.st_mode & S_IFDIR) {
181
+ fe.flags |= FILE_ENTRY_TYPE_DIR;
182
+ fe.fd = -1;
183
+ close(fd);
184
+ } else {
185
+ fe.fd = fd;
186
+ fe.len = st.st_size;
187
+ fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0);
188
+ if (fe.map == MAP_FAILED) {
189
+ std::cerr << "mmap: " << strerror(errno) << std::endl;
190
+ close(fd);
191
+ return {{}, -1};
192
+ }
193
+ }
194
+
195
+ file_cache.emplace(path, fe);
196
+
197
+ return {std::move(fe), 0};
198
+ }
199
+
200
+ void Stream::map_file(const FileEntry &fe) {
201
+ respbuf.begin = respbuf.pos = static_cast<uint8_t *>(fe.map);
202
+ respbuf.end = respbuf.last = respbuf.begin + fe.len;
203
+ }
204
+
205
+ int Stream::send_status_response(unsigned int status_code) {
206
+ status_resp_body = make_status_body(status_code);
207
+
208
+ respbuf.begin = respbuf.pos =
209
+ reinterpret_cast<uint8_t *>(status_resp_body.data());
210
+ respbuf.end = respbuf.last = respbuf.begin + status_resp_body.size();
211
+
212
+ handler->add_sendq(this);
213
+ handler->shutdown_read(stream_id, 0);
214
+
215
+ return 0;
216
+ }
217
+
218
+ int Stream::start_response() {
219
+ if (uri.empty()) {
220
+ return send_status_response(400);
221
+ }
222
+
223
+ auto req = request_path(uri);
224
+ if (req.path.empty()) {
225
+ return send_status_response(400);
226
+ }
227
+
228
+ auto path = config.htdocs + req.path;
229
+ auto [fe, rv] = open_file(path);
230
+ if (rv != 0) {
231
+ send_status_response(404);
232
+ return 0;
233
+ }
234
+
235
+ if (fe.flags & FILE_ENTRY_TYPE_DIR) {
236
+ send_status_response(308);
237
+ return 0;
238
+ }
239
+
240
+ map_file(fe);
241
+
242
+ if (!config.quiet) {
243
+ std::array<nghttp3_nv, 1> nva{
244
+ util::make_nv_nn(":status", "200"),
245
+ };
246
+
247
+ debug::print_http_response_headers(stream_id, nva.data(), nva.size());
248
+ }
249
+
250
+ handler->add_sendq(this);
251
+
252
+ return 0;
253
+ }
254
+
255
+ namespace {
256
+ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
257
+ auto h = static_cast<Handler *>(w->data);
258
+ auto s = h->server();
259
+
260
+ switch (h->on_write()) {
261
+ case 0:
262
+ case NETWORK_ERR_CLOSE_WAIT:
263
+ return;
264
+ default:
265
+ s->remove(h);
266
+ }
267
+ }
268
+ } // namespace
269
+
270
+ namespace {
271
+ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) {
272
+ auto h = static_cast<Handler *>(w->data);
273
+ auto s = h->server();
274
+ auto conn = h->conn();
275
+
276
+ if (ngtcp2_conn_is_in_closing_period(conn)) {
277
+ if (!config.quiet) {
278
+ std::cerr << "Closing Period is over" << std::endl;
279
+ }
280
+
281
+ s->remove(h);
282
+ return;
283
+ }
284
+ if (ngtcp2_conn_is_in_draining_period(conn)) {
285
+ if (!config.quiet) {
286
+ std::cerr << "Draining Period is over" << std::endl;
287
+ }
288
+
289
+ s->remove(h);
290
+ return;
291
+ }
292
+
293
+ assert(0);
294
+ }
295
+ } // namespace
296
+
297
+ namespace {
298
+ void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
299
+ int rv;
300
+
301
+ auto h = static_cast<Handler *>(w->data);
302
+ auto s = h->server();
303
+
304
+ if (!config.quiet) {
305
+ std::cerr << "Timer expired" << std::endl;
306
+ }
307
+
308
+ rv = h->handle_expiry();
309
+ if (rv != 0) {
310
+ goto fail;
311
+ }
312
+
313
+ rv = h->on_write();
314
+ if (rv != 0) {
315
+ goto fail;
316
+ }
317
+
318
+ return;
319
+
320
+ fail:
321
+ switch (rv) {
322
+ case NETWORK_ERR_CLOSE_WAIT:
323
+ ev_timer_stop(loop, w);
324
+ return;
325
+ default:
326
+ s->remove(h);
327
+ return;
328
+ }
329
+ }
330
+ } // namespace
331
+
332
+ Handler::Handler(struct ev_loop *loop, Server *server)
333
+ : loop_(loop),
334
+ server_(server),
335
+ qlog_(nullptr),
336
+ scid_{},
337
+ nkey_update_(0),
338
+ no_gso_{
339
+ #ifdef UDP_SEGMENT
340
+ false
341
+ #else // !UDP_SEGMENT
342
+ true
343
+ #endif // !UDP_SEGMENT
344
+ },
345
+ tx_{
346
+ .data = std::unique_ptr<uint8_t[]>(new uint8_t[64_k]),
347
+ } {
348
+ ev_io_init(&wev_, writecb, 0, EV_WRITE);
349
+ wev_.data = this;
350
+ ev_timer_init(&timer_, timeoutcb, 0., 0.);
351
+ timer_.data = this;
352
+ }
353
+
354
+ Handler::~Handler() {
355
+ if (!config.quiet) {
356
+ std::cerr << scid_ << " Closing QUIC connection " << std::endl;
357
+ }
358
+
359
+ ev_timer_stop(loop_, &timer_);
360
+ ev_io_stop(loop_, &wev_);
361
+
362
+ if (qlog_) {
363
+ fclose(qlog_);
364
+ }
365
+ }
366
+
367
+ namespace {
368
+ int handshake_completed(ngtcp2_conn *conn, void *user_data) {
369
+ auto h = static_cast<Handler *>(user_data);
370
+
371
+ if (!config.quiet) {
372
+ debug::handshake_completed(conn, user_data);
373
+ }
374
+
375
+ if (h->handshake_completed() != 0) {
376
+ return NGTCP2_ERR_CALLBACK_FAILURE;
377
+ }
378
+
379
+ return 0;
380
+ }
381
+ } // namespace
382
+
383
+ int Handler::handshake_completed() {
384
+ if (!config.quiet) {
385
+ std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name()
386
+ << std::endl;
387
+ std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn()
388
+ << std::endl;
389
+ }
390
+
391
+ std::array<uint8_t, NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN> token;
392
+
393
+ auto path = ngtcp2_conn_get_path(conn_);
394
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
395
+ std::chrono::system_clock::now().time_since_epoch())
396
+ .count();
397
+
398
+ auto tokenlen = ngtcp2_crypto_generate_regular_token(
399
+ token.data(), config.static_secret.data(), config.static_secret.size(),
400
+ path->remote.addr, path->remote.addrlen, t);
401
+ if (tokenlen < 0) {
402
+ if (!config.quiet) {
403
+ std::cerr << "Unable to generate token" << std::endl;
404
+ }
405
+ return 0;
406
+ }
407
+
408
+ if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), tokenlen);
409
+ rv != 0) {
410
+ if (!config.quiet) {
411
+ std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
412
+ << std::endl;
413
+ }
414
+ return -1;
415
+ }
416
+
417
+ return 0;
418
+ }
419
+
420
+ namespace {
421
+ int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
422
+ const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) {
423
+ if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) {
424
+ return NGTCP2_ERR_CALLBACK_FAILURE;
425
+ }
426
+
427
+ if (!config.quiet && config.show_secret) {
428
+ debug::print_hp_mask(dest, NGTCP2_HP_MASKLEN, sample, NGTCP2_HP_SAMPLELEN);
429
+ }
430
+
431
+ return 0;
432
+ }
433
+ } // namespace
434
+
435
+ namespace {
436
+ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
437
+ uint64_t offset, const uint8_t *data, size_t datalen,
438
+ void *user_data) {
439
+ if (!config.quiet && !config.no_quic_dump) {
440
+ debug::print_crypto_data(crypto_level, data, datalen);
441
+ }
442
+
443
+ return ngtcp2_crypto_recv_crypto_data_cb(conn, crypto_level, offset, data,
444
+ datalen, user_data);
445
+ }
446
+ } // namespace
447
+
448
+ namespace {
449
+ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
450
+ uint64_t offset, const uint8_t *data, size_t datalen,
451
+ void *user_data, void *stream_user_data) {
452
+ auto h = static_cast<Handler *>(user_data);
453
+
454
+ if (h->recv_stream_data(flags, stream_id, data, datalen) != 0) {
455
+ return NGTCP2_ERR_CALLBACK_FAILURE;
456
+ }
457
+
458
+ return 0;
459
+ }
460
+ } // namespace
461
+
462
+ namespace {
463
+ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id,
464
+ uint64_t offset, uint64_t datalen, void *user_data,
465
+ void *stream_user_data) {
466
+ auto h = static_cast<Handler *>(user_data);
467
+ if (h->acked_stream_data_offset(stream_id, offset, datalen) != 0) {
468
+ return NGTCP2_ERR_CALLBACK_FAILURE;
469
+ }
470
+ return 0;
471
+ }
472
+ } // namespace
473
+
474
+ int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t offset,
475
+ uint64_t datalen) {
476
+ auto it = streams_.find(stream_id);
477
+ assert(it != std::end(streams_));
478
+ auto &stream = (*it).second;
479
+ (void)stream;
480
+
481
+ assert(static_cast<uint64_t>(stream->respbuf.end - stream->respbuf.begin) >=
482
+ offset + datalen);
483
+
484
+ return 0;
485
+ }
486
+
487
+ namespace {
488
+ int stream_open(ngtcp2_conn *conn, int64_t stream_id, void *user_data) {
489
+ auto h = static_cast<Handler *>(user_data);
490
+ h->on_stream_open(stream_id);
491
+ return 0;
492
+ }
493
+ } // namespace
494
+
495
+ void Handler::on_stream_open(int64_t stream_id) {
496
+ if (!ngtcp2_is_bidi_stream(stream_id)) {
497
+ return;
498
+ }
499
+ auto it = streams_.find(stream_id);
500
+ (void)it;
501
+ assert(it == std::end(streams_));
502
+ streams_.emplace(stream_id, std::make_unique<Stream>(stream_id, this));
503
+ }
504
+
505
+ namespace {
506
+ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
507
+ uint64_t app_error_code, void *user_data,
508
+ void *stream_user_data) {
509
+ auto h = static_cast<Handler *>(user_data);
510
+ if (h->on_stream_close(stream_id, app_error_code) != 0) {
511
+ return NGTCP2_ERR_CALLBACK_FAILURE;
512
+ }
513
+ return 0;
514
+ }
515
+ } // namespace
516
+
517
+ namespace {
518
+ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) {
519
+ auto dis = std::uniform_int_distribution<uint8_t>();
520
+ std::generate(dest, dest + destlen, [&dis]() { return dis(randgen); });
521
+ }
522
+ } // namespace
523
+
524
+ namespace {
525
+ int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
526
+ size_t cidlen, void *user_data) {
527
+ if (util::generate_secure_random(cid->data, cidlen) != 0) {
528
+ return NGTCP2_ERR_CALLBACK_FAILURE;
529
+ }
530
+
531
+ cid->datalen = cidlen;
532
+ if (ngtcp2_crypto_generate_stateless_reset_token(
533
+ token, config.static_secret.data(), config.static_secret.size(),
534
+ cid) != 0) {
535
+ return NGTCP2_ERR_CALLBACK_FAILURE;
536
+ }
537
+
538
+ auto h = static_cast<Handler *>(user_data);
539
+ h->server()->associate_cid(cid, h);
540
+
541
+ return 0;
542
+ }
543
+ } // namespace
544
+
545
+ namespace {
546
+ int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid,
547
+ void *user_data) {
548
+ auto h = static_cast<Handler *>(user_data);
549
+ h->server()->dissociate_cid(cid);
550
+ return 0;
551
+ }
552
+ } // namespace
553
+
554
+ namespace {
555
+ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
556
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
557
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
558
+ const uint8_t *current_rx_secret,
559
+ const uint8_t *current_tx_secret, size_t secretlen,
560
+ void *user_data) {
561
+ auto h = static_cast<Handler *>(user_data);
562
+ if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx,
563
+ tx_iv, current_rx_secret, current_tx_secret,
564
+ secretlen) != 0) {
565
+ return NGTCP2_ERR_CALLBACK_FAILURE;
566
+ }
567
+ return 0;
568
+ }
569
+ } // namespace
570
+
571
+ namespace {
572
+ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
573
+ ngtcp2_path_validation_result res, void *user_data) {
574
+ if (!config.quiet) {
575
+ debug::path_validation(path, res);
576
+ }
577
+ return 0;
578
+ }
579
+ } // namespace
580
+
581
+ namespace {
582
+ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id,
583
+ uint64_t max_data, void *user_data,
584
+ void *stream_user_data) {
585
+ auto h = static_cast<Handler *>(user_data);
586
+ if (h->extend_max_stream_data(stream_id, max_data) != 0) {
587
+ return NGTCP2_ERR_CALLBACK_FAILURE;
588
+ }
589
+ return 0;
590
+ }
591
+ } // namespace
592
+
593
+ int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) {
594
+ auto it = streams_.find(stream_id);
595
+ assert(it != std::end(streams_));
596
+ auto &stream = (*it).second;
597
+
598
+ if (nghttp3_buf_len(&stream->respbuf)) {
599
+ sendq_.emplace(stream.get());
600
+ }
601
+
602
+ return 0;
603
+ }
604
+
605
+ namespace {
606
+ void write_qlog(void *user_data, uint32_t flags, const void *data,
607
+ size_t datalen) {
608
+ auto h = static_cast<Handler *>(user_data);
609
+ h->write_qlog(data, datalen);
610
+ }
611
+ } // namespace
612
+
613
+ void Handler::write_qlog(const void *data, size_t datalen) {
614
+ assert(qlog_);
615
+ fwrite(data, 1, datalen, qlog_);
616
+ }
617
+
618
+ int Handler::init(const Endpoint &ep, const Address &local_addr,
619
+ const sockaddr *sa, socklen_t salen, const ngtcp2_cid *dcid,
620
+ const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
621
+ const uint8_t *token, size_t tokenlen, uint32_t version,
622
+ TLSServerContext &tls_ctx) {
623
+ auto callbacks = ngtcp2_callbacks{
624
+ nullptr, // client_initial
625
+ ngtcp2_crypto_recv_client_initial_cb,
626
+ ::recv_crypto_data,
627
+ ::handshake_completed,
628
+ nullptr, // recv_version_negotiation
629
+ ngtcp2_crypto_encrypt_cb,
630
+ ngtcp2_crypto_decrypt_cb,
631
+ do_hp_mask,
632
+ ::recv_stream_data,
633
+ ::acked_stream_data_offset,
634
+ stream_open,
635
+ stream_close,
636
+ nullptr, // recv_stateless_reset
637
+ nullptr, // recv_retry
638
+ nullptr, // extend_max_streams_bidi
639
+ nullptr, // extend_max_streams_uni
640
+ rand,
641
+ get_new_connection_id,
642
+ remove_connection_id,
643
+ ::update_key,
644
+ path_validation,
645
+ nullptr, // select_preferred_addr
646
+ nullptr, // stream_reset
647
+ nullptr, // extend_max_remote_streams_bidi
648
+ nullptr, // extend_max_remote_streams_uni
649
+ ::extend_max_stream_data,
650
+ nullptr, // dcid_status
651
+ nullptr, // handshake_confirmed
652
+ nullptr, // recv_new_token
653
+ ngtcp2_crypto_delete_crypto_aead_ctx_cb,
654
+ ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
655
+ nullptr, // recv_datagram
656
+ nullptr, // ack_datagram
657
+ nullptr, // lost_datagram
658
+ ngtcp2_crypto_get_path_challenge_data_cb,
659
+ nullptr, // stream_stop_sending
660
+ ngtcp2_crypto_version_negotiation_cb,
661
+ nullptr, // recv_rx_key
662
+ nullptr, // recv_tx_key
663
+ };
664
+
665
+ scid_.datalen = NGTCP2_SV_SCIDLEN;
666
+ if (util::generate_secure_random(scid_.data, scid_.datalen) != 0) {
667
+ std::cerr << "Could not generate connection ID" << std::endl;
668
+ return -1;
669
+ }
670
+
671
+ ngtcp2_settings settings;
672
+ ngtcp2_settings_default(&settings);
673
+ settings.log_printf = config.quiet ? nullptr : debug::log_printf;
674
+ settings.initial_ts = util::timestamp(loop_);
675
+ settings.token = token;
676
+ settings.tokenlen = tokenlen;
677
+ settings.cc_algo = config.cc_algo;
678
+ settings.initial_rtt = config.initial_rtt;
679
+ settings.max_window = config.max_window;
680
+ settings.max_stream_window = config.max_stream_window;
681
+ settings.handshake_timeout = config.handshake_timeout;
682
+ settings.no_pmtud = config.no_pmtud;
683
+ settings.ack_thresh = config.ack_thresh;
684
+ if (config.max_udp_payload_size) {
685
+ settings.max_tx_udp_payload_size = config.max_udp_payload_size;
686
+ settings.no_tx_udp_payload_size_shaping = 1;
687
+ }
688
+ if (!config.qlog_dir.empty()) {
689
+ auto path = std::string{config.qlog_dir};
690
+ path += '/';
691
+ path += util::format_hex(scid_.data, scid_.datalen);
692
+ path += ".sqlog";
693
+ qlog_ = fopen(path.c_str(), "w");
694
+ if (qlog_ == nullptr) {
695
+ std::cerr << "Could not open qlog file " << std::quoted(path) << ": "
696
+ << strerror(errno) << std::endl;
697
+ return -1;
698
+ }
699
+ settings.qlog.write = ::write_qlog;
700
+ settings.qlog.odcid = *scid;
701
+ }
702
+ if (!config.preferred_versions.empty()) {
703
+ settings.preferred_versions = config.preferred_versions.data();
704
+ settings.preferred_versionslen = config.preferred_versions.size();
705
+ }
706
+ if (!config.available_versions.empty()) {
707
+ settings.available_versions = config.available_versions.data();
708
+ settings.available_versionslen = config.available_versions.size();
709
+ }
710
+
711
+ ngtcp2_transport_params params;
712
+ ngtcp2_transport_params_default(&params);
713
+ params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local;
714
+ params.initial_max_stream_data_bidi_remote =
715
+ config.max_stream_data_bidi_remote;
716
+ params.initial_max_stream_data_uni = config.max_stream_data_uni;
717
+ params.initial_max_data = config.max_data;
718
+ params.initial_max_streams_bidi = config.max_streams_bidi;
719
+ params.initial_max_streams_uni = 0;
720
+ params.max_idle_timeout = config.timeout;
721
+ params.stateless_reset_token_present = 1;
722
+ params.active_connection_id_limit = 7;
723
+
724
+ if (ocid) {
725
+ params.original_dcid = *ocid;
726
+ params.retry_scid = *scid;
727
+ params.retry_scid_present = 1;
728
+ } else {
729
+ params.original_dcid = *scid;
730
+ }
731
+
732
+ if (util::generate_secure_random(params.stateless_reset_token,
733
+ sizeof(params.stateless_reset_token)) != 0) {
734
+ std::cerr << "Could not generate stateless reset token" << std::endl;
735
+ return -1;
736
+ }
737
+
738
+ if (config.preferred_ipv4_addr.len || config.preferred_ipv6_addr.len) {
739
+ params.preferred_address_present = 1;
740
+
741
+ if (config.preferred_ipv4_addr.len) {
742
+ params.preferred_address.ipv4 = config.preferred_ipv4_addr.su.in;
743
+ params.preferred_address.ipv4_present = 1;
744
+ }
745
+
746
+ if (config.preferred_ipv6_addr.len) {
747
+ params.preferred_address.ipv6 = config.preferred_ipv6_addr.su.in6;
748
+ params.preferred_address.ipv6_present = 1;
749
+ }
750
+
751
+ auto &token = params.preferred_address.stateless_reset_token;
752
+ if (util::generate_secure_random(token, sizeof(token)) != 0) {
753
+ std::cerr << "Could not generate preferred address stateless reset token"
754
+ << std::endl;
755
+ return -1;
756
+ }
757
+
758
+ params.preferred_address.cid.datalen = NGTCP2_SV_SCIDLEN;
759
+ if (util::generate_secure_random(params.preferred_address.cid.data,
760
+ params.preferred_address.cid.datalen) !=
761
+ 0) {
762
+ std::cerr << "Could not generate preferred address connection ID"
763
+ << std::endl;
764
+ return -1;
765
+ }
766
+ }
767
+
768
+ auto path = ngtcp2_path{
769
+ {
770
+ const_cast<sockaddr *>(&local_addr.su.sa),
771
+ local_addr.len,
772
+ },
773
+ {
774
+ const_cast<sockaddr *>(sa),
775
+ salen,
776
+ },
777
+ const_cast<Endpoint *>(&ep),
778
+ };
779
+ if (auto rv =
780
+ ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version,
781
+ &callbacks, &settings, &params, nullptr, this);
782
+ rv != 0) {
783
+ std::cerr << "ngtcp2_conn_server_new: " << ngtcp2_strerror(rv) << std::endl;
784
+ return -1;
785
+ }
786
+
787
+ if (tls_session_.init(tls_ctx, this) != 0) {
788
+ return -1;
789
+ }
790
+
791
+ tls_session_.enable_keylog();
792
+
793
+ ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle());
794
+
795
+ ev_io_set(&wev_, ep.fd, EV_WRITE);
796
+
797
+ return 0;
798
+ }
799
+
800
+ int Handler::feed_data(const Endpoint &ep, const Address &local_addr,
801
+ const sockaddr *sa, socklen_t salen,
802
+ const ngtcp2_pkt_info *pi, uint8_t *data,
803
+ size_t datalen) {
804
+ auto path = ngtcp2_path{
805
+ {
806
+ const_cast<sockaddr *>(&local_addr.su.sa),
807
+ local_addr.len,
808
+ },
809
+ {
810
+ const_cast<sockaddr *>(sa),
811
+ salen,
812
+ },
813
+ const_cast<Endpoint *>(&ep),
814
+ };
815
+
816
+ if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data, datalen,
817
+ util::timestamp(loop_));
818
+ rv != 0) {
819
+ std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
820
+ switch (rv) {
821
+ case NGTCP2_ERR_DRAINING:
822
+ start_draining_period();
823
+ return NETWORK_ERR_CLOSE_WAIT;
824
+ case NGTCP2_ERR_RETRY:
825
+ return NETWORK_ERR_RETRY;
826
+ case NGTCP2_ERR_DROP_CONN:
827
+ return NETWORK_ERR_DROP_CONN;
828
+ case NGTCP2_ERR_CRYPTO:
829
+ if (!last_error_.error_code) {
830
+ ngtcp2_connection_close_error_set_transport_error_tls_alert(
831
+ &last_error_, ngtcp2_conn_get_tls_alert(conn_), nullptr, 0);
832
+ }
833
+ break;
834
+ default:
835
+ if (!last_error_.error_code) {
836
+ ngtcp2_connection_close_error_set_transport_error_liberr(
837
+ &last_error_, rv, nullptr, 0);
838
+ }
839
+ }
840
+ return handle_error();
841
+ }
842
+
843
+ return 0;
844
+ }
845
+
846
+ int Handler::on_read(const Endpoint &ep, const Address &local_addr,
847
+ const sockaddr *sa, socklen_t salen,
848
+ const ngtcp2_pkt_info *pi, uint8_t *data, size_t datalen) {
849
+ if (auto rv = feed_data(ep, local_addr, sa, salen, pi, data, datalen);
850
+ rv != 0) {
851
+ return rv;
852
+ }
853
+
854
+ update_timer();
855
+
856
+ return 0;
857
+ }
858
+
859
+ int Handler::handle_expiry() {
860
+ auto now = util::timestamp(loop_);
861
+ if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) {
862
+ std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv)
863
+ << std::endl;
864
+ ngtcp2_connection_close_error_set_transport_error_liberr(&last_error_, rv,
865
+ nullptr, 0);
866
+ return handle_error();
867
+ }
868
+
869
+ return 0;
870
+ }
871
+
872
+ int Handler::on_write() {
873
+ if (ngtcp2_conn_is_in_closing_period(conn_) ||
874
+ ngtcp2_conn_is_in_draining_period(conn_)) {
875
+ return 0;
876
+ }
877
+
878
+ if (tx_.send_blocked) {
879
+ if (auto rv = send_blocked_packet(); rv != 0) {
880
+ return rv;
881
+ }
882
+
883
+ if (tx_.send_blocked) {
884
+ return 0;
885
+ }
886
+ }
887
+
888
+ ev_io_stop(loop_, &wev_);
889
+
890
+ if (auto rv = write_streams(); rv != 0) {
891
+ return rv;
892
+ }
893
+
894
+ update_timer();
895
+
896
+ return 0;
897
+ }
898
+
899
+ int Handler::write_streams() {
900
+ ngtcp2_vec vec;
901
+ ngtcp2_path_storage ps, prev_ps;
902
+ uint32_t prev_ecn = 0;
903
+ size_t pktcnt = 0;
904
+ auto max_udp_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(conn_);
905
+ auto path_max_udp_payload_size =
906
+ ngtcp2_conn_get_path_max_tx_udp_payload_size(conn_);
907
+ auto max_pktcnt = ngtcp2_conn_get_send_quantum(conn_) / max_udp_payload_size;
908
+ uint8_t *bufpos = tx_.data.get();
909
+ ngtcp2_pkt_info pi;
910
+ size_t gso_size = 0;
911
+ auto ts = util::timestamp(loop_);
912
+
913
+ ngtcp2_path_storage_zero(&ps);
914
+ ngtcp2_path_storage_zero(&prev_ps);
915
+
916
+ max_pktcnt = std::min(max_pktcnt, static_cast<size_t>(config.max_gso_dgrams));
917
+
918
+ for (;;) {
919
+ int64_t stream_id = -1;
920
+ size_t vcnt = 0;
921
+ uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
922
+ Stream *stream = nullptr;
923
+
924
+ if (!sendq_.empty() && ngtcp2_conn_get_max_data_left(conn_)) {
925
+ stream = *std::begin(sendq_);
926
+
927
+ stream_id = stream->stream_id;
928
+ vec.base = stream->respbuf.pos;
929
+ vec.len = nghttp3_buf_len(&stream->respbuf);
930
+ vcnt = 1;
931
+ flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
932
+ }
933
+
934
+ ngtcp2_ssize ndatalen;
935
+
936
+ auto nwrite = ngtcp2_conn_writev_stream(conn_, &ps.path, &pi, bufpos,
937
+ max_udp_payload_size, &ndatalen,
938
+ flags, stream_id, &vec, vcnt, ts);
939
+ if (nwrite < 0) {
940
+ switch (nwrite) {
941
+ case NGTCP2_ERR_STREAM_DATA_BLOCKED:
942
+ case NGTCP2_ERR_STREAM_SHUT_WR:
943
+ assert(ndatalen == -1);
944
+ sendq_.erase(std::begin(sendq_));
945
+ continue;
946
+ case NGTCP2_ERR_WRITE_MORE:
947
+ assert(ndatalen >= 0);
948
+ stream->respbuf.pos += ndatalen;
949
+ if (nghttp3_buf_len(&stream->respbuf) == 0) {
950
+ sendq_.erase(std::begin(sendq_));
951
+ }
952
+ continue;
953
+ }
954
+
955
+ assert(ndatalen == -1);
956
+
957
+ std::cerr << "ngtcp2_conn_writev_stream: " << ngtcp2_strerror(nwrite)
958
+ << std::endl;
959
+ ngtcp2_connection_close_error_set_transport_error_liberr(
960
+ &last_error_, nwrite, nullptr, 0);
961
+ return handle_error();
962
+ } else if (ndatalen >= 0) {
963
+ stream->respbuf.pos += ndatalen;
964
+ if (nghttp3_buf_len(&stream->respbuf) == 0) {
965
+ sendq_.erase(std::begin(sendq_));
966
+ }
967
+ }
968
+
969
+ if (nwrite == 0) {
970
+ if (bufpos - tx_.data.get()) {
971
+ auto &ep = *static_cast<Endpoint *>(prev_ps.path.user_data);
972
+ auto data = tx_.data.get();
973
+ auto datalen = bufpos - data;
974
+
975
+ if (auto [nsent, rv] = server_->send_packet(
976
+ ep, no_gso_, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
977
+ data, datalen, gso_size);
978
+ rv != NETWORK_ERR_OK) {
979
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
980
+
981
+ on_send_blocked(ep, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
982
+ data + nsent, datalen - nsent, gso_size);
983
+
984
+ start_wev_endpoint(ep);
985
+ }
986
+ }
987
+
988
+ // We are congestion limited.
989
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
990
+ return 0;
991
+ }
992
+
993
+ bufpos += nwrite;
994
+
995
+ if (pktcnt == 0) {
996
+ ngtcp2_path_copy(&prev_ps.path, &ps.path);
997
+ prev_ecn = pi.ecn;
998
+ gso_size = nwrite;
999
+ } else if (!ngtcp2_path_eq(&prev_ps.path, &ps.path) || prev_ecn != pi.ecn ||
1000
+ static_cast<size_t>(nwrite) > gso_size ||
1001
+ (gso_size > path_max_udp_payload_size &&
1002
+ static_cast<size_t>(nwrite) != gso_size)) {
1003
+ auto &ep = *static_cast<Endpoint *>(prev_ps.path.user_data);
1004
+ auto data = tx_.data.get();
1005
+ auto datalen = bufpos - data - nwrite;
1006
+
1007
+ if (auto [nsent, rv] = server_->send_packet(
1008
+ ep, no_gso_, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1009
+ data, datalen, gso_size);
1010
+ rv != 0) {
1011
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1012
+
1013
+ on_send_blocked(ep, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1014
+ data + nsent, datalen - nsent, gso_size);
1015
+
1016
+ on_send_blocked(*static_cast<Endpoint *>(ps.path.user_data),
1017
+ ps.path.local, ps.path.remote, pi.ecn, bufpos - nwrite,
1018
+ nwrite, 0);
1019
+
1020
+ start_wev_endpoint(ep);
1021
+ } else {
1022
+ auto &ep = *static_cast<Endpoint *>(ps.path.user_data);
1023
+ auto data = bufpos - nwrite;
1024
+
1025
+ if (auto [nsent, rv] =
1026
+ server_->send_packet(ep, no_gso_, ps.path.local, ps.path.remote,
1027
+ pi.ecn, data, nwrite, nwrite);
1028
+ rv != 0) {
1029
+ assert(nsent == 0);
1030
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1031
+
1032
+ on_send_blocked(ep, ps.path.local, ps.path.remote, pi.ecn, data,
1033
+ nwrite, 0);
1034
+
1035
+ start_wev_endpoint(ep);
1036
+ }
1037
+ }
1038
+
1039
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1040
+ return 0;
1041
+ }
1042
+
1043
+ if (++pktcnt == max_pktcnt || static_cast<size_t>(nwrite) < gso_size) {
1044
+ auto &ep = *static_cast<Endpoint *>(ps.path.user_data);
1045
+ auto data = tx_.data.get();
1046
+ auto datalen = bufpos - data;
1047
+
1048
+ if (auto [nsent, rv] =
1049
+ server_->send_packet(ep, no_gso_, ps.path.local, ps.path.remote,
1050
+ pi.ecn, data, datalen, gso_size);
1051
+ rv != 0) {
1052
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1053
+
1054
+ on_send_blocked(ep, ps.path.local, ps.path.remote, pi.ecn, data + nsent,
1055
+ datalen - nsent, gso_size);
1056
+
1057
+ start_wev_endpoint(ep);
1058
+ }
1059
+
1060
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1061
+ return 0;
1062
+ }
1063
+ }
1064
+ }
1065
+
1066
+ void Handler::on_send_blocked(Endpoint &ep, const ngtcp2_addr &local_addr,
1067
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
1068
+ const uint8_t *data, size_t datalen,
1069
+ size_t gso_size) {
1070
+ assert(tx_.num_blocked || !tx_.send_blocked);
1071
+ assert(tx_.num_blocked < 2);
1072
+
1073
+ tx_.send_blocked = true;
1074
+
1075
+ auto &p = tx_.blocked[tx_.num_blocked++];
1076
+
1077
+ memcpy(&p.local_addr.su, local_addr.addr, local_addr.addrlen);
1078
+ memcpy(&p.remote_addr.su, remote_addr.addr, remote_addr.addrlen);
1079
+
1080
+ p.local_addr.len = local_addr.addrlen;
1081
+ p.remote_addr.len = remote_addr.addrlen;
1082
+ p.endpoint = &ep;
1083
+ p.ecn = ecn;
1084
+ p.data = data;
1085
+ p.datalen = datalen;
1086
+ p.gso_size = gso_size;
1087
+ }
1088
+
1089
+ void Handler::start_wev_endpoint(const Endpoint &ep) {
1090
+ // We do not close ep.fd, so we can expect that each Endpoint has
1091
+ // unique fd.
1092
+ if (ep.fd != wev_.fd) {
1093
+ if (ev_is_active(&wev_)) {
1094
+ ev_io_stop(loop_, &wev_);
1095
+ }
1096
+
1097
+ ev_io_set(&wev_, ep.fd, EV_WRITE);
1098
+ }
1099
+
1100
+ ev_io_start(loop_, &wev_);
1101
+ }
1102
+
1103
+ int Handler::send_blocked_packet() {
1104
+ assert(tx_.send_blocked);
1105
+
1106
+ for (; tx_.num_blocked_sent < tx_.num_blocked; ++tx_.num_blocked_sent) {
1107
+ auto &p = tx_.blocked[tx_.num_blocked_sent];
1108
+
1109
+ ngtcp2_addr local_addr{
1110
+ .addr = &p.local_addr.su.sa,
1111
+ .addrlen = p.local_addr.len,
1112
+ };
1113
+ ngtcp2_addr remote_addr{
1114
+ .addr = &p.remote_addr.su.sa,
1115
+ .addrlen = p.remote_addr.len,
1116
+ };
1117
+
1118
+ auto [nsent, rv] =
1119
+ server_->send_packet(*p.endpoint, no_gso_, local_addr, remote_addr,
1120
+ p.ecn, p.data, p.datalen, p.gso_size);
1121
+ if (rv != 0) {
1122
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1123
+
1124
+ p.data += nsent;
1125
+ p.datalen -= nsent;
1126
+
1127
+ start_wev_endpoint(*p.endpoint);
1128
+
1129
+ return 0;
1130
+ }
1131
+ }
1132
+
1133
+ tx_.send_blocked = false;
1134
+ tx_.num_blocked = 0;
1135
+ tx_.num_blocked_sent = 0;
1136
+
1137
+ return 0;
1138
+ }
1139
+
1140
+ void Handler::signal_write() { ev_io_start(loop_, &wev_); }
1141
+
1142
+ void Handler::start_draining_period() {
1143
+ ev_io_stop(loop_, &wev_);
1144
+
1145
+ ev_set_cb(&timer_, close_waitcb);
1146
+ timer_.repeat =
1147
+ static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1148
+ ev_timer_again(loop_, &timer_);
1149
+
1150
+ if (!config.quiet) {
1151
+ std::cerr << "Draining period has started (" << timer_.repeat << " seconds)"
1152
+ << std::endl;
1153
+ }
1154
+ }
1155
+
1156
+ int Handler::start_closing_period() {
1157
+ if (!conn_ || ngtcp2_conn_is_in_closing_period(conn_) ||
1158
+ ngtcp2_conn_is_in_draining_period(conn_)) {
1159
+ return 0;
1160
+ }
1161
+
1162
+ ev_io_stop(loop_, &wev_);
1163
+
1164
+ ev_set_cb(&timer_, close_waitcb);
1165
+ timer_.repeat =
1166
+ static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1167
+ ev_timer_again(loop_, &timer_);
1168
+
1169
+ if (!config.quiet) {
1170
+ std::cerr << "Closing period has started (" << timer_.repeat << " seconds)"
1171
+ << std::endl;
1172
+ }
1173
+
1174
+ conn_closebuf_ = std::make_unique<Buffer>(NGTCP2_MAX_UDP_PAYLOAD_SIZE);
1175
+
1176
+ ngtcp2_path_storage ps;
1177
+
1178
+ ngtcp2_path_storage_zero(&ps);
1179
+
1180
+ ngtcp2_pkt_info pi;
1181
+ auto n = ngtcp2_conn_write_connection_close(
1182
+ conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(),
1183
+ &last_error_, util::timestamp(loop_));
1184
+ if (n < 0) {
1185
+ std::cerr << "ngtcp2_conn_write_connection_close: " << ngtcp2_strerror(n)
1186
+ << std::endl;
1187
+ return -1;
1188
+ }
1189
+
1190
+ if (n == 0) {
1191
+ return 0;
1192
+ }
1193
+
1194
+ conn_closebuf_->push(n);
1195
+
1196
+ return 0;
1197
+ }
1198
+
1199
+ int Handler::handle_error() {
1200
+ if (last_error_.type ==
1201
+ NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE) {
1202
+ return -1;
1203
+ }
1204
+
1205
+ if (start_closing_period() != 0) {
1206
+ return -1;
1207
+ }
1208
+
1209
+ if (ngtcp2_conn_is_in_draining_period(conn_)) {
1210
+ return NETWORK_ERR_CLOSE_WAIT;
1211
+ }
1212
+
1213
+ if (auto rv = send_conn_close(); rv != NETWORK_ERR_OK) {
1214
+ return rv;
1215
+ }
1216
+
1217
+ return NETWORK_ERR_CLOSE_WAIT;
1218
+ }
1219
+
1220
+ int Handler::send_conn_close() {
1221
+ if (!config.quiet) {
1222
+ std::cerr << "Closing Period: TX CONNECTION_CLOSE" << std::endl;
1223
+ }
1224
+
1225
+ assert(conn_closebuf_ && conn_closebuf_->size());
1226
+ assert(conn_);
1227
+ assert(!ngtcp2_conn_is_in_draining_period(conn_));
1228
+
1229
+ auto path = ngtcp2_conn_get_path(conn_);
1230
+
1231
+ return server_->send_packet(
1232
+ *static_cast<Endpoint *>(path->user_data), path->local, path->remote,
1233
+ /* ecn = */ 0, conn_closebuf_->rpos(), conn_closebuf_->size());
1234
+ }
1235
+
1236
+ void Handler::update_timer() {
1237
+ auto expiry = ngtcp2_conn_get_expiry(conn_);
1238
+ auto now = util::timestamp(loop_);
1239
+
1240
+ if (expiry <= now) {
1241
+ if (!config.quiet) {
1242
+ auto t = static_cast<ev_tstamp>(now - expiry) / NGTCP2_SECONDS;
1243
+ std::cerr << "Timer has already expired: " << std::fixed << t << "s"
1244
+ << std::defaultfloat << std::endl;
1245
+ }
1246
+
1247
+ ev_feed_event(loop_, &timer_, EV_TIMER);
1248
+
1249
+ return;
1250
+ }
1251
+
1252
+ auto t = static_cast<ev_tstamp>(expiry - now) / NGTCP2_SECONDS;
1253
+ if (!config.quiet) {
1254
+ std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat
1255
+ << std::endl;
1256
+ }
1257
+ timer_.repeat = t;
1258
+ ev_timer_again(loop_, &timer_);
1259
+ }
1260
+
1261
+ namespace {
1262
+ int on_msg_begin(http_parser *htp) {
1263
+ auto s = static_cast<Stream *>(htp->data);
1264
+ if (s->eos) {
1265
+ return -1;
1266
+ }
1267
+ return 0;
1268
+ }
1269
+ } // namespace
1270
+
1271
+ namespace {
1272
+ int on_url_cb(http_parser *htp, const char *data, size_t datalen) {
1273
+ auto s = static_cast<Stream *>(htp->data);
1274
+ s->uri.append(data, datalen);
1275
+ return 0;
1276
+ }
1277
+ } // namespace
1278
+
1279
+ namespace {
1280
+ int on_msg_complete(http_parser *htp) {
1281
+ auto s = static_cast<Stream *>(htp->data);
1282
+ s->eos = true;
1283
+ if (s->start_response() != 0) {
1284
+ return -1;
1285
+ }
1286
+ return 0;
1287
+ }
1288
+ } // namespace
1289
+
1290
+ auto htp_settings = http_parser_settings{
1291
+ on_msg_begin, // on_message_begin
1292
+ on_url_cb, // on_url
1293
+ nullptr, // on_status
1294
+ nullptr, // on_header_field
1295
+ nullptr, // on_header_value
1296
+ nullptr, // on_headers_complete
1297
+ nullptr, // on_body
1298
+ on_msg_complete, // on_message_complete
1299
+ nullptr, // on_chunk_header,
1300
+ nullptr, // on_chunk_complete
1301
+ };
1302
+
1303
+ int Handler::recv_stream_data(uint32_t flags, int64_t stream_id,
1304
+ const uint8_t *data, size_t datalen) {
1305
+ if (!config.quiet && !config.no_quic_dump) {
1306
+ debug::print_stream_data(stream_id, data, datalen);
1307
+ }
1308
+
1309
+ auto it = streams_.find(stream_id);
1310
+ assert(it != std::end(streams_));
1311
+ auto &stream = (*it).second;
1312
+
1313
+ if (!stream->eos) {
1314
+ auto nread =
1315
+ http_parser_execute(&stream->htp, &htp_settings,
1316
+ reinterpret_cast<const char *>(data), datalen);
1317
+ if (nread != datalen) {
1318
+ if (auto rv = ngtcp2_conn_shutdown_stream(conn_, stream_id,
1319
+ /* app error code */ 1);
1320
+ rv != 0) {
1321
+ std::cerr << "ngtcp2_conn_shutdown_stream: " << ngtcp2_strerror(rv)
1322
+ << std::endl;
1323
+ ngtcp2_connection_close_error_set_transport_error_liberr(
1324
+ &last_error_, NGTCP2_ERR_INTERNAL, nullptr, 0);
1325
+ return -1;
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, datalen);
1331
+ ngtcp2_conn_extend_max_offset(conn_, datalen);
1332
+
1333
+ return 0;
1334
+ }
1335
+
1336
+ int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret,
1337
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
1338
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
1339
+ const uint8_t *current_rx_secret,
1340
+ const uint8_t *current_tx_secret, size_t secretlen) {
1341
+ auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_);
1342
+ auto aead = &crypto_ctx->aead;
1343
+ auto keylen = ngtcp2_crypto_aead_keylen(aead);
1344
+ auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
1345
+
1346
+ ++nkey_update_;
1347
+
1348
+ std::array<uint8_t, 64> rx_key, tx_key;
1349
+
1350
+ if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx,
1351
+ rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(),
1352
+ tx_iv, current_rx_secret, current_tx_secret,
1353
+ secretlen) != 0) {
1354
+ return -1;
1355
+ }
1356
+
1357
+ if (!config.quiet && config.show_secret) {
1358
+ std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl;
1359
+ debug::print_secrets(rx_secret, secretlen, rx_key.data(), keylen, rx_iv,
1360
+ ivlen);
1361
+ std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl;
1362
+ debug::print_secrets(tx_secret, secretlen, tx_key.data(), keylen, tx_iv,
1363
+ ivlen);
1364
+ }
1365
+
1366
+ return 0;
1367
+ }
1368
+
1369
+ Server *Handler::server() const { return server_; }
1370
+
1371
+ int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) {
1372
+ if (!config.quiet) {
1373
+ std::cerr << "QUIC stream " << stream_id << " closed" << std::endl;
1374
+ }
1375
+
1376
+ auto it = streams_.find(stream_id);
1377
+ assert(it != std::end(streams_));
1378
+ auto &stream = (*it).second;
1379
+
1380
+ sendq_.erase(stream.get());
1381
+
1382
+ if (!config.quiet) {
1383
+ std::cerr << "HTTP stream " << stream_id << " closed with error code "
1384
+ << app_error_code << std::endl;
1385
+ }
1386
+
1387
+ streams_.erase(it);
1388
+
1389
+ if (ngtcp2_is_bidi_stream(stream_id)) {
1390
+ assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
1391
+ ngtcp2_conn_extend_max_streams_bidi(conn_, 1);
1392
+ }
1393
+
1394
+ return 0;
1395
+ }
1396
+
1397
+ void Handler::shutdown_read(int64_t stream_id, int app_error_code) {
1398
+ ngtcp2_conn_shutdown_stream_read(conn_, stream_id, app_error_code);
1399
+ }
1400
+
1401
+ void Handler::add_sendq(Stream *stream) { sendq_.emplace(stream); }
1402
+
1403
+ namespace {
1404
+ void sreadcb(struct ev_loop *loop, ev_io *w, int revents) {
1405
+ auto ep = static_cast<Endpoint *>(w->data);
1406
+
1407
+ ep->server->on_read(*ep);
1408
+ }
1409
+ } // namespace
1410
+
1411
+ namespace {
1412
+ void siginthandler(struct ev_loop *loop, ev_signal *watcher, int revents) {
1413
+ ev_break(loop, EVBREAK_ALL);
1414
+ }
1415
+ } // namespace
1416
+
1417
+ Server::Server(struct ev_loop *loop, TLSServerContext &tls_ctx)
1418
+ : loop_(loop), tls_ctx_(tls_ctx) {
1419
+ ev_signal_init(&sigintev_, siginthandler, SIGINT);
1420
+ }
1421
+
1422
+ Server::~Server() {
1423
+ disconnect();
1424
+ close();
1425
+ }
1426
+
1427
+ void Server::disconnect() {
1428
+ config.tx_loss_prob = 0;
1429
+
1430
+ for (auto &ep : endpoints_) {
1431
+ ev_io_stop(loop_, &ep.rev);
1432
+ }
1433
+
1434
+ ev_signal_stop(loop_, &sigintev_);
1435
+
1436
+ while (!handlers_.empty()) {
1437
+ auto it = std::begin(handlers_);
1438
+ auto &h = (*it).second;
1439
+
1440
+ h->handle_error();
1441
+
1442
+ remove(h);
1443
+ }
1444
+ }
1445
+
1446
+ void Server::close() {
1447
+ for (auto &ep : endpoints_) {
1448
+ ::close(ep.fd);
1449
+ }
1450
+
1451
+ endpoints_.clear();
1452
+ }
1453
+
1454
+ namespace {
1455
+ int create_sock(Address &local_addr, const char *addr, const char *port,
1456
+ int family) {
1457
+ addrinfo hints{};
1458
+ addrinfo *res, *rp;
1459
+ int val = 1;
1460
+
1461
+ hints.ai_family = family;
1462
+ hints.ai_socktype = SOCK_DGRAM;
1463
+ hints.ai_flags = AI_PASSIVE;
1464
+
1465
+ if (strcmp(addr, "*") == 0) {
1466
+ addr = nullptr;
1467
+ }
1468
+
1469
+ if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) {
1470
+ std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl;
1471
+ return -1;
1472
+ }
1473
+
1474
+ auto res_d = defer(freeaddrinfo, res);
1475
+
1476
+ int fd = -1;
1477
+
1478
+ for (rp = res; rp; rp = rp->ai_next) {
1479
+ fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype,
1480
+ rp->ai_protocol);
1481
+ if (fd == -1) {
1482
+ continue;
1483
+ }
1484
+
1485
+ if (rp->ai_family == AF_INET6) {
1486
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
1487
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1488
+ close(fd);
1489
+ continue;
1490
+ }
1491
+
1492
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
1493
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1494
+ close(fd);
1495
+ continue;
1496
+ }
1497
+ } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
1498
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1499
+ close(fd);
1500
+ continue;
1501
+ }
1502
+
1503
+ if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
1504
+ break;
1505
+ }
1506
+
1507
+ close(fd);
1508
+ }
1509
+
1510
+ if (!rp) {
1511
+ std::cerr << "Could not bind" << std::endl;
1512
+ return -1;
1513
+ }
1514
+
1515
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
1516
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1517
+ close(fd);
1518
+ return -1;
1519
+ }
1520
+
1521
+ fd_set_recv_ecn(fd, rp->ai_family);
1522
+ fd_set_ip_mtu_discover(fd, rp->ai_family);
1523
+ fd_set_ip_dontfrag(fd, family);
1524
+
1525
+ socklen_t len = sizeof(local_addr.su.storage);
1526
+ if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
1527
+ std::cerr << "getsockname: " << strerror(errno) << std::endl;
1528
+ close(fd);
1529
+ return -1;
1530
+ }
1531
+ local_addr.len = len;
1532
+ local_addr.ifindex = 0;
1533
+
1534
+ return fd;
1535
+ }
1536
+
1537
+ } // namespace
1538
+
1539
+ namespace {
1540
+ int add_endpoint(std::vector<Endpoint> &endpoints, const char *addr,
1541
+ const char *port, int af) {
1542
+ Address dest;
1543
+ auto fd = create_sock(dest, addr, port, af);
1544
+ if (fd == -1) {
1545
+ return -1;
1546
+ }
1547
+
1548
+ endpoints.emplace_back();
1549
+ auto &ep = endpoints.back();
1550
+ ep.addr = dest;
1551
+ ep.fd = fd;
1552
+ ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
1553
+
1554
+ return 0;
1555
+ }
1556
+ } // namespace
1557
+
1558
+ namespace {
1559
+ int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
1560
+ auto fd = util::create_nonblock_socket(addr.su.sa.sa_family, SOCK_DGRAM, 0);
1561
+ if (fd == -1) {
1562
+ std::cerr << "socket: " << strerror(errno) << std::endl;
1563
+ return -1;
1564
+ }
1565
+
1566
+ int val = 1;
1567
+ if (addr.su.sa.sa_family == AF_INET6) {
1568
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
1569
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1570
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
1571
+ close(fd);
1572
+ return -1;
1573
+ }
1574
+
1575
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
1576
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1577
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
1578
+ close(fd);
1579
+ return -1;
1580
+ }
1581
+ } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
1582
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1583
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
1584
+ close(fd);
1585
+ return -1;
1586
+ }
1587
+
1588
+ if (bind(fd, &addr.su.sa, addr.len) == -1) {
1589
+ std::cerr << "bind: " << strerror(errno) << std::endl;
1590
+ close(fd);
1591
+ return -1;
1592
+ }
1593
+
1594
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
1595
+ static_cast<socklen_t>(sizeof(val))) == -1) {
1596
+ close(fd);
1597
+ return -1;
1598
+ }
1599
+
1600
+ fd_set_recv_ecn(fd, addr.su.sa.sa_family);
1601
+ fd_set_ip_mtu_discover(fd, addr.su.sa.sa_family);
1602
+ fd_set_ip_dontfrag(fd, addr.su.sa.sa_family);
1603
+
1604
+ endpoints.emplace_back(Endpoint{});
1605
+ auto &ep = endpoints.back();
1606
+ ep.addr = addr;
1607
+ ep.fd = fd;
1608
+ ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
1609
+
1610
+ return 0;
1611
+ }
1612
+ } // namespace
1613
+
1614
+ int Server::init(const char *addr, const char *port) {
1615
+ endpoints_.reserve(4);
1616
+
1617
+ auto ready = false;
1618
+ if (!util::numeric_host(addr, AF_INET6) &&
1619
+ add_endpoint(endpoints_, addr, port, AF_INET) == 0) {
1620
+ ready = true;
1621
+ }
1622
+ if (!util::numeric_host(addr, AF_INET) &&
1623
+ add_endpoint(endpoints_, addr, port, AF_INET6) == 0) {
1624
+ ready = true;
1625
+ }
1626
+ if (!ready) {
1627
+ return -1;
1628
+ }
1629
+
1630
+ if (config.preferred_ipv4_addr.len &&
1631
+ add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) {
1632
+ return -1;
1633
+ }
1634
+ if (config.preferred_ipv6_addr.len &&
1635
+ add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) {
1636
+ return -1;
1637
+ }
1638
+
1639
+ for (auto &ep : endpoints_) {
1640
+ ep.server = this;
1641
+ ep.rev.data = &ep;
1642
+
1643
+ ev_io_set(&ep.rev, ep.fd, EV_READ);
1644
+
1645
+ ev_io_start(loop_, &ep.rev);
1646
+ }
1647
+
1648
+ ev_signal_start(loop_, &sigintev_);
1649
+
1650
+ return 0;
1651
+ }
1652
+
1653
+ int Server::on_read(Endpoint &ep) {
1654
+ sockaddr_union su;
1655
+ std::array<uint8_t, 64_k> buf;
1656
+ ngtcp2_pkt_hd hd;
1657
+ size_t pktcnt = 0;
1658
+ ngtcp2_pkt_info pi;
1659
+
1660
+ iovec msg_iov;
1661
+ msg_iov.iov_base = buf.data();
1662
+ msg_iov.iov_len = buf.size();
1663
+
1664
+ msghdr msg{};
1665
+ msg.msg_name = &su;
1666
+ msg.msg_iov = &msg_iov;
1667
+ msg.msg_iovlen = 1;
1668
+
1669
+ uint8_t
1670
+ msg_ctrl[CMSG_SPACE(sizeof(uint8_t)) + CMSG_SPACE(sizeof(in6_pktinfo))];
1671
+ msg.msg_control = msg_ctrl;
1672
+
1673
+ for (; pktcnt < 10;) {
1674
+ msg.msg_namelen = sizeof(su);
1675
+ msg.msg_controllen = sizeof(msg_ctrl);
1676
+
1677
+ auto nread = recvmsg(ep.fd, &msg, 0);
1678
+ if (nread == -1) {
1679
+ if (!(errno == EAGAIN || errno == ENOTCONN)) {
1680
+ std::cerr << "recvmsg: " << strerror(errno) << std::endl;
1681
+ }
1682
+ return 0;
1683
+ }
1684
+
1685
+ ++pktcnt;
1686
+
1687
+ pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
1688
+ auto local_addr = msghdr_get_local_addr(&msg, su.storage.ss_family);
1689
+ if (!local_addr) {
1690
+ std::cerr << "Unable to obtain local address" << std::endl;
1691
+ continue;
1692
+ }
1693
+
1694
+ set_port(*local_addr, ep.addr);
1695
+
1696
+ if (!config.quiet) {
1697
+ std::array<char, IF_NAMESIZE> ifname;
1698
+ std::cerr << "Received packet: local="
1699
+ << util::straddr(&local_addr->su.sa, local_addr->len)
1700
+ << " remote=" << util::straddr(&su.sa, msg.msg_namelen)
1701
+ << " if=" << if_indextoname(local_addr->ifindex, ifname.data())
1702
+ << " ecn=0x" << std::hex << pi.ecn << std::dec << " " << nread
1703
+ << " bytes" << std::endl;
1704
+ }
1705
+
1706
+ if (debug::packet_lost(config.rx_loss_prob)) {
1707
+ if (!config.quiet) {
1708
+ std::cerr << "** Simulated incoming packet loss **" << std::endl;
1709
+ }
1710
+ continue;
1711
+ }
1712
+
1713
+ if (nread == 0) {
1714
+ continue;
1715
+ }
1716
+
1717
+ ngtcp2_version_cid vc;
1718
+
1719
+ switch (auto rv = ngtcp2_pkt_decode_version_cid(&vc, buf.data(), nread,
1720
+ NGTCP2_SV_SCIDLEN);
1721
+ rv) {
1722
+ case 0:
1723
+ break;
1724
+ case NGTCP2_ERR_VERSION_NEGOTIATION:
1725
+ send_version_negotiation(vc.version, vc.scid, vc.scidlen, vc.dcid,
1726
+ vc.dcidlen, ep, *local_addr, &su.sa,
1727
+ msg.msg_namelen);
1728
+ continue;
1729
+ default:
1730
+ std::cerr << "Could not decode version and CID from QUIC packet header: "
1731
+ << ngtcp2_strerror(rv) << std::endl;
1732
+ continue;
1733
+ }
1734
+
1735
+ auto dcid_key = util::make_cid_key(vc.dcid, vc.dcidlen);
1736
+
1737
+ auto handler_it = handlers_.find(dcid_key);
1738
+ if (handler_it == std::end(handlers_)) {
1739
+ if (auto rv = ngtcp2_accept(&hd, buf.data(), nread); rv != 0) {
1740
+ if (!config.quiet) {
1741
+ std::cerr << "Unexpected packet received: length=" << nread
1742
+ << std::endl;
1743
+ }
1744
+ continue;
1745
+ }
1746
+
1747
+ ngtcp2_cid ocid;
1748
+ ngtcp2_cid *pocid = nullptr;
1749
+
1750
+ assert(hd.type == NGTCP2_PKT_INITIAL);
1751
+
1752
+ if (config.validate_addr || hd.tokenlen) {
1753
+ std::cerr << "Perform stateless address validation" << std::endl;
1754
+ if (hd.tokenlen == 0) {
1755
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen, nread * 3);
1756
+ continue;
1757
+ }
1758
+
1759
+ if (hd.token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY &&
1760
+ hd.dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) {
1761
+ send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
1762
+ msg.msg_namelen);
1763
+ continue;
1764
+ }
1765
+
1766
+ switch (hd.token[0]) {
1767
+ case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY:
1768
+ if (verify_retry_token(&ocid, &hd, &su.sa, msg.msg_namelen) != 0) {
1769
+ send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
1770
+ msg.msg_namelen);
1771
+ continue;
1772
+ }
1773
+ pocid = &ocid;
1774
+ break;
1775
+ case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR:
1776
+ if (verify_token(&hd, &su.sa, msg.msg_namelen) != 0) {
1777
+ if (config.validate_addr) {
1778
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen,
1779
+ nread * 3);
1780
+ continue;
1781
+ }
1782
+
1783
+ hd.token = nullptr;
1784
+ hd.tokenlen = 0;
1785
+ }
1786
+ break;
1787
+ default:
1788
+ if (!config.quiet) {
1789
+ std::cerr << "Ignore unrecognized token" << std::endl;
1790
+ }
1791
+ if (config.validate_addr) {
1792
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen,
1793
+ nread * 3);
1794
+ continue;
1795
+ }
1796
+
1797
+ hd.token = nullptr;
1798
+ hd.tokenlen = 0;
1799
+ break;
1800
+ }
1801
+ }
1802
+
1803
+ auto h = std::make_unique<Handler>(loop_, this);
1804
+ if (h->init(ep, *local_addr, &su.sa, msg.msg_namelen, &hd.scid, &hd.dcid,
1805
+ pocid, hd.token, hd.tokenlen, hd.version, tls_ctx_) != 0) {
1806
+ continue;
1807
+ }
1808
+
1809
+ switch (h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
1810
+ buf.data(), nread)) {
1811
+ case 0:
1812
+ break;
1813
+ case NETWORK_ERR_RETRY:
1814
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen, nread * 3);
1815
+ continue;
1816
+ default:
1817
+ continue;
1818
+ }
1819
+
1820
+ switch (h->on_write()) {
1821
+ case 0:
1822
+ break;
1823
+ default:
1824
+ continue;
1825
+ }
1826
+
1827
+ std::array<ngtcp2_cid, 2> scids;
1828
+ auto conn = h->conn();
1829
+
1830
+ auto num_scid = ngtcp2_conn_get_num_scid(conn);
1831
+
1832
+ assert(num_scid <= scids.size());
1833
+
1834
+ ngtcp2_conn_get_scid(conn, scids.data());
1835
+
1836
+ for (size_t i = 0; i < num_scid; ++i) {
1837
+ associate_cid(&scids[i], h.get());
1838
+ }
1839
+
1840
+ handlers_.emplace(dcid_key, h.get());
1841
+
1842
+ h.release();
1843
+
1844
+ continue;
1845
+ }
1846
+
1847
+ auto h = (*handler_it).second;
1848
+ auto conn = h->conn();
1849
+ if (ngtcp2_conn_is_in_closing_period(conn)) {
1850
+ // TODO do exponential backoff.
1851
+ switch (h->send_conn_close()) {
1852
+ case 0:
1853
+ break;
1854
+ default:
1855
+ remove(h);
1856
+ }
1857
+ continue;
1858
+ }
1859
+ if (ngtcp2_conn_is_in_draining_period(conn)) {
1860
+ continue;
1861
+ }
1862
+
1863
+ if (auto rv = h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
1864
+ buf.data(), nread);
1865
+ rv != 0) {
1866
+ if (rv != NETWORK_ERR_CLOSE_WAIT) {
1867
+ remove(h);
1868
+ }
1869
+ continue;
1870
+ }
1871
+
1872
+ h->signal_write();
1873
+ }
1874
+
1875
+ return 0;
1876
+ }
1877
+
1878
+ namespace {
1879
+ uint32_t generate_reserved_version(const sockaddr *sa, socklen_t salen,
1880
+ uint32_t version) {
1881
+ uint32_t h = 0x811C9DC5u;
1882
+ const uint8_t *p = (const uint8_t *)sa;
1883
+ const uint8_t *ep = p + salen;
1884
+ for (; p != ep; ++p) {
1885
+ h ^= *p;
1886
+ h *= 0x01000193u;
1887
+ }
1888
+ version = htonl(version);
1889
+ p = (const uint8_t *)&version;
1890
+ ep = p + sizeof(version);
1891
+ for (; p != ep; ++p) {
1892
+ h ^= *p;
1893
+ h *= 0x01000193u;
1894
+ }
1895
+ h &= 0xf0f0f0f0u;
1896
+ h |= 0x0a0a0a0au;
1897
+ return h;
1898
+ }
1899
+ } // namespace
1900
+
1901
+ int Server::send_version_negotiation(uint32_t version, const uint8_t *dcid,
1902
+ size_t dcidlen, const uint8_t *scid,
1903
+ size_t scidlen, Endpoint &ep,
1904
+ const Address &local_addr,
1905
+ const sockaddr *sa, socklen_t salen) {
1906
+ Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
1907
+ std::array<uint32_t, 1 + max_preferred_versionslen> sv;
1908
+
1909
+ auto p = std::begin(sv);
1910
+
1911
+ *p++ = generate_reserved_version(sa, salen, version);
1912
+
1913
+ if (config.preferred_versions.empty()) {
1914
+ *p++ = NGTCP2_PROTO_VER_V1;
1915
+ } else {
1916
+ for (auto v : config.preferred_versions) {
1917
+ *p++ = v;
1918
+ }
1919
+ }
1920
+
1921
+ auto nwrite = ngtcp2_pkt_write_version_negotiation(
1922
+ buf.wpos(), buf.left(), std::uniform_int_distribution<uint8_t>()(randgen),
1923
+ dcid, dcidlen, scid, scidlen, sv.data(), p - std::begin(sv));
1924
+ if (nwrite < 0) {
1925
+ std::cerr << "ngtcp2_pkt_write_version_negotiation: "
1926
+ << ngtcp2_strerror(nwrite) << std::endl;
1927
+ return -1;
1928
+ }
1929
+
1930
+ buf.push(nwrite);
1931
+
1932
+ ngtcp2_addr laddr{
1933
+ const_cast<sockaddr *>(&local_addr.su.sa),
1934
+ local_addr.len,
1935
+ };
1936
+ ngtcp2_addr raddr{
1937
+ const_cast<sockaddr *>(sa),
1938
+ salen,
1939
+ };
1940
+
1941
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
1942
+ NETWORK_ERR_OK) {
1943
+ return -1;
1944
+ }
1945
+
1946
+ return 0;
1947
+ }
1948
+
1949
+ int Server::send_retry(const ngtcp2_pkt_hd *chd, Endpoint &ep,
1950
+ const Address &local_addr, const sockaddr *sa,
1951
+ socklen_t salen, size_t max_pktlen) {
1952
+ std::array<char, NI_MAXHOST> host;
1953
+ std::array<char, NI_MAXSERV> port;
1954
+
1955
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
1956
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
1957
+ rv != 0) {
1958
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
1959
+ return -1;
1960
+ }
1961
+
1962
+ if (!config.quiet) {
1963
+ std::cerr << "Sending Retry packet to [" << host.data()
1964
+ << "]:" << port.data() << std::endl;
1965
+ }
1966
+
1967
+ ngtcp2_cid scid;
1968
+
1969
+ scid.datalen = NGTCP2_SV_SCIDLEN;
1970
+ if (util::generate_secure_random(scid.data, scid.datalen) != 0) {
1971
+ return -1;
1972
+ }
1973
+
1974
+ std::array<uint8_t, NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN> token;
1975
+
1976
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
1977
+ std::chrono::system_clock::now().time_since_epoch())
1978
+ .count();
1979
+
1980
+ auto tokenlen = ngtcp2_crypto_generate_retry_token(
1981
+ token.data(), config.static_secret.data(), config.static_secret.size(),
1982
+ chd->version, sa, salen, &scid, &chd->dcid, t);
1983
+ if (tokenlen < 0) {
1984
+ return -1;
1985
+ }
1986
+
1987
+ if (!config.quiet) {
1988
+ std::cerr << "Generated address validation token:" << std::endl;
1989
+ util::hexdump(stderr, token.data(), tokenlen);
1990
+ }
1991
+
1992
+ Buffer buf{
1993
+ std::min(static_cast<size_t>(NGTCP2_MAX_UDP_PAYLOAD_SIZE), max_pktlen)};
1994
+
1995
+ auto nwrite = ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version,
1996
+ &chd->scid, &scid, &chd->dcid,
1997
+ token.data(), tokenlen);
1998
+ if (nwrite < 0) {
1999
+ std::cerr << "ngtcp2_crypto_write_retry failed" << std::endl;
2000
+ return -1;
2001
+ }
2002
+
2003
+ buf.push(nwrite);
2004
+
2005
+ ngtcp2_addr laddr{
2006
+ const_cast<sockaddr *>(&local_addr.su.sa),
2007
+ local_addr.len,
2008
+ };
2009
+ ngtcp2_addr raddr{
2010
+ const_cast<sockaddr *>(sa),
2011
+ salen,
2012
+ };
2013
+
2014
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
2015
+ NETWORK_ERR_OK) {
2016
+ return -1;
2017
+ }
2018
+
2019
+ return 0;
2020
+ }
2021
+
2022
+ int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
2023
+ Endpoint &ep,
2024
+ const Address &local_addr,
2025
+ const sockaddr *sa,
2026
+ socklen_t salen) {
2027
+ Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2028
+
2029
+ auto nwrite = ngtcp2_crypto_write_connection_close(
2030
+ buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid,
2031
+ NGTCP2_INVALID_TOKEN, nullptr, 0);
2032
+ if (nwrite < 0) {
2033
+ std::cerr << "ngtcp2_crypto_write_connection_close failed" << std::endl;
2034
+ return -1;
2035
+ }
2036
+
2037
+ buf.push(nwrite);
2038
+
2039
+ ngtcp2_addr laddr{
2040
+ const_cast<sockaddr *>(&local_addr.su.sa),
2041
+ local_addr.len,
2042
+ };
2043
+ ngtcp2_addr raddr{
2044
+ const_cast<sockaddr *>(sa),
2045
+ salen,
2046
+ };
2047
+
2048
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
2049
+ NETWORK_ERR_OK) {
2050
+ return -1;
2051
+ }
2052
+
2053
+ return 0;
2054
+ }
2055
+
2056
+ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
2057
+ const sockaddr *sa, socklen_t salen) {
2058
+ std::array<char, NI_MAXHOST> host;
2059
+ std::array<char, NI_MAXSERV> port;
2060
+
2061
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2062
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2063
+ rv != 0) {
2064
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2065
+ return -1;
2066
+ }
2067
+
2068
+ if (!config.quiet) {
2069
+ std::cerr << "Verifying Retry token from [" << host.data()
2070
+ << "]:" << port.data() << std::endl;
2071
+ util::hexdump(stderr, hd->token, hd->tokenlen);
2072
+ }
2073
+
2074
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2075
+ std::chrono::system_clock::now().time_since_epoch())
2076
+ .count();
2077
+
2078
+ if (ngtcp2_crypto_verify_retry_token(
2079
+ ocid, hd->token, hd->tokenlen, config.static_secret.data(),
2080
+ config.static_secret.size(), hd->version, sa, salen, &hd->dcid,
2081
+ 10 * NGTCP2_SECONDS, t) != 0) {
2082
+ std::cerr << "Could not verify Retry token" << std::endl;
2083
+
2084
+ return -1;
2085
+ }
2086
+
2087
+ if (!config.quiet) {
2088
+ std::cerr << "Token was successfully validated" << std::endl;
2089
+ }
2090
+
2091
+ return 0;
2092
+ }
2093
+
2094
+ int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
2095
+ socklen_t salen) {
2096
+ std::array<char, NI_MAXHOST> host;
2097
+ std::array<char, NI_MAXSERV> port;
2098
+
2099
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2100
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2101
+ rv != 0) {
2102
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2103
+ return -1;
2104
+ }
2105
+
2106
+ if (!config.quiet) {
2107
+ std::cerr << "Verifying token from [" << host.data() << "]:" << port.data()
2108
+ << std::endl;
2109
+ util::hexdump(stderr, hd->token, hd->tokenlen);
2110
+ }
2111
+
2112
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2113
+ std::chrono::system_clock::now().time_since_epoch())
2114
+ .count();
2115
+
2116
+ if (ngtcp2_crypto_verify_regular_token(hd->token, hd->tokenlen,
2117
+ config.static_secret.data(),
2118
+ config.static_secret.size(), sa, salen,
2119
+ 3600 * NGTCP2_SECONDS, t) != 0) {
2120
+ std::cerr << "Could not verify token" << std::endl;
2121
+
2122
+ return -1;
2123
+ }
2124
+
2125
+ if (!config.quiet) {
2126
+ std::cerr << "Token was successfully validated" << std::endl;
2127
+ }
2128
+
2129
+ return 0;
2130
+ }
2131
+
2132
+ int Server::send_packet(Endpoint &ep, const ngtcp2_addr &local_addr,
2133
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
2134
+ const uint8_t *data, size_t datalen) {
2135
+ auto no_gso = false;
2136
+ auto [_, rv] = send_packet(ep, no_gso, local_addr, remote_addr, ecn, data,
2137
+ datalen, datalen);
2138
+
2139
+ return rv;
2140
+ }
2141
+
2142
+ std::pair<size_t, int>
2143
+ Server::send_packet(Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr,
2144
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
2145
+ const uint8_t *data, size_t datalen, size_t gso_size) {
2146
+ assert(gso_size);
2147
+
2148
+ if (debug::packet_lost(config.tx_loss_prob)) {
2149
+ if (!config.quiet) {
2150
+ std::cerr << "** Simulated outgoing packet loss **" << std::endl;
2151
+ }
2152
+ return {0, NETWORK_ERR_OK};
2153
+ }
2154
+
2155
+ if (no_gso && datalen > gso_size) {
2156
+ size_t nsent = 0;
2157
+
2158
+ for (auto p = data; p < data + datalen; p += gso_size) {
2159
+ auto len = std::min(gso_size, static_cast<size_t>(data + datalen - p));
2160
+
2161
+ auto [n, rv] =
2162
+ send_packet(ep, no_gso, local_addr, remote_addr, ecn, p, len, len);
2163
+ if (rv != 0) {
2164
+ return {nsent, rv};
2165
+ }
2166
+
2167
+ nsent += n;
2168
+ }
2169
+
2170
+ return {nsent, 0};
2171
+ }
2172
+
2173
+ iovec msg_iov;
2174
+ msg_iov.iov_base = const_cast<uint8_t *>(data);
2175
+ msg_iov.iov_len = datalen;
2176
+
2177
+ msghdr msg{};
2178
+ msg.msg_name = const_cast<sockaddr *>(remote_addr.addr);
2179
+ msg.msg_namelen = remote_addr.addrlen;
2180
+ msg.msg_iov = &msg_iov;
2181
+ msg.msg_iovlen = 1;
2182
+
2183
+ uint8_t
2184
+ msg_ctrl[CMSG_SPACE(sizeof(uint16_t)) + CMSG_SPACE(sizeof(in6_pktinfo))];
2185
+
2186
+ memset(msg_ctrl, 0, sizeof(msg_ctrl));
2187
+
2188
+ msg.msg_control = msg_ctrl;
2189
+ msg.msg_controllen = sizeof(msg_ctrl);
2190
+
2191
+ size_t controllen = 0;
2192
+
2193
+ auto cm = CMSG_FIRSTHDR(&msg);
2194
+
2195
+ switch (local_addr.addr->sa_family) {
2196
+ case AF_INET: {
2197
+ controllen += CMSG_SPACE(sizeof(in_pktinfo));
2198
+ cm->cmsg_level = IPPROTO_IP;
2199
+ cm->cmsg_type = IP_PKTINFO;
2200
+ cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
2201
+ auto pktinfo = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cm));
2202
+ memset(pktinfo, 0, sizeof(in_pktinfo));
2203
+ auto addrin = reinterpret_cast<sockaddr_in *>(local_addr.addr);
2204
+ pktinfo->ipi_spec_dst = addrin->sin_addr;
2205
+ break;
2206
+ }
2207
+ case AF_INET6: {
2208
+ controllen += CMSG_SPACE(sizeof(in6_pktinfo));
2209
+ cm->cmsg_level = IPPROTO_IPV6;
2210
+ cm->cmsg_type = IPV6_PKTINFO;
2211
+ cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
2212
+ auto pktinfo = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cm));
2213
+ memset(pktinfo, 0, sizeof(in6_pktinfo));
2214
+ auto addrin = reinterpret_cast<sockaddr_in6 *>(local_addr.addr);
2215
+ pktinfo->ipi6_addr = addrin->sin6_addr;
2216
+ break;
2217
+ }
2218
+ default:
2219
+ assert(0);
2220
+ }
2221
+
2222
+ #ifdef UDP_SEGMENT
2223
+ if (datalen > gso_size) {
2224
+ controllen += CMSG_SPACE(sizeof(uint16_t));
2225
+ cm = CMSG_NXTHDR(&msg, cm);
2226
+ cm->cmsg_level = SOL_UDP;
2227
+ cm->cmsg_type = UDP_SEGMENT;
2228
+ cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
2229
+ *(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
2230
+ }
2231
+ #endif // UDP_SEGMENT
2232
+
2233
+ msg.msg_controllen = controllen;
2234
+
2235
+ if (ep.ecn != ecn) {
2236
+ ep.ecn = ecn;
2237
+ fd_set_ecn(ep.fd, ep.addr.su.storage.ss_family, ecn);
2238
+ }
2239
+
2240
+ ssize_t nwrite = 0;
2241
+
2242
+ do {
2243
+ nwrite = sendmsg(ep.fd, &msg, 0);
2244
+ } while (nwrite == -1 && errno == EINTR);
2245
+
2246
+ if (nwrite == -1) {
2247
+ switch (errno) {
2248
+ case EAGAIN:
2249
+ #if EAGAIN != EWOULDBLOCK
2250
+ case EWOULDBLOCK:
2251
+ #endif // EAGAIN != EWOULDBLOCK
2252
+ return {0, NETWORK_ERR_SEND_BLOCKED};
2253
+ #ifdef UDP_SEGMENT
2254
+ case EIO:
2255
+ if (datalen > gso_size) {
2256
+ // GSO failure; send each packet in a separate sendmsg call.
2257
+ std::cerr << "sendmsg: disabling GSO due to " << strerror(errno)
2258
+ << std::endl;
2259
+
2260
+ no_gso = true;
2261
+
2262
+ return send_packet(ep, no_gso, local_addr, remote_addr, ecn, data,
2263
+ datalen, gso_size);
2264
+ }
2265
+ break;
2266
+ #endif // UDP_SEGMENT
2267
+ }
2268
+
2269
+ std::cerr << "sendmsg: " << strerror(errno) << std::endl;
2270
+ // TODO We have packet which is expected to fail to send (e.g.,
2271
+ // path validation to old path).
2272
+ return {0, NETWORK_ERR_OK};
2273
+ }
2274
+
2275
+ if (!config.quiet) {
2276
+ std::cerr << "Sent packet: local="
2277
+ << util::straddr(local_addr.addr, local_addr.addrlen)
2278
+ << " remote="
2279
+ << util::straddr(remote_addr.addr, remote_addr.addrlen)
2280
+ << " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite
2281
+ << " bytes" << std::endl;
2282
+ }
2283
+
2284
+ return {nwrite, NETWORK_ERR_OK};
2285
+ }
2286
+
2287
+ void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) {
2288
+ handlers_.emplace(util::make_cid_key(cid), h);
2289
+ }
2290
+
2291
+ void Server::dissociate_cid(const ngtcp2_cid *cid) {
2292
+ handlers_.erase(util::make_cid_key(cid));
2293
+ }
2294
+
2295
+ void Server::remove(const Handler *h) {
2296
+ auto conn = h->conn();
2297
+
2298
+ dissociate_cid(ngtcp2_conn_get_client_initial_dcid(conn));
2299
+
2300
+ std::vector<ngtcp2_cid> cids(ngtcp2_conn_get_num_scid(conn));
2301
+ ngtcp2_conn_get_scid(conn, cids.data());
2302
+
2303
+ for (auto &cid : cids) {
2304
+ dissociate_cid(&cid);
2305
+ }
2306
+
2307
+ delete h;
2308
+ }
2309
+
2310
+ namespace {
2311
+ int parse_host_port(Address &dest, int af, const char *first,
2312
+ const char *last) {
2313
+ if (std::distance(first, last) == 0) {
2314
+ return -1;
2315
+ }
2316
+
2317
+ const char *host_begin, *host_end, *it;
2318
+ if (*first == '[') {
2319
+ host_begin = first + 1;
2320
+ it = std::find(host_begin, last, ']');
2321
+ if (it == last) {
2322
+ return -1;
2323
+ }
2324
+ host_end = it;
2325
+ ++it;
2326
+ if (it == last || *it != ':') {
2327
+ return -1;
2328
+ }
2329
+ } else {
2330
+ host_begin = first;
2331
+ it = std::find(host_begin, last, ':');
2332
+ if (it == last) {
2333
+ return -1;
2334
+ }
2335
+ host_end = it;
2336
+ }
2337
+
2338
+ if (++it == last) {
2339
+ return -1;
2340
+ }
2341
+ auto svc_begin = it;
2342
+
2343
+ std::array<char, NI_MAXHOST> host;
2344
+ *std::copy(host_begin, host_end, std::begin(host)) = '\0';
2345
+
2346
+ addrinfo hints{}, *res;
2347
+ hints.ai_family = af;
2348
+ hints.ai_socktype = SOCK_DGRAM;
2349
+
2350
+ if (auto rv = getaddrinfo(host.data(), svc_begin, &hints, &res); rv != 0) {
2351
+ std::cerr << "getaddrinfo: [" << host.data() << "]:" << svc_begin << ": "
2352
+ << gai_strerror(rv) << std::endl;
2353
+ return -1;
2354
+ }
2355
+
2356
+ dest.len = res->ai_addrlen;
2357
+ memcpy(&dest.su, res->ai_addr, res->ai_addrlen);
2358
+
2359
+ freeaddrinfo(res);
2360
+
2361
+ return 0;
2362
+ }
2363
+ } // namespace
2364
+
2365
+ namespace {
2366
+ void print_usage() {
2367
+ std::cerr << "Usage: server [OPTIONS] <ADDR> <PORT> <PRIVATE_KEY_FILE> "
2368
+ "<CERTIFICATE_FILE>"
2369
+ << std::endl;
2370
+ }
2371
+ } // namespace
2372
+
2373
+ namespace {
2374
+ void config_set_default(Config &config) {
2375
+ config = Config{};
2376
+ config.tx_loss_prob = 0.;
2377
+ config.rx_loss_prob = 0.;
2378
+ config.ciphers = util::crypto_default_ciphers();
2379
+ config.groups = util::crypto_default_groups();
2380
+ config.timeout = 30 * NGTCP2_SECONDS;
2381
+ {
2382
+ auto path = realpath(".", nullptr);
2383
+ assert(path);
2384
+ config.htdocs = path;
2385
+ free(path);
2386
+ }
2387
+ config.mime_types_file = "/etc/mime.types"sv;
2388
+ config.max_data = 1_m;
2389
+ config.max_stream_data_bidi_local = 256_k;
2390
+ config.max_stream_data_bidi_remote = 256_k;
2391
+ config.max_stream_data_uni = 256_k;
2392
+ config.max_window = 6_m;
2393
+ config.max_stream_window = 6_m;
2394
+ config.max_streams_bidi = 100;
2395
+ config.max_streams_uni = 3;
2396
+ config.max_dyn_length = 20_m;
2397
+ config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
2398
+ config.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
2399
+ config.max_gso_dgrams = 64;
2400
+ config.handshake_timeout = UINT64_MAX;
2401
+ config.ack_thresh = 2;
2402
+ }
2403
+ } // namespace
2404
+
2405
+ namespace {
2406
+ void print_help() {
2407
+ print_usage();
2408
+
2409
+ config_set_default(config);
2410
+
2411
+ std::cout << R"(
2412
+ <ADDR> Address to listen to. '*' binds to any address.
2413
+ <PORT> Port
2414
+ <PRIVATE_KEY_FILE>
2415
+ Path to private key file
2416
+ <CERTIFICATE_FILE>
2417
+ Path to certificate file
2418
+ Options:
2419
+ -t, --tx-loss=<P>
2420
+ The probability of losing outgoing packets. <P> must be
2421
+ [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
2422
+ means 100% packet loss.
2423
+ -r, --rx-loss=<P>
2424
+ The probability of losing incoming packets. <P> must be
2425
+ [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
2426
+ means 100% packet loss.
2427
+ --ciphers=<CIPHERS>
2428
+ Specify the cipher suite list to enable.
2429
+ Default: )"
2430
+ << config.ciphers << R"(
2431
+ --groups=<GROUPS>
2432
+ Specify the supported groups.
2433
+ Default: )"
2434
+ << config.groups << R"(
2435
+ -d, --htdocs=<PATH>
2436
+ Specify document root. If this option is not specified,
2437
+ the document root is the current working directory.
2438
+ -q, --quiet Suppress debug output.
2439
+ -s, --show-secret
2440
+ Print out secrets unless --quiet is used.
2441
+ --timeout=<DURATION>
2442
+ Specify idle timeout.
2443
+ Default: )"
2444
+ << util::format_duration(config.timeout) << R"(
2445
+ -V, --validate-addr
2446
+ Perform address validation.
2447
+ --preferred-ipv4-addr=<ADDR>:<PORT>
2448
+ Specify preferred IPv4 address and port.
2449
+ --preferred-ipv6-addr=<ADDR>:<PORT>
2450
+ Specify preferred IPv6 address and port. A numeric IPv6
2451
+ address must be enclosed by '[' and ']' (e.g.,
2452
+ [::1]:8443)
2453
+ --mime-types-file=<PATH>
2454
+ Path to file that contains MIME media types and the
2455
+ extensions.
2456
+ Default: )"
2457
+ << config.mime_types_file << R"(
2458
+ --early-response
2459
+ Start sending response when it receives HTTP header
2460
+ fields without waiting for request body. If HTTP
2461
+ response data is written before receiving request body,
2462
+ STOP_SENDING is sent.
2463
+ --verify-client
2464
+ Request a client certificate. At the moment, we just
2465
+ request a certificate and no verification is done.
2466
+ --qlog-dir=<PATH>
2467
+ Path to the directory where qlog file is stored. The
2468
+ file name of each qlog is the Source Connection ID of
2469
+ server.
2470
+ --no-quic-dump
2471
+ Disables printing QUIC STREAM and CRYPTO frame data out.
2472
+ --no-http-dump
2473
+ Disables printing HTTP response body out.
2474
+ --max-data=<SIZE>
2475
+ The initial connection-level flow control window.
2476
+ Default: )"
2477
+ << util::format_uint_iec(config.max_data) << R"(
2478
+ --max-stream-data-bidi-local=<SIZE>
2479
+ The initial stream-level flow control window for a
2480
+ bidirectional stream that the local endpoint initiates.
2481
+ Default: )"
2482
+ << util::format_uint_iec(config.max_stream_data_bidi_local) << R"(
2483
+ --max-stream-data-bidi-remote=<SIZE>
2484
+ The initial stream-level flow control window for a
2485
+ bidirectional stream that the remote endpoint initiates.
2486
+ Default: )"
2487
+ << util::format_uint_iec(config.max_stream_data_bidi_remote) << R"(
2488
+ --max-stream-data-uni=<SIZE>
2489
+ The initial stream-level flow control window for a
2490
+ unidirectional stream.
2491
+ Default: )"
2492
+ << util::format_uint_iec(config.max_stream_data_uni) << R"(
2493
+ --max-streams-bidi=<N>
2494
+ The number of the concurrent bidirectional streams.
2495
+ Default: )"
2496
+ << config.max_streams_bidi << R"(
2497
+ --max-streams-uni=<N>
2498
+ The number of the concurrent unidirectional streams.
2499
+ Default: )"
2500
+ << config.max_streams_uni << R"(
2501
+ --max-dyn-length=<SIZE>
2502
+ The maximum length of a dynamically generated content.
2503
+ Default: )"
2504
+ << util::format_uint_iec(config.max_dyn_length) << R"(
2505
+ --cc=(cubic|reno|bbr|bbr2)
2506
+ The name of congestion controller algorithm.
2507
+ Default: )"
2508
+ << util::strccalgo(config.cc_algo) << R"(
2509
+ --initial-rtt=<DURATION>
2510
+ Set an initial RTT.
2511
+ Default: )"
2512
+ << util::format_duration(config.initial_rtt) << R"(
2513
+ --max-udp-payload-size=<SIZE>
2514
+ Override maximum UDP payload size that server transmits.
2515
+ --max-window=<SIZE>
2516
+ Maximum connection-level flow control window size. The
2517
+ window auto-tuning is enabled if nonzero value is given,
2518
+ and window size is scaled up to this value.
2519
+ Default: )"
2520
+ << util::format_uint_iec(config.max_window) << R"(
2521
+ --max-stream-window=<SIZE>
2522
+ Maximum stream-level flow control window size. The
2523
+ window auto-tuning is enabled if nonzero value is given,
2524
+ and window size is scaled up to this value.
2525
+ Default: )"
2526
+ << util::format_uint_iec(config.max_stream_window) << R"(
2527
+ --send-trailers
2528
+ Send trailer fields.
2529
+ --max-gso-dgrams=<N>
2530
+ Maximum number of UDP datagrams that are sent in a
2531
+ single GSO sendmsg call.
2532
+ Default: )"
2533
+ << config.max_gso_dgrams << R"(
2534
+ --handshake-timeout=<DURATION>
2535
+ Set the QUIC handshake timeout. It defaults to no
2536
+ timeout.
2537
+ --preferred-versions=<HEX>[[,<HEX>]...]
2538
+ Specify QUIC versions in hex string in the order of
2539
+ preference. Server negotiates one of those versions if
2540
+ client initially selects a less preferred version.
2541
+ These versions must be supported by libngtcp2. Instead
2542
+ of specifying hex string, there are special aliases
2543
+ available: "v1" indicates QUIC v1, and "v2" indicates
2544
+ QUIC v2.
2545
+ --available-versions=<HEX>[[,<HEX>]...]
2546
+ Specify QUIC versions in hex string that are sent in
2547
+ available_versions field of version_information
2548
+ transport parameter. This list can include a version
2549
+ which is not supported by libngtcp2. Instead of
2550
+ specifying hex string, there are special aliases
2551
+ available: "v1" indicates QUIC v1, and "v2" indicates
2552
+ QUIC v2.
2553
+ --no-pmtud Disables Path MTU Discovery.
2554
+ --ack-thresh=<N>
2555
+ The minimum number of the received ACK eliciting packets
2556
+ that triggers immediate acknowledgement.
2557
+ Default: )"
2558
+ << config.ack_thresh << R"(
2559
+ -h, --help Display this help and exit.
2560
+
2561
+ ---
2562
+
2563
+ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
2564
+ 10 * 1024). Units are K, M and G (powers of 1024).
2565
+
2566
+ The <DURATION> argument is an integer and an optional unit (e.g., 1s
2567
+ is 1 second and 500ms is 500 milliseconds). Units are h, m, s, ms,
2568
+ us, or ns (hours, minutes, seconds, milliseconds, microseconds, and
2569
+ nanoseconds respectively). If a unit is omitted, a second is used
2570
+ as unit.
2571
+
2572
+ The <HEX> argument is an hex string which must start with "0x"
2573
+ (e.g., 0x00000001).)"
2574
+ << std::endl;
2575
+ }
2576
+ } // namespace
2577
+
2578
+ std::ofstream keylog_file;
2579
+
2580
+ int main(int argc, char **argv) {
2581
+ config_set_default(config);
2582
+
2583
+ for (;;) {
2584
+ static int flag = 0;
2585
+ constexpr static option long_opts[] = {
2586
+ {"help", no_argument, nullptr, 'h'},
2587
+ {"tx-loss", required_argument, nullptr, 't'},
2588
+ {"rx-loss", required_argument, nullptr, 'r'},
2589
+ {"htdocs", required_argument, nullptr, 'd'},
2590
+ {"quiet", no_argument, nullptr, 'q'},
2591
+ {"show-secret", no_argument, nullptr, 's'},
2592
+ {"validate-addr", no_argument, nullptr, 'V'},
2593
+ {"ciphers", required_argument, &flag, 1},
2594
+ {"groups", required_argument, &flag, 2},
2595
+ {"timeout", required_argument, &flag, 3},
2596
+ {"preferred-ipv4-addr", required_argument, &flag, 4},
2597
+ {"preferred-ipv6-addr", required_argument, &flag, 5},
2598
+ {"mime-types-file", required_argument, &flag, 6},
2599
+ {"early-response", no_argument, &flag, 7},
2600
+ {"verify-client", no_argument, &flag, 8},
2601
+ {"qlog-dir", required_argument, &flag, 9},
2602
+ {"no-quic-dump", no_argument, &flag, 10},
2603
+ {"no-http-dump", no_argument, &flag, 11},
2604
+ {"max-data", required_argument, &flag, 12},
2605
+ {"max-stream-data-bidi-local", required_argument, &flag, 13},
2606
+ {"max-stream-data-bidi-remote", required_argument, &flag, 14},
2607
+ {"max-stream-data-uni", required_argument, &flag, 15},
2608
+ {"max-streams-bidi", required_argument, &flag, 16},
2609
+ {"max-streams-uni", required_argument, &flag, 17},
2610
+ {"max-dyn-length", required_argument, &flag, 18},
2611
+ {"cc", required_argument, &flag, 19},
2612
+ {"initial-rtt", required_argument, &flag, 20},
2613
+ {"max-udp-payload-size", required_argument, &flag, 21},
2614
+ {"send-trailers", no_argument, &flag, 22},
2615
+ {"max-window", required_argument, &flag, 23},
2616
+ {"max-stream-window", required_argument, &flag, 24},
2617
+ {"max-gso-dgrams", required_argument, &flag, 25},
2618
+ {"handshake-timeout", required_argument, &flag, 26},
2619
+ {"preferred-versions", required_argument, &flag, 27},
2620
+ {"available-versions", required_argument, &flag, 28},
2621
+ {"no-pmtud", no_argument, &flag, 29},
2622
+ {"ack-thresh", required_argument, &flag, 30},
2623
+ {nullptr, 0, nullptr, 0}};
2624
+
2625
+ auto optidx = 0;
2626
+ auto c = getopt_long(argc, argv, "d:hqr:st:V", long_opts, &optidx);
2627
+ if (c == -1) {
2628
+ break;
2629
+ }
2630
+ switch (c) {
2631
+ case 'd': {
2632
+ // --htdocs
2633
+ auto path = realpath(optarg, nullptr);
2634
+ if (path == nullptr) {
2635
+ std::cerr << "path: invalid path " << std::quoted(optarg) << std::endl;
2636
+ exit(EXIT_FAILURE);
2637
+ }
2638
+ config.htdocs = path;
2639
+ free(path);
2640
+ break;
2641
+ }
2642
+ case 'h':
2643
+ // --help
2644
+ print_help();
2645
+ exit(EXIT_SUCCESS);
2646
+ case 'q':
2647
+ // --quiet
2648
+ config.quiet = true;
2649
+ break;
2650
+ case 'r':
2651
+ // --rx-loss
2652
+ config.rx_loss_prob = strtod(optarg, nullptr);
2653
+ break;
2654
+ case 's':
2655
+ // --show-secret
2656
+ config.show_secret = true;
2657
+ break;
2658
+ case 't':
2659
+ // --tx-loss
2660
+ config.tx_loss_prob = strtod(optarg, nullptr);
2661
+ break;
2662
+ case 'V':
2663
+ // --validate-addr
2664
+ config.validate_addr = true;
2665
+ break;
2666
+ case '?':
2667
+ print_usage();
2668
+ exit(EXIT_FAILURE);
2669
+ case 0:
2670
+ switch (flag) {
2671
+ case 1:
2672
+ // --ciphers
2673
+ config.ciphers = optarg;
2674
+ break;
2675
+ case 2:
2676
+ // --groups
2677
+ config.groups = optarg;
2678
+ break;
2679
+ case 3:
2680
+ // --timeout
2681
+ if (auto t = util::parse_duration(optarg); !t) {
2682
+ std::cerr << "timeout: invalid argument" << std::endl;
2683
+ exit(EXIT_FAILURE);
2684
+ } else {
2685
+ config.timeout = *t;
2686
+ }
2687
+ break;
2688
+ case 4:
2689
+ // --preferred-ipv4-addr
2690
+ if (parse_host_port(config.preferred_ipv4_addr, AF_INET, optarg,
2691
+ optarg + strlen(optarg)) != 0) {
2692
+ std::cerr << "preferred-ipv4-addr: could not use "
2693
+ << std::quoted(optarg) << std::endl;
2694
+ exit(EXIT_FAILURE);
2695
+ }
2696
+ break;
2697
+ case 5:
2698
+ // --preferred-ipv6-addr
2699
+ if (parse_host_port(config.preferred_ipv6_addr, AF_INET6, optarg,
2700
+ optarg + strlen(optarg)) != 0) {
2701
+ std::cerr << "preferred-ipv6-addr: could not use "
2702
+ << std::quoted(optarg) << std::endl;
2703
+ exit(EXIT_FAILURE);
2704
+ }
2705
+ break;
2706
+ case 6:
2707
+ // --mime-types-file
2708
+ config.mime_types_file = optarg;
2709
+ break;
2710
+ case 7:
2711
+ // --early-response
2712
+ config.early_response = true;
2713
+ break;
2714
+ case 8:
2715
+ // --verify-client
2716
+ config.verify_client = true;
2717
+ break;
2718
+ case 9:
2719
+ // --qlog-dir
2720
+ config.qlog_dir = optarg;
2721
+ break;
2722
+ case 10:
2723
+ // --no-quic-dump
2724
+ config.no_quic_dump = true;
2725
+ break;
2726
+ case 11:
2727
+ // --no-http-dump
2728
+ config.no_http_dump = true;
2729
+ break;
2730
+ case 12:
2731
+ // --max-data
2732
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2733
+ std::cerr << "max-data: invalid argument" << std::endl;
2734
+ exit(EXIT_FAILURE);
2735
+ } else {
2736
+ config.max_data = *n;
2737
+ }
2738
+ break;
2739
+ case 13:
2740
+ // --max-stream-data-bidi-local
2741
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2742
+ std::cerr << "max-stream-data-bidi-local: invalid argument"
2743
+ << std::endl;
2744
+ exit(EXIT_FAILURE);
2745
+ } else {
2746
+ config.max_stream_data_bidi_local = *n;
2747
+ }
2748
+ break;
2749
+ case 14:
2750
+ // --max-stream-data-bidi-remote
2751
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2752
+ std::cerr << "max-stream-data-bidi-remote: invalid argument"
2753
+ << std::endl;
2754
+ exit(EXIT_FAILURE);
2755
+ } else {
2756
+ config.max_stream_data_bidi_remote = *n;
2757
+ }
2758
+ break;
2759
+ case 15:
2760
+ // --max-stream-data-uni
2761
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2762
+ std::cerr << "max-stream-data-uni: invalid argument" << std::endl;
2763
+ exit(EXIT_FAILURE);
2764
+ } else {
2765
+ config.max_stream_data_uni = *n;
2766
+ }
2767
+ break;
2768
+ case 16:
2769
+ // --max-streams-bidi
2770
+ if (auto n = util::parse_uint(optarg); !n) {
2771
+ std::cerr << "max-streams-bidi: invalid argument" << std::endl;
2772
+ exit(EXIT_FAILURE);
2773
+ } else {
2774
+ config.max_streams_bidi = *n;
2775
+ }
2776
+ break;
2777
+ case 17:
2778
+ // --max-streams-uni
2779
+ if (auto n = util::parse_uint(optarg); !n) {
2780
+ std::cerr << "max-streams-uni: invalid argument" << std::endl;
2781
+ exit(EXIT_FAILURE);
2782
+ } else {
2783
+ config.max_streams_uni = *n;
2784
+ }
2785
+ break;
2786
+ case 18:
2787
+ // --max-dyn-length
2788
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2789
+ std::cerr << "max-dyn-length: invalid argument" << std::endl;
2790
+ exit(EXIT_FAILURE);
2791
+ } else {
2792
+ config.max_dyn_length = *n;
2793
+ }
2794
+ break;
2795
+ case 19:
2796
+ // --cc
2797
+ if (strcmp("cubic", optarg) == 0) {
2798
+ config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
2799
+ break;
2800
+ }
2801
+ if (strcmp("reno", optarg) == 0) {
2802
+ config.cc_algo = NGTCP2_CC_ALGO_RENO;
2803
+ break;
2804
+ }
2805
+ if (strcmp("bbr", optarg) == 0) {
2806
+ config.cc_algo = NGTCP2_CC_ALGO_BBR;
2807
+ break;
2808
+ }
2809
+ if (strcmp("bbr2", optarg) == 0) {
2810
+ config.cc_algo = NGTCP2_CC_ALGO_BBR2;
2811
+ break;
2812
+ }
2813
+ std::cerr << "cc: specify cubic, reno, bbr, or bbr2" << std::endl;
2814
+ exit(EXIT_FAILURE);
2815
+ case 20:
2816
+ // --initial-rtt
2817
+ if (auto t = util::parse_duration(optarg); !t) {
2818
+ std::cerr << "initial-rtt: invalid argument" << std::endl;
2819
+ exit(EXIT_FAILURE);
2820
+ } else {
2821
+ config.initial_rtt = *t;
2822
+ }
2823
+ break;
2824
+ case 21:
2825
+ // --max-udp-payload-size
2826
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2827
+ std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
2828
+ exit(EXIT_FAILURE);
2829
+ } else if (*n > 64_k) {
2830
+ std::cerr << "max-udp-payload-size: must not exceed 65536"
2831
+ << std::endl;
2832
+ exit(EXIT_FAILURE);
2833
+ } else {
2834
+ config.max_udp_payload_size = *n;
2835
+ }
2836
+ break;
2837
+ case 22:
2838
+ // --send-trailers
2839
+ config.send_trailers = true;
2840
+ break;
2841
+ case 23:
2842
+ // --max-window
2843
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2844
+ std::cerr << "max-window: invalid argument" << std::endl;
2845
+ exit(EXIT_FAILURE);
2846
+ } else {
2847
+ config.max_window = *n;
2848
+ }
2849
+ break;
2850
+ case 24:
2851
+ // --max-stream-window
2852
+ if (auto n = util::parse_uint_iec(optarg); !n) {
2853
+ std::cerr << "max-stream-window: invalid argument" << std::endl;
2854
+ exit(EXIT_FAILURE);
2855
+ } else {
2856
+ config.max_stream_window = *n;
2857
+ }
2858
+ break;
2859
+ case 25:
2860
+ // --max-gso-dgrams
2861
+ if (auto n = util::parse_uint(optarg); !n) {
2862
+ std::cerr << "max-gso-dgrams: invalid argument" << std::endl;
2863
+ exit(EXIT_FAILURE);
2864
+ } else {
2865
+ config.max_gso_dgrams = *n;
2866
+ }
2867
+ break;
2868
+ case 26:
2869
+ // --handshake-timeout
2870
+ if (auto t = util::parse_duration(optarg); !t) {
2871
+ std::cerr << "handshake-timeout: invalid argument" << std::endl;
2872
+ exit(EXIT_FAILURE);
2873
+ } else {
2874
+ config.handshake_timeout = *t;
2875
+ }
2876
+ break;
2877
+ case 27: {
2878
+ // --preferred-versions
2879
+ auto l = util::split_str(optarg);
2880
+ if (l.size() > max_preferred_versionslen) {
2881
+ std::cerr << "preferred-versions: too many versions > "
2882
+ << max_preferred_versionslen << std::endl;
2883
+ }
2884
+ config.preferred_versions.resize(l.size());
2885
+ auto it = std::begin(config.preferred_versions);
2886
+ for (const auto &k : l) {
2887
+ if (k == "v1"sv) {
2888
+ *it++ = NGTCP2_PROTO_VER_V1;
2889
+ continue;
2890
+ }
2891
+ if (k == "v2"sv) {
2892
+ *it++ = NGTCP2_PROTO_VER_V2;
2893
+ continue;
2894
+ }
2895
+ auto rv = util::parse_version(k);
2896
+ if (!rv) {
2897
+ std::cerr << "preferred-versions: invalid version "
2898
+ << std::quoted(k) << std::endl;
2899
+ exit(EXIT_FAILURE);
2900
+ }
2901
+ if (!ngtcp2_is_supported_version(*rv)) {
2902
+ std::cerr << "preferred-versions: unsupported version "
2903
+ << std::quoted(k) << std::endl;
2904
+ exit(EXIT_FAILURE);
2905
+ }
2906
+ *it++ = *rv;
2907
+ }
2908
+ break;
2909
+ }
2910
+ case 28: {
2911
+ // --available-versions
2912
+ auto l = util::split_str(optarg);
2913
+ config.available_versions.resize(l.size());
2914
+ auto it = std::begin(config.available_versions);
2915
+ for (const auto &k : l) {
2916
+ if (k == "v1"sv) {
2917
+ *it++ = NGTCP2_PROTO_VER_V1;
2918
+ continue;
2919
+ }
2920
+ if (k == "v2"sv) {
2921
+ *it++ = NGTCP2_PROTO_VER_V2;
2922
+ continue;
2923
+ }
2924
+ auto rv = util::parse_version(k);
2925
+ if (!rv) {
2926
+ std::cerr << "available-versions: invalid version "
2927
+ << std::quoted(k) << std::endl;
2928
+ exit(EXIT_FAILURE);
2929
+ }
2930
+ *it++ = *rv;
2931
+ }
2932
+ break;
2933
+ }
2934
+ case 29:
2935
+ // --no-pmtud
2936
+ config.no_pmtud = true;
2937
+ break;
2938
+ case 30:
2939
+ // --ack-thresh
2940
+ if (auto n = util::parse_uint(optarg); !n) {
2941
+ std::cerr << "ack-thresh: invalid argument" << std::endl;
2942
+ exit(EXIT_FAILURE);
2943
+ } else if (*n > 100) {
2944
+ std::cerr << "ack-thresh: must not exceed 100" << std::endl;
2945
+ exit(EXIT_FAILURE);
2946
+ } else {
2947
+ config.ack_thresh = *n;
2948
+ }
2949
+ break;
2950
+ }
2951
+ break;
2952
+ default:
2953
+ break;
2954
+ };
2955
+ }
2956
+
2957
+ if (argc - optind < 4) {
2958
+ std::cerr << "Too few arguments" << std::endl;
2959
+ print_usage();
2960
+ exit(EXIT_FAILURE);
2961
+ }
2962
+
2963
+ auto addr = argv[optind++];
2964
+ auto port = argv[optind++];
2965
+ auto private_key_file = argv[optind++];
2966
+ auto cert_file = argv[optind++];
2967
+
2968
+ if (auto n = util::parse_uint(port); !n) {
2969
+ std::cerr << "port: invalid port number" << std::endl;
2970
+ exit(EXIT_FAILURE);
2971
+ } else if (*n > 65535) {
2972
+ std::cerr << "port: must not exceed 65535" << std::endl;
2973
+ exit(EXIT_FAILURE);
2974
+ } else {
2975
+ config.port = *n;
2976
+ }
2977
+
2978
+ if (auto mt = util::read_mime_types(config.mime_types_file); !mt) {
2979
+ std::cerr << "mime-types-file: Could not read MIME media types file "
2980
+ << std::quoted(config.mime_types_file) << std::endl;
2981
+ } else {
2982
+ config.mime_types = std::move(*mt);
2983
+ }
2984
+
2985
+ TLSServerContext tls_ctx;
2986
+
2987
+ if (tls_ctx.init(private_key_file, cert_file, AppProtocol::HQ) != 0) {
2988
+ exit(EXIT_FAILURE);
2989
+ }
2990
+
2991
+ if (config.htdocs.back() != '/') {
2992
+ config.htdocs += '/';
2993
+ }
2994
+
2995
+ std::cerr << "Using document root " << config.htdocs << std::endl;
2996
+
2997
+ auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
2998
+
2999
+ auto keylog_filename = getenv("SSLKEYLOGFILE");
3000
+ if (keylog_filename) {
3001
+ keylog_file.open(keylog_filename, std::ios_base::app);
3002
+ if (keylog_file) {
3003
+ tls_ctx.enable_keylog();
3004
+ }
3005
+ }
3006
+
3007
+ if (util::generate_secret(config.static_secret.data(),
3008
+ config.static_secret.size()) != 0) {
3009
+ std::cerr << "Unable to generate static secret" << std::endl;
3010
+ exit(EXIT_FAILURE);
3011
+ }
3012
+
3013
+ Server s(EV_DEFAULT, tls_ctx);
3014
+ if (s.init(addr, port) != 0) {
3015
+ exit(EXIT_FAILURE);
3016
+ }
3017
+
3018
+ ev_run(EV_DEFAULT, 0);
3019
+
3020
+ s.disconnect();
3021
+ s.close();
3022
+
3023
+ return EXIT_SUCCESS;
3024
+ }