From c1f196fa964bb9e5392a56a86376e43f3f128101 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Fri, 23 Jan 2026 14:55:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9A=94=E7=A6=BB=E5=87=BAudp=E5=8C=85?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sdlan/src/sdlan_stun.erl | 138 +++++++++++++++++----------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/apps/sdlan/src/sdlan_stun.erl b/apps/sdlan/src/sdlan_stun.erl index ce44302..8be0762 100644 --- a/apps/sdlan/src/sdlan_stun.erl +++ b/apps/sdlan/src/sdlan_stun.erl @@ -100,77 +100,11 @@ handle_cast({stun_relay, Ip, Port, Reply}, State = #state{socket = Sock}) -> {noreply, NewState :: #state{}} | {noreply, NewState :: #state{}, timeout() | hibernate} | {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), - %% 告知网络当前的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; - -%% 网络nat类型的探测机制, 需要借助其他服务一起才能实现 -%% 辅助节点没有assist的配置,不支持attr = 2的探测 -handle_info({udp, Sock, Ip, Port, <>}, 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]), - - ProbeReply = sdlan_pb:encode_msg(#sdl_stun_probe_reply { - cookie = Cookie, - port = Port, - ip = int_ip(Ip) - }), - Packet = <>, - - case Attr of - ?STUN_ATTR_CHANGE_NONE -> - ok = gen_udp:send(Sock, Ip, Port, Packet); - ?STUN_ATTR_CHANGE_PORT -> - sdlan_stun_port_assist:stun_relay(Ip, Port, Packet); - ?STUN_ATTR_CHANGE_PEER -> - sdlan_stun_peer_assist:stun_relay(Ip, Port, Packet) - end, +handle_info({udp, Sock, Ip, Port, Packet}, State = #state{socket = Sock}) -> + catch handle_packet(Sock, Ip, Port, Packet), {noreply, State}; - -%% 转发消息, 跨服务器的stun_reply的转发通过socket来转发 -handle_info({udp, Sock, _, _, <>}, State = #state{socket = Sock}) -> - logger:debug("[sdlan_stun] get stun_probe_replay request, reply: ~p", [Reply]), - gen_udp:send(Sock, {Ip0, Ip1, Ip2, Ip3}, Port, Reply), - {noreply, State}; - -handle_info({udp, _, _Ip, _Port, <>}, 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)]), - maybe - {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({udp, _, Ip, Port, <>}, State = #state{socket = Sock}) -> - #sdl_arp_request{network_id = NetworkId, target_ip = TargetIp} = sdlan_pb:decode_msg(Body, sdl_arp_request), - logger:debug("[sdlan_stun] stun sdl_arp_request, network_id: ~p, target_ip: ~p", [NetworkId, TargetIp]), - maybe - {ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId), - {ok, TargetMac} ?= sdlan_network:arp_query(NetworkPid, TargetIp), - ArpResponse = sdlan_pb:encode_msg(#sdl_arp_response{network_id = NetworkId, target_ip = TargetIp, target_mac = TargetMac}), - ok ?= gen_udp:send(Sock, Ip, Port, ArpResponse) - end, - {noreply, State}; - +handle_info({udp_error , Sock, Reason}, State = #state{socket = Sock}) -> + {stop, Reason, State}; handle_info(Info, State) -> logger:error("[sdlan_stun] get a unknown message: ~p, channel will closed", [Info]), {noreply, State}. @@ -197,6 +131,70 @@ code_change(_OldVsn, State = #state{}, _Extra) -> %%% Internal functions %%%=================================================================== +-spec handle_packet(Sock :: inet:socket(), Ip :: inet:ip4_address(), Port :: integer(), Packet :: binary()) -> no_return(). +handle_packet(Sock, Ip, Port, <>) -> + #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的映射关系 + case sdlan_network:get_pid(NetworkId) of + undefined -> + logger:debug("[sdlan_stun] stun_request network_id: ~p, client_id: ~p, not found", [NetworkId, ClientId]), + ok; + 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}]) + end; + +%% 网络nat类型的探测机制, 需要借助其他服务一起才能实现 +%% 辅助节点没有assist的配置,不支持attr = 2的探测 +handle_packet(Sock, Ip, Port, <>) -> + #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]), + + ProbeReply = sdlan_pb:encode_msg(#sdl_stun_probe_reply { + cookie = Cookie, + port = Port, + ip = int_ip(Ip) + }), + Packet = <>, + + case Attr of + ?STUN_ATTR_CHANGE_NONE -> + ok = gen_udp:send(Sock, Ip, Port, Packet); + ?STUN_ATTR_CHANGE_PORT -> + sdlan_stun_port_assist:stun_relay(Ip, Port, Packet); + ?STUN_ATTR_CHANGE_PEER -> + sdlan_stun_peer_assist:stun_relay(Ip, Port, Packet) + end; + +%% 转发消息, 跨服务器的stun_reply的转发通过socket来转发 +handle_packet(Sock, _, _, <>) -> + logger:debug("[sdlan_stun] get stun_probe_replay request, reply: ~p", [Reply]), + gen_udp:send(Sock, {Ip0, Ip1, Ip2, Ip3}, Port, Reply); + +handle_packet(Sock, _Ip, _Port, <>) -> + 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)]), + maybe + {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; + +handle_packet(Sock, Ip, Port, <>) -> + #sdl_arp_request{network_id = NetworkId, target_ip = TargetIp} = sdlan_pb:decode_msg(Body, sdl_arp_request), + logger:debug("[sdlan_stun] stun sdl_arp_request, network_id: ~p, target_ip: ~p", [NetworkId, TargetIp]), + maybe + {ok, NetworkPid} ?= sdlan_network:lookup_pid(NetworkId), + {ok, TargetMac} ?= sdlan_network:arp_query(NetworkPid, TargetIp), + ArpResponse = sdlan_pb:encode_msg(#sdl_arp_response{network_id = NetworkId, target_ip = TargetIp, target_mac = TargetMac}), + ok ?= gen_udp:send(Sock, Ip, Port, ArpResponse) + end. + -spec int_ip(tuple()) -> integer(). int_ip({Ip0, Ip1, Ip2, Ip3}) -> <> = <>,