feat(quic): compile and start quicer listener.

This commit is contained in:
William Yang 2021-03-27 14:03:10 +01:00
parent 52743839d0
commit a49a1c6acf
5 changed files with 575 additions and 1 deletions

View File

@ -2071,6 +2071,312 @@ listener.wss.external.allow_origin_absence = true
## Value: http://url eg. https://localhost:8084, https://127.0.0.1:8084
listener.wss.external.check_origins = https://localhost:8084, https://127.0.0.1:8084
##--------------------------------------------------------------------
## External QUIC listener for MQTT Protocol
## listener.quic.$name is the IP address and port that the MQTT/QUIC
## listener will bind.
##
## Value: IP:Port | Port
##
## Examples: 8084, 127.0.0.1:8084, ::1:8084
listener.quic.external = 4567
## The path of WebSocket MQTT endpoint
##
## Value: URL Path
listener.quic.external.mqtt_path = /mqtt
## The acceptor pool for external MQTT/QUIC listener.
##
## Value: Number
listener.quic.external.acceptors = 4
## Maximum number of concurrent MQTT/Webwocket/SSL connections.
##
## Value: Number
listener.quic.external.max_connections = 16
## Maximum MQTT/QUIC connections per second.
##
## See: listener.tcp.$name.max_conn_rate
##
## Value: Number
listener.quic.external.max_conn_rate = 1000
## Simulate the {active, N} option for the MQTT/QUIC connections.
##
## Value: Number
listener.quic.external.active_n = 100
## Zone of the external MQTT/QUIC listener belonged to.
##
## Value: String
listener.quic.external.zone = external
## The access control rules for the MQTT/QUIC listener.
##
## See: listener.tcp.$name.access.<no>
##
## Value: ACL Rule
listener.quic.external.access.1 = allow all
## If set to true, the server fails if the client does not have a Sec-WebSocket-Protocol to send.
## Set to false for WeChat MiniApp.
##
## Value: true | false
## listener.quic.external.fail_if_no_subprotocol = true
## Supported subprotocols
##
## Default: mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5
## listener.quic.external.supported_subprotocols = mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5
## Enable the Proxy Protocol V1/2 support.
##
## See: listener.tcp.$name.proxy_protocol
##
## Value: on | off
## listener.quic.external.proxy_protocol = on
## Sets the timeout for proxy protocol.
##
## See: listener.tcp.$name.proxy_protocol_timeout
##
## Value: Duration
## listener.quic.external.proxy_protocol_timeout = 3s
## TLS versions only to protect from POODLE attack.
##
## See: listener.ssl.$name.tls_versions
##
## Value: String, seperated by ','
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
## listener.quic.external.tls_versions = tlsv1.3,tlsv1.2,tlsv1.1,tlsv1
## Path to the file containing the user's private PEM-encoded key.
##
## See: listener.ssl.$name.keyfile
##
## Value: File
listener.quic.external.keyfile = {{ platform_etc_dir }}/certs/key.pem
## Path to a file containing the user certificate.
##
## See: listener.ssl.$name.certfile
##
## Value: File
listener.quic.external.certfile = {{ platform_etc_dir }}/certs/cert.pem
## Path to the file containing PEM-encoded CA certificates.
##
## See: listener.ssl.$name.cacert
##
## Value: File
## listener.quic.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem
## Maximum number of non-self-issued intermediate certificates that
## can follow the peer certificate in a valid certification path.
##
## See: listener.ssl.external.depth
##
## Value: Number
## listener.quic.external.depth = 10
## String containing the user's password. Only used if the private keyfile
## is password-protected.
##
## See: listener.ssl.$name.key_password
##
## Value: String
## listener.quic.external.key_password = yourpass
## See: listener.ssl.$name.dhfile
##
## Value: File
## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem
## See: listener.ssl.$name.verify
##
## Value: verify_peer | verify_none
## listener.quic.external.verify = verify_peer
## See: listener.ssl.$name.fail_if_no_peer_cert
##
## Value: false | true
## listener.quic.external.fail_if_no_peer_cert = true
## See: listener.ssl.$name.ciphers
##
## Value: Ciphers
listener.quic.external.ciphers = TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_CCM_SHA256,TLS_AES_128_CCM_8_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA
## Ciphers for TLS PSK.
## Note that 'listener.quic.external.ciphers' and 'listener.quic.external.psk_ciphers' cannot
## be configured at the same time.
## See 'https://tools.ietf.org/html/rfc4279#section-2'.
## listener.quic.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA
## See: listener.ssl.$name.secure_renegotiate
##
## Value: on | off
## listener.quic.external.secure_renegotiate = off
## See: listener.ssl.$name.reuse_sessions
##
## Value: on | off
## listener.quic.external.reuse_sessions = on
## See: listener.ssl.$name.honor_cipher_order
##
## Value: on | off
## listener.quic.external.honor_cipher_order = on
## See: listener.ssl.$name.peer_cert_as_username
##
## Value: cn | dn | crt | pem | md5
## listener.quic.external.peer_cert_as_username = cn
## See: listener.ssl.$name.peer_cert_as_clientid
##
## Value: cn | dn | crt | pem | md5
## listener.quic.external.peer_cert_as_clientid = cn
## TCP backlog for the QUIC connection.
##
## See: listener.tcp.$name.backlog
##
## Value: Number >= 0
listener.quic.external.backlog = 1024
## The TCP send timeout for the QUIC connection.
##
## See: listener.tcp.$name.send_timeout
##
## Value: Duration
listener.quic.external.send_timeout = 15s
## Close the QUIC connection if send timeout.
##
## See: listener.tcp.$name.send_timeout_close
##
## Value: on | off
listener.quic.external.send_timeout_close = on
## The TCP receive buffer(os kernel) for the QUIC connections.
##
## See: listener.tcp.$name.recbuf
##
## Value: Bytes
## listener.quic.external.recbuf = 4KB
## The TCP send buffer(os kernel) for the QUIC connections.
##
## See: listener.tcp.$name.sndbuf
##
## Value: Bytes
## listener.quic.external.sndbuf = 4KB
## The size of the user-level software buffer used by the driver.
##
## See: listener.tcp.$name.buffer
##
## Value: Bytes
## listener.quic.external.buffer = 4KB
## The TCP_NODELAY flag for QUIC connections.
##
## See: listener.tcp.$name.nodelay
##
## Value: true | false
## listener.quic.external.nodelay = true
## The compress flag for external QUIC connections.
##
## If this Value is set true,the websocket message would be compressed
##
## Value: true | false
## listener.quic.external.compress = true
## The level of deflate options for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.level
##
## Value: none | default | best_compression | best_speed
## listener.quic.external.deflate_opts.level = default
## The mem_level of deflate options for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.mem_level
##
## Valid range is 1-9
## listener.quic.external.deflate_opts.mem_level = 8
## The strategy of deflate options for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.strategy
##
## Value: default | filtered | huffman_only | rle
## listener.quic.external.deflate_opts.strategy = default
## The deflate option for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.server_context_takeover
##
## Value: takeover | no_takeover
## listener.quic.external.deflate_opts.server_context_takeover = takeover
## The deflate option for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.client_context_takeover
##
## Value: takeover | no_takeover
## listener.quic.external.deflate_opts.client_context_takeover = takeover
## The deflate options for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.server_max_window_bits
##
## Valid range is 8-15
## listener.quic.external.deflate_opts.server_max_window_bits = 15
## The deflate options for external QUIC connections.
##
## See: listener.quic.$name.deflate_opts.client_max_window_bits
##
## Valid range is 8-15
## listener.quic.external.deflate_opts.client_max_window_bits = 15
## The idle timeout for external QUIC connections.
##
## See: listener.quic.$name.idle_timeout
##
## Value: Duration
## listener.quic.external.idle_timeout = 60s
## The max frame size for external QUIC connections.
##
## Value: Number
## listener.quic.external.max_frame_size = 0
## Whether a WebSocket message is allowed to contain multiple MQTT packets
##
## Value: single | multiple
listener.quic.external.mqtt_piggyback = multiple
## Enable origin check in header for secure websocket connection
##
## Value: true | false (default false)
listener.quic.external.check_origin_enable = false
## Allow origin to be absent in header in secure websocket connection when check_origin_enable is true
##
## Value: true | false (default true)
listener.quic.external.allow_origin_absence = true
## Comma separated list of allowed origin in header for secure websocket connection
##
## Value: http://url eg. https://localhost:8084, https://127.0.0.1:8084
listener.quic.external.check_origins = https://localhost:8084, https://127.0.0.1:8084
## CONFIG_SECTION_END=listeners ================================================
## CONFIG_SECTION_BGN=modules ==================================================

