Current section
Files
Jump to
Current section
Files
src/quicer_server_conn_callback.erl
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(quicer_server_conn_callback).
-behavior(quicer_connection).
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
-include("quicer_types.hrl").
%% Callback init
-export([ init/1 ]).
%% Connection Callbacks
-export([ new_conn/3
, connected/3
, transport_shutdown/3
, shutdown/3
, closed/3
, local_address_changed/3
, peer_address_changed/3
, streams_available/3
, peer_needs_streams/3
, resumed/3
, nst_received/3
, new_stream/3
]).
init(ConnOpts) when is_list(ConnOpts) ->
init(maps:from_list(ConnOpts));
init(#{stream_opts := SOpts} = S) when is_list(SOpts) ->
init(S#{stream_opts := maps:from_list(SOpts)});
init(ConnOpts) when is_map(ConnOpts) ->
{ok, ConnOpts}.
closed(_Conn, #{} = _Flags, S)->
{stop, normal, S}.
new_conn(Conn, #{version := _Vsn}, #{stream_opts := SOpts} = S) ->
%% @TODO configurable behavior of spawning stream acceptor
case quicer_stream:start_link(maps:get(stream_callback, SOpts), Conn, SOpts) of
{ok, Pid} ->
ok = quicer:async_handshake(Conn),
{ok, S#{ conn => Conn
%% @TODO track the streams?
, streams => [{Pid, accepting}]}};
{error, _} = Error ->
Error
end.
resumed(Conn, Data, #{resumed_callback := ResumeFun} = S)
when is_function(ResumeFun) ->
ResumeFun(Conn, Data, S);
resumed(_Conn, _Data, S) ->
{ok, S}.
nst_received(_Conn, _Data, S) ->
{stop, no_nst_for_server, S}.
%% handles stream when there is no stream acceptors.
new_stream(Stream, #{is_orphan := true} = StreamProps,
#{conn := Conn, streams := Streams, stream_opts := SOpts} = CBState) ->
%% Spawn new stream
case quicer_stream:start_link(maps:get(stream_callback, SOpts), Stream, Conn,
SOpts, StreamProps)
of
{ok, StreamOwner} ->
case quicer:handoff_stream(Stream, StreamOwner) of
ok ->
{ok, CBState#{ streams := [ {StreamOwner, Stream} | Streams] }};
{error, _} = E ->
E
end;
Other ->
Other
end.
shutdown(Conn, _ErrorCode, S) ->
quicer:async_close_connection(Conn),
{ok, S}.
transport_shutdown(_C, _DownInfo, S) ->
{ok, S}.
peer_address_changed(_C, _NewAddr, S) ->
{ok, S}.
local_address_changed(_C, _NewAddr, S) ->
{ok, S}.
streams_available(_C, {BidirCnt, UnidirCnt}, S) ->
{ok, S# { peer_unidi_stream_count => UnidirCnt
, peer_bidi_stream_count => BidirCnt}}.
%% @doc May integrate with App flow control
peer_needs_streams(_C, _UnidiOrBidi, S) ->
{ok, S}.
connected(Conn, _Flags, #{ slow_start := false, stream_opts := SOpts
, stream_callback := Callback} = S) ->
%% @TODO configurable behavior of spawing stream acceptor
_ = quicer_stream:start_link(Callback, Conn, SOpts),
{ok, S#{conn => Conn}};
connected(_Connecion, _Flags, S) ->
{ok, S}.
%% Internals
-ifdef(EUNIT).
-endif.