%%%------------------------------------------------------------------- %%% @author anlicheng %%% @copyright (C) 2026, %%% @doc %%% %%% @end %%% Created : 11. 2月 2026 21:26 %%%------------------------------------------------------------------- -module(sdlan_quic_server). -author("anlicheng"). %% API -export([start_link/0, init/0]). start_link() -> {ok, spawn_link(?MODULE, init, [])}. init() -> {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), CertFile = proplists:get_value(certfile, Props), KeyFile = proplists:get_value(keyfile, Props), %% 获取环境变量 Path = os:getenv("QUIC_CERT_PATH", code:priv_dir(sdlan)), LOptions = #{ addr_family => inet, % 必选:QUIC/TLS证书配置 certfile => Path ++ "/" ++ CertFile, keyfile => Path ++ "/" ++ KeyFile, alpn => Alpn, peer_bidi_stream_count => 1, conn_acceptors => 10 }, ListenAddr = "0.0.0.0:" ++ integer_to_list(Port), case quicer:listen(ListenAddr, LOptions) of {ok, L} -> loop_accept(L, Limits); Error -> exit(Error) end. loop_accept(L, Limits) -> case quicer:accept(L, #{}, infinity) of {ok, Conn} -> logger:debug("[sdlan_quic_server] accept a new connection: ~p", [Conn]), case quicer:handshake(Conn) of {ok, NConn} -> case sdlan_quic_channel_sup:start_channel(NConn, Limits) of {ok, ChannelPid} -> logger:debug("[sdlan_quic_server] conn: ~p, handshake success, channel pid: ~p", [NConn, ChannelPid]), quicer:controlling_process(NConn, ChannelPid); Error -> quicer:close_connection(NConn), logger:notice("[sdlan_quic_server] start channel get error: ~p", [Error]) end, loop_accept(L, Limits); {error, _} -> quicer:close_connection(Conn), loop_accept(L, Limits) end; {error, Reason} -> logger:debug("[sdlan_quic_server] accept failed: ~p", [Reason]), loop_accept(L, Limits) end.