View File

@ -1872,6 +1872,254 @@ end}.
hidden
]}.
%%--------------------------------------------------------------------
%% MQTT/QUIC SSL Listeners
{mapping, "listener.quic.$name", "emqx.listeners", [
{datatype, [integer, ip]}
]}.
{mapping, "listener.quic.$name.mqtt_path", "emqx.listeners", [
{default, "/mqtt"},
{datatype, string}
]}.
{mapping, "listener.quic.$name.acceptors", "emqx.listeners", [
{default, 8},
{datatype, integer}
]}.
{mapping, "listener.quic.$name.max_connections", "emqx.listeners", [
{default, 1024},
{datatype, integer}
]}.
{mapping, "listener.quic.$name.max_conn_rate", "emqx.listeners", [
{datatype, integer}
]}.
{mapping, "listener.quic.$name.active_n", "emqx.listeners", [
{default, 100},
{datatype, integer}
]}.
{mapping, "listener.quic.$name.zone", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.rate_limit", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.fail_if_no_subprotocol", "emqx.listeners", [
{default, true},
{datatype, {enum, [true, false]}}
]}.
{mapping, "listener.quic.$name.supported_subprotocols", "emqx.listeners", [
{default, "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5"},
{datatype, string}
]}.
{mapping, "listener.quic.$name.access.$id", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.proxy_protocol", "emqx.listeners", [
{datatype, flag}
]}.
{mapping, "listener.quic.$name.proxy_protocol_timeout", "emqx.listeners", [
{datatype, {duration, ms}}
]}.
%%{mapping, "listener.quic.$name.handshake_timeout", "emqx.listeners", [
%% {default, "15s"},
%% {datatype, {duration, ms}}
%%]}.
{mapping, "listener.quic.$name.backlog", "emqx.listeners", [
{default, 1024},
{datatype, integer}
]}.
{mapping, "listener.quic.$name.send_timeout", "emqx.listeners", [
{datatype, {duration, ms}},
{default, "15s"}
]}.
{mapping, "listener.quic.$name.send_timeout_close", "emqx.listeners", [
{datatype, flag},
{default, on}
]}.
{mapping, "listener.quic.$name.recbuf", "emqx.listeners", [
{datatype, bytesize},
hidden
]}.
{mapping, "listener.quic.$name.sndbuf", "emqx.listeners", [
{datatype, bytesize},
hidden
]}.
{mapping, "listener.quic.$name.buffer", "emqx.listeners", [
{datatype, bytesize},
hidden
]}.
{mapping, "listener.quic.$name.tune_buffer", "emqx.listeners", [
{datatype, flag},
hidden
]}.
{mapping, "listener.quic.$name.nodelay", "emqx.listeners", [
{datatype, {enum, [true, false]}},
hidden
]}.
{mapping, "listener.quic.$name.tls_versions", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.ciphers", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.psk_ciphers", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.keyfile", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.certfile", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.cacertfile", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.dhfile", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.depth", "emqx.listeners", [
{default, 10},
{datatype, integer}
]}.
{mapping, "listener.quic.$name.key_password", "emqx.listeners", [
{datatype, string}
]}.
{mapping, "listener.quic.$name.verify", "emqx.listeners", [
{datatype, atom}
]}.
{mapping, "listener.quic.$name.fail_if_no_peer_cert", "emqx.listeners", [
{datatype, {enum, [true, false]}}
]}.
{mapping, "listener.quic.$name.secure_renegotiate", "emqx.listeners", [
{datatype, flag}
]}.
{mapping, "listener.quic.$name.reuse_sessions", "emqx.listeners", [
{default, on},
{datatype, flag}
]}.
{mapping, "listener.quic.$name.honor_cipher_order", "emqx.listeners", [
{datatype, flag}
]}.
{mapping, "listener.quic.$name.peer_cert_as_username", "emqx.listeners", [
{datatype, {enum, [cn, dn, crt, pem, md5]}}
]}.
{mapping, "listener.quic.$name.peer_cert_as_clientid", "emqx.listeners", [
{datatype, {enum, [cn, dn, crt, pem, md5]}}
]}.
{mapping, "listener.quic.$name.compress", "emqx.listeners", [
{datatype, {enum, [true, false]}},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.level", "emqx.listeners", [
{datatype, {enum, [none, default, best_compression, best_speed]}},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.mem_level", "emqx.listeners", [
{datatype, integer},
{validators, ["range:1-9"]},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.strategy", "emqx.listeners", [
{datatype, {enum, [default, filtered, huffman_only, rle]}},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.server_context_takeover", "emqx.listeners", [
{datatype, {enum, [takeover, no_takeover]}},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.client_context_takeover", "emqx.listeners", [
{datatype, {enum, [takeover, no_takeover]}},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.server_max_window_bits", "emqx.listeners", [
{datatype, integer},
{validators, ["range:8-15"]},
hidden
]}.
{mapping, "listener.quic.$name.deflate_opts.client_max_window_bits", "emqx.listeners", [
{datatype, integer},
{validators, ["range:8-15"]},
hidden
]}.
{mapping, "listener.quic.$name.idle_timeout", "emqx.listeners", [
{datatype, {duration, ms}},
hidden
]}.
{mapping, "listener.quic.$name.max_frame_size", "emqx.listeners", [
{datatype, integer},
hidden
]}.
{mapping, "listener.quic.$name.mqtt_piggyback", "emqx.listeners", [
{datatype, {enum, [single, multiple]}},
{default, multiple},
hidden
]}.
{mapping, "listener.quic.$name.check_origin_enable", "emqx.listeners", [
{datatype, {enum, [true, false]}},
{default, false},
hidden
]}.
{mapping, "listener.quic.$name.allow_origin_absence", "emqx.listeners", [
{datatype, {enum, [true, false]}},
{default, true},
hidden
]}.
{mapping, "listener.quic.$name.check_origins", "emqx.listeners", [
{datatype, string},
hidden
]}.
{translation, "emqx.listeners", fun(Conf) ->
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
@ -2059,6 +2307,7 @@ end}.
++
[SslListeners(Type, Name) || {["listener", Type, Name], ListenOn}
<- cuttlefish_variable:filter_by_prefix("listener.ssl", Conf)
++ cuttlefish_variable:filter_by_prefix("listener.quic", Conf)
++ cuttlefish_variable:filter_by_prefix("listener.wss", Conf)])
end}.

