解决register的问题
This commit is contained in:
parent
c1f196fa96
commit
abf6e11a34
127
apps/sdlan/src/sdlan_register_worker.erl
Normal file
127
apps/sdlan/src/sdlan_register_worker.erl
Normal 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)).
|
||||||
65
apps/sdlan/src/sdlan_register_worker_sup.erl
Normal file
65
apps/sdlan/src/sdlan_register_worker_sup.erl
Normal 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]).
|
||||||
@ -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().
|
-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>>) ->
|
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),
|
#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的映射关系
|
%% 告知网络当前的ip对应的nat的映射关系
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user