From e2fd4f18cb7374a0518342aa68591d692cb94b14 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 15 Jan 2026 11:29:51 +0800 Subject: [PATCH] fix network --- apps/sdlan/src/sdlan_network.erl | 86 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/apps/sdlan/src/sdlan_network.erl b/apps/sdlan/src/sdlan_network.erl index a0b8e6e..9e1198e 100644 --- a/apps/sdlan/src/sdlan_network.erl +++ b/apps/sdlan/src/sdlan_network.erl @@ -64,7 +64,7 @@ aes_key :: binary(), %% 记录已经使用了的ip, #{mac :: integer() => #endpoint{}} - used_map = #{} + endpoints = #{} }). %%%=================================================================== @@ -184,7 +184,7 @@ init([Id]) when is_integer(Id) -> {stop, Reason :: term(), NewState :: #state{}}). %% 给客户端分配ip地址 handle_call({assign_ip_addr, ChannelPid, ClientId, Mac}, _From, - State = #state{network_id = NetworkId, domain = Domain, used_map = UsedMap, mask_len = MaskLen, aes_key = AesKey}) -> + State = #state{network_id = NetworkId, domain = Domain, endpoints = Endpoints, mask_len = MaskLen, aes_key = AesKey}) -> case sdlan_api:assign_ip_address(NetworkId, ClientId, Mac) of {ok, #{<<"ip">> := Ip, <<"host_name">> := HostName}} -> @@ -192,20 +192,20 @@ handle_call({assign_ip_addr, ChannelPid, ClientId, Mac}, _From, lager:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, net_addr: ~p", [NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(Ip)]), %% 关闭之前的channel - maybe_close_channel(maps:get(Mac, UsedMap, undefined)), + maybe_close_channel(maps:get(Mac, Endpoints, undefined)), %% 添加域名->ip的映射关系 sdlan_hostname_regedit:insert(HostName, Domain, Ip), %% 建立到新的channel之间的关系 MRef = monitor(process, ChannelPid), - NUsedMap = maps:put(Mac, #endpoint{client_id = ClientId, ip = Ip, channel_pid = ChannelPid, monitor_ref = MRef}, UsedMap), + NEndpoints = maps:put(Mac, #endpoint{client_id = ClientId, ip = Ip, channel_pid = ChannelPid, monitor_ref = MRef}, Endpoints), - {reply, {ok, Domain, Ip, MaskLen, AesKey}, State#state{used_map = NUsedMap}}; + {reply, {ok, Domain, Ip, MaskLen, AesKey}, State#state{endpoints = NEndpoints}}; {error, Reason} -> {reply, {error, Reason}, State} end; -handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) -> +handle_call(get_used_map, _From, State = #state{endpoints = Endpoints}) -> UsedInfos = maps:map(fun(_, #endpoint{hole = Hole, v6_info = V6Info}) -> HoleMap = case Hole of #hole{peer = {NatIp, NatPort}} -> @@ -227,24 +227,23 @@ handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) -> #{} end, #{<<"hole">> => HoleMap, <<"v6_info">> => V6Map} - end, UsedMap), + end, Endpoints), {reply, {ok, UsedInfos}, State}; %% client设置为禁止状态,不允许重连 -handle_call({disable_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) -> - case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of +handle_call({disable_client, ClientId}, _From, State = #state{endpoints = Endpoints}) -> + case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(Endpoints)) of {value, {Mac, #endpoint{channel_pid = ChannelPid, monitor_ref = MRef}}} -> is_reference(MRef) andalso demonitor(MRef), sdlan_channel:stop(ChannelPid, disable), - NUsedMap = maps:remove(Mac, UsedMap), - {reply, ok, State#state{used_map = NUsedMap}}; + {reply, ok, State#state{endpoints = maps:remove(Mac, Endpoints)}}; false -> {reply, error, State} end; -handle_call({get_channel, ClientId}, _From, State = #state{used_map = UsedMap}) -> - case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of +handle_call({get_channel, ClientId}, _From, State = #state{endpoints = Endpoints}) -> + case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(Endpoints)) of {value, {_Ip, #endpoint{channel_pid = ChannelPid}}} -> {reply, {ok, ChannelPid}, State}; false -> @@ -252,12 +251,11 @@ handle_call({get_channel, ClientId}, _From, State = #state{used_map = UsedMap}) end; %% 区别在于是否关闭掉channel, 这里是在网络迁移中的功能; drop的时候需要从当前网络中移除 -handle_call({dropout_client, ClientId}, _From, State = #state{used_map = UsedMap}) -> - case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of +handle_call({dropout_client, ClientId}, _From, State = #state{endpoints = Endpoints}) -> + case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(Endpoints)) of {value, {Mac, #endpoint{channel_pid = ChannelPid, monitor_ref = MRef}}} -> is_reference(MRef) andalso demonitor(MRef), - NUsedMap = maps:remove(Mac, UsedMap), - {reply, {ok, ChannelPid}, State#state{used_map = NUsedMap}}; + {reply, {ok, ChannelPid}, State#state{endpoints = maps:remove(Mac, Endpoints)}}; false -> {reply, error, State} end; @@ -266,11 +264,11 @@ handle_call(get_network_id, _From, State = #state{network_id = NetworkId}) -> {reply, {ok, NetworkId}, State}; %% 网络存在的nat_peer信息 -handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMap}) -> - case maps:find(DstMac, UsedMap) of +handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{endpoints = Endpoints}) -> + case maps:find(DstMac, Endpoints) of {ok, #endpoint{channel_pid = DstChannelPid, hole = #hole{peer = DstNatPeer, nat_type = DstNatType}, v6_info = DstV6Info}} -> %% 让目标服务器发送sendRegister事件(2024-06-25 新增,提高打洞的成功率) - case maps:get(SrcMac, UsedMap, undefined) of + case maps:get(SrcMac, Endpoints, undefined) of #endpoint{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = NatType}, v6_info = SrcV6Info} -> Event = sdlan_pb:encode_msg(#sdl_send_register_event { dst_mac = SrcMac, @@ -288,13 +286,13 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMa {reply, error, State} end; -handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, used_map = UsedMap}) -> +handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, endpoints = Endpoints}) -> Reply = #{ <<"network_id">> => NetworkId, <<"ipaddr">> => IpAddr, <<"mask_len">> => MaskLen, <<"owner_id">> => OwnerId, - <<"used_ips">> => lists:map(fun format_endpoint/1, maps:to_list(UsedMap)) + <<"used_ips">> => lists:map(fun format_endpoint/1, maps:to_list(Endpoints)) }, {reply, Reply, State}. @@ -305,11 +303,11 @@ handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = I {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). %% 网络数据转发, mac地址单播 -handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, throttle_key = ThrottleKey, forward_bytes = ForwardBytes}) - when is_map_key(SrcMac, UsedMap), is_map_key(DstMac, UsedMap) -> +handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, endpoints = Endpoints, throttle_key = ThrottleKey, forward_bytes = ForwardBytes}) + when is_map_key(SrcMac, Endpoints), is_map_key(DstMac, Endpoints) -> PacketBytes = byte_size(Packet), - case maps:find(DstMac, UsedMap) of + case maps:find(DstMac, Endpoints) of {ok, #endpoint{hole = #hole{peer = Peer = {Ip, Port}}}} -> case limiting_check(ThrottleKey) of pass -> @@ -336,8 +334,8 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = %% 网络数据转发, ip广播或组播, 不限流 %% TODO 需要处理arp请求,arp请求就不要广播出去了,network是知道目标的ip信息的 -handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, forward_bytes = ForwardBytes}) - when is_map_key(SrcMac, UsedMap) -> +handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, endpoints = Endpoints, forward_bytes = ForwardBytes}) + when is_map_key(SrcMac, Endpoints) -> %% 广播地址和组播地址,需要转发到整个网络 case sdlan_util:is_broadcast_mac(DstMac) orelse sdlan_util:is_multicast_mac(DstMac) of true -> @@ -349,7 +347,7 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = TargetMac = <<>>, ArpResponse = arp_packet:marshal(arp_packet:arp_response(ArpRequestPkt, TargetMac, TargetIp)), - #endpoint{hole = #hole{peer = {NatIp, NatPort}}} = maps:get(SrcMac, UsedMap), + #endpoint{hole = #hole{peer = {NatIp, NatPort}}} = maps:get(SrcMac, Endpoints), gen_udp:send(Sock, NatIp, NatPort, ArpResponse); error -> @@ -362,7 +360,7 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = _ -> ok end - end, UsedMap), + end, Endpoints), %% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat lager:debug("[sdlan_network] broadcast data networkd_id: ~p, src_mac: ~p, dst_mac: ~p", @@ -382,20 +380,20 @@ handle_cast({forward, _Sock, SrcMac, DstMac, _Packet}, State = #state{network_id {noreply, State}; %% 删除ip的占用并关闭channel -handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> +handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId, endpoints = Endpoints}) -> lager:debug("[sdlan_network] networkd_id: ~p, unregister Mac: ~p", [NetworkId, sdlan_util:format_mac(Mac)]), - case maps:take(Mac, UsedMap) of + case maps:take(Mac, Endpoints) of error -> {noreply, State}; - {#endpoint{channel_pid = ChannelPid, monitor_ref = MRef}, NUsedMap} -> + {#endpoint{channel_pid = ChannelPid, monitor_ref = MRef}, NEndpoints} -> is_reference(MRef) andalso demonitor(MRef), sdlan_channel:stop(ChannelPid, normal), - {noreply, State#state{used_map = NUsedMap}} + {noreply, State#state{endpoints = NEndpoints}} end; %% 需要判断,client是属于当前网络的 -handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{used_map = UsedMap}) -> - case maps:find(Mac, UsedMap) of +handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{endpoints = Endpoints}) -> + case maps:find(Mac, Endpoints) of {ok, Endpoint0 = #endpoint{client_id = ClientId0, ip = Ip, hole = OldHole}} when ClientId =:= ClientId0 -> case OldHole =:= undefined orelse (OldHole#hole.peer =/= Peer orelse OldHole#hole.nat_type =/= NatType) of true -> @@ -403,13 +401,13 @@ handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{ mac = Mac, ip = Ip }), - broadcast(?PACKET_EVENT_NAT_CHANGED, NatChangedEvent, Mac, UsedMap); + broadcast(?PACKET_EVENT_NAT_CHANGED, NatChangedEvent, Mac, Endpoints); false -> ok end, Endpoint = Endpoint0#endpoint{hole = #hole{peer = Peer, nat_type = NatType}, v6_info = V6Info}, - {noreply, State#state{used_map = maps:put(Mac, Endpoint, UsedMap)}}; + {noreply, State#state{endpoints = maps:put(Mac, Endpoint, Endpoints)}}; _ -> {noreply, State} end. @@ -425,15 +423,15 @@ handle_info({timeout, _, flow_report_ticker}, State = #state{network_id = Networ catch sdlan_api:network_forward_report(NetworkId, ForwardBytes), {noreply, State#state{forward_bytes = 0}}; -handle_info({'EXIT', _Pid, shutdown}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> +handle_info({'EXIT', _Pid, shutdown}, State = #state{network_id = NetworkId, endpoints = UsedMap}) -> lager:warning("[sdlan_network] network: ~p, get shutdown message", [NetworkId]), broadcast_shutdown(UsedMap), {stop, shutdown, State}; %% Channel进程退出, hole里面的数据也需要清理 -handle_info({'DOWN', _MRef, process, ChannelPid, Reason}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> +handle_info({'DOWN', _MRef, process, ChannelPid, Reason}, State = #state{network_id = NetworkId, endpoints = Endpoints}) -> lager:notice("[sdlan_network] network_id: ~p, channel_pid: ~p, close with reason: ~p", [NetworkId, ChannelPid, Reason]), - NUsedMap = maps:filter(fun(_, #endpoint{channel_pid = ChannelPid0}) -> ChannelPid =/= ChannelPid0 end, UsedMap), - {noreply, State#state{used_map = NUsedMap}}. + NUsedMap = maps:filter(fun(_, #endpoint{channel_pid = ChannelPid0}) -> ChannelPid =/= ChannelPid0 end, Endpoints), + {noreply, State#state{endpoints = NUsedMap}}. %% @private %% @doc This function is called by a gen_server when it is about to @@ -442,14 +440,14 @@ handle_info({'DOWN', _MRef, process, ChannelPid, Reason}, State = #state{network %% with Reason. The return value is ignored. -spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), State :: #state{}) -> term()). -terminate(Reason, #state{network_id = NetworkId, used_map = UsedMap}) -> +terminate(Reason, #state{network_id = NetworkId, endpoints = Endpoints}) -> lager:debug("[sdlan_network] network: ~p, will terminate with reason: ~p", [NetworkId, Reason]), - broadcast_shutdown(UsedMap), + broadcast_shutdown(Endpoints), %% 整个网络下的设备都需要重新连接 maps:foreach(fun(_, #endpoint{channel_pid = ChannelPid, monitor_ref = MRef}) -> is_reference(MRef) andalso demonitor(MRef), is_process_alive(ChannelPid) andalso sdlan_channel:stop(ChannelPid, normal) - end, UsedMap), + end, Endpoints), ok. %% @private