protocol-quic 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }