diff --git a/apps/sdlan/src/quic/sdlan_quic_channel.erl b/apps/sdlan/src/quic/sdlan_quic_channel.erl index 70e7a4b..db6b66e 100644 --- a/apps/sdlan/src/quic/sdlan_quic_channel.erl +++ b/apps/sdlan/src/quic/sdlan_quic_channel.erl @@ -141,7 +141,7 @@ handle_event(info, {frame, <>} %% 建立到network的对应关系 case sdlan_network:get_pid(NetworkId) of NetworkPid when is_pid(NetworkPid) -> - {ok, AesKey, SessionToken} = sdlan_network:attach(NetworkPid, {ClientIp, ClientPort}, ClientId, Mac, Ip, HostName), + {ok, AesKey, SessionToken} = sdlan_network:attach(NetworkPid, self(), ClientId, Mac, Ip, HostName), RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey), EncodedAesKey = rsa_encode(AesKey, RsaPubKey), diff --git a/apps/sdlan/src/sdlan_network.erl b/apps/sdlan/src/sdlan_network.erl index 529e003..cf9d57b 100644 --- a/apps/sdlan/src/sdlan_network.erl +++ b/apps/sdlan/src/sdlan_network.erl @@ -21,7 +21,7 @@ %% API -export([start_link/2]). --export([get_name/1, get_pid/1, peer_info/3, unregister/3, debug_info/1, get_network_id/1, attach/6]). +-export([get_name/1, get_pid/1, lookup_pid/1, peer_info/3, unregister/3, debug_info/1, get_network_id/1, attach/6]). -export([forward/5, update_hole/6, disable_client/2, get_channel/2]). -export([test_event/1]). @@ -79,6 +79,15 @@ test_event(Pid) -> get_pid(Id) when is_integer(Id) -> whereis(get_name(Id)). +-spec lookup_pid(Id :: integer()) -> {ok, Pid :: pid()} | error. +lookup_pid(Id) when is_integer(Id) -> + case whereis(get_name(Id)) of + undefined -> + error; + Pid -> + {ok, Pid} + end. + -spec get_name(Id :: integer()) -> atom(). get_name(Id) when is_integer(Id) -> list_to_atom("sdlan_network:" ++ integer_to_list(Id)). @@ -87,7 +96,8 @@ get_name(Id) when is_integer(Id) -> get_network_id(Pid) when is_pid(Pid) -> gen_server:call(Pid, get_network_id). --spec attach(Pid :: pid(), ChannelPid :: pid(), ClientId :: binary(), Mac :: binary(), Ip :: integer(), Hostname :: binary()) -> any(). +-spec attach(Pid :: pid(), ChannelPid :: pid(), ClientId :: binary(), Mac :: binary(), Ip :: integer(), Hostname :: binary()) -> + {ok, AesKey :: binary(), SessionToken :: binary()}. attach(Pid, ChannelPid, ClientId, Mac, Ip, Hostname) when is_pid(Pid), is_pid(ChannelPid), is_binary(ClientId), is_binary(Mac), is_integer(Ip), is_binary(Hostname) -> gen_server:call(Pid, {attach, ChannelPid, ClientId, Mac, Ip, Hostname}). diff --git a/apps/sdlan/src/sdlan_stun.erl b/apps/sdlan/src/sdlan_stun.erl index 66e1449..a8bdc4b 100644 --- a/apps/sdlan/src/sdlan_stun.erl +++ b/apps/sdlan/src/sdlan_stun.erl @@ -99,44 +99,42 @@ handle_cast({stun_relay, Ip, Port, Reply}, State = #state{socket = Sock}) -> {stop, Reason :: term(), NewState :: #state{}}). handle_info({udp, Sock, Ip, Port, <>}, State = #state{socket = Sock}) -> - #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), + StunRequest = catch sdlan_pb:decode_msg(Body, sdl_stun_request), %% 告知网络当前的ip对应的nat的映射关系 - - case sdlan_network:get_pid(NetworkId) of - undefined -> - logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, not found", [NetworkId, ClientId]), - {noreply, State}; - NetworkPid when is_pid(NetworkPid) -> - sdlan_network:update_hole(NetworkPid, ClientId, Mac, {Ip, Port}, NatType, V6Info), - StunReply = sdlan_pb:encode_msg(#sdl_stun_reply{ - cookie = Cookie - }), - ok = gen_udp:send(Sock, Ip, Port, <>), - logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, hole: ~p", [NetworkId, ClientId, {Ip, Port}]), - {noreply, State} - end; + maybe + #sdl_stun_request{cookie = Cookie, client_id = ClientId, network_id = NetworkId, mac = Mac, nat_type = NatType, v6_info = V6Info} ?= StunRequest, + {ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId), + sdlan_network:update_hole(NetworkPid, ClientId, Mac, {Ip, Port}, NatType, V6Info), + StunReply = sdlan_pb:encode_msg(#sdl_stun_reply{ + cookie = Cookie + }), + ok = gen_udp:send(Sock, Ip, Port, <>), + logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, hole: ~p", [NetworkId, ClientId, {Ip, Port}]) + end, + {noreply, State}; %% 网络nat类型的探测机制, 需要借助其他服务一起才能实现 %% 辅助节点没有assist的配置,不支持attr = 2的探测 handle_info({udp, Sock, ClientIp, ClientPort, <>}, State = #state{socket = Sock}) -> - #sdl_stun_probe{cookie = Cookie, attr = Attr} = sdlan_pb:decode_msg(Body, sdl_stun_probe), - logger:debug("[sdlan_stun] get stun_probe request, att: ~p", [Attr]), - - ProbeReplyPkt = sdlan_pb:encode_msg(#sdl_stun_probe_reply { - cookie = Cookie, - port = ClientPort, - ip = int_ip(ClientIp) - }), - - case Attr of - ?STUN_ATTR_CHANGE_NONE -> - ok = gen_udp:send(Sock, ClientIp, ClientPort, <>); - ?STUN_ATTR_CHANGE_PORT -> - %% 切换端口和ip - sdlan_stun_peer_assist:stun_relay(ClientIp, ClientPort, ProbeReplyPkt); - ?STUN_ATTR_CHANGE_PEER -> - %% 切换端口返回 - sdlan_stun_port_assist:stun_relay(ClientIp, ClientPort, ProbeReplyPkt) + StunProbe = catch sdlan_pb:decode_msg(Body, sdl_stun_probe), + maybe + #sdl_stun_probe{cookie = Cookie, attr = Attr} ?= StunProbe, + logger:debug("[sdlan_stun] get stun_probe request, att: ~p", [Attr]), + ProbeReplyPkt = sdlan_pb:encode_msg(#sdl_stun_probe_reply { + cookie = Cookie, + port = ClientPort, + ip = int_ip(ClientIp) + }), + case Attr of + ?STUN_ATTR_CHANGE_NONE -> + ok = gen_udp:send(Sock, ClientIp, ClientPort, <>); + ?STUN_ATTR_CHANGE_PORT -> + %% 切换端口和ip + sdlan_stun_peer_assist:stun_relay(ClientIp, ClientPort, ProbeReplyPkt); + ?STUN_ATTR_CHANGE_PEER -> + %% 切换端口返回 + sdlan_stun_port_assist:stun_relay(ClientIp, ClientPort, ProbeReplyPkt) + end end, {noreply, State}; @@ -147,19 +145,14 @@ handle_info({udp, Sock, _, _, <>}, State = #state{socket = Sock}) -> - Data = #sdl_data{network_id = NetworkId, src_mac = SrcMac, dst_mac = DstMac, ttl = TTL} = sdlan_pb:decode_msg(Body, sdl_data), - - logger:debug("[sdlan_stun] stun data, src_mac: ~p, dst_mac: ~p", [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), - - %% 重新打包数据ttl需要减1 - case sdlan_network:get_pid(NetworkId) of - NetworkPid when is_pid(NetworkPid) -> - NData = sdlan_pb:encode_msg(Data#sdl_data{ttl = TTL - 1, is_p2p = false}), - sdlan_network:forward(NetworkPid, Sock, SrcMac, DstMac, <>); - _ -> - ok + Data = catch sdlan_pb:decode_msg(Body, sdl_data), + maybe + #sdl_data{network_id = NetworkId, src_mac = SrcMac, dst_mac = DstMac, ttl = TTL} ?= Data, + {ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId), + %% 重新打包数据ttl需要减1 + NData = sdlan_pb:encode_msg(Data#sdl_data{ttl = TTL - 1, is_p2p = false}), + sdlan_network:forward(NetworkPid, Sock, SrcMac, DstMac, <>) end, - {noreply, State}; handle_info(Info, State) ->