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,3731 @@
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 "server.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_DYNBUFLEN = 10_m;
65
+ } // namespace
66
+
67
+ namespace {
68
+ constexpr size_t max_preferred_versionslen = 4;
69
+ } // namespace
70
+
71
+ namespace {
72
+ auto randgen = util::make_mt19937();
73
+ } // namespace
74
+
75
+ Config config{};
76
+
77
+ Stream::Stream(int64_t stream_id, Handler *handler)
78
+ : stream_id(stream_id),
79
+ handler(handler),
80
+ data(nullptr),
81
+ datalen(0),
82
+ dynresp(false),
83
+ dyndataleft(0),
84
+ dynbuflen(0) {}
85
+
86
+ namespace {
87
+ constexpr auto NGTCP2_SERVER = "nghttp3/ngtcp2 server"sv;
88
+ } // namespace
89
+
90
+ namespace {
91
+ std::string make_status_body(unsigned int status_code) {
92
+ auto status_string = util::format_uint(status_code);
93
+ auto reason_phrase = http::get_reason_phrase(status_code);
94
+
95
+ std::string body;
96
+ body = "<html><head><title>";
97
+ body += status_string;
98
+ body += ' ';
99
+ body += reason_phrase;
100
+ body += "</title></head><body><h1>";
101
+ body += status_string;
102
+ body += ' ';
103
+ body += reason_phrase;
104
+ body += "</h1><hr><address>";
105
+ body += NGTCP2_SERVER;
106
+ body += " at port ";
107
+ body += util::format_uint(config.port);
108
+ body += "</address>";
109
+ body += "</body></html>";
110
+ return body;
111
+ }
112
+ } // namespace
113
+
114
+ struct Request {
115
+ std::string path;
116
+ struct {
117
+ int32_t urgency;
118
+ int inc;
119
+ } pri;
120
+ };
121
+
122
+ namespace {
123
+ Request request_path(const std::string_view &uri, bool is_connect) {
124
+ http_parser_url u;
125
+ Request req;
126
+
127
+ req.pri.urgency = -1;
128
+ req.pri.inc = -1;
129
+
130
+ http_parser_url_init(&u);
131
+
132
+ if (auto rv = http_parser_parse_url(uri.data(), uri.size(), is_connect, &u);
133
+ rv != 0) {
134
+ return req;
135
+ }
136
+
137
+ if (u.field_set & (1 << UF_PATH)) {
138
+ req.path = std::string(uri.data() + u.field_data[UF_PATH].off,
139
+ u.field_data[UF_PATH].len);
140
+ if (req.path.find('%') != std::string::npos) {
141
+ req.path = util::percent_decode(std::begin(req.path), std::end(req.path));
142
+ }
143
+ if (!req.path.empty() && req.path.back() == '/') {
144
+ req.path += "index.html";
145
+ }
146
+ } else {
147
+ req.path = "/index.html";
148
+ }
149
+
150
+ req.path = util::normalize_path(req.path);
151
+ if (req.path == "/") {
152
+ req.path = "/index.html";
153
+ }
154
+
155
+ if (u.field_set & (1 << UF_QUERY)) {
156
+ static constexpr auto urgency_prefix = "u="sv;
157
+ static constexpr auto inc_prefix = "i="sv;
158
+ auto q = std::string(uri.data() + u.field_data[UF_QUERY].off,
159
+ u.field_data[UF_QUERY].len);
160
+ for (auto p = std::begin(q); p != std::end(q);) {
161
+ if (util::istarts_with(p, std::end(q), std::begin(urgency_prefix),
162
+ std::end(urgency_prefix))) {
163
+ auto urgency_start = p + urgency_prefix.size();
164
+ auto urgency_end = std::find(urgency_start, std::end(q), '&');
165
+ if (urgency_start + 1 == urgency_end && '0' <= *urgency_start &&
166
+ *urgency_start <= '7') {
167
+ req.pri.urgency = *urgency_start - '0';
168
+ }
169
+ if (urgency_end == std::end(q)) {
170
+ break;
171
+ }
172
+ p = urgency_end + 1;
173
+ continue;
174
+ }
175
+ if (util::istarts_with(p, std::end(q), std::begin(inc_prefix),
176
+ std::end(inc_prefix))) {
177
+ auto inc_start = p + inc_prefix.size();
178
+ auto inc_end = std::find(inc_start, std::end(q), '&');
179
+ if (inc_start + 1 == inc_end &&
180
+ (*inc_start == '0' || *inc_start == '1')) {
181
+ req.pri.inc = *inc_start - '0';
182
+ }
183
+ if (inc_end == std::end(q)) {
184
+ break;
185
+ }
186
+ p = inc_end + 1;
187
+ continue;
188
+ }
189
+
190
+ p = std::find(p, std::end(q), '&');
191
+ if (p == std::end(q)) {
192
+ break;
193
+ }
194
+ ++p;
195
+ }
196
+ }
197
+ return req;
198
+ }
199
+ } // namespace
200
+
201
+ enum FileEntryFlag {
202
+ FILE_ENTRY_TYPE_DIR = 0x1,
203
+ };
204
+
205
+ struct FileEntry {
206
+ uint64_t len;
207
+ void *map;
208
+ int fd;
209
+ uint8_t flags;
210
+ };
211
+
212
+ namespace {
213
+ std::unordered_map<std::string, FileEntry> file_cache;
214
+ } // namespace
215
+
216
+ std::pair<FileEntry, int> Stream::open_file(const std::string &path) {
217
+ auto it = file_cache.find(path);
218
+ if (it != std::end(file_cache)) {
219
+ return {(*it).second, 0};
220
+ }
221
+
222
+ auto fd = open(path.c_str(), O_RDONLY);
223
+ if (fd == -1) {
224
+ return {{}, -1};
225
+ }
226
+
227
+ struct stat st {};
228
+ if (fstat(fd, &st) != 0) {
229
+ close(fd);
230
+ return {{}, -1};
231
+ }
232
+
233
+ FileEntry fe{};
234
+ if (st.st_mode & S_IFDIR) {
235
+ fe.flags |= FILE_ENTRY_TYPE_DIR;
236
+ fe.fd = -1;
237
+ close(fd);
238
+ } else {
239
+ fe.fd = fd;
240
+ fe.len = st.st_size;
241
+ fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0);
242
+ if (fe.map == MAP_FAILED) {
243
+ std::cerr << "mmap: " << strerror(errno) << std::endl;
244
+ close(fd);
245
+ return {{}, -1};
246
+ }
247
+ }
248
+
249
+ file_cache.emplace(path, fe);
250
+
251
+ return {std::move(fe), 0};
252
+ }
253
+
254
+ void Stream::map_file(const FileEntry &fe) {
255
+ data = static_cast<uint8_t *>(fe.map);
256
+ datalen = fe.len;
257
+ }
258
+
259
+ int64_t Stream::find_dyn_length(const std::string_view &path) {
260
+ assert(path[0] == '/');
261
+
262
+ if (path.size() == 1) {
263
+ return -1;
264
+ }
265
+
266
+ uint64_t n = 0;
267
+
268
+ for (auto it = std::begin(path) + 1; it != std::end(path); ++it) {
269
+ if (*it < '0' || '9' < *it) {
270
+ return -1;
271
+ }
272
+ auto d = *it - '0';
273
+ if (n > (((1ull << 62) - 1) - d) / 10) {
274
+ return -1;
275
+ }
276
+ n = n * 10 + d;
277
+ if (n > config.max_dyn_length) {
278
+ return -1;
279
+ }
280
+ }
281
+
282
+ return static_cast<int64_t>(n);
283
+ }
284
+
285
+ namespace {
286
+ nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec,
287
+ size_t veccnt, uint32_t *pflags, void *user_data,
288
+ void *stream_user_data) {
289
+ auto stream = static_cast<Stream *>(stream_user_data);
290
+
291
+ vec[0].base = stream->data;
292
+ vec[0].len = stream->datalen;
293
+ *pflags |= NGHTTP3_DATA_FLAG_EOF;
294
+ if (config.send_trailers) {
295
+ *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM;
296
+ }
297
+
298
+ return 1;
299
+ }
300
+ } // namespace
301
+
302
+ auto dyn_buf = std::make_unique<std::array<uint8_t, 16_k>>();
303
+
304
+ namespace {
305
+ nghttp3_ssize dyn_read_data(nghttp3_conn *conn, int64_t stream_id,
306
+ nghttp3_vec *vec, size_t veccnt, uint32_t *pflags,
307
+ void *user_data, void *stream_user_data) {
308
+ auto stream = static_cast<Stream *>(stream_user_data);
309
+
310
+ if (stream->dynbuflen > MAX_DYNBUFLEN) {
311
+ return NGHTTP3_ERR_WOULDBLOCK;
312
+ }
313
+
314
+ auto len =
315
+ std::min(dyn_buf->size(), static_cast<size_t>(stream->dyndataleft));
316
+
317
+ vec[0].base = dyn_buf->data();
318
+ vec[0].len = len;
319
+
320
+ stream->dynbuflen += len;
321
+ stream->dyndataleft -= len;
322
+
323
+ if (stream->dyndataleft == 0) {
324
+ *pflags |= NGHTTP3_DATA_FLAG_EOF;
325
+ if (config.send_trailers) {
326
+ *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM;
327
+ auto stream_id_str = util::format_uint(stream_id);
328
+ std::array<nghttp3_nv, 1> trailers{
329
+ util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str),
330
+ };
331
+
332
+ if (auto rv = nghttp3_conn_submit_trailers(
333
+ conn, stream_id, trailers.data(), trailers.size());
334
+ rv != 0) {
335
+ std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
336
+ << std::endl;
337
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
338
+ }
339
+ }
340
+ }
341
+
342
+ return 1;
343
+ }
344
+ } // namespace
345
+
346
+ void Stream::http_acked_stream_data(uint64_t datalen) {
347
+ if (!dynresp) {
348
+ return;
349
+ }
350
+
351
+ assert(dynbuflen >= datalen);
352
+
353
+ dynbuflen -= datalen;
354
+ }
355
+
356
+ int Stream::send_status_response(nghttp3_conn *httpconn,
357
+ unsigned int status_code,
358
+ const std::vector<HTTPHeader> &extra_headers) {
359
+ status_resp_body = make_status_body(status_code);
360
+
361
+ auto status_code_str = util::format_uint(status_code);
362
+ auto content_length_str = util::format_uint(status_resp_body.size());
363
+
364
+ std::vector<nghttp3_nv> nva(4 + extra_headers.size());
365
+ nva[0] = util::make_nv_nc(":status"sv, status_code_str);
366
+ nva[1] = util::make_nv_nn("server"sv, NGTCP2_SERVER);
367
+ nva[2] = util::make_nv_nn("content-type"sv, "text/html; charset=utf-8");
368
+ nva[3] = util::make_nv_nc("content-length"sv, content_length_str);
369
+ for (size_t i = 0; i < extra_headers.size(); ++i) {
370
+ auto &hdr = extra_headers[i];
371
+ auto &nv = nva[4 + i];
372
+ nv = util::make_nv_cc(hdr.name, hdr.value);
373
+ }
374
+
375
+ data = (uint8_t *)status_resp_body.data();
376
+ datalen = status_resp_body.size();
377
+
378
+ nghttp3_data_reader dr{};
379
+ dr.read_data = read_data;
380
+
381
+ if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(),
382
+ nva.size(), &dr);
383
+ rv != 0) {
384
+ std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv)
385
+ << std::endl;
386
+ return -1;
387
+ }
388
+
389
+ if (config.send_trailers) {
390
+ auto stream_id_str = util::format_uint(stream_id);
391
+ std::array<nghttp3_nv, 1> trailers{
392
+ util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str),
393
+ };
394
+
395
+ if (auto rv = nghttp3_conn_submit_trailers(
396
+ httpconn, stream_id, trailers.data(), trailers.size());
397
+ rv != 0) {
398
+ std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
399
+ << std::endl;
400
+ return -1;
401
+ }
402
+ }
403
+
404
+ handler->shutdown_read(stream_id, NGHTTP3_H3_NO_ERROR);
405
+
406
+ return 0;
407
+ }
408
+
409
+ int Stream::send_redirect_response(nghttp3_conn *httpconn,
410
+ unsigned int status_code,
411
+ const std::string_view &path) {
412
+ return send_status_response(httpconn, status_code, {{"location", path}});
413
+ }
414
+
415
+ int Stream::start_response(nghttp3_conn *httpconn) {
416
+ // TODO This should be handled by nghttp3
417
+ if (uri.empty() || method.empty()) {
418
+ return send_status_response(httpconn, 400);
419
+ }
420
+
421
+ auto req = request_path(uri, method == "CONNECT");
422
+ if (req.path.empty()) {
423
+ return send_status_response(httpconn, 400);
424
+ }
425
+
426
+ auto dyn_len = find_dyn_length(req.path);
427
+
428
+ int64_t content_length = -1;
429
+ nghttp3_data_reader dr{};
430
+ auto content_type = "text/plain"sv;
431
+
432
+ if (dyn_len == -1) {
433
+ auto path = config.htdocs + req.path;
434
+ auto [fe, rv] = open_file(path);
435
+ if (rv != 0) {
436
+ send_status_response(httpconn, 404);
437
+ return 0;
438
+ }
439
+
440
+ if (fe.flags & FILE_ENTRY_TYPE_DIR) {
441
+ send_redirect_response(httpconn, 308,
442
+ path.substr(config.htdocs.size() - 1) + '/');
443
+ return 0;
444
+ }
445
+
446
+ content_length = fe.len;
447
+
448
+ if (method != "HEAD") {
449
+ map_file(fe);
450
+ }
451
+
452
+ dr.read_data = read_data;
453
+
454
+ auto ext = std::end(req.path) - 1;
455
+ for (; ext != std::begin(req.path) && *ext != '.' && *ext != '/'; --ext)
456
+ ;
457
+ if (*ext == '.') {
458
+ ++ext;
459
+ auto it = config.mime_types.find(std::string{ext, std::end(req.path)});
460
+ if (it != std::end(config.mime_types)) {
461
+ content_type = (*it).second;
462
+ }
463
+ }
464
+ } else {
465
+ content_length = dyn_len;
466
+ dynresp = true;
467
+ dr.read_data = dyn_read_data;
468
+
469
+ if (method != "HEAD") {
470
+ datalen = dyn_len;
471
+ dyndataleft = dyn_len;
472
+ }
473
+
474
+ content_type = "application/octet-stream"sv;
475
+ }
476
+
477
+ auto content_length_str = util::format_uint(content_length);
478
+
479
+ std::array<nghttp3_nv, 5> nva{
480
+ util::make_nv_nn(":status"sv, "200"sv),
481
+ util::make_nv_nn("server"sv, NGTCP2_SERVER),
482
+ util::make_nv_nn("content-type"sv, content_type),
483
+ util::make_nv_nc("content-length"sv, content_length_str),
484
+ };
485
+
486
+ size_t nvlen = 4;
487
+
488
+ std::string prival;
489
+
490
+ if (req.pri.urgency != -1 || req.pri.inc != -1) {
491
+ nghttp3_pri pri;
492
+
493
+ if (auto rv = nghttp3_conn_get_stream_priority(httpconn, &pri, stream_id);
494
+ rv != 0) {
495
+ std::cerr << "nghttp3_conn_get_stream_priority: " << nghttp3_strerror(rv)
496
+ << std::endl;
497
+ return -1;
498
+ }
499
+
500
+ if (req.pri.urgency != -1) {
501
+ pri.urgency = req.pri.urgency;
502
+ }
503
+ if (req.pri.inc != -1) {
504
+ pri.inc = req.pri.inc;
505
+ }
506
+
507
+ if (auto rv = nghttp3_conn_set_stream_priority(httpconn, stream_id, &pri);
508
+ rv != 0) {
509
+ std::cerr << "nghttp3_conn_set_stream_priority: " << nghttp3_strerror(rv)
510
+ << std::endl;
511
+ return -1;
512
+ }
513
+
514
+ prival = "u=";
515
+ prival += pri.urgency + '0';
516
+ prival += ",i";
517
+ if (!pri.inc) {
518
+ prival += "=?0";
519
+ }
520
+
521
+ nva[nvlen++] = util::make_nv_nc("priority"sv, prival);
522
+ }
523
+
524
+ if (!config.quiet) {
525
+ debug::print_http_response_headers(stream_id, nva.data(), nvlen);
526
+ }
527
+
528
+ if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(),
529
+ nvlen, &dr);
530
+ rv != 0) {
531
+ std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv)
532
+ << std::endl;
533
+ return -1;
534
+ }
535
+
536
+ if (config.send_trailers && dyn_len == -1) {
537
+ auto stream_id_str = util::format_uint(stream_id);
538
+ std::array<nghttp3_nv, 1> trailers{
539
+ util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str),
540
+ };
541
+
542
+ if (auto rv = nghttp3_conn_submit_trailers(
543
+ httpconn, stream_id, trailers.data(), trailers.size());
544
+ rv != 0) {
545
+ std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv)
546
+ << std::endl;
547
+ return -1;
548
+ }
549
+ }
550
+
551
+ return 0;
552
+ }
553
+
554
+ namespace {
555
+ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
556
+ auto h = static_cast<Handler *>(w->data);
557
+ auto s = h->server();
558
+
559
+ switch (h->on_write()) {
560
+ case 0:
561
+ case NETWORK_ERR_CLOSE_WAIT:
562
+ return;
563
+ default:
564
+ s->remove(h);
565
+ }
566
+ }
567
+ } // namespace
568
+
569
+ namespace {
570
+ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) {
571
+ auto h = static_cast<Handler *>(w->data);
572
+ auto s = h->server();
573
+ auto conn = h->conn();
574
+
575
+ if (ngtcp2_conn_is_in_closing_period(conn)) {
576
+ if (!config.quiet) {
577
+ std::cerr << "Closing Period is over" << std::endl;
578
+ }
579
+
580
+ s->remove(h);
581
+ return;
582
+ }
583
+ if (ngtcp2_conn_is_in_draining_period(conn)) {
584
+ if (!config.quiet) {
585
+ std::cerr << "Draining Period is over" << std::endl;
586
+ }
587
+
588
+ s->remove(h);
589
+ return;
590
+ }
591
+
592
+ assert(0);
593
+ }
594
+ } // namespace
595
+
596
+ namespace {
597
+ void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
598
+ int rv;
599
+
600
+ auto h = static_cast<Handler *>(w->data);
601
+ auto s = h->server();
602
+
603
+ if (!config.quiet) {
604
+ std::cerr << "Timer expired" << std::endl;
605
+ }
606
+
607
+ rv = h->handle_expiry();
608
+ if (rv != 0) {
609
+ goto fail;
610
+ }
611
+
612
+ rv = h->on_write();
613
+ if (rv != 0) {
614
+ goto fail;
615
+ }
616
+
617
+ return;
618
+
619
+ fail:
620
+ switch (rv) {
621
+ case NETWORK_ERR_CLOSE_WAIT:
622
+ ev_timer_stop(loop, w);
623
+ return;
624
+ default:
625
+ s->remove(h);
626
+ return;
627
+ }
628
+ }
629
+ } // namespace
630
+
631
+ Handler::Handler(struct ev_loop *loop, Server *server)
632
+ : loop_(loop),
633
+ server_(server),
634
+ qlog_(nullptr),
635
+ scid_{},
636
+ httpconn_{nullptr},
637
+ nkey_update_(0),
638
+ no_gso_{
639
+ #ifdef UDP_SEGMENT
640
+ false
641
+ #else // !UDP_SEGMENT
642
+ true
643
+ #endif // !UDP_SEGMENT
644
+ },
645
+ tx_{
646
+ .data = std::unique_ptr<uint8_t[]>(new uint8_t[64_k]),
647
+ } {
648
+ ev_io_init(&wev_, writecb, 0, EV_WRITE);
649
+ wev_.data = this;
650
+ ev_timer_init(&timer_, timeoutcb, 0., 0.);
651
+ timer_.data = this;
652
+ }
653
+
654
+ Handler::~Handler() {
655
+ if (!config.quiet) {
656
+ std::cerr << scid_ << " Closing QUIC connection " << std::endl;
657
+ }
658
+
659
+ ev_timer_stop(loop_, &timer_);
660
+ ev_io_stop(loop_, &wev_);
661
+
662
+ if (httpconn_) {
663
+ nghttp3_conn_del(httpconn_);
664
+ }
665
+
666
+ if (qlog_) {
667
+ fclose(qlog_);
668
+ }
669
+ }
670
+
671
+ namespace {
672
+ int handshake_completed(ngtcp2_conn *conn, void *user_data) {
673
+ auto h = static_cast<Handler *>(user_data);
674
+
675
+ if (!config.quiet) {
676
+ debug::handshake_completed(conn, user_data);
677
+ }
678
+
679
+ if (h->handshake_completed() != 0) {
680
+ return NGTCP2_ERR_CALLBACK_FAILURE;
681
+ }
682
+
683
+ return 0;
684
+ }
685
+ } // namespace
686
+
687
+ int Handler::handshake_completed() {
688
+ if (!config.quiet) {
689
+ std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name()
690
+ << std::endl;
691
+ std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn()
692
+ << std::endl;
693
+ }
694
+
695
+ if (tls_session_.send_session_ticket() != 0) {
696
+ std::cerr << "Unable to send session ticket" << std::endl;
697
+ }
698
+
699
+ std::array<uint8_t, NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN> token;
700
+
701
+ auto path = ngtcp2_conn_get_path(conn_);
702
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
703
+ std::chrono::system_clock::now().time_since_epoch())
704
+ .count();
705
+
706
+ auto tokenlen = ngtcp2_crypto_generate_regular_token(
707
+ token.data(), config.static_secret.data(), config.static_secret.size(),
708
+ path->remote.addr, path->remote.addrlen, t);
709
+ if (tokenlen < 0) {
710
+ if (!config.quiet) {
711
+ std::cerr << "Unable to generate token" << std::endl;
712
+ }
713
+ return 0;
714
+ }
715
+
716
+ if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), tokenlen);
717
+ rv != 0) {
718
+ if (!config.quiet) {
719
+ std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
720
+ << std::endl;
721
+ }
722
+ return -1;
723
+ }
724
+
725
+ return 0;
726
+ }
727
+
728
+ namespace {
729
+ int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
730
+ const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) {
731
+ if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) {
732
+ return NGTCP2_ERR_CALLBACK_FAILURE;
733
+ }
734
+
735
+ if (!config.quiet && config.show_secret) {
736
+ debug::print_hp_mask(dest, NGTCP2_HP_MASKLEN, sample, NGTCP2_HP_SAMPLELEN);
737
+ }
738
+
739
+ return 0;
740
+ }
741
+ } // namespace
742
+
743
+ namespace {
744
+ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
745
+ uint64_t offset, const uint8_t *data, size_t datalen,
746
+ void *user_data) {
747
+ if (!config.quiet && !config.no_quic_dump) {
748
+ debug::print_crypto_data(crypto_level, data, datalen);
749
+ }
750
+
751
+ return ngtcp2_crypto_recv_crypto_data_cb(conn, crypto_level, offset, data,
752
+ datalen, user_data);
753
+ }
754
+ } // namespace
755
+
756
+ namespace {
757
+ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
758
+ uint64_t offset, const uint8_t *data, size_t datalen,
759
+ void *user_data, void *stream_user_data) {
760
+ auto h = static_cast<Handler *>(user_data);
761
+
762
+ if (h->recv_stream_data(flags, stream_id, data, datalen) != 0) {
763
+ return NGTCP2_ERR_CALLBACK_FAILURE;
764
+ }
765
+
766
+ return 0;
767
+ }
768
+ } // namespace
769
+
770
+ namespace {
771
+ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id,
772
+ uint64_t offset, uint64_t datalen, void *user_data,
773
+ void *stream_user_data) {
774
+ auto h = static_cast<Handler *>(user_data);
775
+ if (h->acked_stream_data_offset(stream_id, datalen) != 0) {
776
+ return NGTCP2_ERR_CALLBACK_FAILURE;
777
+ }
778
+ return 0;
779
+ }
780
+ } // namespace
781
+
782
+ int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) {
783
+ if (!httpconn_) {
784
+ return 0;
785
+ }
786
+
787
+ if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen);
788
+ rv != 0) {
789
+ std::cerr << "nghttp3_conn_add_ack_offset: " << nghttp3_strerror(rv)
790
+ << std::endl;
791
+ return -1;
792
+ }
793
+
794
+ return 0;
795
+ }
796
+
797
+ namespace {
798
+ int stream_open(ngtcp2_conn *conn, int64_t stream_id, void *user_data) {
799
+ auto h = static_cast<Handler *>(user_data);
800
+ h->on_stream_open(stream_id);
801
+ return 0;
802
+ }
803
+ } // namespace
804
+
805
+ void Handler::on_stream_open(int64_t stream_id) {
806
+ if (!ngtcp2_is_bidi_stream(stream_id)) {
807
+ return;
808
+ }
809
+ auto it = streams_.find(stream_id);
810
+ (void)it;
811
+ assert(it == std::end(streams_));
812
+ streams_.emplace(stream_id, std::make_unique<Stream>(stream_id, this));
813
+ }
814
+
815
+ namespace {
816
+ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
817
+ uint64_t app_error_code, void *user_data,
818
+ void *stream_user_data) {
819
+ auto h = static_cast<Handler *>(user_data);
820
+
821
+ if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
822
+ app_error_code = NGHTTP3_H3_NO_ERROR;
823
+ }
824
+
825
+ if (h->on_stream_close(stream_id, app_error_code) != 0) {
826
+ return NGTCP2_ERR_CALLBACK_FAILURE;
827
+ }
828
+ return 0;
829
+ }
830
+ } // namespace
831
+
832
+ namespace {
833
+ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
834
+ uint64_t app_error_code, void *user_data,
835
+ void *stream_user_data) {
836
+ auto h = static_cast<Handler *>(user_data);
837
+ if (h->on_stream_reset(stream_id) != 0) {
838
+ return NGTCP2_ERR_CALLBACK_FAILURE;
839
+ }
840
+ return 0;
841
+ }
842
+ } // namespace
843
+
844
+ int Handler::on_stream_reset(int64_t stream_id) {
845
+ if (httpconn_) {
846
+ if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id);
847
+ rv != 0) {
848
+ std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv)
849
+ << std::endl;
850
+ return -1;
851
+ }
852
+ }
853
+ return 0;
854
+ }
855
+
856
+ namespace {
857
+ int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id,
858
+ uint64_t app_error_code, void *user_data,
859
+ void *stream_user_data) {
860
+ auto h = static_cast<Handler *>(user_data);
861
+ if (h->on_stream_stop_sending(stream_id) != 0) {
862
+ return NGTCP2_ERR_CALLBACK_FAILURE;
863
+ }
864
+ return 0;
865
+ }
866
+ } // namespace
867
+
868
+ int Handler::on_stream_stop_sending(int64_t stream_id) {
869
+ if (!httpconn_) {
870
+ return 0;
871
+ }
872
+
873
+ if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id);
874
+ rv != 0) {
875
+ std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv)
876
+ << std::endl;
877
+ return -1;
878
+ }
879
+
880
+ return 0;
881
+ }
882
+
883
+ namespace {
884
+ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) {
885
+ auto dis = std::uniform_int_distribution<uint8_t>();
886
+ std::generate(dest, dest + destlen, [&dis]() { return dis(randgen); });
887
+ }
888
+ } // namespace
889
+
890
+ namespace {
891
+ int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
892
+ size_t cidlen, void *user_data) {
893
+ if (util::generate_secure_random(cid->data, cidlen) != 0) {
894
+ return NGTCP2_ERR_CALLBACK_FAILURE;
895
+ }
896
+
897
+ cid->datalen = cidlen;
898
+ if (ngtcp2_crypto_generate_stateless_reset_token(
899
+ token, config.static_secret.data(), config.static_secret.size(),
900
+ cid) != 0) {
901
+ return NGTCP2_ERR_CALLBACK_FAILURE;
902
+ }
903
+
904
+ auto h = static_cast<Handler *>(user_data);
905
+ h->server()->associate_cid(cid, h);
906
+
907
+ return 0;
908
+ }
909
+ } // namespace
910
+
911
+ namespace {
912
+ int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid,
913
+ void *user_data) {
914
+ auto h = static_cast<Handler *>(user_data);
915
+ h->server()->dissociate_cid(cid);
916
+ return 0;
917
+ }
918
+ } // namespace
919
+
920
+ namespace {
921
+ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
922
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
923
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
924
+ const uint8_t *current_rx_secret,
925
+ const uint8_t *current_tx_secret, size_t secretlen,
926
+ void *user_data) {
927
+ auto h = static_cast<Handler *>(user_data);
928
+ if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx,
929
+ tx_iv, current_rx_secret, current_tx_secret,
930
+ secretlen) != 0) {
931
+ return NGTCP2_ERR_CALLBACK_FAILURE;
932
+ }
933
+ return 0;
934
+ }
935
+ } // namespace
936
+
937
+ namespace {
938
+ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
939
+ ngtcp2_path_validation_result res, void *user_data) {
940
+ if (!config.quiet) {
941
+ debug::path_validation(path, res);
942
+ }
943
+ return 0;
944
+ }
945
+ } // namespace
946
+
947
+ namespace {
948
+ int extend_max_remote_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams,
949
+ void *user_data) {
950
+ auto h = static_cast<Handler *>(user_data);
951
+ h->extend_max_remote_streams_bidi(max_streams);
952
+ return 0;
953
+ }
954
+ } // namespace
955
+
956
+ void Handler::extend_max_remote_streams_bidi(uint64_t max_streams) {
957
+ if (!httpconn_) {
958
+ return;
959
+ }
960
+
961
+ nghttp3_conn_set_max_client_streams_bidi(httpconn_, max_streams);
962
+ }
963
+
964
+ namespace {
965
+ int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
966
+ size_t datalen, void *user_data, void *stream_user_data) {
967
+ if (!config.quiet && !config.no_http_dump) {
968
+ debug::print_http_data(stream_id, data, datalen);
969
+ }
970
+ auto h = static_cast<Handler *>(user_data);
971
+ h->http_consume(stream_id, datalen);
972
+ return 0;
973
+ }
974
+ } // namespace
975
+
976
+ namespace {
977
+ int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
978
+ size_t nconsumed, void *user_data,
979
+ void *stream_user_data) {
980
+ auto h = static_cast<Handler *>(user_data);
981
+ h->http_consume(stream_id, nconsumed);
982
+ return 0;
983
+ }
984
+ } // namespace
985
+
986
+ void Handler::http_consume(int64_t stream_id, size_t nconsumed) {
987
+ ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed);
988
+ ngtcp2_conn_extend_max_offset(conn_, nconsumed);
989
+ }
990
+
991
+ namespace {
992
+ int http_begin_request_headers(nghttp3_conn *conn, int64_t stream_id,
993
+ void *user_data, void *stream_user_data) {
994
+ if (!config.quiet) {
995
+ debug::print_http_begin_request_headers(stream_id);
996
+ }
997
+
998
+ auto h = static_cast<Handler *>(user_data);
999
+ h->http_begin_request_headers(stream_id);
1000
+ return 0;
1001
+ }
1002
+ } // namespace
1003
+
1004
+ void Handler::http_begin_request_headers(int64_t stream_id) {
1005
+ auto it = streams_.find(stream_id);
1006
+ assert(it != std::end(streams_));
1007
+ auto &stream = (*it).second;
1008
+
1009
+ nghttp3_conn_set_stream_user_data(httpconn_, stream_id, stream.get());
1010
+ }
1011
+
1012
+ namespace {
1013
+ int http_recv_request_header(nghttp3_conn *conn, int64_t stream_id,
1014
+ int32_t token, nghttp3_rcbuf *name,
1015
+ nghttp3_rcbuf *value, uint8_t flags,
1016
+ void *user_data, void *stream_user_data) {
1017
+ if (!config.quiet) {
1018
+ debug::print_http_header(stream_id, name, value, flags);
1019
+ }
1020
+
1021
+ auto h = static_cast<Handler *>(user_data);
1022
+ auto stream = static_cast<Stream *>(stream_user_data);
1023
+ h->http_recv_request_header(stream, token, name, value);
1024
+ return 0;
1025
+ }
1026
+ } // namespace
1027
+
1028
+ void Handler::http_recv_request_header(Stream *stream, int32_t token,
1029
+ nghttp3_rcbuf *name,
1030
+ nghttp3_rcbuf *value) {
1031
+ auto v = nghttp3_rcbuf_get_buf(value);
1032
+
1033
+ switch (token) {
1034
+ case NGHTTP3_QPACK_TOKEN__PATH:
1035
+ stream->uri = std::string{v.base, v.base + v.len};
1036
+ break;
1037
+ case NGHTTP3_QPACK_TOKEN__METHOD:
1038
+ stream->method = std::string{v.base, v.base + v.len};
1039
+ break;
1040
+ case NGHTTP3_QPACK_TOKEN__AUTHORITY:
1041
+ stream->authority = std::string{v.base, v.base + v.len};
1042
+ break;
1043
+ }
1044
+ }
1045
+
1046
+ namespace {
1047
+ int http_end_request_headers(nghttp3_conn *conn, int64_t stream_id, int fin,
1048
+ void *user_data, void *stream_user_data) {
1049
+ if (!config.quiet) {
1050
+ debug::print_http_end_headers(stream_id);
1051
+ }
1052
+
1053
+ auto h = static_cast<Handler *>(user_data);
1054
+ auto stream = static_cast<Stream *>(stream_user_data);
1055
+ if (h->http_end_request_headers(stream) != 0) {
1056
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
1057
+ }
1058
+ return 0;
1059
+ }
1060
+ } // namespace
1061
+
1062
+ int Handler::http_end_request_headers(Stream *stream) {
1063
+ if (config.early_response) {
1064
+ if (start_response(stream) != 0) {
1065
+ return -1;
1066
+ }
1067
+
1068
+ shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR);
1069
+ }
1070
+ return 0;
1071
+ }
1072
+
1073
+ namespace {
1074
+ int http_end_stream(nghttp3_conn *conn, int64_t stream_id, void *user_data,
1075
+ void *stream_user_data) {
1076
+ auto h = static_cast<Handler *>(user_data);
1077
+ auto stream = static_cast<Stream *>(stream_user_data);
1078
+ if (h->http_end_stream(stream) != 0) {
1079
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
1080
+ }
1081
+ return 0;
1082
+ }
1083
+ } // namespace
1084
+
1085
+ int Handler::http_end_stream(Stream *stream) {
1086
+ if (!config.early_response) {
1087
+ return start_response(stream);
1088
+ }
1089
+ return 0;
1090
+ }
1091
+
1092
+ int Handler::start_response(Stream *stream) {
1093
+ return stream->start_response(httpconn_);
1094
+ }
1095
+
1096
+ namespace {
1097
+ int http_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1098
+ uint64_t datalen, void *user_data,
1099
+ void *stream_user_data) {
1100
+ auto h = static_cast<Handler *>(user_data);
1101
+ auto stream = static_cast<Stream *>(stream_user_data);
1102
+ h->http_acked_stream_data(stream, datalen);
1103
+ return 0;
1104
+ }
1105
+ } // namespace
1106
+
1107
+ void Handler::http_acked_stream_data(Stream *stream, uint64_t datalen) {
1108
+ stream->http_acked_stream_data(datalen);
1109
+
1110
+ if (stream->dynresp && stream->dynbuflen < MAX_DYNBUFLEN - 16_k) {
1111
+ if (auto rv = nghttp3_conn_resume_stream(httpconn_, stream->stream_id);
1112
+ rv != 0) {
1113
+ // TODO Handle error
1114
+ std::cerr << "nghttp3_conn_resume_stream: " << nghttp3_strerror(rv)
1115
+ << std::endl;
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ namespace {
1121
+ int http_stream_close(nghttp3_conn *conn, int64_t stream_id,
1122
+ uint64_t app_error_code, void *conn_user_data,
1123
+ void *stream_user_data) {
1124
+ auto h = static_cast<Handler *>(conn_user_data);
1125
+ h->http_stream_close(stream_id, app_error_code);
1126
+ return 0;
1127
+ }
1128
+ } // namespace
1129
+
1130
+ void Handler::http_stream_close(int64_t stream_id, uint64_t app_error_code) {
1131
+ auto it = streams_.find(stream_id);
1132
+ if (it == std::end(streams_)) {
1133
+ return;
1134
+ }
1135
+
1136
+ if (!config.quiet) {
1137
+ std::cerr << "HTTP stream " << stream_id << " closed with error code "
1138
+ << app_error_code << std::endl;
1139
+ }
1140
+
1141
+ streams_.erase(it);
1142
+
1143
+ if (ngtcp2_is_bidi_stream(stream_id)) {
1144
+ assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
1145
+ ngtcp2_conn_extend_max_streams_bidi(conn_, 1);
1146
+ }
1147
+ }
1148
+
1149
+ namespace {
1150
+ int http_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1151
+ uint64_t app_error_code, void *user_data,
1152
+ void *stream_user_data) {
1153
+ auto h = static_cast<Handler *>(user_data);
1154
+ if (h->http_stop_sending(stream_id, app_error_code) != 0) {
1155
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
1156
+ }
1157
+ return 0;
1158
+ }
1159
+ } // namespace
1160
+
1161
+ int Handler::http_stop_sending(int64_t stream_id, uint64_t app_error_code) {
1162
+ if (auto rv =
1163
+ ngtcp2_conn_shutdown_stream_read(conn_, stream_id, app_error_code);
1164
+ rv != 0) {
1165
+ std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv)
1166
+ << std::endl;
1167
+ return -1;
1168
+ }
1169
+ return 0;
1170
+ }
1171
+
1172
+ namespace {
1173
+ int http_reset_stream(nghttp3_conn *conn, int64_t stream_id,
1174
+ uint64_t app_error_code, void *user_data,
1175
+ void *stream_user_data) {
1176
+ auto h = static_cast<Handler *>(user_data);
1177
+ if (h->http_reset_stream(stream_id, app_error_code) != 0) {
1178
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
1179
+ }
1180
+ return 0;
1181
+ }
1182
+ } // namespace
1183
+
1184
+ int Handler::http_reset_stream(int64_t stream_id, uint64_t app_error_code) {
1185
+ if (auto rv =
1186
+ ngtcp2_conn_shutdown_stream_write(conn_, stream_id, app_error_code);
1187
+ rv != 0) {
1188
+ std::cerr << "ngtcp2_conn_shutdown_stream_write: " << ngtcp2_strerror(rv)
1189
+ << std::endl;
1190
+ return -1;
1191
+ }
1192
+ return 0;
1193
+ }
1194
+
1195
+ int Handler::setup_httpconn() {
1196
+ if (httpconn_) {
1197
+ return 0;
1198
+ }
1199
+
1200
+ if (ngtcp2_conn_get_max_local_streams_uni(conn_) < 3) {
1201
+ std::cerr << "peer does not allow at least 3 unidirectional streams."
1202
+ << std::endl;
1203
+ return -1;
1204
+ }
1205
+
1206
+ nghttp3_callbacks callbacks{
1207
+ ::http_acked_stream_data, // acked_stream_data
1208
+ ::http_stream_close,
1209
+ ::http_recv_data,
1210
+ ::http_deferred_consume,
1211
+ ::http_begin_request_headers,
1212
+ ::http_recv_request_header,
1213
+ ::http_end_request_headers,
1214
+ nullptr, // begin_trailers
1215
+ nullptr, // recv_trailer
1216
+ nullptr, // end_trailers
1217
+ ::http_stop_sending,
1218
+ ::http_end_stream,
1219
+ ::http_reset_stream,
1220
+ };
1221
+ nghttp3_settings settings;
1222
+ nghttp3_settings_default(&settings);
1223
+ settings.qpack_max_dtable_capacity = 4096;
1224
+ settings.qpack_blocked_streams = 100;
1225
+
1226
+ auto mem = nghttp3_mem_default();
1227
+
1228
+ if (auto rv =
1229
+ nghttp3_conn_server_new(&httpconn_, &callbacks, &settings, mem, this);
1230
+ rv != 0) {
1231
+ std::cerr << "nghttp3_conn_server_new: " << nghttp3_strerror(rv)
1232
+ << std::endl;
1233
+ return -1;
1234
+ }
1235
+
1236
+ auto params = ngtcp2_conn_get_local_transport_params(conn_);
1237
+
1238
+ nghttp3_conn_set_max_client_streams_bidi(httpconn_,
1239
+ params->initial_max_streams_bidi);
1240
+
1241
+ int64_t ctrl_stream_id;
1242
+
1243
+ if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr);
1244
+ rv != 0) {
1245
+ std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1246
+ << std::endl;
1247
+ return -1;
1248
+ }
1249
+
1250
+ if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id);
1251
+ rv != 0) {
1252
+ std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv)
1253
+ << std::endl;
1254
+ return -1;
1255
+ }
1256
+
1257
+ if (!config.quiet) {
1258
+ fprintf(stderr, "http: control stream=%" PRIx64 "\n", ctrl_stream_id);
1259
+ }
1260
+
1261
+ int64_t qpack_enc_stream_id, qpack_dec_stream_id;
1262
+
1263
+ if (auto rv =
1264
+ ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr);
1265
+ rv != 0) {
1266
+ std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1267
+ << std::endl;
1268
+ return -1;
1269
+ }
1270
+
1271
+ if (auto rv =
1272
+ ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr);
1273
+ rv != 0) {
1274
+ std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
1275
+ << std::endl;
1276
+ return -1;
1277
+ }
1278
+
1279
+ if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id,
1280
+ qpack_dec_stream_id);
1281
+ rv != 0) {
1282
+ std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv)
1283
+ << std::endl;
1284
+ return -1;
1285
+ }
1286
+
1287
+ if (!config.quiet) {
1288
+ fprintf(stderr,
1289
+ "http: QPACK streams encoder=%" PRIx64 " decoder=%" PRIx64 "\n",
1290
+ qpack_enc_stream_id, qpack_dec_stream_id);
1291
+ }
1292
+
1293
+ return 0;
1294
+ }
1295
+
1296
+ namespace {
1297
+ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id,
1298
+ uint64_t max_data, void *user_data,
1299
+ void *stream_user_data) {
1300
+ auto h = static_cast<Handler *>(user_data);
1301
+ if (h->extend_max_stream_data(stream_id, max_data) != 0) {
1302
+ return NGTCP2_ERR_CALLBACK_FAILURE;
1303
+ }
1304
+ return 0;
1305
+ }
1306
+ } // namespace
1307
+
1308
+ int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) {
1309
+ if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) {
1310
+ std::cerr << "nghttp3_conn_unblock_stream: " << nghttp3_strerror(rv)
1311
+ << std::endl;
1312
+ return -1;
1313
+ }
1314
+ return 0;
1315
+ }
1316
+
1317
+ namespace {
1318
+ int recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level, void *user_data) {
1319
+ if (level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
1320
+ return 0;
1321
+ }
1322
+
1323
+ auto h = static_cast<Handler *>(user_data);
1324
+ if (h->setup_httpconn() != 0) {
1325
+ return NGTCP2_ERR_CALLBACK_FAILURE;
1326
+ }
1327
+
1328
+ return 0;
1329
+ }
1330
+ } // namespace
1331
+
1332
+ namespace {
1333
+ void write_qlog(void *user_data, uint32_t flags, const void *data,
1334
+ size_t datalen) {
1335
+ auto h = static_cast<Handler *>(user_data);
1336
+ h->write_qlog(data, datalen);
1337
+ }
1338
+ } // namespace
1339
+
1340
+ void Handler::write_qlog(const void *data, size_t datalen) {
1341
+ assert(qlog_);
1342
+ fwrite(data, 1, datalen, qlog_);
1343
+ }
1344
+
1345
+ int Handler::init(const Endpoint &ep, const Address &local_addr,
1346
+ const sockaddr *sa, socklen_t salen, const ngtcp2_cid *dcid,
1347
+ const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
1348
+ const uint8_t *token, size_t tokenlen, uint32_t version,
1349
+ TLSServerContext &tls_ctx) {
1350
+ auto callbacks = ngtcp2_callbacks{
1351
+ nullptr, // client_initial
1352
+ ngtcp2_crypto_recv_client_initial_cb,
1353
+ ::recv_crypto_data,
1354
+ ::handshake_completed,
1355
+ nullptr, // recv_version_negotiation
1356
+ ngtcp2_crypto_encrypt_cb,
1357
+ ngtcp2_crypto_decrypt_cb,
1358
+ do_hp_mask,
1359
+ ::recv_stream_data,
1360
+ ::acked_stream_data_offset,
1361
+ stream_open,
1362
+ stream_close,
1363
+ nullptr, // recv_stateless_reset
1364
+ nullptr, // recv_retry
1365
+ nullptr, // extend_max_streams_bidi
1366
+ nullptr, // extend_max_streams_uni
1367
+ rand,
1368
+ get_new_connection_id,
1369
+ remove_connection_id,
1370
+ ::update_key,
1371
+ path_validation,
1372
+ nullptr, // select_preferred_addr
1373
+ ::stream_reset,
1374
+ ::extend_max_remote_streams_bidi,
1375
+ nullptr, // extend_max_remote_streams_uni
1376
+ ::extend_max_stream_data,
1377
+ nullptr, // dcid_status
1378
+ nullptr, // handshake_confirmed
1379
+ nullptr, // recv_new_token
1380
+ ngtcp2_crypto_delete_crypto_aead_ctx_cb,
1381
+ ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
1382
+ nullptr, // recv_datagram
1383
+ nullptr, // ack_datagram
1384
+ nullptr, // lost_datagram
1385
+ ngtcp2_crypto_get_path_challenge_data_cb,
1386
+ stream_stop_sending,
1387
+ ngtcp2_crypto_version_negotiation_cb,
1388
+ nullptr, // recv_rx_key
1389
+ ::recv_tx_key,
1390
+ };
1391
+
1392
+ scid_.datalen = NGTCP2_SV_SCIDLEN;
1393
+ if (util::generate_secure_random(scid_.data, scid_.datalen) != 0) {
1394
+ std::cerr << "Could not generate connection ID" << std::endl;
1395
+ return -1;
1396
+ }
1397
+
1398
+ ngtcp2_settings settings;
1399
+ ngtcp2_settings_default(&settings);
1400
+ settings.log_printf = config.quiet ? nullptr : debug::log_printf;
1401
+ settings.initial_ts = util::timestamp(loop_);
1402
+ settings.token = token;
1403
+ settings.tokenlen = tokenlen;
1404
+ settings.cc_algo = config.cc_algo;
1405
+ settings.initial_rtt = config.initial_rtt;
1406
+ settings.max_window = config.max_window;
1407
+ settings.max_stream_window = config.max_stream_window;
1408
+ settings.handshake_timeout = config.handshake_timeout;
1409
+ settings.no_pmtud = config.no_pmtud;
1410
+ settings.ack_thresh = config.ack_thresh;
1411
+ if (config.max_udp_payload_size) {
1412
+ settings.max_tx_udp_payload_size = config.max_udp_payload_size;
1413
+ settings.no_tx_udp_payload_size_shaping = 1;
1414
+ }
1415
+ if (!config.qlog_dir.empty()) {
1416
+ auto path = std::string{config.qlog_dir};
1417
+ path += '/';
1418
+ path += util::format_hex(scid_.data, scid_.datalen);
1419
+ path += ".sqlog";
1420
+ qlog_ = fopen(path.c_str(), "w");
1421
+ if (qlog_ == nullptr) {
1422
+ std::cerr << "Could not open qlog file " << std::quoted(path) << ": "
1423
+ << strerror(errno) << std::endl;
1424
+ return -1;
1425
+ }
1426
+ settings.qlog.write = ::write_qlog;
1427
+ settings.qlog.odcid = *scid;
1428
+ }
1429
+ if (!config.preferred_versions.empty()) {
1430
+ settings.preferred_versions = config.preferred_versions.data();
1431
+ settings.preferred_versionslen = config.preferred_versions.size();
1432
+ }
1433
+ if (!config.available_versions.empty()) {
1434
+ settings.available_versions = config.available_versions.data();
1435
+ settings.available_versionslen = config.available_versions.size();
1436
+ }
1437
+
1438
+ ngtcp2_transport_params params;
1439
+ ngtcp2_transport_params_default(&params);
1440
+ params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local;
1441
+ params.initial_max_stream_data_bidi_remote =
1442
+ config.max_stream_data_bidi_remote;
1443
+ params.initial_max_stream_data_uni = config.max_stream_data_uni;
1444
+ params.initial_max_data = config.max_data;
1445
+ params.initial_max_streams_bidi = config.max_streams_bidi;
1446
+ params.initial_max_streams_uni = config.max_streams_uni;
1447
+ params.max_idle_timeout = config.timeout;
1448
+ params.stateless_reset_token_present = 1;
1449
+ params.active_connection_id_limit = 7;
1450
+
1451
+ if (ocid) {
1452
+ params.original_dcid = *ocid;
1453
+ params.retry_scid = *scid;
1454
+ params.retry_scid_present = 1;
1455
+ } else {
1456
+ params.original_dcid = *scid;
1457
+ }
1458
+
1459
+ if (util::generate_secure_random(params.stateless_reset_token,
1460
+ sizeof(params.stateless_reset_token)) != 0) {
1461
+ std::cerr << "Could not generate stateless reset token" << std::endl;
1462
+ return -1;
1463
+ }
1464
+
1465
+ if (config.preferred_ipv4_addr.len || config.preferred_ipv6_addr.len) {
1466
+ params.preferred_address_present = 1;
1467
+
1468
+ if (config.preferred_ipv4_addr.len) {
1469
+ params.preferred_address.ipv4 = config.preferred_ipv4_addr.su.in;
1470
+ params.preferred_address.ipv4_present = 1;
1471
+ }
1472
+
1473
+ if (config.preferred_ipv6_addr.len) {
1474
+ params.preferred_address.ipv6 = config.preferred_ipv6_addr.su.in6;
1475
+ params.preferred_address.ipv6_present = 1;
1476
+ }
1477
+
1478
+ auto &token = params.preferred_address.stateless_reset_token;
1479
+ if (util::generate_secure_random(token, sizeof(token)) != 0) {
1480
+ std::cerr << "Could not generate preferred address stateless reset token"
1481
+ << std::endl;
1482
+ return -1;
1483
+ }
1484
+
1485
+ params.preferred_address.cid.datalen = NGTCP2_SV_SCIDLEN;
1486
+ if (util::generate_secure_random(params.preferred_address.cid.data,
1487
+ params.preferred_address.cid.datalen) !=
1488
+ 0) {
1489
+ std::cerr << "Could not generate preferred address connection ID"
1490
+ << std::endl;
1491
+ return -1;
1492
+ }
1493
+ }
1494
+
1495
+ auto path = ngtcp2_path{
1496
+ {
1497
+ const_cast<sockaddr *>(&local_addr.su.sa),
1498
+ local_addr.len,
1499
+ },
1500
+ {
1501
+ const_cast<sockaddr *>(sa),
1502
+ salen,
1503
+ },
1504
+ const_cast<Endpoint *>(&ep),
1505
+ };
1506
+ if (auto rv =
1507
+ ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version,
1508
+ &callbacks, &settings, &params, nullptr, this);
1509
+ rv != 0) {
1510
+ std::cerr << "ngtcp2_conn_server_new: " << ngtcp2_strerror(rv) << std::endl;
1511
+ return -1;
1512
+ }
1513
+
1514
+ if (tls_session_.init(tls_ctx, this) != 0) {
1515
+ return -1;
1516
+ }
1517
+
1518
+ tls_session_.enable_keylog();
1519
+
1520
+ ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle());
1521
+
1522
+ ev_io_set(&wev_, ep.fd, EV_WRITE);
1523
+
1524
+ return 0;
1525
+ }
1526
+
1527
+ int Handler::feed_data(const Endpoint &ep, const Address &local_addr,
1528
+ const sockaddr *sa, socklen_t salen,
1529
+ const ngtcp2_pkt_info *pi, uint8_t *data,
1530
+ size_t datalen) {
1531
+ auto path = ngtcp2_path{
1532
+ {
1533
+ const_cast<sockaddr *>(&local_addr.su.sa),
1534
+ local_addr.len,
1535
+ },
1536
+ {
1537
+ const_cast<sockaddr *>(sa),
1538
+ salen,
1539
+ },
1540
+ const_cast<Endpoint *>(&ep),
1541
+ };
1542
+
1543
+ if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data, datalen,
1544
+ util::timestamp(loop_));
1545
+ rv != 0) {
1546
+ std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
1547
+ switch (rv) {
1548
+ case NGTCP2_ERR_DRAINING:
1549
+ start_draining_period();
1550
+ return NETWORK_ERR_CLOSE_WAIT;
1551
+ case NGTCP2_ERR_RETRY:
1552
+ return NETWORK_ERR_RETRY;
1553
+ case NGTCP2_ERR_DROP_CONN:
1554
+ return NETWORK_ERR_DROP_CONN;
1555
+ case NGTCP2_ERR_CRYPTO:
1556
+ if (!last_error_.error_code) {
1557
+ ngtcp2_connection_close_error_set_transport_error_tls_alert(
1558
+ &last_error_, ngtcp2_conn_get_tls_alert(conn_), nullptr, 0);
1559
+ }
1560
+ break;
1561
+ default:
1562
+ if (!last_error_.error_code) {
1563
+ ngtcp2_connection_close_error_set_transport_error_liberr(
1564
+ &last_error_, rv, nullptr, 0);
1565
+ }
1566
+ }
1567
+ return handle_error();
1568
+ }
1569
+
1570
+ return 0;
1571
+ }
1572
+
1573
+ int Handler::on_read(const Endpoint &ep, const Address &local_addr,
1574
+ const sockaddr *sa, socklen_t salen,
1575
+ const ngtcp2_pkt_info *pi, uint8_t *data, size_t datalen) {
1576
+ if (auto rv = feed_data(ep, local_addr, sa, salen, pi, data, datalen);
1577
+ rv != 0) {
1578
+ return rv;
1579
+ }
1580
+
1581
+ update_timer();
1582
+
1583
+ return 0;
1584
+ }
1585
+
1586
+ int Handler::handle_expiry() {
1587
+ auto now = util::timestamp(loop_);
1588
+ if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) {
1589
+ std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv)
1590
+ << std::endl;
1591
+ ngtcp2_connection_close_error_set_transport_error_liberr(&last_error_, rv,
1592
+ nullptr, 0);
1593
+ return handle_error();
1594
+ }
1595
+
1596
+ return 0;
1597
+ }
1598
+
1599
+ int Handler::on_write() {
1600
+ if (ngtcp2_conn_is_in_closing_period(conn_) ||
1601
+ ngtcp2_conn_is_in_draining_period(conn_)) {
1602
+ return 0;
1603
+ }
1604
+
1605
+ if (tx_.send_blocked) {
1606
+ if (auto rv = send_blocked_packet(); rv != 0) {
1607
+ return rv;
1608
+ }
1609
+
1610
+ if (tx_.send_blocked) {
1611
+ return 0;
1612
+ }
1613
+ }
1614
+
1615
+ ev_io_stop(loop_, &wev_);
1616
+
1617
+ if (auto rv = write_streams(); rv != 0) {
1618
+ return rv;
1619
+ }
1620
+
1621
+ update_timer();
1622
+
1623
+ return 0;
1624
+ }
1625
+
1626
+ int Handler::write_streams() {
1627
+ std::array<nghttp3_vec, 16> vec;
1628
+ ngtcp2_path_storage ps, prev_ps;
1629
+ uint32_t prev_ecn = 0;
1630
+ size_t pktcnt = 0;
1631
+ auto max_udp_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(conn_);
1632
+ auto path_max_udp_payload_size =
1633
+ ngtcp2_conn_get_path_max_tx_udp_payload_size(conn_);
1634
+ auto max_pktcnt = ngtcp2_conn_get_send_quantum(conn_) / max_udp_payload_size;
1635
+ uint8_t *bufpos = tx_.data.get();
1636
+ ngtcp2_pkt_info pi;
1637
+ size_t gso_size = 0;
1638
+ auto ts = util::timestamp(loop_);
1639
+
1640
+ ngtcp2_path_storage_zero(&ps);
1641
+ ngtcp2_path_storage_zero(&prev_ps);
1642
+
1643
+ max_pktcnt = std::min(max_pktcnt, static_cast<size_t>(config.max_gso_dgrams));
1644
+
1645
+ for (;;) {
1646
+ int64_t stream_id = -1;
1647
+ int fin = 0;
1648
+ nghttp3_ssize sveccnt = 0;
1649
+
1650
+ if (httpconn_ && ngtcp2_conn_get_max_data_left(conn_)) {
1651
+ sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin,
1652
+ vec.data(), vec.size());
1653
+ if (sveccnt < 0) {
1654
+ std::cerr << "nghttp3_conn_writev_stream: " << nghttp3_strerror(sveccnt)
1655
+ << std::endl;
1656
+ ngtcp2_connection_close_error_set_application_error(
1657
+ &last_error_, nghttp3_err_infer_quic_app_error_code(sveccnt),
1658
+ nullptr, 0);
1659
+ return handle_error();
1660
+ }
1661
+ }
1662
+
1663
+ ngtcp2_ssize ndatalen;
1664
+ auto v = vec.data();
1665
+ auto vcnt = static_cast<size_t>(sveccnt);
1666
+
1667
+ uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
1668
+ if (fin) {
1669
+ flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
1670
+ }
1671
+
1672
+ auto nwrite = ngtcp2_conn_writev_stream(
1673
+ conn_, &ps.path, &pi, bufpos, max_udp_payload_size, &ndatalen, flags,
1674
+ stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt, ts);
1675
+ if (nwrite < 0) {
1676
+ switch (nwrite) {
1677
+ case NGTCP2_ERR_STREAM_DATA_BLOCKED:
1678
+ assert(ndatalen == -1);
1679
+ nghttp3_conn_block_stream(httpconn_, stream_id);
1680
+ continue;
1681
+ case NGTCP2_ERR_STREAM_SHUT_WR:
1682
+ assert(ndatalen == -1);
1683
+ nghttp3_conn_shutdown_stream_write(httpconn_, stream_id);
1684
+ continue;
1685
+ case NGTCP2_ERR_WRITE_MORE:
1686
+ assert(ndatalen >= 0);
1687
+ if (auto rv =
1688
+ nghttp3_conn_add_write_offset(httpconn_, stream_id, ndatalen);
1689
+ rv != 0) {
1690
+ std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv)
1691
+ << std::endl;
1692
+ ngtcp2_connection_close_error_set_application_error(
1693
+ &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr,
1694
+ 0);
1695
+ return handle_error();
1696
+ }
1697
+ continue;
1698
+ }
1699
+
1700
+ assert(ndatalen == -1);
1701
+
1702
+ std::cerr << "ngtcp2_conn_writev_stream: " << ngtcp2_strerror(nwrite)
1703
+ << std::endl;
1704
+ ngtcp2_connection_close_error_set_transport_error_liberr(
1705
+ &last_error_, nwrite, nullptr, 0);
1706
+ return handle_error();
1707
+ } else if (ndatalen >= 0) {
1708
+ if (auto rv =
1709
+ nghttp3_conn_add_write_offset(httpconn_, stream_id, ndatalen);
1710
+ rv != 0) {
1711
+ std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv)
1712
+ << std::endl;
1713
+ ngtcp2_connection_close_error_set_application_error(
1714
+ &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr,
1715
+ 0);
1716
+ return handle_error();
1717
+ }
1718
+ }
1719
+
1720
+ if (nwrite == 0) {
1721
+ if (bufpos - tx_.data.get()) {
1722
+ auto &ep = *static_cast<Endpoint *>(prev_ps.path.user_data);
1723
+ auto data = tx_.data.get();
1724
+ auto datalen = bufpos - data;
1725
+
1726
+ if (auto [nsent, rv] = server_->send_packet(
1727
+ ep, no_gso_, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1728
+ data, datalen, gso_size);
1729
+ rv != NETWORK_ERR_OK) {
1730
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1731
+
1732
+ on_send_blocked(ep, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1733
+ data + nsent, datalen - nsent, gso_size);
1734
+
1735
+ start_wev_endpoint(ep);
1736
+ }
1737
+ }
1738
+
1739
+ // We are congestion limited.
1740
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1741
+ return 0;
1742
+ }
1743
+
1744
+ bufpos += nwrite;
1745
+
1746
+ if (pktcnt == 0) {
1747
+ ngtcp2_path_copy(&prev_ps.path, &ps.path);
1748
+ prev_ecn = pi.ecn;
1749
+ gso_size = nwrite;
1750
+ } else if (!ngtcp2_path_eq(&prev_ps.path, &ps.path) || prev_ecn != pi.ecn ||
1751
+ static_cast<size_t>(nwrite) > gso_size ||
1752
+ (gso_size > path_max_udp_payload_size &&
1753
+ static_cast<size_t>(nwrite) != gso_size)) {
1754
+ auto &ep = *static_cast<Endpoint *>(prev_ps.path.user_data);
1755
+ auto data = tx_.data.get();
1756
+ auto datalen = bufpos - data - nwrite;
1757
+
1758
+ if (auto [nsent, rv] = server_->send_packet(
1759
+ ep, no_gso_, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1760
+ data, datalen, gso_size);
1761
+ rv != 0) {
1762
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1763
+
1764
+ on_send_blocked(ep, prev_ps.path.local, prev_ps.path.remote, prev_ecn,
1765
+ data + nsent, datalen - nsent, gso_size);
1766
+
1767
+ on_send_blocked(*static_cast<Endpoint *>(ps.path.user_data),
1768
+ ps.path.local, ps.path.remote, pi.ecn, bufpos - nwrite,
1769
+ nwrite, 0);
1770
+
1771
+ start_wev_endpoint(ep);
1772
+ } else {
1773
+ auto &ep = *static_cast<Endpoint *>(ps.path.user_data);
1774
+ auto data = bufpos - nwrite;
1775
+
1776
+ if (auto [nsent, rv] =
1777
+ server_->send_packet(ep, no_gso_, ps.path.local, ps.path.remote,
1778
+ pi.ecn, data, nwrite, nwrite);
1779
+ rv != 0) {
1780
+ assert(nsent == 0);
1781
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1782
+
1783
+ on_send_blocked(ep, ps.path.local, ps.path.remote, pi.ecn, data,
1784
+ nwrite, 0);
1785
+
1786
+ start_wev_endpoint(ep);
1787
+ }
1788
+ }
1789
+
1790
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1791
+ return 0;
1792
+ }
1793
+
1794
+ if (++pktcnt == max_pktcnt || static_cast<size_t>(nwrite) < gso_size) {
1795
+ auto &ep = *static_cast<Endpoint *>(ps.path.user_data);
1796
+ auto data = tx_.data.get();
1797
+ auto datalen = bufpos - data;
1798
+
1799
+ if (auto [nsent, rv] =
1800
+ server_->send_packet(ep, no_gso_, ps.path.local, ps.path.remote,
1801
+ pi.ecn, data, datalen, gso_size);
1802
+ rv != 0) {
1803
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1804
+
1805
+ on_send_blocked(ep, ps.path.local, ps.path.remote, pi.ecn, data + nsent,
1806
+ datalen - nsent, gso_size);
1807
+
1808
+ start_wev_endpoint(ep);
1809
+ }
1810
+
1811
+ ngtcp2_conn_update_pkt_tx_time(conn_, ts);
1812
+ return 0;
1813
+ }
1814
+ }
1815
+ }
1816
+
1817
+ void Handler::on_send_blocked(Endpoint &ep, const ngtcp2_addr &local_addr,
1818
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
1819
+ const uint8_t *data, size_t datalen,
1820
+ size_t gso_size) {
1821
+ assert(tx_.num_blocked || !tx_.send_blocked);
1822
+ assert(tx_.num_blocked < 2);
1823
+
1824
+ tx_.send_blocked = true;
1825
+
1826
+ auto &p = tx_.blocked[tx_.num_blocked++];
1827
+
1828
+ memcpy(&p.local_addr.su, local_addr.addr, local_addr.addrlen);
1829
+ memcpy(&p.remote_addr.su, remote_addr.addr, remote_addr.addrlen);
1830
+
1831
+ p.local_addr.len = local_addr.addrlen;
1832
+ p.remote_addr.len = remote_addr.addrlen;
1833
+ p.endpoint = &ep;
1834
+ p.ecn = ecn;
1835
+ p.data = data;
1836
+ p.datalen = datalen;
1837
+ p.gso_size = gso_size;
1838
+ }
1839
+
1840
+ void Handler::start_wev_endpoint(const Endpoint &ep) {
1841
+ // We do not close ep.fd, so we can expect that each Endpoint has
1842
+ // unique fd.
1843
+ if (ep.fd != wev_.fd) {
1844
+ if (ev_is_active(&wev_)) {
1845
+ ev_io_stop(loop_, &wev_);
1846
+ }
1847
+
1848
+ ev_io_set(&wev_, ep.fd, EV_WRITE);
1849
+ }
1850
+
1851
+ ev_io_start(loop_, &wev_);
1852
+ }
1853
+
1854
+ int Handler::send_blocked_packet() {
1855
+ assert(tx_.send_blocked);
1856
+
1857
+ for (; tx_.num_blocked_sent < tx_.num_blocked; ++tx_.num_blocked_sent) {
1858
+ auto &p = tx_.blocked[tx_.num_blocked_sent];
1859
+
1860
+ ngtcp2_addr local_addr{
1861
+ .addr = &p.local_addr.su.sa,
1862
+ .addrlen = p.local_addr.len,
1863
+ };
1864
+ ngtcp2_addr remote_addr{
1865
+ .addr = &p.remote_addr.su.sa,
1866
+ .addrlen = p.remote_addr.len,
1867
+ };
1868
+
1869
+ auto [nsent, rv] =
1870
+ server_->send_packet(*p.endpoint, no_gso_, local_addr, remote_addr,
1871
+ p.ecn, p.data, p.datalen, p.gso_size);
1872
+ if (rv != 0) {
1873
+ assert(NETWORK_ERR_SEND_BLOCKED == rv);
1874
+
1875
+ p.data += nsent;
1876
+ p.datalen -= nsent;
1877
+
1878
+ start_wev_endpoint(*p.endpoint);
1879
+
1880
+ return 0;
1881
+ }
1882
+ }
1883
+
1884
+ tx_.send_blocked = false;
1885
+ tx_.num_blocked = 0;
1886
+ tx_.num_blocked_sent = 0;
1887
+
1888
+ return 0;
1889
+ }
1890
+
1891
+ void Handler::signal_write() { ev_io_start(loop_, &wev_); }
1892
+
1893
+ void Handler::start_draining_period() {
1894
+ ev_io_stop(loop_, &wev_);
1895
+
1896
+ ev_set_cb(&timer_, close_waitcb);
1897
+ timer_.repeat =
1898
+ static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1899
+ ev_timer_again(loop_, &timer_);
1900
+
1901
+ if (!config.quiet) {
1902
+ std::cerr << "Draining period has started (" << timer_.repeat << " seconds)"
1903
+ << std::endl;
1904
+ }
1905
+ }
1906
+
1907
+ int Handler::start_closing_period() {
1908
+ if (!conn_ || ngtcp2_conn_is_in_closing_period(conn_) ||
1909
+ ngtcp2_conn_is_in_draining_period(conn_)) {
1910
+ return 0;
1911
+ }
1912
+
1913
+ ev_io_stop(loop_, &wev_);
1914
+
1915
+ ev_set_cb(&timer_, close_waitcb);
1916
+ timer_.repeat =
1917
+ static_cast<ev_tstamp>(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3;
1918
+ ev_timer_again(loop_, &timer_);
1919
+
1920
+ if (!config.quiet) {
1921
+ std::cerr << "Closing period has started (" << timer_.repeat << " seconds)"
1922
+ << std::endl;
1923
+ }
1924
+
1925
+ conn_closebuf_ = std::make_unique<Buffer>(NGTCP2_MAX_UDP_PAYLOAD_SIZE);
1926
+
1927
+ ngtcp2_path_storage ps;
1928
+
1929
+ ngtcp2_path_storage_zero(&ps);
1930
+
1931
+ ngtcp2_pkt_info pi;
1932
+ auto n = ngtcp2_conn_write_connection_close(
1933
+ conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(),
1934
+ &last_error_, util::timestamp(loop_));
1935
+ if (n < 0) {
1936
+ std::cerr << "ngtcp2_conn_write_connection_close: " << ngtcp2_strerror(n)
1937
+ << std::endl;
1938
+ return -1;
1939
+ }
1940
+
1941
+ if (n == 0) {
1942
+ return 0;
1943
+ }
1944
+
1945
+ conn_closebuf_->push(n);
1946
+
1947
+ return 0;
1948
+ }
1949
+
1950
+ int Handler::handle_error() {
1951
+ if (last_error_.type ==
1952
+ NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE) {
1953
+ return -1;
1954
+ }
1955
+
1956
+ if (start_closing_period() != 0) {
1957
+ return -1;
1958
+ }
1959
+
1960
+ if (ngtcp2_conn_is_in_draining_period(conn_)) {
1961
+ return NETWORK_ERR_CLOSE_WAIT;
1962
+ }
1963
+
1964
+ if (auto rv = send_conn_close(); rv != NETWORK_ERR_OK) {
1965
+ return rv;
1966
+ }
1967
+
1968
+ return NETWORK_ERR_CLOSE_WAIT;
1969
+ }
1970
+
1971
+ int Handler::send_conn_close() {
1972
+ if (!config.quiet) {
1973
+ std::cerr << "Closing Period: TX CONNECTION_CLOSE" << std::endl;
1974
+ }
1975
+
1976
+ assert(conn_closebuf_ && conn_closebuf_->size());
1977
+ assert(conn_);
1978
+ assert(!ngtcp2_conn_is_in_draining_period(conn_));
1979
+
1980
+ auto path = ngtcp2_conn_get_path(conn_);
1981
+
1982
+ return server_->send_packet(
1983
+ *static_cast<Endpoint *>(path->user_data), path->local, path->remote,
1984
+ /* ecn = */ 0, conn_closebuf_->rpos(), conn_closebuf_->size());
1985
+ }
1986
+
1987
+ void Handler::update_timer() {
1988
+ auto expiry = ngtcp2_conn_get_expiry(conn_);
1989
+ auto now = util::timestamp(loop_);
1990
+
1991
+ if (expiry <= now) {
1992
+ if (!config.quiet) {
1993
+ auto t = static_cast<ev_tstamp>(now - expiry) / NGTCP2_SECONDS;
1994
+ std::cerr << "Timer has already expired: " << std::fixed << t << "s"
1995
+ << std::defaultfloat << std::endl;
1996
+ }
1997
+
1998
+ ev_feed_event(loop_, &timer_, EV_TIMER);
1999
+
2000
+ return;
2001
+ }
2002
+
2003
+ auto t = static_cast<ev_tstamp>(expiry - now) / NGTCP2_SECONDS;
2004
+ if (!config.quiet) {
2005
+ std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat
2006
+ << std::endl;
2007
+ }
2008
+ timer_.repeat = t;
2009
+ ev_timer_again(loop_, &timer_);
2010
+ }
2011
+
2012
+ int Handler::recv_stream_data(uint32_t flags, int64_t stream_id,
2013
+ const uint8_t *data, size_t datalen) {
2014
+ if (!config.quiet && !config.no_quic_dump) {
2015
+ debug::print_stream_data(stream_id, data, datalen);
2016
+ }
2017
+
2018
+ if (!httpconn_) {
2019
+ return 0;
2020
+ }
2021
+
2022
+ auto nconsumed = nghttp3_conn_read_stream(
2023
+ httpconn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN);
2024
+ if (nconsumed < 0) {
2025
+ std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed)
2026
+ << std::endl;
2027
+ ngtcp2_connection_close_error_set_application_error(
2028
+ &last_error_, nghttp3_err_infer_quic_app_error_code(nconsumed), nullptr,
2029
+ 0);
2030
+ return -1;
2031
+ }
2032
+
2033
+ ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed);
2034
+ ngtcp2_conn_extend_max_offset(conn_, nconsumed);
2035
+
2036
+ return 0;
2037
+ }
2038
+
2039
+ int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret,
2040
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
2041
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
2042
+ const uint8_t *current_rx_secret,
2043
+ const uint8_t *current_tx_secret, size_t secretlen) {
2044
+ auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_);
2045
+ auto aead = &crypto_ctx->aead;
2046
+ auto keylen = ngtcp2_crypto_aead_keylen(aead);
2047
+ auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
2048
+
2049
+ ++nkey_update_;
2050
+
2051
+ std::array<uint8_t, 64> rx_key, tx_key;
2052
+
2053
+ if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx,
2054
+ rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(),
2055
+ tx_iv, current_rx_secret, current_tx_secret,
2056
+ secretlen) != 0) {
2057
+ return -1;
2058
+ }
2059
+
2060
+ if (!config.quiet && config.show_secret) {
2061
+ std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl;
2062
+ debug::print_secrets(rx_secret, secretlen, rx_key.data(), keylen, rx_iv,
2063
+ ivlen);
2064
+ std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl;
2065
+ debug::print_secrets(tx_secret, secretlen, tx_key.data(), keylen, tx_iv,
2066
+ ivlen);
2067
+ }
2068
+
2069
+ return 0;
2070
+ }
2071
+
2072
+ Server *Handler::server() const { return server_; }
2073
+
2074
+ int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) {
2075
+ if (!config.quiet) {
2076
+ std::cerr << "QUIC stream " << stream_id << " closed" << std::endl;
2077
+ }
2078
+
2079
+ if (httpconn_) {
2080
+ if (app_error_code == 0) {
2081
+ app_error_code = NGHTTP3_H3_NO_ERROR;
2082
+ }
2083
+ auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code);
2084
+ switch (rv) {
2085
+ case 0:
2086
+ break;
2087
+ case NGHTTP3_ERR_STREAM_NOT_FOUND:
2088
+ if (ngtcp2_is_bidi_stream(stream_id)) {
2089
+ assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
2090
+ ngtcp2_conn_extend_max_streams_bidi(conn_, 1);
2091
+ }
2092
+ break;
2093
+ default:
2094
+ std::cerr << "nghttp3_conn_close_stream: " << nghttp3_strerror(rv)
2095
+ << std::endl;
2096
+ ngtcp2_connection_close_error_set_application_error(
2097
+ &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0);
2098
+ return -1;
2099
+ }
2100
+ }
2101
+
2102
+ return 0;
2103
+ }
2104
+
2105
+ void Handler::shutdown_read(int64_t stream_id, int app_error_code) {
2106
+ ngtcp2_conn_shutdown_stream_read(conn_, stream_id, app_error_code);
2107
+ }
2108
+
2109
+ namespace {
2110
+ void sreadcb(struct ev_loop *loop, ev_io *w, int revents) {
2111
+ auto ep = static_cast<Endpoint *>(w->data);
2112
+
2113
+ ep->server->on_read(*ep);
2114
+ }
2115
+ } // namespace
2116
+
2117
+ namespace {
2118
+ void siginthandler(struct ev_loop *loop, ev_signal *watcher, int revents) {
2119
+ ev_break(loop, EVBREAK_ALL);
2120
+ }
2121
+ } // namespace
2122
+
2123
+ Server::Server(struct ev_loop *loop, TLSServerContext &tls_ctx)
2124
+ : loop_(loop), tls_ctx_(tls_ctx) {
2125
+ ev_signal_init(&sigintev_, siginthandler, SIGINT);
2126
+ }
2127
+
2128
+ Server::~Server() {
2129
+ disconnect();
2130
+ close();
2131
+ }
2132
+
2133
+ void Server::disconnect() {
2134
+ config.tx_loss_prob = 0;
2135
+
2136
+ for (auto &ep : endpoints_) {
2137
+ ev_io_stop(loop_, &ep.rev);
2138
+ }
2139
+
2140
+ ev_signal_stop(loop_, &sigintev_);
2141
+
2142
+ while (!handlers_.empty()) {
2143
+ auto it = std::begin(handlers_);
2144
+ auto &h = (*it).second;
2145
+
2146
+ h->handle_error();
2147
+
2148
+ remove(h);
2149
+ }
2150
+ }
2151
+
2152
+ void Server::close() {
2153
+ for (auto &ep : endpoints_) {
2154
+ ::close(ep.fd);
2155
+ }
2156
+
2157
+ endpoints_.clear();
2158
+ }
2159
+
2160
+ namespace {
2161
+ int create_sock(Address &local_addr, const char *addr, const char *port,
2162
+ int family) {
2163
+ addrinfo hints{};
2164
+ addrinfo *res, *rp;
2165
+ int val = 1;
2166
+
2167
+ hints.ai_family = family;
2168
+ hints.ai_socktype = SOCK_DGRAM;
2169
+ hints.ai_flags = AI_PASSIVE;
2170
+
2171
+ if (strcmp(addr, "*") == 0) {
2172
+ addr = nullptr;
2173
+ }
2174
+
2175
+ if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) {
2176
+ std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl;
2177
+ return -1;
2178
+ }
2179
+
2180
+ auto res_d = defer(freeaddrinfo, res);
2181
+
2182
+ int fd = -1;
2183
+
2184
+ for (rp = res; rp; rp = rp->ai_next) {
2185
+ fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype,
2186
+ rp->ai_protocol);
2187
+ if (fd == -1) {
2188
+ continue;
2189
+ }
2190
+
2191
+ if (rp->ai_family == AF_INET6) {
2192
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
2193
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2194
+ close(fd);
2195
+ continue;
2196
+ }
2197
+
2198
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
2199
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2200
+ close(fd);
2201
+ continue;
2202
+ }
2203
+ } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
2204
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2205
+ close(fd);
2206
+ continue;
2207
+ }
2208
+
2209
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
2210
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2211
+ close(fd);
2212
+ continue;
2213
+ }
2214
+
2215
+ fd_set_recv_ecn(fd, rp->ai_family);
2216
+ fd_set_ip_mtu_discover(fd, rp->ai_family);
2217
+ fd_set_ip_dontfrag(fd, family);
2218
+
2219
+ if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
2220
+ break;
2221
+ }
2222
+
2223
+ close(fd);
2224
+ }
2225
+
2226
+ if (!rp) {
2227
+ std::cerr << "Could not bind" << std::endl;
2228
+ return -1;
2229
+ }
2230
+
2231
+ socklen_t len = sizeof(local_addr.su.storage);
2232
+ if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
2233
+ std::cerr << "getsockname: " << strerror(errno) << std::endl;
2234
+ close(fd);
2235
+ return -1;
2236
+ }
2237
+ local_addr.len = len;
2238
+ local_addr.ifindex = 0;
2239
+
2240
+ return fd;
2241
+ }
2242
+
2243
+ } // namespace
2244
+
2245
+ namespace {
2246
+ int add_endpoint(std::vector<Endpoint> &endpoints, const char *addr,
2247
+ const char *port, int af) {
2248
+ Address dest;
2249
+ auto fd = create_sock(dest, addr, port, af);
2250
+ if (fd == -1) {
2251
+ return -1;
2252
+ }
2253
+
2254
+ endpoints.emplace_back();
2255
+ auto &ep = endpoints.back();
2256
+ ep.addr = dest;
2257
+ ep.fd = fd;
2258
+ ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
2259
+
2260
+ return 0;
2261
+ }
2262
+ } // namespace
2263
+
2264
+ namespace {
2265
+ int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
2266
+ auto fd = util::create_nonblock_socket(addr.su.sa.sa_family, SOCK_DGRAM, 0);
2267
+ if (fd == -1) {
2268
+ std::cerr << "socket: " << strerror(errno) << std::endl;
2269
+ return -1;
2270
+ }
2271
+
2272
+ int val = 1;
2273
+ if (addr.su.sa.sa_family == AF_INET6) {
2274
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
2275
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2276
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2277
+ close(fd);
2278
+ return -1;
2279
+ }
2280
+
2281
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
2282
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2283
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2284
+ close(fd);
2285
+ return -1;
2286
+ }
2287
+ } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
2288
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2289
+ std::cerr << "setsockopt: " << strerror(errno) << std::endl;
2290
+ close(fd);
2291
+ return -1;
2292
+ }
2293
+
2294
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
2295
+ static_cast<socklen_t>(sizeof(val))) == -1) {
2296
+ close(fd);
2297
+ return -1;
2298
+ }
2299
+
2300
+ fd_set_recv_ecn(fd, addr.su.sa.sa_family);
2301
+ fd_set_ip_mtu_discover(fd, addr.su.sa.sa_family);
2302
+ fd_set_ip_dontfrag(fd, addr.su.sa.sa_family);
2303
+
2304
+ if (bind(fd, &addr.su.sa, addr.len) == -1) {
2305
+ std::cerr << "bind: " << strerror(errno) << std::endl;
2306
+ close(fd);
2307
+ return -1;
2308
+ }
2309
+
2310
+ endpoints.emplace_back(Endpoint{});
2311
+ auto &ep = endpoints.back();
2312
+ ep.addr = addr;
2313
+ ep.fd = fd;
2314
+ ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
2315
+
2316
+ return 0;
2317
+ }
2318
+ } // namespace
2319
+
2320
+ int Server::init(const char *addr, const char *port) {
2321
+ endpoints_.reserve(4);
2322
+
2323
+ auto ready = false;
2324
+ if (!util::numeric_host(addr, AF_INET6) &&
2325
+ add_endpoint(endpoints_, addr, port, AF_INET) == 0) {
2326
+ ready = true;
2327
+ }
2328
+ if (!util::numeric_host(addr, AF_INET) &&
2329
+ add_endpoint(endpoints_, addr, port, AF_INET6) == 0) {
2330
+ ready = true;
2331
+ }
2332
+ if (!ready) {
2333
+ return -1;
2334
+ }
2335
+
2336
+ if (config.preferred_ipv4_addr.len &&
2337
+ add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) {
2338
+ return -1;
2339
+ }
2340
+ if (config.preferred_ipv6_addr.len &&
2341
+ add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) {
2342
+ return -1;
2343
+ }
2344
+
2345
+ for (auto &ep : endpoints_) {
2346
+ ep.server = this;
2347
+ ep.rev.data = &ep;
2348
+
2349
+ ev_io_set(&ep.rev, ep.fd, EV_READ);
2350
+
2351
+ ev_io_start(loop_, &ep.rev);
2352
+ }
2353
+
2354
+ ev_signal_start(loop_, &sigintev_);
2355
+
2356
+ return 0;
2357
+ }
2358
+
2359
+ int Server::on_read(Endpoint &ep) {
2360
+ sockaddr_union su;
2361
+ std::array<uint8_t, 64_k> buf;
2362
+ ngtcp2_pkt_hd hd;
2363
+ size_t pktcnt = 0;
2364
+ ngtcp2_pkt_info pi;
2365
+
2366
+ iovec msg_iov;
2367
+ msg_iov.iov_base = buf.data();
2368
+ msg_iov.iov_len = buf.size();
2369
+
2370
+ msghdr msg{};
2371
+ msg.msg_name = &su;
2372
+ msg.msg_iov = &msg_iov;
2373
+ msg.msg_iovlen = 1;
2374
+
2375
+ uint8_t
2376
+ msg_ctrl[CMSG_SPACE(sizeof(uint8_t)) + CMSG_SPACE(sizeof(in6_pktinfo))];
2377
+ msg.msg_control = msg_ctrl;
2378
+
2379
+ for (; pktcnt < 10;) {
2380
+ msg.msg_namelen = sizeof(su);
2381
+ msg.msg_controllen = sizeof(msg_ctrl);
2382
+
2383
+ auto nread = recvmsg(ep.fd, &msg, 0);
2384
+ if (nread == -1) {
2385
+ if (!(errno == EAGAIN || errno == ENOTCONN)) {
2386
+ std::cerr << "recvmsg: " << strerror(errno) << std::endl;
2387
+ }
2388
+ return 0;
2389
+ }
2390
+
2391
+ ++pktcnt;
2392
+
2393
+ pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
2394
+ auto local_addr = msghdr_get_local_addr(&msg, su.storage.ss_family);
2395
+ if (!local_addr) {
2396
+ std::cerr << "Unable to obtain local address" << std::endl;
2397
+ continue;
2398
+ }
2399
+
2400
+ set_port(*local_addr, ep.addr);
2401
+
2402
+ if (!config.quiet) {
2403
+ std::array<char, IF_NAMESIZE> ifname;
2404
+ std::cerr << "Received packet: local="
2405
+ << util::straddr(&local_addr->su.sa, local_addr->len)
2406
+ << " remote=" << util::straddr(&su.sa, msg.msg_namelen)
2407
+ << " if=" << if_indextoname(local_addr->ifindex, ifname.data())
2408
+ << " ecn=0x" << std::hex << pi.ecn << std::dec << " " << nread
2409
+ << " bytes" << std::endl;
2410
+ }
2411
+
2412
+ if (debug::packet_lost(config.rx_loss_prob)) {
2413
+ if (!config.quiet) {
2414
+ std::cerr << "** Simulated incoming packet loss **" << std::endl;
2415
+ }
2416
+ continue;
2417
+ }
2418
+
2419
+ if (nread == 0) {
2420
+ continue;
2421
+ }
2422
+
2423
+ ngtcp2_version_cid vc;
2424
+
2425
+ switch (auto rv = ngtcp2_pkt_decode_version_cid(&vc, buf.data(), nread,
2426
+ NGTCP2_SV_SCIDLEN);
2427
+ rv) {
2428
+ case 0:
2429
+ break;
2430
+ case NGTCP2_ERR_VERSION_NEGOTIATION:
2431
+ send_version_negotiation(vc.version, vc.scid, vc.scidlen, vc.dcid,
2432
+ vc.dcidlen, ep, *local_addr, &su.sa,
2433
+ msg.msg_namelen);
2434
+ continue;
2435
+ default:
2436
+ std::cerr << "Could not decode version and CID from QUIC packet header: "
2437
+ << ngtcp2_strerror(rv) << std::endl;
2438
+ continue;
2439
+ }
2440
+
2441
+ auto dcid_key = util::make_cid_key(vc.dcid, vc.dcidlen);
2442
+
2443
+ auto handler_it = handlers_.find(dcid_key);
2444
+ if (handler_it == std::end(handlers_)) {
2445
+ if (auto rv = ngtcp2_accept(&hd, buf.data(), nread); rv != 0) {
2446
+ if (!config.quiet) {
2447
+ std::cerr << "Unexpected packet received: length=" << nread
2448
+ << std::endl;
2449
+ }
2450
+ continue;
2451
+ }
2452
+
2453
+ ngtcp2_cid ocid;
2454
+ ngtcp2_cid *pocid = nullptr;
2455
+
2456
+ assert(hd.type == NGTCP2_PKT_INITIAL);
2457
+
2458
+ if (config.validate_addr || hd.tokenlen) {
2459
+ std::cerr << "Perform stateless address validation" << std::endl;
2460
+ if (hd.tokenlen == 0) {
2461
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen, nread * 3);
2462
+ continue;
2463
+ }
2464
+
2465
+ if (hd.token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY &&
2466
+ hd.dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) {
2467
+ send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
2468
+ msg.msg_namelen);
2469
+ continue;
2470
+ }
2471
+
2472
+ switch (hd.token[0]) {
2473
+ case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY:
2474
+ if (verify_retry_token(&ocid, &hd, &su.sa, msg.msg_namelen) != 0) {
2475
+ send_stateless_connection_close(&hd, ep, *local_addr, &su.sa,
2476
+ msg.msg_namelen);
2477
+ continue;
2478
+ }
2479
+ pocid = &ocid;
2480
+ break;
2481
+ case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR:
2482
+ if (verify_token(&hd, &su.sa, msg.msg_namelen) != 0) {
2483
+ if (config.validate_addr) {
2484
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen,
2485
+ nread * 3);
2486
+ continue;
2487
+ }
2488
+
2489
+ hd.token = nullptr;
2490
+ hd.tokenlen = 0;
2491
+ }
2492
+ break;
2493
+ default:
2494
+ if (!config.quiet) {
2495
+ std::cerr << "Ignore unrecognized token" << std::endl;
2496
+ }
2497
+ if (config.validate_addr) {
2498
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen,
2499
+ nread * 3);
2500
+ continue;
2501
+ }
2502
+
2503
+ hd.token = nullptr;
2504
+ hd.tokenlen = 0;
2505
+ break;
2506
+ }
2507
+ }
2508
+
2509
+ auto h = std::make_unique<Handler>(loop_, this);
2510
+ if (h->init(ep, *local_addr, &su.sa, msg.msg_namelen, &hd.scid, &hd.dcid,
2511
+ pocid, hd.token, hd.tokenlen, hd.version, tls_ctx_) != 0) {
2512
+ continue;
2513
+ }
2514
+
2515
+ switch (h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
2516
+ buf.data(), nread)) {
2517
+ case 0:
2518
+ break;
2519
+ case NETWORK_ERR_RETRY:
2520
+ send_retry(&hd, ep, *local_addr, &su.sa, msg.msg_namelen, nread * 3);
2521
+ continue;
2522
+ default:
2523
+ continue;
2524
+ }
2525
+
2526
+ switch (h->on_write()) {
2527
+ case 0:
2528
+ break;
2529
+ default:
2530
+ continue;
2531
+ }
2532
+
2533
+ std::array<ngtcp2_cid, 2> scids;
2534
+ auto conn = h->conn();
2535
+
2536
+ auto num_scid = ngtcp2_conn_get_num_scid(conn);
2537
+
2538
+ assert(num_scid <= scids.size());
2539
+
2540
+ ngtcp2_conn_get_scid(conn, scids.data());
2541
+
2542
+ for (size_t i = 0; i < num_scid; ++i) {
2543
+ associate_cid(&scids[i], h.get());
2544
+ }
2545
+
2546
+ handlers_.emplace(dcid_key, h.get());
2547
+
2548
+ h.release();
2549
+
2550
+ continue;
2551
+ }
2552
+
2553
+ auto h = (*handler_it).second;
2554
+ auto conn = h->conn();
2555
+ if (ngtcp2_conn_is_in_closing_period(conn)) {
2556
+ // TODO do exponential backoff.
2557
+ switch (h->send_conn_close()) {
2558
+ case 0:
2559
+ break;
2560
+ default:
2561
+ remove(h);
2562
+ }
2563
+ continue;
2564
+ }
2565
+ if (ngtcp2_conn_is_in_draining_period(conn)) {
2566
+ continue;
2567
+ }
2568
+
2569
+ if (auto rv = h->on_read(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
2570
+ buf.data(), nread);
2571
+ rv != 0) {
2572
+ if (rv != NETWORK_ERR_CLOSE_WAIT) {
2573
+ remove(h);
2574
+ }
2575
+ continue;
2576
+ }
2577
+
2578
+ h->signal_write();
2579
+ }
2580
+
2581
+ return 0;
2582
+ }
2583
+
2584
+ namespace {
2585
+ uint32_t generate_reserved_version(const sockaddr *sa, socklen_t salen,
2586
+ uint32_t version) {
2587
+ uint32_t h = 0x811C9DC5u;
2588
+ const uint8_t *p = (const uint8_t *)sa;
2589
+ const uint8_t *ep = p + salen;
2590
+ for (; p != ep; ++p) {
2591
+ h ^= *p;
2592
+ h *= 0x01000193u;
2593
+ }
2594
+ version = htonl(version);
2595
+ p = (const uint8_t *)&version;
2596
+ ep = p + sizeof(version);
2597
+ for (; p != ep; ++p) {
2598
+ h ^= *p;
2599
+ h *= 0x01000193u;
2600
+ }
2601
+ h &= 0xf0f0f0f0u;
2602
+ h |= 0x0a0a0a0au;
2603
+ return h;
2604
+ }
2605
+ } // namespace
2606
+
2607
+ int Server::send_version_negotiation(uint32_t version, const uint8_t *dcid,
2608
+ size_t dcidlen, const uint8_t *scid,
2609
+ size_t scidlen, Endpoint &ep,
2610
+ const Address &local_addr,
2611
+ const sockaddr *sa, socklen_t salen) {
2612
+ Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2613
+ std::array<uint32_t, 1 + max_preferred_versionslen> sv;
2614
+
2615
+ auto p = std::begin(sv);
2616
+
2617
+ *p++ = generate_reserved_version(sa, salen, version);
2618
+
2619
+ if (config.preferred_versions.empty()) {
2620
+ *p++ = NGTCP2_PROTO_VER_V1;
2621
+ } else {
2622
+ for (auto v : config.preferred_versions) {
2623
+ *p++ = v;
2624
+ }
2625
+ }
2626
+
2627
+ auto nwrite = ngtcp2_pkt_write_version_negotiation(
2628
+ buf.wpos(), buf.left(), std::uniform_int_distribution<uint8_t>()(randgen),
2629
+ dcid, dcidlen, scid, scidlen, sv.data(), p - std::begin(sv));
2630
+ if (nwrite < 0) {
2631
+ std::cerr << "ngtcp2_pkt_write_version_negotiation: "
2632
+ << ngtcp2_strerror(nwrite) << std::endl;
2633
+ return -1;
2634
+ }
2635
+
2636
+ buf.push(nwrite);
2637
+
2638
+ ngtcp2_addr laddr{
2639
+ const_cast<sockaddr *>(&local_addr.su.sa),
2640
+ local_addr.len,
2641
+ };
2642
+ ngtcp2_addr raddr{
2643
+ const_cast<sockaddr *>(sa),
2644
+ salen,
2645
+ };
2646
+
2647
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
2648
+ NETWORK_ERR_OK) {
2649
+ return -1;
2650
+ }
2651
+
2652
+ return 0;
2653
+ }
2654
+
2655
+ int Server::send_retry(const ngtcp2_pkt_hd *chd, Endpoint &ep,
2656
+ const Address &local_addr, const sockaddr *sa,
2657
+ socklen_t salen, size_t max_pktlen) {
2658
+ std::array<char, NI_MAXHOST> host;
2659
+ std::array<char, NI_MAXSERV> port;
2660
+
2661
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2662
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2663
+ rv != 0) {
2664
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2665
+ return -1;
2666
+ }
2667
+
2668
+ if (!config.quiet) {
2669
+ std::cerr << "Sending Retry packet to [" << host.data()
2670
+ << "]:" << port.data() << std::endl;
2671
+ }
2672
+
2673
+ ngtcp2_cid scid;
2674
+
2675
+ scid.datalen = NGTCP2_SV_SCIDLEN;
2676
+ if (util::generate_secure_random(scid.data, scid.datalen) != 0) {
2677
+ return -1;
2678
+ }
2679
+
2680
+ std::array<uint8_t, NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN> token;
2681
+
2682
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2683
+ std::chrono::system_clock::now().time_since_epoch())
2684
+ .count();
2685
+
2686
+ auto tokenlen = ngtcp2_crypto_generate_retry_token(
2687
+ token.data(), config.static_secret.data(), config.static_secret.size(),
2688
+ chd->version, sa, salen, &scid, &chd->dcid, t);
2689
+ if (tokenlen < 0) {
2690
+ return -1;
2691
+ }
2692
+
2693
+ if (!config.quiet) {
2694
+ std::cerr << "Generated address validation token:" << std::endl;
2695
+ util::hexdump(stderr, token.data(), tokenlen);
2696
+ }
2697
+
2698
+ Buffer buf{
2699
+ std::min(static_cast<size_t>(NGTCP2_MAX_UDP_PAYLOAD_SIZE), max_pktlen)};
2700
+
2701
+ auto nwrite = ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version,
2702
+ &chd->scid, &scid, &chd->dcid,
2703
+ token.data(), tokenlen);
2704
+ if (nwrite < 0) {
2705
+ std::cerr << "ngtcp2_crypto_write_retry failed" << std::endl;
2706
+ return -1;
2707
+ }
2708
+
2709
+ buf.push(nwrite);
2710
+
2711
+ ngtcp2_addr laddr{
2712
+ const_cast<sockaddr *>(&local_addr.su.sa),
2713
+ local_addr.len,
2714
+ };
2715
+ ngtcp2_addr raddr{
2716
+ const_cast<sockaddr *>(sa),
2717
+ salen,
2718
+ };
2719
+
2720
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
2721
+ NETWORK_ERR_OK) {
2722
+ return -1;
2723
+ }
2724
+
2725
+ return 0;
2726
+ }
2727
+
2728
+ int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
2729
+ Endpoint &ep,
2730
+ const Address &local_addr,
2731
+ const sockaddr *sa,
2732
+ socklen_t salen) {
2733
+ Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
2734
+
2735
+ auto nwrite = ngtcp2_crypto_write_connection_close(
2736
+ buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid,
2737
+ NGTCP2_INVALID_TOKEN, nullptr, 0);
2738
+ if (nwrite < 0) {
2739
+ std::cerr << "ngtcp2_crypto_write_connection_close failed" << std::endl;
2740
+ return -1;
2741
+ }
2742
+
2743
+ buf.push(nwrite);
2744
+
2745
+ ngtcp2_addr laddr{
2746
+ const_cast<sockaddr *>(&local_addr.su.sa),
2747
+ local_addr.len,
2748
+ };
2749
+ ngtcp2_addr raddr{
2750
+ const_cast<sockaddr *>(sa),
2751
+ salen,
2752
+ };
2753
+
2754
+ if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.rpos(), buf.size()) !=
2755
+ NETWORK_ERR_OK) {
2756
+ return -1;
2757
+ }
2758
+
2759
+ return 0;
2760
+ }
2761
+
2762
+ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
2763
+ const sockaddr *sa, socklen_t salen) {
2764
+ std::array<char, NI_MAXHOST> host;
2765
+ std::array<char, NI_MAXSERV> port;
2766
+
2767
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2768
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2769
+ rv != 0) {
2770
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2771
+ return -1;
2772
+ }
2773
+
2774
+ if (!config.quiet) {
2775
+ std::cerr << "Verifying Retry token from [" << host.data()
2776
+ << "]:" << port.data() << std::endl;
2777
+ util::hexdump(stderr, hd->token, hd->tokenlen);
2778
+ }
2779
+
2780
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2781
+ std::chrono::system_clock::now().time_since_epoch())
2782
+ .count();
2783
+
2784
+ if (ngtcp2_crypto_verify_retry_token(
2785
+ ocid, hd->token, hd->tokenlen, config.static_secret.data(),
2786
+ config.static_secret.size(), hd->version, sa, salen, &hd->dcid,
2787
+ 10 * NGTCP2_SECONDS, t) != 0) {
2788
+ std::cerr << "Could not verify Retry token" << std::endl;
2789
+
2790
+ return -1;
2791
+ }
2792
+
2793
+ if (!config.quiet) {
2794
+ std::cerr << "Token was successfully validated" << std::endl;
2795
+ }
2796
+
2797
+ return 0;
2798
+ }
2799
+
2800
+ int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
2801
+ socklen_t salen) {
2802
+ std::array<char, NI_MAXHOST> host;
2803
+ std::array<char, NI_MAXSERV> port;
2804
+
2805
+ if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
2806
+ port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
2807
+ rv != 0) {
2808
+ std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
2809
+ return -1;
2810
+ }
2811
+
2812
+ if (!config.quiet) {
2813
+ std::cerr << "Verifying token from [" << host.data() << "]:" << port.data()
2814
+ << std::endl;
2815
+ util::hexdump(stderr, hd->token, hd->tokenlen);
2816
+ }
2817
+
2818
+ auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
2819
+ std::chrono::system_clock::now().time_since_epoch())
2820
+ .count();
2821
+
2822
+ if (ngtcp2_crypto_verify_regular_token(hd->token, hd->tokenlen,
2823
+ config.static_secret.data(),
2824
+ config.static_secret.size(), sa, salen,
2825
+ 3600 * NGTCP2_SECONDS, t) != 0) {
2826
+ if (!config.quiet) {
2827
+ std::cerr << "Could not verify token" << std::endl;
2828
+ }
2829
+ return -1;
2830
+ }
2831
+
2832
+ if (!config.quiet) {
2833
+ std::cerr << "Token was successfully validated" << std::endl;
2834
+ }
2835
+
2836
+ return 0;
2837
+ }
2838
+
2839
+ int Server::send_packet(Endpoint &ep, const ngtcp2_addr &local_addr,
2840
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
2841
+ const uint8_t *data, size_t datalen) {
2842
+ auto no_gso = false;
2843
+ auto [_, rv] = send_packet(ep, no_gso, local_addr, remote_addr, ecn, data,
2844
+ datalen, datalen);
2845
+
2846
+ return rv;
2847
+ }
2848
+
2849
+ std::pair<size_t, int>
2850
+ Server::send_packet(Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr,
2851
+ const ngtcp2_addr &remote_addr, unsigned int ecn,
2852
+ const uint8_t *data, size_t datalen, size_t gso_size) {
2853
+ assert(gso_size);
2854
+
2855
+ if (debug::packet_lost(config.tx_loss_prob)) {
2856
+ if (!config.quiet) {
2857
+ std::cerr << "** Simulated outgoing packet loss **" << std::endl;
2858
+ }
2859
+ return {0, NETWORK_ERR_OK};
2860
+ }
2861
+
2862
+ if (no_gso && datalen > gso_size) {
2863
+ size_t nsent = 0;
2864
+
2865
+ for (auto p = data; p < data + datalen; p += gso_size) {
2866
+ auto len = std::min(gso_size, static_cast<size_t>(data + datalen - p));
2867
+
2868
+ auto [n, rv] =
2869
+ send_packet(ep, no_gso, local_addr, remote_addr, ecn, p, len, len);
2870
+ if (rv != 0) {
2871
+ return {nsent, rv};
2872
+ }
2873
+
2874
+ nsent += n;
2875
+ }
2876
+
2877
+ return {nsent, 0};
2878
+ }
2879
+
2880
+ iovec msg_iov;
2881
+ msg_iov.iov_base = const_cast<uint8_t *>(data);
2882
+ msg_iov.iov_len = datalen;
2883
+
2884
+ msghdr msg{};
2885
+ msg.msg_name = const_cast<sockaddr *>(remote_addr.addr);
2886
+ msg.msg_namelen = remote_addr.addrlen;
2887
+ msg.msg_iov = &msg_iov;
2888
+ msg.msg_iovlen = 1;
2889
+
2890
+ uint8_t
2891
+ msg_ctrl[CMSG_SPACE(sizeof(uint16_t)) + CMSG_SPACE(sizeof(in6_pktinfo))];
2892
+
2893
+ memset(msg_ctrl, 0, sizeof(msg_ctrl));
2894
+
2895
+ msg.msg_control = msg_ctrl;
2896
+ msg.msg_controllen = sizeof(msg_ctrl);
2897
+
2898
+ size_t controllen = 0;
2899
+
2900
+ auto cm = CMSG_FIRSTHDR(&msg);
2901
+
2902
+ switch (local_addr.addr->sa_family) {
2903
+ case AF_INET: {
2904
+ controllen += CMSG_SPACE(sizeof(in_pktinfo));
2905
+ cm->cmsg_level = IPPROTO_IP;
2906
+ cm->cmsg_type = IP_PKTINFO;
2907
+ cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
2908
+ auto pktinfo = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cm));
2909
+ memset(pktinfo, 0, sizeof(in_pktinfo));
2910
+ auto addrin = reinterpret_cast<sockaddr_in *>(local_addr.addr);
2911
+ pktinfo->ipi_spec_dst = addrin->sin_addr;
2912
+ break;
2913
+ }
2914
+ case AF_INET6: {
2915
+ controllen += CMSG_SPACE(sizeof(in6_pktinfo));
2916
+ cm->cmsg_level = IPPROTO_IPV6;
2917
+ cm->cmsg_type = IPV6_PKTINFO;
2918
+ cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
2919
+ auto pktinfo = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cm));
2920
+ memset(pktinfo, 0, sizeof(in6_pktinfo));
2921
+ auto addrin = reinterpret_cast<sockaddr_in6 *>(local_addr.addr);
2922
+ pktinfo->ipi6_addr = addrin->sin6_addr;
2923
+ break;
2924
+ }
2925
+ default:
2926
+ assert(0);
2927
+ }
2928
+
2929
+ #ifdef UDP_SEGMENT
2930
+ if (datalen > gso_size) {
2931
+ controllen += CMSG_SPACE(sizeof(uint16_t));
2932
+ cm = CMSG_NXTHDR(&msg, cm);
2933
+ cm->cmsg_level = SOL_UDP;
2934
+ cm->cmsg_type = UDP_SEGMENT;
2935
+ cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
2936
+ *(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
2937
+ }
2938
+ #endif // UDP_SEGMENT
2939
+
2940
+ msg.msg_controllen = controllen;
2941
+
2942
+ if (ep.ecn != ecn) {
2943
+ ep.ecn = ecn;
2944
+ fd_set_ecn(ep.fd, ep.addr.su.storage.ss_family, ecn);
2945
+ }
2946
+
2947
+ ssize_t nwrite = 0;
2948
+
2949
+ do {
2950
+ nwrite = sendmsg(ep.fd, &msg, 0);
2951
+ } while (nwrite == -1 && errno == EINTR);
2952
+
2953
+ if (nwrite == -1) {
2954
+ switch (errno) {
2955
+ case EAGAIN:
2956
+ #if EAGAIN != EWOULDBLOCK
2957
+ case EWOULDBLOCK:
2958
+ #endif // EAGAIN != EWOULDBLOCK
2959
+ return {0, NETWORK_ERR_SEND_BLOCKED};
2960
+ #ifdef UDP_SEGMENT
2961
+ case EIO:
2962
+ if (datalen > gso_size) {
2963
+ // GSO failure; send each packet in a separate sendmsg call.
2964
+ std::cerr << "sendmsg: disabling GSO due to " << strerror(errno)
2965
+ << std::endl;
2966
+
2967
+ no_gso = true;
2968
+
2969
+ return send_packet(ep, no_gso, local_addr, remote_addr, ecn, data,
2970
+ datalen, gso_size);
2971
+ }
2972
+ break;
2973
+ #endif // UDP_SEGMENT
2974
+ }
2975
+
2976
+ std::cerr << "sendmsg: " << strerror(errno) << std::endl;
2977
+ // TODO We have packet which is expected to fail to send (e.g.,
2978
+ // path validation to old path).
2979
+ return {0, NETWORK_ERR_OK};
2980
+ }
2981
+
2982
+ if (!config.quiet) {
2983
+ std::cerr << "Sent packet: local="
2984
+ << util::straddr(local_addr.addr, local_addr.addrlen)
2985
+ << " remote="
2986
+ << util::straddr(remote_addr.addr, remote_addr.addrlen)
2987
+ << " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite
2988
+ << " bytes" << std::endl;
2989
+ }
2990
+
2991
+ return {nwrite, NETWORK_ERR_OK};
2992
+ }
2993
+
2994
+ void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) {
2995
+ handlers_.emplace(util::make_cid_key(cid), h);
2996
+ }
2997
+
2998
+ void Server::dissociate_cid(const ngtcp2_cid *cid) {
2999
+ handlers_.erase(util::make_cid_key(cid));
3000
+ }
3001
+
3002
+ void Server::remove(const Handler *h) {
3003
+ auto conn = h->conn();
3004
+
3005
+ dissociate_cid(ngtcp2_conn_get_client_initial_dcid(conn));
3006
+
3007
+ std::vector<ngtcp2_cid> cids(ngtcp2_conn_get_num_scid(conn));
3008
+ ngtcp2_conn_get_scid(conn, cids.data());
3009
+
3010
+ for (auto &cid : cids) {
3011
+ dissociate_cid(&cid);
3012
+ }
3013
+
3014
+ delete h;
3015
+ }
3016
+
3017
+ namespace {
3018
+ int parse_host_port(Address &dest, int af, const char *first,
3019
+ const char *last) {
3020
+ if (std::distance(first, last) == 0) {
3021
+ return -1;
3022
+ }
3023
+
3024
+ const char *host_begin, *host_end, *it;
3025
+ if (*first == '[') {
3026
+ host_begin = first + 1;
3027
+ it = std::find(host_begin, last, ']');
3028
+ if (it == last) {
3029
+ return -1;
3030
+ }
3031
+ host_end = it;
3032
+ ++it;
3033
+ if (it == last || *it != ':') {
3034
+ return -1;
3035
+ }
3036
+ } else {
3037
+ host_begin = first;
3038
+ it = std::find(host_begin, last, ':');
3039
+ if (it == last) {
3040
+ return -1;
3041
+ }
3042
+ host_end = it;
3043
+ }
3044
+
3045
+ if (++it == last) {
3046
+ return -1;
3047
+ }
3048
+ auto svc_begin = it;
3049
+
3050
+ std::array<char, NI_MAXHOST> host;
3051
+ *std::copy(host_begin, host_end, std::begin(host)) = '\0';
3052
+
3053
+ addrinfo hints{}, *res;
3054
+ hints.ai_family = af;
3055
+ hints.ai_socktype = SOCK_DGRAM;
3056
+
3057
+ if (auto rv = getaddrinfo(host.data(), svc_begin, &hints, &res); rv != 0) {
3058
+ std::cerr << "getaddrinfo: [" << host.data() << "]:" << svc_begin << ": "
3059
+ << gai_strerror(rv) << std::endl;
3060
+ return -1;
3061
+ }
3062
+
3063
+ dest.len = res->ai_addrlen;
3064
+ memcpy(&dest.su, res->ai_addr, res->ai_addrlen);
3065
+
3066
+ freeaddrinfo(res);
3067
+
3068
+ return 0;
3069
+ }
3070
+ } // namespace
3071
+
3072
+ namespace {
3073
+ void print_usage() {
3074
+ std::cerr << "Usage: server [OPTIONS] <ADDR> <PORT> <PRIVATE_KEY_FILE> "
3075
+ "<CERTIFICATE_FILE>"
3076
+ << std::endl;
3077
+ }
3078
+ } // namespace
3079
+
3080
+ namespace {
3081
+ void config_set_default(Config &config) {
3082
+ config = Config{};
3083
+ config.tx_loss_prob = 0.;
3084
+ config.rx_loss_prob = 0.;
3085
+ config.ciphers = util::crypto_default_ciphers();
3086
+ config.groups = util::crypto_default_groups();
3087
+ config.timeout = 30 * NGTCP2_SECONDS;
3088
+ {
3089
+ auto path = realpath(".", nullptr);
3090
+ assert(path);
3091
+ config.htdocs = path;
3092
+ free(path);
3093
+ }
3094
+ config.mime_types_file = "/etc/mime.types"sv;
3095
+ config.max_data = 1_m;
3096
+ config.max_stream_data_bidi_local = 256_k;
3097
+ config.max_stream_data_bidi_remote = 256_k;
3098
+ config.max_stream_data_uni = 256_k;
3099
+ config.max_window = 6_m;
3100
+ config.max_stream_window = 6_m;
3101
+ config.max_streams_bidi = 100;
3102
+ config.max_streams_uni = 3;
3103
+ config.max_dyn_length = 20_m;
3104
+ config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
3105
+ config.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
3106
+ config.max_gso_dgrams = 64;
3107
+ config.handshake_timeout = UINT64_MAX;
3108
+ config.ack_thresh = 2;
3109
+ }
3110
+ } // namespace
3111
+
3112
+ namespace {
3113
+ void print_help() {
3114
+ print_usage();
3115
+
3116
+ config_set_default(config);
3117
+
3118
+ std::cout << R"(
3119
+ <ADDR> Address to listen to. '*' binds to any address.
3120
+ <PORT> Port
3121
+ <PRIVATE_KEY_FILE>
3122
+ Path to private key file
3123
+ <CERTIFICATE_FILE>
3124
+ Path to certificate file
3125
+ Options:
3126
+ -t, --tx-loss=<P>
3127
+ The probability of losing outgoing packets. <P> must be
3128
+ [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
3129
+ means 100% packet loss.
3130
+ -r, --rx-loss=<P>
3131
+ The probability of losing incoming packets. <P> must be
3132
+ [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0
3133
+ means 100% packet loss.
3134
+ --ciphers=<CIPHERS>
3135
+ Specify the cipher suite list to enable.
3136
+ Default: )"
3137
+ << config.ciphers << R"(
3138
+ --groups=<GROUPS>
3139
+ Specify the supported groups.
3140
+ Default: )"
3141
+ << config.groups << R"(
3142
+ -d, --htdocs=<PATH>
3143
+ Specify document root. If this option is not specified,
3144
+ the document root is the current working directory.
3145
+ -q, --quiet Suppress debug output.
3146
+ -s, --show-secret
3147
+ Print out secrets unless --quiet is used.
3148
+ --timeout=<DURATION>
3149
+ Specify idle timeout.
3150
+ Default: )"
3151
+ << util::format_duration(config.timeout) << R"(
3152
+ -V, --validate-addr
3153
+ Perform address validation.
3154
+ --preferred-ipv4-addr=<ADDR>:<PORT>
3155
+ Specify preferred IPv4 address and port.
3156
+ --preferred-ipv6-addr=<ADDR>:<PORT>
3157
+ Specify preferred IPv6 address and port. A numeric IPv6
3158
+ address must be enclosed by '[' and ']' (e.g.,
3159
+ [::1]:8443)
3160
+ --mime-types-file=<PATH>
3161
+ Path to file that contains MIME media types and the
3162
+ extensions.
3163
+ Default: )"
3164
+ << config.mime_types_file << R"(
3165
+ --early-response
3166
+ Start sending response when it receives HTTP header
3167
+ fields without waiting for request body. If HTTP
3168
+ response data is written before receiving request body,
3169
+ STOP_SENDING is sent.
3170
+ --verify-client
3171
+ Request a client certificate. At the moment, we just
3172
+ request a certificate and no verification is done.
3173
+ --qlog-dir=<PATH>
3174
+ Path to the directory where qlog file is stored. The
3175
+ file name of each qlog is the Source Connection ID of
3176
+ server.
3177
+ --no-quic-dump
3178
+ Disables printing QUIC STREAM and CRYPTO frame data out.
3179
+ --no-http-dump
3180
+ Disables printing HTTP response body out.
3181
+ --max-data=<SIZE>
3182
+ The initial connection-level flow control window.
3183
+ Default: )"
3184
+ << util::format_uint_iec(config.max_data) << R"(
3185
+ --max-stream-data-bidi-local=<SIZE>
3186
+ The initial stream-level flow control window for a
3187
+ bidirectional stream that the local endpoint initiates.
3188
+ Default: )"
3189
+ << util::format_uint_iec(config.max_stream_data_bidi_local) << R"(
3190
+ --max-stream-data-bidi-remote=<SIZE>
3191
+ The initial stream-level flow control window for a
3192
+ bidirectional stream that the remote endpoint initiates.
3193
+ Default: )"
3194
+ << util::format_uint_iec(config.max_stream_data_bidi_remote) << R"(
3195
+ --max-stream-data-uni=<SIZE>
3196
+ The initial stream-level flow control window for a
3197
+ unidirectional stream.
3198
+ Default: )"
3199
+ << util::format_uint_iec(config.max_stream_data_uni) << R"(
3200
+ --max-streams-bidi=<N>
3201
+ The number of the concurrent bidirectional streams.
3202
+ Default: )"
3203
+ << config.max_streams_bidi << R"(
3204
+ --max-streams-uni=<N>
3205
+ The number of the concurrent unidirectional streams.
3206
+ Default: )"
3207
+ << config.max_streams_uni << R"(
3208
+ --max-dyn-length=<SIZE>
3209
+ The maximum length of a dynamically generated content.
3210
+ Default: )"
3211
+ << util::format_uint_iec(config.max_dyn_length) << R"(
3212
+ --cc=(cubic|reno|bbr|bbr2)
3213
+ The name of congestion controller algorithm.
3214
+ Default: )"
3215
+ << util::strccalgo(config.cc_algo) << R"(
3216
+ --initial-rtt=<DURATION>
3217
+ Set an initial RTT.
3218
+ Default: )"
3219
+ << util::format_duration(config.initial_rtt) << R"(
3220
+ --max-udp-payload-size=<SIZE>
3221
+ Override maximum UDP payload size that server transmits.
3222
+ --send-trailers
3223
+ Send trailer fields.
3224
+ --max-window=<SIZE>
3225
+ Maximum connection-level flow control window size. The
3226
+ window auto-tuning is enabled if nonzero value is given,
3227
+ and window size is scaled up to this value.
3228
+ Default: )"
3229
+ << util::format_uint_iec(config.max_window) << R"(
3230
+ --max-stream-window=<SIZE>
3231
+ Maximum stream-level flow control window size. The
3232
+ window auto-tuning is enabled if nonzero value is given,
3233
+ and window size is scaled up to this value.
3234
+ Default: )"
3235
+ << util::format_uint_iec(config.max_stream_window) << R"(
3236
+ --max-gso-dgrams=<N>
3237
+ Maximum number of UDP datagrams that are sent in a
3238
+ single GSO sendmsg call.
3239
+ Default: )"
3240
+ << config.max_gso_dgrams << R"(
3241
+ --handshake-timeout=<DURATION>
3242
+ Set the QUIC handshake timeout. It defaults to no
3243
+ timeout.
3244
+ --preferred-versions=<HEX>[[,<HEX>]...]
3245
+ Specify QUIC versions in hex string in the order of
3246
+ preference. Server negotiates one of those versions if
3247
+ client initially selects a less preferred version.
3248
+ These versions must be supported by libngtcp2. Instead
3249
+ of specifying hex string, there are special aliases
3250
+ available: "v1" indicates QUIC v1, and "v2" indicates
3251
+ QUIC v2.
3252
+ --available-versions=<HEX>[[,<HEX>]...]
3253
+ Specify QUIC versions in hex string that are sent in
3254
+ available_versions field of version_information
3255
+ transport parameter. This list can include a version
3256
+ which is not supported by libngtcp2. Instead of
3257
+ specifying hex string, there are special aliases
3258
+ available: "v1" indicates QUIC v1, and "v2" indicates
3259
+ QUIC v2.
3260
+ --no-pmtud Disables Path MTU Discovery.
3261
+ --ack-thresh=<N>
3262
+ The minimum number of the received ACK eliciting packets
3263
+ that triggers immediate acknowledgement.
3264
+ Default: )"
3265
+ << config.ack_thresh << R"(
3266
+ -h, --help Display this help and exit.
3267
+
3268
+ ---
3269
+
3270
+ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
3271
+ 10 * 1024). Units are K, M and G (powers of 1024).
3272
+
3273
+ The <DURATION> argument is an integer and an optional unit (e.g., 1s
3274
+ is 1 second and 500ms is 500 milliseconds). Units are h, m, s, ms,
3275
+ us, or ns (hours, minutes, seconds, milliseconds, microseconds, and
3276
+ nanoseconds respectively). If a unit is omitted, a second is used
3277
+ as unit.
3278
+
3279
+ The <HEX> argument is an hex string which must start with "0x"
3280
+ (e.g., 0x00000001).)"
3281
+ << std::endl;
3282
+ }
3283
+ } // namespace
3284
+
3285
+ std::ofstream keylog_file;
3286
+
3287
+ int main(int argc, char **argv) {
3288
+ config_set_default(config);
3289
+
3290
+ for (;;) {
3291
+ static int flag = 0;
3292
+ constexpr static option long_opts[] = {
3293
+ {"help", no_argument, nullptr, 'h'},
3294
+ {"tx-loss", required_argument, nullptr, 't'},
3295
+ {"rx-loss", required_argument, nullptr, 'r'},
3296
+ {"htdocs", required_argument, nullptr, 'd'},
3297
+ {"quiet", no_argument, nullptr, 'q'},
3298
+ {"show-secret", no_argument, nullptr, 's'},
3299
+ {"validate-addr", no_argument, nullptr, 'V'},
3300
+ {"ciphers", required_argument, &flag, 1},
3301
+ {"groups", required_argument, &flag, 2},
3302
+ {"timeout", required_argument, &flag, 3},
3303
+ {"preferred-ipv4-addr", required_argument, &flag, 4},
3304
+ {"preferred-ipv6-addr", required_argument, &flag, 5},
3305
+ {"mime-types-file", required_argument, &flag, 6},
3306
+ {"early-response", no_argument, &flag, 7},
3307
+ {"verify-client", no_argument, &flag, 8},
3308
+ {"qlog-dir", required_argument, &flag, 9},
3309
+ {"no-quic-dump", no_argument, &flag, 10},
3310
+ {"no-http-dump", no_argument, &flag, 11},
3311
+ {"max-data", required_argument, &flag, 12},
3312
+ {"max-stream-data-bidi-local", required_argument, &flag, 13},
3313
+ {"max-stream-data-bidi-remote", required_argument, &flag, 14},
3314
+ {"max-stream-data-uni", required_argument, &flag, 15},
3315
+ {"max-streams-bidi", required_argument, &flag, 16},
3316
+ {"max-streams-uni", required_argument, &flag, 17},
3317
+ {"max-dyn-length", required_argument, &flag, 18},
3318
+ {"cc", required_argument, &flag, 19},
3319
+ {"initial-rtt", required_argument, &flag, 20},
3320
+ {"max-udp-payload-size", required_argument, &flag, 21},
3321
+ {"send-trailers", no_argument, &flag, 22},
3322
+ {"max-window", required_argument, &flag, 23},
3323
+ {"max-stream-window", required_argument, &flag, 24},
3324
+ {"max-gso-dgrams", required_argument, &flag, 25},
3325
+ {"handshake-timeout", required_argument, &flag, 26},
3326
+ {"preferred-versions", required_argument, &flag, 27},
3327
+ {"available-versions", required_argument, &flag, 28},
3328
+ {"no-pmtud", no_argument, &flag, 29},
3329
+ {"ack-thresh", required_argument, &flag, 30},
3330
+ {nullptr, 0, nullptr, 0}};
3331
+
3332
+ auto optidx = 0;
3333
+ auto c = getopt_long(argc, argv, "d:hqr:st:V", long_opts, &optidx);
3334
+ if (c == -1) {
3335
+ break;
3336
+ }
3337
+ switch (c) {
3338
+ case 'd': {
3339
+ // --htdocs
3340
+ auto path = realpath(optarg, nullptr);
3341
+ if (path == nullptr) {
3342
+ std::cerr << "path: invalid path " << std::quoted(optarg) << std::endl;
3343
+ exit(EXIT_FAILURE);
3344
+ }
3345
+ config.htdocs = path;
3346
+ free(path);
3347
+ break;
3348
+ }
3349
+ case 'h':
3350
+ // --help
3351
+ print_help();
3352
+ exit(EXIT_SUCCESS);
3353
+ case 'q':
3354
+ // --quiet
3355
+ config.quiet = true;
3356
+ break;
3357
+ case 'r':
3358
+ // --rx-loss
3359
+ config.rx_loss_prob = strtod(optarg, nullptr);
3360
+ break;
3361
+ case 's':
3362
+ // --show-secret
3363
+ config.show_secret = true;
3364
+ break;
3365
+ case 't':
3366
+ // --tx-loss
3367
+ config.tx_loss_prob = strtod(optarg, nullptr);
3368
+ break;
3369
+ case 'V':
3370
+ // --validate-addr
3371
+ config.validate_addr = true;
3372
+ break;
3373
+ case '?':
3374
+ print_usage();
3375
+ exit(EXIT_FAILURE);
3376
+ case 0:
3377
+ switch (flag) {
3378
+ case 1:
3379
+ // --ciphers
3380
+ config.ciphers = optarg;
3381
+ break;
3382
+ case 2:
3383
+ // --groups
3384
+ config.groups = optarg;
3385
+ break;
3386
+ case 3:
3387
+ // --timeout
3388
+ if (auto t = util::parse_duration(optarg); !t) {
3389
+ std::cerr << "timeout: invalid argument" << std::endl;
3390
+ exit(EXIT_FAILURE);
3391
+ } else {
3392
+ config.timeout = *t;
3393
+ }
3394
+ break;
3395
+ case 4:
3396
+ // --preferred-ipv4-addr
3397
+ if (parse_host_port(config.preferred_ipv4_addr, AF_INET, optarg,
3398
+ optarg + strlen(optarg)) != 0) {
3399
+ std::cerr << "preferred-ipv4-addr: could not use "
3400
+ << std::quoted(optarg) << std::endl;
3401
+ exit(EXIT_FAILURE);
3402
+ }
3403
+ break;
3404
+ case 5:
3405
+ // --preferred-ipv6-addr
3406
+ if (parse_host_port(config.preferred_ipv6_addr, AF_INET6, optarg,
3407
+ optarg + strlen(optarg)) != 0) {
3408
+ std::cerr << "preferred-ipv6-addr: could not use "
3409
+ << std::quoted(optarg) << std::endl;
3410
+ exit(EXIT_FAILURE);
3411
+ }
3412
+ break;
3413
+ case 6:
3414
+ // --mime-types-file
3415
+ config.mime_types_file = optarg;
3416
+ break;
3417
+ case 7:
3418
+ // --early-response
3419
+ config.early_response = true;
3420
+ break;
3421
+ case 8:
3422
+ // --verify-client
3423
+ config.verify_client = true;
3424
+ break;
3425
+ case 9:
3426
+ // --qlog-dir
3427
+ config.qlog_dir = optarg;
3428
+ break;
3429
+ case 10:
3430
+ // --no-quic-dump
3431
+ config.no_quic_dump = true;
3432
+ break;
3433
+ case 11:
3434
+ // --no-http-dump
3435
+ config.no_http_dump = true;
3436
+ break;
3437
+ case 12:
3438
+ // --max-data
3439
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3440
+ std::cerr << "max-data: invalid argument" << std::endl;
3441
+ exit(EXIT_FAILURE);
3442
+ } else {
3443
+ config.max_data = *n;
3444
+ }
3445
+ break;
3446
+ case 13:
3447
+ // --max-stream-data-bidi-local
3448
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3449
+ std::cerr << "max-stream-data-bidi-local: invalid argument"
3450
+ << std::endl;
3451
+ exit(EXIT_FAILURE);
3452
+ } else {
3453
+ config.max_stream_data_bidi_local = *n;
3454
+ }
3455
+ break;
3456
+ case 14:
3457
+ // --max-stream-data-bidi-remote
3458
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3459
+ std::cerr << "max-stream-data-bidi-remote: invalid argument"
3460
+ << std::endl;
3461
+ exit(EXIT_FAILURE);
3462
+ } else {
3463
+ config.max_stream_data_bidi_remote = *n;
3464
+ }
3465
+ break;
3466
+ case 15:
3467
+ // --max-stream-data-uni
3468
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3469
+ std::cerr << "max-stream-data-uni: invalid argument" << std::endl;
3470
+ exit(EXIT_FAILURE);
3471
+ } else {
3472
+ config.max_stream_data_uni = *n;
3473
+ }
3474
+ break;
3475
+ case 16:
3476
+ // --max-streams-bidi
3477
+ if (auto n = util::parse_uint(optarg); !n) {
3478
+ std::cerr << "max-streams-bidi: invalid argument" << std::endl;
3479
+ exit(EXIT_FAILURE);
3480
+ } else {
3481
+ config.max_streams_bidi = *n;
3482
+ }
3483
+ break;
3484
+ case 17:
3485
+ // --max-streams-uni
3486
+ if (auto n = util::parse_uint(optarg); !n) {
3487
+ std::cerr << "max-streams-uni: invalid argument" << std::endl;
3488
+ exit(EXIT_FAILURE);
3489
+ } else {
3490
+ config.max_streams_uni = *n;
3491
+ }
3492
+ break;
3493
+ case 18:
3494
+ // --max-dyn-length
3495
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3496
+ std::cerr << "max-dyn-length: invalid argument" << std::endl;
3497
+ exit(EXIT_FAILURE);
3498
+ } else {
3499
+ config.max_dyn_length = *n;
3500
+ }
3501
+ break;
3502
+ case 19:
3503
+ // --cc
3504
+ if (strcmp("cubic", optarg) == 0) {
3505
+ config.cc_algo = NGTCP2_CC_ALGO_CUBIC;
3506
+ break;
3507
+ }
3508
+ if (strcmp("reno", optarg) == 0) {
3509
+ config.cc_algo = NGTCP2_CC_ALGO_RENO;
3510
+ break;
3511
+ }
3512
+ if (strcmp("bbr", optarg) == 0) {
3513
+ config.cc_algo = NGTCP2_CC_ALGO_BBR;
3514
+ break;
3515
+ }
3516
+ if (strcmp("bbr2", optarg) == 0) {
3517
+ config.cc_algo = NGTCP2_CC_ALGO_BBR2;
3518
+ break;
3519
+ }
3520
+ std::cerr << "cc: specify cubic, reno, bbr, or bbr2" << std::endl;
3521
+ exit(EXIT_FAILURE);
3522
+ case 20:
3523
+ // --initial-rtt
3524
+ if (auto t = util::parse_duration(optarg); !t) {
3525
+ std::cerr << "initial-rtt: invalid argument" << std::endl;
3526
+ exit(EXIT_FAILURE);
3527
+ } else {
3528
+ config.initial_rtt = *t;
3529
+ }
3530
+ break;
3531
+ case 21:
3532
+ // --max-udp-payload-size
3533
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3534
+ std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
3535
+ exit(EXIT_FAILURE);
3536
+ } else if (*n > 64_k) {
3537
+ std::cerr << "max-udp-payload-size: must not exceed 65536"
3538
+ << std::endl;
3539
+ exit(EXIT_FAILURE);
3540
+ } else {
3541
+ config.max_udp_payload_size = *n;
3542
+ }
3543
+ break;
3544
+ case 22:
3545
+ // --send-trailers
3546
+ config.send_trailers = true;
3547
+ break;
3548
+ case 23:
3549
+ // --max-window
3550
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3551
+ std::cerr << "max-window: invalid argument" << std::endl;
3552
+ exit(EXIT_FAILURE);
3553
+ } else {
3554
+ config.max_window = *n;
3555
+ }
3556
+ break;
3557
+ case 24:
3558
+ // --max-stream-window
3559
+ if (auto n = util::parse_uint_iec(optarg); !n) {
3560
+ std::cerr << "max-stream-window: invalid argument" << std::endl;
3561
+ exit(EXIT_FAILURE);
3562
+ } else {
3563
+ config.max_stream_window = *n;
3564
+ }
3565
+ break;
3566
+ case 25:
3567
+ // --max-gso-dgrams
3568
+ if (auto n = util::parse_uint(optarg); !n) {
3569
+ std::cerr << "max-gso-dgrams: invalid argument" << std::endl;
3570
+ exit(EXIT_FAILURE);
3571
+ } else {
3572
+ config.max_gso_dgrams = *n;
3573
+ }
3574
+ break;
3575
+ case 26:
3576
+ // --handshake-timeout
3577
+ if (auto t = util::parse_duration(optarg); !t) {
3578
+ std::cerr << "handshake-timeout: invalid argument" << std::endl;
3579
+ exit(EXIT_FAILURE);
3580
+ } else {
3581
+ config.handshake_timeout = *t;
3582
+ }
3583
+ break;
3584
+ case 27: {
3585
+ // --preferred-versions
3586
+ auto l = util::split_str(optarg);
3587
+ if (l.size() > max_preferred_versionslen) {
3588
+ std::cerr << "preferred-versions: too many versions > "
3589
+ << max_preferred_versionslen << std::endl;
3590
+ }
3591
+ config.preferred_versions.resize(l.size());
3592
+ auto it = std::begin(config.preferred_versions);
3593
+ for (const auto &k : l) {
3594
+ if (k == "v1"sv) {
3595
+ *it++ = NGTCP2_PROTO_VER_V1;
3596
+ continue;
3597
+ }
3598
+ if (k == "v2"sv) {
3599
+ *it++ = NGTCP2_PROTO_VER_V2;
3600
+ continue;
3601
+ }
3602
+ auto rv = util::parse_version(k);
3603
+ if (!rv) {
3604
+ std::cerr << "preferred-versions: invalid version "
3605
+ << std::quoted(k) << std::endl;
3606
+ exit(EXIT_FAILURE);
3607
+ }
3608
+ if (!ngtcp2_is_supported_version(*rv)) {
3609
+ std::cerr << "preferred-versions: unsupported version "
3610
+ << std::quoted(k) << std::endl;
3611
+ exit(EXIT_FAILURE);
3612
+ }
3613
+ *it++ = *rv;
3614
+ }
3615
+ break;
3616
+ }
3617
+ case 28: {
3618
+ // --available-versions
3619
+ auto l = util::split_str(optarg);
3620
+ config.available_versions.resize(l.size());
3621
+ auto it = std::begin(config.available_versions);
3622
+ for (const auto &k : l) {
3623
+ if (k == "v1"sv) {
3624
+ *it++ = NGTCP2_PROTO_VER_V1;
3625
+ continue;
3626
+ }
3627
+ if (k == "v2"sv) {
3628
+ *it++ = NGTCP2_PROTO_VER_V2;
3629
+ continue;
3630
+ }
3631
+ auto rv = util::parse_version(k);
3632
+ if (!rv) {
3633
+ std::cerr << "available-versions: invalid version "
3634
+ << std::quoted(k) << std::endl;
3635
+ exit(EXIT_FAILURE);
3636
+ }
3637
+ *it++ = *rv;
3638
+ }
3639
+ break;
3640
+ }
3641
+ case 29:
3642
+ // --no-pmtud
3643
+ config.no_pmtud = true;
3644
+ break;
3645
+ case 30:
3646
+ // --ack-thresh
3647
+ if (auto n = util::parse_uint(optarg); !n) {
3648
+ std::cerr << "ack-thresh: invalid argument" << std::endl;
3649
+ exit(EXIT_FAILURE);
3650
+ } else if (*n > 100) {
3651
+ std::cerr << "ack-thresh: must not exceed 100" << std::endl;
3652
+ exit(EXIT_FAILURE);
3653
+ } else {
3654
+ config.ack_thresh = *n;
3655
+ }
3656
+ break;
3657
+ }
3658
+ break;
3659
+ default:
3660
+ break;
3661
+ };
3662
+ }
3663
+
3664
+ if (argc - optind < 4) {
3665
+ std::cerr << "Too few arguments" << std::endl;
3666
+ print_usage();
3667
+ exit(EXIT_FAILURE);
3668
+ }
3669
+
3670
+ auto addr = argv[optind++];
3671
+ auto port = argv[optind++];
3672
+ auto private_key_file = argv[optind++];
3673
+ auto cert_file = argv[optind++];
3674
+
3675
+ if (auto n = util::parse_uint(port); !n) {
3676
+ std::cerr << "port: invalid port number" << std::endl;
3677
+ exit(EXIT_FAILURE);
3678
+ } else if (*n > 65535) {
3679
+ std::cerr << "port: must not exceed 65535" << std::endl;
3680
+ exit(EXIT_FAILURE);
3681
+ } else {
3682
+ config.port = *n;
3683
+ }
3684
+
3685
+ if (auto mt = util::read_mime_types(config.mime_types_file); !mt) {
3686
+ std::cerr << "mime-types-file: Could not read MIME media types file "
3687
+ << std::quoted(config.mime_types_file) << std::endl;
3688
+ } else {
3689
+ config.mime_types = std::move(*mt);
3690
+ }
3691
+
3692
+ TLSServerContext tls_ctx;
3693
+
3694
+ if (tls_ctx.init(private_key_file, cert_file, AppProtocol::H3) != 0) {
3695
+ exit(EXIT_FAILURE);
3696
+ }
3697
+
3698
+ if (config.htdocs.back() != '/') {
3699
+ config.htdocs += '/';
3700
+ }
3701
+
3702
+ std::cerr << "Using document root " << config.htdocs << std::endl;
3703
+
3704
+ auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
3705
+
3706
+ auto keylog_filename = getenv("SSLKEYLOGFILE");
3707
+ if (keylog_filename) {
3708
+ keylog_file.open(keylog_filename, std::ios_base::app);
3709
+ if (keylog_file) {
3710
+ tls_ctx.enable_keylog();
3711
+ }
3712
+ }
3713
+
3714
+ if (util::generate_secret(config.static_secret.data(),
3715
+ config.static_secret.size()) != 0) {
3716
+ std::cerr << "Unable to generate static secret" << std::endl;
3717
+ exit(EXIT_FAILURE);
3718
+ }
3719
+
3720
+ Server s(EV_DEFAULT, tls_ctx);
3721
+ if (s.init(addr, port) != 0) {
3722
+ exit(EXIT_FAILURE);
3723
+ }
3724
+
3725
+ ev_run(EV_DEFAULT, 0);
3726
+
3727
+ s.disconnect();
3728
+ s.close();
3729
+
3730
+ return EXIT_SUCCESS;
3731
+ }