summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--doc/.gitignore1
-rw-r--r--doc/Makefile.am65
-rw-r--r--doc/make.bat35
-rwxr-xr-xdoc/mkapiref.py357
-rw-r--r--doc/source/.gitignore9
-rw-r--r--doc/source/conf.py.in95
-rw-r--r--doc/source/index.rst22
-rw-r--r--doc/source/programmers-guide.rst446
-rw-r--r--docker/Dockerfile39
9 files changed, 1069 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..e2339bd
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,65 @@
+# ngtcp2
+
+# Copyright (c) 2020 ngtcp2 contributors
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help html apiref cryptoapiref
+
+apiref: mkapiref.py \
+ $(top_builddir)/lib/includes/ngtcp2/version.h \
+ $(top_srcdir)/lib/includes/ngtcp2/ngtcp2.h
+ $(top_srcdir)/doc/mkapiref.py \
+ --title='ngtcp2 API reference' \
+ source/apiref.rst source/macros.rst source/enums.rst source/types.rst \
+ source $(wordlist 2, $(words $^), $^)
+
+cryptoapiref: mkapiref.py \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto.h \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto_gnutls.h \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h \
+ $(top_srcdir)/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h
+ $(top_srcdir)/doc/mkapiref.py \
+ --title='ngtcp2 crypto API reference' \
+ source/crypto_apiref.rst source/crypto_macros.rst \
+ source/crypto_enums.rst source/crypto_types.rst \
+ source $(wordlist 2, $(words $^), $^)
+
+html-local: apiref cryptoapiref
+ @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+clean-local:
+ -rm -rf "$(BUILDDIR)"
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..2119f51
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/doc/mkapiref.py b/doc/mkapiref.py
new file mode 100755
index 0000000..a0d0483
--- /dev/null
+++ b/doc/mkapiref.py
@@ -0,0 +1,357 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# nghttp2 - HTTP/2 C Library
+#
+# Copyright (c) 2020 ngtcp2 contributors
+# Copyright (c) 2012 Tatsuhiro Tsujikawa
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Generates API reference from C source code.
+
+import re, sys, argparse, os.path
+
+class FunctionDoc:
+ def __init__(self, name, content, domain, filename):
+ self.name = name
+ self.content = content
+ self.domain = domain
+ if self.domain == 'function':
+ self.funcname = re.search(r'(ngtcp2_[^ )]+)\(', self.name).group(1)
+ self.filename = filename
+
+ def write(self, out):
+ out.write('.. {}:: {}\n'.format(self.domain, self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+class StructDoc:
+ def __init__(self, name, content, members, member_domain):
+ self.name = name
+ self.content = content
+ self.members = members
+ self.member_domain = member_domain
+
+ def write(self, out):
+ if self.name:
+ out.write('.. type:: {}\n'.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+ for name, content in self.members:
+ out.write(' .. {}:: {}\n'.format(self.member_domain, name))
+ out.write('\n')
+ for line in content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+
+class EnumDoc:
+ def __init__(self, name, content, members):
+ self.name = name
+ self.content = content
+ self.members = members
+
+ def write(self, out):
+ if self.name:
+ out.write('.. type:: {}\n'.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+ for name, content in self.members:
+ out.write(' .. enum:: {}\n'.format(name))
+ out.write('\n')
+ for line in content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+
+class MacroDoc:
+ def __init__(self, name, content):
+ self.name = name
+ self.content = content
+
+ def write(self, out):
+ out.write('''.. macro:: {}\n'''.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+class MacroSectionDoc:
+ def __init__(self, content):
+ self.content = content
+
+ def write(self, out):
+ out.write('\n')
+ c = ' '.join(self.content).strip()
+ out.write(c)
+ out.write('\n')
+ out.write('-' * len(c))
+ out.write('\n\n')
+
+class TypedefDoc:
+ def __init__(self, name, content):
+ self.name = name
+ self.content = content
+
+ def write(self, out):
+ out.write('''.. type:: {}\n'''.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+def make_api_ref(infile):
+ macros = []
+ enums = []
+ types = []
+ functions = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif line == '/**\n':
+ line = infile.readline()
+ doctype = line.split()[1]
+ if doctype == '@function':
+ functions.append(process_function('function', infile))
+ elif doctype == '@functypedef':
+ types.append(process_function('type', infile))
+ elif doctype == '@struct' or doctype == '@union':
+ types.append(process_struct(infile))
+ elif doctype == '@enum':
+ enums.append(process_enum(infile))
+ elif doctype == '@macro':
+ macros.append(process_macro(infile))
+ elif doctype == '@macrosection':
+ macros.append(process_macrosection(infile))
+ elif doctype == '@typedef':
+ types.append(process_typedef(infile))
+ return macros, enums, types, functions
+
+def output(
+ title, indexfile, macrosfile, enumsfile, typesfile, funcsdir,
+ macros, enums, types, functions):
+ indexfile.write('''
+{title}
+{titledecoration}
+
+.. toctree::
+ :maxdepth: 1
+
+ {macros}
+ {enums}
+ {types}
+'''.format(
+ title=title, titledecoration='='*len(title),
+ macros=os.path.splitext(os.path.basename(macrosfile.name))[0],
+ enums=os.path.splitext(os.path.basename(enumsfile.name))[0],
+ types=os.path.splitext(os.path.basename(typesfile.name))[0],
+))
+
+ for doc in functions:
+ indexfile.write(' {}\n'.format(doc.funcname))
+
+ macrosfile.write('''
+Macros
+======
+''')
+ for doc in macros:
+ doc.write(macrosfile)
+
+ enumsfile.write('''
+Enums
+=====
+''')
+ for doc in enums:
+ doc.write(enumsfile)
+
+ typesfile.write('''
+Types (structs, unions and typedefs)
+====================================
+''')
+ for doc in types:
+ doc.write(typesfile)
+
+ for doc in functions:
+ with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
+ f.write('''
+{funcname}
+{secul}
+
+Synopsis
+--------
+
+*#include <ngtcp2/{filename}>*
+
+'''.format(funcname=doc.funcname, secul='='*len(doc.funcname),
+ filename=doc.filename))
+ doc.write(f)
+
+def process_macro(infile):
+ content = read_content(infile)
+ lines = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ line = line.rstrip()
+ lines.append(line.rstrip('\\'))
+ if not line.endswith('\\'):
+ break
+
+ macro_name = re.sub(r'#define ', '', ''.join(lines))
+ m = re.match(r'^[^( ]+(:?\(.*?\))?', macro_name)
+ macro_name = m.group(0)
+ return MacroDoc(macro_name, content)
+
+def process_macrosection(infile):
+ content = read_content(infile)
+ return MacroSectionDoc(content)
+
+def process_typedef(infile):
+ content = read_content(infile)
+ typedef = infile.readline()
+ typedef = re.sub(r';\n$', '', typedef)
+ typedef = re.sub(r'typedef ', '', typedef)
+ return TypedefDoc(typedef, content)
+
+def process_enum(infile):
+ members = []
+ enum_name = None
+ content = read_content(infile)
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif re.match(r'\s*/\*\*\n', line):
+ member_content = read_content(infile)
+ line = infile.readline()
+ items = line.split()
+ member_name = items[0].rstrip(',')
+ if len(items) >= 3:
+ member_content.insert(0, '(``{}``) '\
+ .format(' '.join(items[2:]).rstrip(',')))
+ members.append((member_name, member_content))
+ elif line.startswith('}'):
+ enum_name = line.rstrip().split()[1]
+ enum_name = re.sub(r';$', '', enum_name)
+ break
+ return EnumDoc(enum_name, content, members)
+
+def process_struct(infile):
+ members = []
+ struct_name = None
+ content = read_content(infile)
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif re.match(r'\s*/\*\*\n', line):
+ member_content = read_content(infile)
+ line = infile.readline()
+ member_name = line.rstrip().rstrip(';')
+ members.append((member_name, member_content))
+ elif line.startswith('}') or\
+ (line.startswith('typedef ') and line.endswith(';\n')):
+ if line.startswith('}'):
+ index = 1
+ else:
+ index = 3
+ struct_name = line.rstrip().split()[index]
+ struct_name = re.sub(r';$', '', struct_name)
+ break
+ return StructDoc(struct_name, content, members, 'member')
+
+def process_function(domain, infile):
+ content = read_content(infile)
+ func_proto = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif line == '\n':
+ break
+ else:
+ func_proto.append(line)
+ func_proto = ''.join(func_proto)
+ func_proto = re.sub(r'int (pkt_info|transport_params|conn_stat|settings|callbacks)_version,',
+ '', func_proto)
+ func_proto = re.sub(r'_versioned\(', '(', func_proto)
+ func_proto = re.sub(r';\n$', '', func_proto)
+ func_proto = re.sub(r'\s+', ' ', func_proto)
+ func_proto = re.sub(r'NGTCP2_EXTERN ', '', func_proto)
+ func_proto = re.sub(r'typedef ', '', func_proto)
+ filename = os.path.basename(infile.name)
+ return FunctionDoc(func_proto, content, domain, filename)
+
+def read_content(infile):
+ content = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ if re.match(r'\s*\*/\n', line):
+ break
+ else:
+ content.append(transform_content(line.rstrip()))
+ return content
+
+def arg_repl(matchobj):
+ return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
+
+def transform_content(content):
+ content = re.sub(r'^\s+\* ?', '', content)
+ content = re.sub(r'\|([^\s|]+)\|', arg_repl, content)
+ content = re.sub(r':enum:', ':macro:', content)
+ return content
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description="Generate API reference")
+ parser.add_argument('--title', default='API Reference',
+ help='title of index page')
+ parser.add_argument('index', type=argparse.FileType('w'),
+ help='index output file')
+ parser.add_argument('macros', type=argparse.FileType('w'),
+ help='macros section output file. The filename should be macros.rst')
+ parser.add_argument('enums', type=argparse.FileType('w'),
+ help='enums section output file. The filename should be enums.rst')
+ parser.add_argument('types', type=argparse.FileType('w'),
+ help='types section output file. The filename should be types.rst')
+ parser.add_argument('funcsdir',
+ help='functions doc output dir')
+ parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
+ help='source file')
+ args = parser.parse_args()
+ macros = []
+ enums = []
+ types = []
+ funcs = []
+ for infile in args.files:
+ m, e, t, f = make_api_ref(infile)
+ macros.extend(m)
+ enums.extend(e)
+ types.extend(t)
+ funcs.extend(f)
+ funcs.sort(key=lambda x: x.funcname)
+ output(
+ args.title,
+ args.index, args.macros, args.enums, args.types, args.funcsdir,
+ macros, enums, types, funcs)
diff --git a/doc/source/.gitignore b/doc/source/.gitignore
new file mode 100644
index 0000000..a03e54b
--- /dev/null
+++ b/doc/source/.gitignore
@@ -0,0 +1,9 @@
+/conf.py
+/apiref.rst
+/enums.rst
+/macros.rst
+/types.rst
+/crypto_apiref.rst
+/crypto_enums.rst
+/crypto_macros.rst
+/crypto_types.rst
diff --git a/doc/source/conf.py.in b/doc/source/conf.py.in
new file mode 100644
index 0000000..6ac325c
--- /dev/null
+++ b/doc/source/conf.py.in
@@ -0,0 +1,95 @@
+# ngtcp2
+
+# Copyright (c) 2020 ngtcp2 contributors
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'ngtcp2'
+copyright = '2020, ngtcp2 contributors'
+author = 'ngtcp2 contributors'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+html_theme_path = ['_themes']
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+default_role = 'c:func'
+primary_domain = 'c'
+
+# manpage URL pattern
+manpages_url = 'https://man7.org/linux/man-pages/man{section}/{page}.{section}.html'
+
+# The default language to highlight source code in.
+highlight_language = 'c'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '@PACKAGE_VERSION@'
+# The full version, including alpha/beta/rc tags.
+release = '@PACKAGE_VERSION@'
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..6890563
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,22 @@
+.. ngtcp2 documentation master file, created by
+ sphinx-quickstart on Mon Nov 30 22:15:12 2020.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to ngtcp2's documentation!
+==================================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ programmers-guide
+ apiref
+ crypto_apiref
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/source/programmers-guide.rst b/doc/source/programmers-guide.rst
new file mode 100644
index 0000000..5138361
--- /dev/null
+++ b/doc/source/programmers-guide.rst
@@ -0,0 +1,446 @@
+The ngtcp2 programmers' guide for early adopters
+================================================
+
+This document is written for early adopters of ngtcp2 library. It
+describes a brief introduction of programming ngtcp2.
+
+Prerequisites
+-------------
+
+Reading :rfc:`9000` and :rfc:`9001` helps you a lot to write QUIC
+application. They describes how TLS is integrated into QUIC and why
+the existing TLS stack cannot be used with QUIC.
+
+QUIC requires the special interface from TLS stack, which is probably
+not available from most of the existing TLS stacks. As far as I know,
+the TLS stacks maintained by the active participants of QUIC working
+group only get this interface at the time of this writing. In order
+to build QUIC application you have to choose one of them. Here is the
+list of TLS stacks which are supposed to provide such interface and
+for which we provide crypto helper libraries:
+
+* `OpenSSL with QUIC support
+ <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1q+quic>`_
+* GnuTLS >= 3.7.2
+* BoringSSL
+* Picotls
+* wolfSSL
+
+Creating ngtcp2_conn object
+---------------------------
+
+:type:`ngtcp2_conn` is the primary object to present a single QUIC
+connection. Use `ngtcp2_conn_client_new()` for client application,
+and `ngtcp2_conn_server_new()` for server.
+
+They require :type:`ngtcp2_callbacks`, :type:`ngtcp2_settings`, and
+:type:`ngtcp2_transport_params` objects.
+
+The :type:`ngtcp2_callbacks` contains the callback functions which
+:type:`ngtcp2_conn` calls when a specific event happens, say,
+receiving stream data or stream is closed, etc. Some of the callback
+functions are optional. For client application, the following
+callback functions must be set:
+
+* :member:`client_initial <ngtcp2_callbacks.client_initial>`:
+ `ngtcp2_crypto_client_initial_cb()` can be passed directly.
+* :member:`recv_crypto_data <ngtcp2_callbacks.recv_crypto_data>`:
+ `ngtcp2_crypto_recv_crypto_data_cb()` can be passed directly.
+* :member:`encrypt <ngtcp2_callbacks.encrypt>`:
+ `ngtcp2_crypto_encrypt_cb()` can be passed directly.
+* :member:`decrypt <ngtcp2_callbacks.decrypt>`:
+ `ngtcp2_crypto_decrypt_cb()` can be passed directly.
+* :member:`hp_mask <ngtcp2_callbacks.hp_mask>`:
+ `ngtcp2_crypto_hp_mask_cb()` can be passed directly.
+* :member:`recv_retry <ngtcp2_callbacks.recv_retry>`:
+ `ngtcp2_crypto_recv_retry_cb()` can be passed directly.
+* :member:`rand <ngtcp2_callbacks.rand>`
+* :member:`get_new_connection_id
+ <ngtcp2_callbacks.get_new_connection_id>`
+* :member:`update_key <ngtcp2_callbacks.update_key>`:
+ `ngtcp2_crypto_update_key_cb()` can be passed directly.
+* :member:`delete_crypto_aead_ctx
+ <ngtcp2_callbacks.delete_crypto_aead_ctx>`:
+ `ngtcp2_crypto_delete_crypto_aead_ctx_cb()` can be passed directly.
+* :member:`delete_crypto_cipher_ctx
+ <ngtcp2_callbacks.delete_crypto_cipher_ctx>`:
+ `ngtcp2_crypto_delete_crypto_cipher_ctx_cb()` can be passed
+ directly.
+* :member:`get_path_challenge_data
+ <ngtcp2_callbacks.get_path_challenge_data>`:
+ `ngtcp2_crypto_get_path_challenge_data_cb()` can be passed directly.
+* :member:`version_negotiation
+ <ngtcp2_callbacks.version_negotiation>`:
+ `ngtcp2_crypto_version_negotiation_cb()` can be passed directly.
+
+For server application, the following callback functions must be set:
+
+* :member:`recv_client_initial
+ <ngtcp2_callbacks.recv_client_initial>`:
+ `ngtcp2_crypto_recv_client_initial_cb()` can be passed directly.
+* :member:`recv_crypto_data <ngtcp2_callbacks.recv_crypto_data>`:
+ `ngtcp2_crypto_recv_crypto_data_cb()` can be passed directly.
+* :member:`encrypt <ngtcp2_callbacks.encrypt>`:
+ `ngtcp2_crypto_encrypt_cb()` can be passed directly.
+* :member:`decrypt <ngtcp2_callbacks.decrypt>`:
+ `ngtcp2_crypto_decrypt_cb()` can be passed directly.
+* :member:`hp_mask <ngtcp2_callbacks.hp_mask>`:
+ `ngtcp2_crypto_hp_mask_cb()` can be passed directly.
+* :member:`rand <ngtcp2_callbacks.rand>`
+* :member:`get_new_connection_id
+ <ngtcp2_callbacks.get_new_connection_id>`
+* :member:`update_key <ngtcp2_callbacks.update_key>`:
+ `ngtcp2_crypto_update_key_cb()` can be passed directly.
+* :member:`delete_crypto_aead_ctx
+ <ngtcp2_callbacks.delete_crypto_aead_ctx>`:
+ `ngtcp2_crypto_delete_crypto_aead_ctx_cb()` can be passed directly.
+* :member:`delete_crypto_cipher_ctx
+ <ngtcp2_callbacks.delete_crypto_cipher_ctx>`:
+ `ngtcp2_crypto_delete_crypto_cipher_ctx_cb()` can be passed
+ directly.
+* :member:`get_path_challenge_data
+ <ngtcp2_callbacks.get_path_challenge_data>`:
+ `ngtcp2_crypto_get_path_challenge_data_cb()` can be passed directly.
+* :member:`version_negotiation
+ <ngtcp2_callbacks.version_negotiation>`:
+ `ngtcp2_crypto_version_negotiation_cb()` can be passed directly.
+
+``ngtcp2_crypto_*`` functions are a part of :doc:`ngtcp2 crypto API
+<crypto_apiref>` which provides easy integration with the supported
+TLS backend. It vastly simplifies TLS integration and is strongly
+recommended.
+
+:type:`ngtcp2_settings` contains the settings for QUIC connection.
+All fields must be set. Application should call
+`ngtcp2_settings_default()` to set the default values. It would be
+very useful to enable debug logging by setting logging function to
+:member:`ngtcp2_settings.log_printf` field. ngtcp2 library relies on
+the timestamp fed from application. The initial timestamp must be
+passed to :member:`ngtcp2_settings.initial_ts` field in nanosecond
+resolution. ngtcp2 cares about the difference from that initial
+value. It could be any timestamp which increases monotonically, and
+actual value does not matter.
+
+:type:`ngtcp2_transport_params` contains QUIC transport parameters
+which is sent to a remote endpoint during handshake. All fields must
+be set. Application should call `ngtcp2_transport_params_default()`
+to set the default values.
+
+Client application has to supply Connection IDs to
+`ngtcp2_conn_client_new()`. The *dcid* parameter is the destination
+connection ID (DCID), and which should be random byte string and at
+least 8 bytes long. The *scid* is the source connection ID (SCID)
+which identifies the client itself. The *version* parameter is the
+QUIC version to use. It should be :macro:`NGTCP2_PROTO_VER_V1`.
+
+Similarly, server application has to supply these parameters to
+`ngtcp2_conn_server_new()`. But the *dcid* must be the same value
+which is received from client (which is client SCID). The *scid* is
+chosen by server. Don't use DCID in client packet as server SCID.
+The *version* parameter is the QUIC version to use. It should be
+:macro:`NGTCP2_PROTO_VER_V1`.
+
+A path is very important to QUIC connection. It is the pair of
+endpoints, local and remote. The path passed to
+`ngtcp2_conn_client_new()` and `ngtcp2_conn_server_new()` is a network
+path that handshake is performed. The path must not change during
+handshake. After handshake is confirmed, client can migrate to new
+path. An application must provide actual path to the API function to
+tell the library where a packet comes from. The "write" API function
+takes path parameter and fills it to which the packet should be sent.
+
+TLS integration
+---------------
+
+Use of :doc:`ngtcp2 crypto API <crypto_apiref>` is strongly
+recommended because it vastly simplifies the TLS integration.
+
+The most of the TLS work is done by the callback functions passed to
+:type:`ngtcp2_callbacks` object. There are some operations left to
+application in order to make TLS integration work. We have a set of
+helper functions to make it easier for applications to configure TLS
+stack object to work with QUIC and ngtcp2. They are specific to each
+supported TLS stack:
+
+- OpenSSL
+
+ * `ngtcp2_crypto_openssl_configure_client_context`
+ * `ngtcp2_crypto_openssl_configure_server_context`
+
+- BoringSSL
+
+ * `ngtcp2_crypto_boringssl_configure_client_context`
+ * `ngtcp2_crypto_boringssl_configure_server_context`
+
+- GnuTLS
+
+ * `ngtcp2_crypto_gnutls_configure_client_session`
+ * `ngtcp2_crypto_gnutls_configure_server_session`
+
+- Picotls
+
+ * `ngtcp2_crypto_picotls_configure_client_context`
+ * `ngtcp2_crypto_picotls_configure_server_context`
+ * `ngtcp2_crypto_picotls_configure_client_session`
+ * `ngtcp2_crypto_picotls_configure_server_session`
+
+- wolfSSL
+
+ * `ngtcp2_crypto_wolfssl_configure_client_context`
+ * `ngtcp2_crypto_wolfssl_configure_server_context`
+
+They make the minimal QUIC specific changes to TLS stack object. See
+the ngtcp2 crypto API header files for each supported TLS stack. In
+order to make these functions work, we require that a pointer to
+:type:`ngtcp2_crypto_conn_ref` must be set as a user data in TLS stack
+object, and its :member:`ngtcp2_crypto_conn_ref.get_conn` must point
+to a function which returns :type:`ngtcp2_conn` of the underlying QUIC
+connection.
+
+If you do not use the above helper functions, you need to generate and
+install keys to :type:`ngtcp2_conn`, and pass handshake messages to
+:type:`ngtcp2_conn` as well. When TLS stack generates new secrets,
+they have to be installed to :type:`ngtcp2_conn` by calling
+`ngtcp2_crypto_derive_and_install_rx_key()` and
+`ngtcp2_crypto_derive_and_install_tx_key()`. When TLS stack generates
+new crypto data to send, they must be passed to :type:`ngtcp2_conn` by
+calling `ngtcp2_conn_submit_crypto_data()`.
+
+When QUIC handshake is completed,
+:member:`ngtcp2_callbacks.handshake_completed` callback function is
+called. The local and remote endpoint independently declare handshake
+completion. The endpoint has to confirm that the other endpoint also
+finished handshake. When the handshake is confirmed, client side
+:type:`ngtcp2_conn` will call
+:member:`ngtcp2_callbacks.handshake_confirmed` callback function.
+Server confirms handshake when it declares handshake completion,
+therefore, separate handshake confirmation callback is not called.
+
+Read and write packets
+----------------------
+
+`ngtcp2_conn_read_pkt()` processes the incoming QUIC packets. In
+order to write QUIC packets, call `ngtcp2_conn_writev_stream()` or
+`ngtcp2_conn_write_pkt()`. The *destlen* parameter must be at least
+the value returned from `ngtcp2_conn_get_max_tx_udp_payload_size()`.
+
+In order to send stream data, the application has to first open a
+stream. Use `ngtcp2_conn_open_bidi_stream()` to open bidirectional
+stream. For unidirectional stream, call
+`ngtcp2_conn_open_uni_stream()`. Call `ngtcp2_conn_writev_stream()`
+to send stream data.
+
+An application should pace sending packets.
+`ngtcp2_conn_get_send_quantum()` returns the number of bytes that can
+be sent without packet spacing. After one or more calls of
+`ngtcp2_conn_writev_stream()` (it can be called multiple times to fill
+the buffer sized up to `ngtcp2_conn_get_send_quantum()` bytes), call
+`ngtcp2_conn_update_pkt_tx_time()` to set the timer when the next
+packet should be sent. The timer is integrated into
+`ngtcp2_conn_get_expiry()`.
+
+Packet handling on server side
+------------------------------
+
+Any incoming UDP datagram should be first processed by
+`ngtcp2_pkt_decode_version_cid()`. It can handle Connection ID more
+than 20 bytes which is the maximum length defined in QUIC v1. If the
+function returns :macro:`NGTCP2_ERR_VERSION_NEGOTIATION`, server
+should send Version Negotiation packet. Use
+`ngtcp2_pkt_write_version_negotiation()` for this purpose. If
+`ngtcp2_pkt_decode_version_cid()` succeeds, then check whether the UDP
+datagram belongs to any existing connection by looking up connection
+tables by Destination Connection ID. If it belongs to an existing
+connection, pass the UDP datagram to `ngtcp2_conn_read_pkt()`. If it
+does not belong to any existing connection, it should be passed to
+`ngtcp2_accept()`. If it returns :macro:`NGTCP2_ERR_RETRY`, the
+server should send Retry packet (use `ngtcp2_crypto_write_retry()` to
+create Retry packet). If it returns an other negative error code,
+just drop the packet to the floor and take no action, or send
+Stateless Reset packet (use `ngtcp2_pkt_write_stateless_reset()` to
+create Stateless Reset packet). Otherwise, the UDP datagram is
+acceptable as a new connection. Create :type:`ngtcp2_conn` object and
+pass the UDP datagram to `ngtcp2_conn_read_pkt()`.
+
+Dealing with early data
+-----------------------
+
+Client application has to load resumed TLS session. It also has to
+set the remembered transport parameters using
+`ngtcp2_conn_set_early_remote_transport_params()` function.
+
+Other than that, there is no difference between early data and 1RTT
+data in terms of API usage.
+
+If early data is rejected by a server, client must call
+`ngtcp2_conn_early_data_rejected`. All connection states altered
+during early data transmission are undone. The library does not
+retransmit early data to server as 1RTT data. If an application
+wishes to resend data, it has to reopen streams and writes data again.
+See `ngtcp2_conn_early_data_rejected`.
+
+Stream data ownership
+--------------------------------
+
+Stream data passed to :type:`ngtcp2_conn` must be held by application
+until :member:`ngtcp2_callbacks.acked_stream_data_offset` callbacks is
+invoked, telling that the those data are acknowledged by the remote
+endpoint and no longer used by the library.
+
+Timers
+------
+
+The library does not ask an operating system for any timestamp.
+Instead, an application has to supply timestamp to the library. The
+type of timestamp in ngtcp2 library is :type:`ngtcp2_tstamp` which is
+nanosecond resolution. The library only cares the difference of
+timestamp, so it does not have to be a system clock. A monotonic
+clock should work better. It should be same clock passed to
+:member:`ngtcp2_settings.initial_ts`. The duration in ngtcp2 library
+is :type:`ngtcp2_duration` which is also nanosecond resolution.
+
+`ngtcp2_conn_get_expiry()` tells an application when timer fires.
+When it fires, call `ngtcp2_conn_handle_expiry()`. If it returns
+:macro:`NGTCP2_ERR_IDLE_CLOSE`, it means that an idle timer has fired
+for this particular connection. In this case, drop the connection
+without calling `ngtcp2_conn_write_connection_close()`. Otherwise,
+call `ngtcp2_conn_writev_stream()`. After calling
+`ngtcp2_conn_handle_expiry()` and `ngtcp2_conn_writev_stream()`, new
+expiry is set. The application should call `ngtcp2_conn_get_expiry()`
+to get a new deadline.
+
+Please note that :type:`ngtcp2_tstamp` of value ``UINT64_MAX`` is
+treated as an invalid timestamp. Do not pass ``UINT64_MAX`` to any
+ngtcp2 functions which take :type:`ngtcp2_tstamp` unless it is
+explicitly allowed.
+
+Connection migration
+--------------------
+
+In QUIC, client application can migrate to a new local address.
+`ngtcp2_conn_initiate_immediate_migration()` migrates to a new local
+address without checking reachability. On the other hand,
+`ngtcp2_conn_initiate_migration()` migrates to a new local address
+after a new path is validated (thus reachability is established).
+
+Closing connection abruptly
+---------------------------
+
+In order to close QUIC connection abruptly, call
+`ngtcp2_conn_write_connection_close()` and get a terminal packet.
+After the call, the connection enters the closing state.
+
+The closing and draining state
+------------------------------
+
+After the successful call of `ngtcp2_conn_write_connection_close()`,
+the connection enters the closing state. When
+`ngtcp2_conn_read_pkt()` returns :macro:`NGTCP2_ERR_DRAINING`, the
+connection has entered the draining state. In these states,
+`ngtcp2_conn_writev_stream()` and `ngtcp2_conn_read_pkt()` return an
+error (either :macro:`NGTCP2_ERR_CLOSING` or
+:macro:`NGTCP2_ERR_DRAINING` depending on the state).
+`ngtcp2_conn_write_connection_close()` returns 0 in these states. If
+an application needs to send a packet containing CONNECTION_CLOSE
+frame in the closing state, resend the packet produced by the first
+call of `ngtcp2_conn_write_connection_close()`. Therefore, after a
+connection has entered one of these states, the application can
+discard :type:`ngtcp2_conn` object. The closing and draining state
+should persist at least 3 times the current PTO.
+
+Error handling in general
+-------------------------
+
+In general, when error is returned from the ngtcp2 library function,
+call `ngtcp2_conn_write_connection_close()` to get terminal packet.
+If the successful call of the function creates non-empty packet, the
+QUIC connection enters the closing state.
+
+If :macro:`NGTCP2_ERR_DROP_CONN` is returned from
+`ngtcp2_conn_read_pkt`, a connection should be dropped without calling
+`ngtcp2_conn_write_connection_close()`. Similarly, if
+:macro:`NGTCP2_ERR_IDLE_CLOSE` is returned from
+`ngtcp2_conn_handle_expiry`, a connection should be dropped without
+calling `ngtcp2_conn_write_connection_close()`. If
+:macro:`NGTCP2_ERR_DRAINING` is returned from `ngtcp2_conn_read_pkt`,
+a connection has entered the draining state, and no further packet
+transmission is allowed.
+
+The following error codes must be considered as transitional, and
+application should keep connection alive:
+
+* :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`
+* :macro:`NGTCP2_ERR_STREAM_SHUT_WR`
+* :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`
+* :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED`
+
+Version negotiation
+-------------------
+
+Version negotiation is configured with the following
+:type:`ngtcp2_settings` fields:
+
+* :member:`ngtcp2_settings.preferred_versions` and
+ :member:`ngtcp2_settings.preferred_versionslen`
+* :member:`ngtcp2_settings.other_versions` and
+ :member:`ngtcp2_settings.other_versionslen`
+* :member:`ngtcp2_settings.original_version`
+
+*client_chosen_version* passed to `ngtcp2_conn_client_new` also
+influence the version negotiation process.
+
+By default, client sends *client_chosen_version* passed to
+`ngtcp2_conn_client_new` in other_versions field of
+version_information QUIC transport parameter. That means there is no
+chance for server to select the other compatible version. Meanwhile,
+ngtcp2 supports QUIC v2 draft version
+(:macro:`NGTCP2_PROTO_VER_V2_DRAFT`). Including both
+:macro:`NGTCP2_PROTO_VER_V1` and :macro:`NGTCP2_PROTO_VER_V2_DRAFT` in
+:member:`ngtcp2_settings.other_versions` field allows server to choose
+:macro:`NGTCP2_PROTO_VER_V2_DRAFT` which is compatible to
+:macro:`NGTCP2_PROTO_VER_V1`.
+
+By default, server sends :macro:`NGTCP2_PROTO_VER_V1` in
+other_versions field of version_information QUIC transport parameter.
+Because there is no particular preferred versions specified, server
+will accept any supported version. In order to set the version
+preference, specify :member:`ngtcp2_settings.preferred_versions`
+field. If it is specified, server sends them in other_versions field
+of version_information QUIC transport parameter unless
+:member:`ngtcp2_settings.other_versionslen` is not zero. Specifying
+:member:`ngtcp2_settings.other_versions` overrides the above mentioned
+default behavior. Even if there is no overlap between
+:member:`ngtcp2_settings.preferred_versions` and other_versions field
+plus *client_chosen_version* from client, as long as
+*client_chosen_version* is supported by server, server accepts
+*client_chosen_version*.
+
+If client receives Version Negotiation packet from server,
+`ngtcp2_conn_read_pkt` returns
+:macro:`NGTCP2_ERR_RECV_VERSION_NEGOTIATION`.
+:member:`ngtcp2_callbacks.recv_version_negotiation` is also invoked if
+set. It will provide the versions contained in the packet. Client
+then either gives up the connection attempt, or selects the version
+from Version Negotiation packet, and starts new connection attempt
+with that version. In the latter case, the initial version that used
+in the first connection attempt must be set to
+:member:`ngtcp2_settings.original_version`. The client version
+preference that is used when selecting a version from Version
+Negotiation packet must be set to
+:member:`ngtcp2_settings.preferred_versions`.
+:member:`ngtcp2_settings.other_versions` must include the selected
+version. The selected version becomes *client_chosen_version* in the
+second connection attempt, and must be passed to
+`ngtcp2_conn_client_new`.
+
+Server never know whether client reacted upon Version Negotiation
+packet or not, and there is no particular setup for server to make
+this incompatible version negotiation work.
+
+Thread safety
+-------------
+
+ngtcp2 library is thread-safe as long as a single :type:`ngtcp2_conn`
+object is accessed by a single thread at a time. For multi-threaded
+applications, it is recommended to create :type:`ngtcp2_conn` objects
+per thread to avoid locks.
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..d6141d9
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,39 @@
+FROM debian:11 as build
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ git g++ clang-11 make binutils autoconf automake autotools-dev libtool \
+ pkg-config libev-dev libjemalloc-dev \
+ ca-certificates mime-support && \
+ git clone --depth 1 -b OpenSSL_1_1_1s+quic https://github.com/quictls/openssl && \
+ cd openssl && ./config --openssldir=/etc/ssl && make -j$(nproc) && make install_sw && cd .. && rm -rf openssl && \
+ git clone --depth 1 https://github.com/ngtcp2/nghttp3 && \
+ cd nghttp3 && autoreconf -i && \
+ ./configure --enable-lib-only CC=clang-11 CXX=clang++-11 && \
+ make -j$(nproc) && make install-strip && cd .. && rm -rf nghttp3 && \
+ git clone --depth 1 https://github.com/ngtcp2/ngtcp2 && \
+ cd ngtcp2 && autoreconf -i && \
+ ./configure \
+ CC=clang-11 \
+ CXX=clang++-11 \
+ LIBTOOL_LDFLAGS="-static-libtool-libs" \
+ OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -pthread" \
+ LIBEV_LIBS="-l:libev.a" \
+ JEMALLOC_LIBS="-l:libjemalloc.a -lm" && \
+ make -j$(nproc) && \
+ strip examples/client examples/server && \
+ cp examples/client examples/server /usr/local/bin && \
+ cd .. && rm -rf ngtcp2 && \
+ apt-get -y purge \
+ git g++ clang-11 make binutils autoconf automake autotools-dev libtool \
+ pkg-config libev-dev libjemalloc-dev \
+ ca-certificates && \
+ apt-get -y autoremove --purge && \
+ rm -rf /var/log/*
+
+FROM gcr.io/distroless/cc-debian11:latest-amd64
+
+COPY --from=build /usr/local/bin/client /usr/local/bin/server /usr/local/bin/
+COPY --from=build /etc/mime.types /etc/
+
+CMD ["/usr/local/bin/client"]