View File

@ -52,6 +52,7 @@
, {recon, {git, "https://github.com/ferd/recon", {tag, "2.5.1"}}}
, {observer_cli, "1.6.1"} % NOTE: depends on recon 2.5.1
, {getopt, "1.0.1"}
, {quicer, {git, "https://github.com/qzhuyan/quic.git", {branch, "quicer_application"}}}
]}.
{xref_ignores,

View File

@ -227,11 +227,14 @@ relx_apps(ReleaseType) ->
, compiler
, runtime_tools
, cuttlefish
, quicer
, emqx
, {mnesia, load}
, {ekka, load}
, {emqx_plugin_libs, load}
, observer_cli
, observer
, wx
]
++ [emqx_modules || not is_enterprise()]
++ [emqx_license || is_enterprise()]

View File

@ -132,7 +132,22 @@ start_listener(Proto, ListenOn, Options) when Proto == http; Proto == ws ->
%% Start MQTT/WSS listener
start_listener(Proto, ListenOn, Options) when Proto == https; Proto == wss ->
start_http_listener(fun cowboy:start_tls/3, 'mqtt:wss', ListenOn,
ranch_opts(Options), ws_opts(Options)).
ranch_opts(Options), ws_opts(Options));
%% MQTT over QUIC
start_listener(quic, ListenOn, Options) ->
SSLOpts = proplists:get_value(ssl_options, Options),
ListenOpts = [ {cert, proplists:get_value(certfile, SSLOpts)}
, {key, proplists:get_value(keyfile, SSLOpts)}
, {alpn, ["mqtt"]}
, {conn_acceptors, 32}
],
ConnectionOpts = [ {conn_callback, quicer_server_conn_callback}
, {idle_timeout_ms, 5000}
, {peer_unidi_stream_count, 1}
, {peer_bidi_stream_count, 10}],
StreamOpts = [{stream_callback, quicer_echo_server_stream_callback}],
quicer:start_listener('mqtt:quic', ListenOn, {ListenOpts, ConnectionOpts, StreamOpts}).
replace(Opts, Key, Value) -> [{Key, Value} | proplists:delete(Key, Opts)].