sdlan/src/quic/sdlan_quic_server.erl
2026-05-26 13:46:40 +08:00

94 lines
3.8 KiB
Erlang
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2026, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 11. 2月 2026 21:26
%%%-------------------------------------------------------------------
-module(sdlan_quic_server).
-author("anlicheng").
%% API
-export([start_link/0, init/0]).
-spec start_link() -> {ok, pid()}.
start_link() ->
{ok, spawn_link(?MODULE, init, [])}.
-spec init() -> ok.
init() ->
process_flag(trap_exit, true),
{ok, Props} = application:get_env(sdlan, quic_server),
Port = proplists:get_value(port, Props),
Alpn = proplists:get_value(alpn, Props),
Limits = proplists:get_value(limits, Props),
AcceptorCount = proplists:get_value(acceptors, Props, 10),
%% 证书配置
{CertFile, KeyFile} = sdlan_util:certificate_config(),
LOptions = #{
% 必选QUIC/TLS证书配置
certfile => CertFile,
keyfile => KeyFile,
alpn => Alpn,
peer_bidi_stream_count => 1,
conn_acceptors => AcceptorCount
},
ListenAddr = "0.0.0.0:" ++ integer_to_list(Port),
case quicer:listen(ListenAddr, LOptions) of
{ok, L} ->
logger:notice("[sdlan_quic_server] listen on ~s, acceptors: ~p", [ListenAddr, AcceptorCount]),
Pids = [spawn_link(fun() -> loop_accept(L, Limits, I) end) || I <- lists:seq(1, AcceptorCount)],
wait_acceptors(L, Pids);
Error ->
exit(Error)
end.
wait_acceptors(L, Pids) ->
receive
{'EXIT', Pid, Reason} ->
logger:warning("[sdlan_quic_server] acceptor ~p exit with reason: ~p", [Pid, Reason]),
quicer:close_listener(L),
exit({acceptor_exit, Pid, Reason, Pids});
stop ->
quicer:close_listener(L),
ok;
Info ->
logger:notice("[sdlan_quic_server] get unexpected info: ~p", [Info]),
wait_acceptors(L, Pids)
end.
loop_accept(L, Limits, AcceptorId) ->
case quicer:accept(L, #{}, infinity) of
{ok, Conn} ->
logger:debug("[sdlan_quic_server] acceptor: ~p, accept a new connection: ~p", [AcceptorId, Conn]),
case quicer:handshake(Conn) of
{ok, NConn} ->
case sdlan_quic_transport_sup:start_transport(NConn, Limits) of
{ok, ChannelPid} ->
logger:debug("[sdlan_quic_server] conn: ~p, handshake success, channel pid: ~p", [NConn, ChannelPid]),
case quicer:controlling_process(NConn, ChannelPid) of
ok ->
sdlan_quic_transport:accept_stream(ChannelPid);
{error, Reason} ->
logger:warning("[sdlan_quic_server] conn: ~p, controlling_process failed: ~p", [NConn, Reason]),
sdlan_quic_transport:stop(ChannelPid, {controlling_process_failed, Reason}),
quicer:close_connection(NConn)
end;
Error ->
quicer:close_connection(NConn),
logger:notice("[sdlan_quic_server] start channel get error: ~p", [Error])
end,
loop_accept(L, Limits, AcceptorId);
{error, Reason} ->
logger:debug("[sdlan_quic_server] acceptor: ~p, handshake failed: ~p", [AcceptorId, Reason]),
quicer:close_connection(Conn),
loop_accept(L, Limits, AcceptorId)
end;
{error, Reason} ->
logger:debug("[sdlan_quic_server] acceptor: ~p, accept failed: ~p", [AcceptorId, Reason]),
loop_accept(L, Limits, AcceptorId)
end.