解决register的问题

This commit is contained in:
anlicheng 2026-01-23 15:37:03 +08:00
parent c1f196fa96
commit abf6e11a34
3 changed files with 223 additions and 0 deletions

View File

@ -0,0 +1,127 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2026, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 23. 1 2026 15:20
%%%-------------------------------------------------------------------
-module(sdlan_register_worker).
-author("anlicheng").
-include("sdlan_pb.hrl").
-include("sdlan.hrl").
%% token不存在
-define(NAK_INVALID_TOKEN, 1).
%%
-define(NAK_NODE_DISABLE, 2).
%% IP地址可以用
-define(NAK_NO_IP, 3).
%%
-define(NAK_NETWORK_FAULT, 4).
%%
-define(NAK_INTERNAL_FAULT, 5).
%% hostname被占用
-define(NAK_HOSTNAME_USED, 6).
%% API
-export([start_link/4, do_work/4]).
-spec start_link(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> {ok, pid()}.
start_link(Sock, Ip, Port, Packet) ->
{ok, erlang:spawn_link(?MODULE, do_work, [Sock, Ip, Port, Packet])}.
do_work(Sock, Ip, Port, <<PacketId:32, Body/binary>>) ->
#sdl_register_super{version = Version, client_id = ClientId, dev_addr = #sdl_dev_addr{mac = Mac}, network_code = NetworkCode, token = Token, pub_key = PubKey} = sdlan_pb:decode_msg(Body, sdl_register_super),
%%
logger:debug("[sdlan_channel] client_id: ~p, public_key: ~p, token: ~p, network_code: ~p", [ClientId, PubKey, Token, NetworkCode]),
true = (Mac =/= <<>> andalso PubKey =/= <<>> andalso ClientId =/= <<>>),
%% Mac地址不能是广播地址
true = not (sdlan_util:is_multicast_mac(Mac) orelse sdlan_util:is_broadcast_mac(Mac)),
AuthResult = if
Token /= <<>> ->
logger:debug("[sdlan_channel] auth token: ~p", [Token]),
sdlan_api:auth_token(ClientId, Token, Version);
NetworkCode /= <<>> ->
logger:debug("[sdlan_channel] auth network code: ~p", [NetworkCode]),
sdlan_api:auth_network_code(ClientId, NetworkCode, Version)
end,
case AuthResult of
{ok, #{<<"result">> := #{<<"network_id">> := NetworkId, <<"upgrade_type">> := UpgradeType, <<"upgrade_prompt">> := UpgradePrompt, <<"upgrade_address">> := UpgradeAddress}}} when is_integer(NetworkId) ->
logger:debug("[sdlan_channel] client_id: ~p, mac: ~p, token: ~p, version: ~p, registerd, alloc network_id: ~p", [ClientId, sdlan_util:format_mac(Mac), Token, Version, NetworkId]),
%% network的对应关系
case sdlan_network:get_pid(NetworkId) of
NetworkPid when is_pid(NetworkPid) ->
try sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac) of
{ok, Domain, NetAddr, NetBitLen, AesKey} ->
RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey),
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
RegisterSuperAck = sdlan_pb:encode_msg(#sdl_register_super_ack {
dev_addr = #sdl_dev_addr{
network_id = NetworkId,
net_addr = NetAddr,
mac = Mac,
net_bit_len = NetBitLen,
network_domain = Domain
},
aes_key = EncodedAesKey,
upgrade_type = UpgradeType,
upgrade_prompt = UpgradePrompt,
upgrade_address = UpgradeAddress
}),
%%
Reply = <<?PACKET_REGISTER_SUPER_ACK, PacketId:32, RegisterSuperAck/binary>>,
gen_udp:send(Sock, Ip, Port, Reply),
logger:debug("[sdlan_channel] client_id: ~p, mac: ~p, alloc ip: ~p, register will send ack, aes_key: ~p, enc_aes_key: ~p",
[ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(NetAddr), AesKey, EncodedAesKey]),
%% 线
Result = sdlan_api:node_online(ClientId, NetworkId, sdlan_ipaddr:int_to_ipv4(NetAddr)),
logger:debug("[sdlan_channel] client_id: ~p, set none online, result is: ~p", [ClientId, Result]),
%% TODO session_token的逻辑
ok;
{error, no_ip} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: no_ip", [ClientId, Token]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_NO_IP, <<"No Ip address">>));
{error, host_name_used} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: host_name_used", [ClientId, Token]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_HOSTNAME_USED, <<"Host Name Used">>));
{error, client_disabled} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: client_disabled", [ClientId, Token]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, <<"Client Connection Disable">>))
catch _:Error:Stack ->
logger:warning("[sdlan_channel] get error: ~p, stack: ~p", [Error, Stack])
end;
undefined ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: network not found", [ClientId, Token]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_INTERNAL_FAULT, <<"Internal Error">>))
end;
{ok, #{<<"error">> := #{<<"code">> := 1, <<"message">> := Message}}} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~ts, error_code: 1", [ClientId, Token, Message]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_INVALID_TOKEN, Message));
{ok, #{<<"error">> := #{<<"code">> := 2, <<"message">> := Message}}} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p, error_code: 2", [ClientId, Token, Message]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, Message));
{error, Reason} ->
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p", [ClientId, Token, Reason]),
gen_udp:send(Sock, Ip, Port, register_nak_reply(PacketId, ?NAK_NETWORK_FAULT, <<"Network Error">>))
end,
exit(normal).
-spec register_nak_reply(PacketId :: integer(), ErrorCode :: integer(), ErrorMsg :: binary()) -> binary().
register_nak_reply(PacketId, ErrorCode, ErrorMsg) when is_integer(PacketId), is_integer(ErrorCode), is_binary(ErrorMsg) ->
RegisterNakReply = sdlan_pb:encode_msg(#sdl_register_super_nak {
error_code = ErrorCode,
error_message = ErrorMsg
}),
<<PacketId:32, ?PACKET_REGISTER_SUPER_NAK, RegisterNakReply/binary>>.
rsa_encode(PlainText, RsaPubKey) when is_binary(PlainText) ->
iolist_to_binary(sdlan_cipher:rsa_encrypt(PlainText, RsaPubKey)).

View File

@ -0,0 +1,65 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2026, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 23. 1 2026 15:19
%%%-------------------------------------------------------------------
-module(sdlan_register_worker_sup).
-author("anlicheng").
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([start_worker/4]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%% @doc Starts the supervisor
-spec(start_link() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%% @private
%% @doc Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
-spec(init(Args :: term()) ->
{ok, {SupFlags :: {RestartStrategy :: supervisor:strategy(),
MaxR :: non_neg_integer(), MaxT :: non_neg_integer()},
[ChildSpec :: supervisor:child_spec()]}}
| ignore | {error, Reason :: term()}).
init([]) ->
SupFlags = #{strategy => simple_one_for_one, intensity => 1000, period => 3600},
ChildSpec = #{id => sdlan_register_worker,
start => {sdlan_register_worker, start_link, []},
restart => temporary,
shutdown => 2000,
type => worker,
modules => [sdlan_register_worker]},
{ok, {SupFlags, ChildSpec}}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
-spec start_worker(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> supervisor:startchild_ret().
start_worker(Sock, Ip, Port, Packet) ->
%% Start a temporary worker under the supervisor
supervisor:start_child(?SERVER, [Sock, Ip, Port, Packet]).

View File

@ -132,6 +132,37 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
%%%===================================================================
-spec handle_packet(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> no_return().
%% token或者网络id来注册
handle_packet(Sock, Ip, Port, <<?PACKET_REGISTER_SUPER, Body/binary>>) ->
sdlan_register_worker_sup:start_worker(Sock, Ip, Port, Body);
%handle_packet(Sock, Ip, Port, <<?PACKET_QUERY_INFO, PacketId:32, Body/binary>>) ->
% #sdl_query_info{dst_mac = DstMac} = sdlan_pb:decode_msg(Body, sdl_query_info),
% case sdlan_network:peer_info(NetworkPid, SrcMac, DstMac) of
% error ->
% logger:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer not found",
% [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
%
% Transport:send(Sock, <<PacketId:32, ?PACKET_EMPTY>>),
% {noreply, State};
% {ok, {NatPeer = {{Ip0, Ip1, Ip2, Ip3}, NatPort}, NatType}, V6Info} ->
% logger:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer: ~p",
% [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), NatPeer]),
%
% PeerInfo = sdlan_pb:encode_msg(#sdl_peer_info{
% dst_mac = DstMac,
% v4_info = #sdl_v4_info {
% port = NatPort,
% v4 = <<Ip0, Ip1, Ip2, Ip3>>,
% nat_type = NatType
% },
% v6_info = V6Info
% }),
% Transport:send(Sock, <<PacketId:32, ?PACKET_PEER_INFO, PeerInfo/binary>>),
% {noreply, State}
% end;
handle_packet(Sock, Ip, Port, <<?PACKET_STUN_REQUEST:8, Body/binary>>) ->
#sdl_stun_request{cookie = Cookie, client_id = ClientId, network_id = NetworkId, mac = Mac, nat_type = NatType, v6_info = V6Info} = sdlan_pb:decode_msg(Body, sdl_stun_request),
%% ip对应的nat的映射关系