QUIC protocol erlang library.
msquic NIF binding.
Project Status: WIP (actively), POC quality
API: is not stable, might be changed in the future.
OS | Status |
---|---|
Linux | Supported |
MACOS | Supported |
Windows | TBD |
- OTP22+
- rebar3
- cmake3.16+
- CLOG (required for debug logging only)
- LTTNG2.12 (required for debug build only)
Debug build depedency: CLOG
$ rebar3 compile
# OR
$ make
note,
To enable logging and release build:
export CMAKE_BUILD_TYPE=RelWithDebInfo
export QUIC_ENABLE_LOGGING=ON
make
$ git submodule update --init --recursive
$ cmake -B c_build -DCMAKE_BUILD_TYPE=Release -DQUIC_ENABLE_LOGGING=OFF && make
Port = 4567,
LOptions = [ {cert, "cert.pem"}
, {key, "key.pem"}],
{ok, L} = quicer:listen(Port, LOptions),
{ok, Conn} = quicer:accept(L, [], 5000),
{ok, Stm} = quicer:accept_stream(Conn, []),
receive {quic, <<"ping">>, Stm, _, _, _} -> ok end,
{ok, 4} = quicer:send(Stm, <<"pong">>),
quicer:close_listener(L).
Port = 4567,
{ok, Conn} = quicer:connect("localhost", Port, [], 5000),
{ok, Stm} = quicer:start_stream(Conn, []),
{ok, 4} = quicer:send(Stm, <<"ping">>),
receive {quic, <<"pong">>, Stm, _, _, _} -> ok end,
ok = quicer:close_connection(Conn).
$ make test
All APIs are exported though API MODULE: quicer.erl
Term | Definition |
---|---|
server | listen and accept quic connections from clients |
client | initiates quic connection |
listener | Erlang Process owns listening port |
connection | Quic Connection |
stream | Exchanging app data over a connection |
owner | 'owner' is a process that receives quic events. |
'connection owner' receive events of a connection | |
'stream owner' receive application data and events from a stream | |
'listener owner' receive events from listener | |
When owner is dead, related resources would be released | |
l_ctx | listener nif context |
c_ctx | connection nif context |
s_ctx | stream nif context |
Start listener on specific port.
quicer:listen(Port, Options) ->
{ok, Connection} | {error, any()} | {error, any(), ErrorCode::integer()}.
note: port binding is done in NIF context, thus you cannot see it from inet:i()
.
quicer:close_listener(Listener) -> ok.
Gracefully close listener.
quicer:accept(Listener, Options, Timeout) ->
{ok, Connection} | {error, any()} | {error, any(), ErrorCode::integer()}.
Blocking call to accept new connection.
Caller becomes the owner of new connection.
quicer:connection(Hostname, Port, Options, Timeout) ->
{ok, Connection} | {error, any()} | {error, any(), ErrorCode::integer()}.
quicer:close_connection(Connection) -> ok.
Gracefully Shutdown connection.
quicer:start_stream(Connection, Options) ->
{ok, Stream} | {error, any()} | {error, any(), ErrorCode::integer()}.
accept_stream(Connection, Opts, Timeout) ->
{ok, Stream} | {error, any()} | {error, any(), ErrorCode::integer()}.
Accept stream on a existing connection.
This is a blocking call.
quicer:send(Stream, BinaryData) ->
{ok, Stream} | {error, any()} | {error, any(), ErrorCode::integer()}.
Aync send data over stream.
quicer:recv(Stream, Len) ->
{ok, binary()} | {error, any()} | {error, any(), ErrorCode::integer()}.
Like gen_tcp:recv, passive recv data from stream.
If Len = 0, return all data in buffer if it is not empty. if buffer is empty, blocking for a quic msg from stack to arrive and return all data from that msg. If Len > 0, desired bytes will be returned, other data would be buffered in proc dict.
Suggested to use Len=0 if caller want to buffer or reassemble the data on its own.
quicer:close_stream(Stream) -> ok.
Shutdown stream gracefully.
%% Get Opts in binary format
quicer:getopt(Stream | Connection, [Opt]) ->
{ok, [{OptName::atom(), OptValue::binary()}]}.
%% Get Opts
quicer:getopt(Stream | Connection, [Opt], IsRaw :: boolean) ->
{ok, [{OptName::atom(), OptValue::binary() | any()}]}.
%% Set Opt
quicer:setopt(Stream | Connection, Opt :: atom(), Value :: any()) ->
ok | {error, any()}.
Supported Opts:
OptName | Suport Set/Get | Type | Description |
---|---|---|---|
param_conn_settings | Set | map() | map keys: conn_flow_control_window max_worker_queue_delay_us max_stateless_operations initial_window_packets send_idle_timeout_ms initial_rtt_ms max_ack_delay_ms disconnect_timeout_ms keep_alive_interval_ms peer_bidi_stream_count peer_unidi_stream_count retry_memory_limit load_balancing_mode max_operations_per_drain send_buffering_enabled pacing_enabled migration_enabled datagram_receive_enabled server_resumption_level version_negotiation_ext_enabled desired_versions_list desired_versions_list_length |
|
quicer:getstat(Connection, [inet:stat_option()]) ->
{ok, [{stat_option(), integer()}] | {error, any()}.
note, if state's return value is -1 that means it is unsupported.
quicer:peername(Stream | Connection) ->
{ok, {inet:ip_address(), inet:port_number()}} | {error, any()}.
Returns connection Peer's IP and Port
quicer:sockname(Stream | Connection) ->
{ok, {inet:ip_address(), inet:port_number()}} | {error, any()}.
Returns connection local IP and Port.
Apache License Version 2.0