From 99752ddd2e41e72f7cdc53dc4d1c4af3b50a85cd Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Sat, 13 Dec 2025 20:33:40 +0800 Subject: [PATCH] fix host name --- apps/sdlan/include/sdlan_tables.hrl | 1 + apps/sdlan/src/http_handler/node_handler.erl | 4 +- apps/sdlan/src/mnesia/client_model.erl | 60 +++++++++++++------- apps/sdlan/src/sdlan_channel.erl | 18 ++++-- apps/sdlan/src/sdlan_network.erl | 13 +++-- 5 files changed, 62 insertions(+), 34 deletions(-) diff --git a/apps/sdlan/include/sdlan_tables.hrl b/apps/sdlan/include/sdlan_tables.hrl index 355670f..7bafce0 100644 --- a/apps/sdlan/include/sdlan_tables.hrl +++ b/apps/sdlan/include/sdlan_tables.hrl @@ -13,6 +13,7 @@ client_id :: binary(), mac :: binary(), ip :: integer(), + host_name :: binary(), %% 当前状态 status = normal :: normal | disabled }). \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/node_handler.erl b/apps/sdlan/src/http_handler/node_handler.erl index 9a68acb..e85c13f 100644 --- a/apps/sdlan/src/http_handler/node_handler.erl +++ b/apps/sdlan/src/http_handler/node_handler.erl @@ -45,8 +45,8 @@ handle_request("POST", "/node/move", _, #{<<"client_id">> := ClientId, <<"from_n case {sdlan_network:get_pid(FromNetworkId), sdlan_network:get_pid(ToNetworkId)} of {FromPid, ToPid} when is_pid(FromPid), is_pid(ToPid) -> case sdlan_network:dropout_client(FromPid, ClientId) of - {ok, ChannelPid} -> - Ref = sdlan_channel:move_network(ChannelPid, self(), ToPid), + {ok, ChannelPid, HostName} -> + Ref = sdlan_channel:move_network(ChannelPid, self(), ToPid, HostName), receive {command_reply, Ref, {error, Reason}} -> lager:warning("[node_handler] client_id: ~p, move network from: ~p, to: ~p, get error: ~p", [ClientId, FromPid, ToPid, Reason]), diff --git a/apps/sdlan/src/mnesia/client_model.erl b/apps/sdlan/src/mnesia/client_model.erl index 9187616..306d3d4 100644 --- a/apps/sdlan/src/mnesia/client_model.erl +++ b/apps/sdlan/src/mnesia/client_model.erl @@ -13,7 +13,7 @@ %% API -export([create_table/1, get_table_name/1]). --export([get_clients/1, get_client/2, delete_clients/1, delete_client/2, disable_client/2, alloc_ip/5]). +-export([get_clients/1, get_client/2, delete_clients/1, delete_client/2, disable_client/2, alloc_ip/6]). -export([debug/1]). create_table(Tab) when is_atom(Tab) -> @@ -58,12 +58,23 @@ delete_clients(NetworkId) when is_integer(NetworkId) -> {error, Reason} end. --spec delete_client(NetworkId :: integer(), ClientId :: binary()) -> ok | {error, Reason :: any()}. +-spec delete_client(NetworkId :: integer(), ClientId :: binary()) -> {ok, Client :: #client{}} | {error, Reason :: any()}. delete_client(NetworkId, ClientId) when is_integer(NetworkId), is_binary(ClientId) -> Tab = get_table_name(NetworkId), - case mnesia:transaction(fun() -> mnesia:delete(Tab, ClientId, write) end) of - {'atomic', ok} -> - ok; + + Fun = fun() -> + case mnesia:read(Tab, ClientId, write) of + [] -> + mnesia:abort(not_found); + [Record] -> + mnesia:delete(Tab, ClientId, write), + {ok, Record} + end + end, + + case mnesia:transaction(Fun) of + {'atomic', {ok, Client}} -> + {ok, Client}; {'aborted', Reason} -> {error, Reason} end. @@ -88,16 +99,16 @@ disable_client(NetworkId, ClientId) when is_integer(NetworkId), is_binary(Client end. %% 分配ip地址的时候,以mac地址为唯一基准 --spec alloc_ip(NetworkId :: integer(), Ips :: list(), ClientId :: binary(), Mac :: binary(), NetAddr0 :: integer()) -> +-spec alloc_ip(NetworkId :: integer(), Ips :: list(), ClientId :: binary(), Mac :: binary(), NetAddr0 :: integer(), HostName :: binary()) -> {ok, Ip :: integer()} | {error, Reason :: any()}. -alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0) when is_binary(ClientId), is_integer(NetAddr0), is_binary(Mac) -> - case mnesia:transaction(fun() -> alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0) end) of +alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0, HostName) when is_binary(ClientId), is_integer(NetAddr0), is_binary(Mac), is_binary(HostName) -> + case mnesia:transaction(fun() -> alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0, HostName) end) of {'atomic', Res} -> {ok, Res}; {'aborted', Reason} -> {error, Reason} end. -alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0) -> +alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0, HostName) -> Tab = get_table_name(NetworkId), case mnesia:read(Tab, ClientId) of @@ -107,21 +118,28 @@ alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0) -> [#client{status = disabled}] -> mnesia:abort(client_disabled); [] -> - UsedIps = mnesia:foldl(fun(#client{ip = Ip0}, Acc) -> [Ip0|Acc] end, [], Tab), - case lists:member(NetAddr0, Ips) andalso not lists:member(NetAddr0, UsedIps) of + {UsedIps, UsedHostNames} = mnesia:foldl(fun(#client{ip = Ip0, host_name = HostName0}, {IpAcc, HostNameAcc}) -> + {[Ip0|IpAcc], [HostName0|HostNameAcc]} + end, {[], []}, Tab), + case HostName =/= <<>> andalso lists:member(HostName, UsedHostNames) of true -> - %% 如果ip没有被占用,则分配給当前请求 - Client = #client{client_id = ClientId, mac = Mac, ip = NetAddr0}, - ok = mnesia:write(Tab, Client, write), - NetAddr0; + mnesia:abort(host_name_used); false -> - case Ips -- UsedIps of - [] -> - mnesia:abort(no_ip); - [Ip|_] -> - Client = #client{client_id = ClientId, mac = Mac, ip = Ip, status = normal}, + case lists:member(NetAddr0, Ips) andalso not lists:member(NetAddr0, UsedIps) of + true -> + %% 如果ip没有被占用,则分配給当前请求 + Client = #client{client_id = ClientId, mac = Mac, ip = NetAddr0, host_name = HostName, status = normal}, ok = mnesia:write(Tab, Client, write), - Ip + NetAddr0; + false -> + case Ips -- UsedIps of + [] -> + mnesia:abort(no_ip); + [Ip|_] -> + Client = #client{client_id = ClientId, mac = Mac, ip = Ip, host_name = HostName, status = normal}, + ok = mnesia:write(Tab, Client, write), + Ip + end end end end. diff --git a/apps/sdlan/src/sdlan_channel.erl b/apps/sdlan/src/sdlan_channel.erl index a5fd7c6..5749d76 100644 --- a/apps/sdlan/src/sdlan_channel.erl +++ b/apps/sdlan/src/sdlan_channel.erl @@ -28,6 +28,8 @@ -define(NAK_NETWORK_FAULT, 4). %% 内部错误 -define(NAK_INTERNAL_FAULT, 5). +%% hostname被占用 +-define(NAK_HOSTNAME_USED, 6). %% 升级策略 -define(UPGRADE_NONE, 0). @@ -36,7 +38,7 @@ %% API -export([start_link/4]). --export([publish_command/4, send_event/3, stop/2, move_network/3]). +-export([publish_command/4, send_event/3, stop/2, move_network/4]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -75,10 +77,10 @@ publish_command(Pid, ReceiverPid, CommandType, Msg) when is_pid(Pid), is_pid(Rec Ref. %% 网络迁移是一种特殊的指令信息,需要单独处理 --spec move_network(Pid :: pid(), ReceiverPid :: pid(), NetworkPid :: pid()) -> Ref :: reference(). -move_network(Pid, ReceiverPid, NetworkPid) when is_pid(Pid), is_pid(ReceiverPid), is_pid(NetworkPid) -> +-spec move_network(Pid :: pid(), ReceiverPid :: pid(), NetworkPid :: pid(), HostName :: binary()) -> Ref :: reference(). +move_network(Pid, ReceiverPid, NetworkPid, HostName) when is_pid(Pid), is_pid(ReceiverPid), is_pid(NetworkPid), is_binary(HostName) -> Ref = make_ref(), - Pid ! {move_network, ReceiverPid, Ref, NetworkPid}, + Pid ! {move_network, ReceiverPid, Ref, NetworkPid, HostName}, Ref. %% 向通道中写入消息 @@ -177,6 +179,10 @@ handle_info({tcp, Sock, <>}, S lager:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: no_ip", [ClientId, Token]), Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NO_IP, <<"No Ip address">>)), {stop, normal, State}; + {error, host_name_used} -> + lager:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: host_name_used", [ClientId, Token]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_HOSTNAME_USED, <<"Host Name Used">>)), + {stop, normal, State}; {error, client_disabled} -> lager:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: client_disabled", [ClientId, Token]), Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, <<"Client Connection Disable">>)), @@ -249,11 +255,11 @@ handle_info({timeout, _, ping_ticker}, State = #state{client_id = ClientId, ping end; %% 重新加入网络 -handle_info({move_network, ReceiverPid, Ref, NetworkPid}, +handle_info({move_network, ReceiverPid, Ref, NetworkPid, HostName}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, mac = Mac, pub_key = PubKey, packet_id = PacketId, inflight = Inflight, is_registered = true}) -> %% 建立到network的对应关系 - case sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac, 0) of + case sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac, 0, HostName) of {ok, Domain, NetAddr, NetBitLen, AesKey} -> 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 e605028..39f3175 100644 --- a/apps/sdlan/src/sdlan_network.erl +++ b/apps/sdlan/src/sdlan_network.erl @@ -124,7 +124,7 @@ get_channel(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) -> gen_server:call(Pid, {get_channel, ClientId}). %% 剔除client_id,channel不关闭; channel会被重新绑定到其他的network里面 --spec dropout_client(Pid :: pid(), ClientId :: binary()) -> {ok, ChannelPid :: pid()} | error. +-spec dropout_client(Pid :: pid(), ClientId :: binary()) -> {ok, ChannelPid :: pid(), HostName :: binary()} | error. dropout_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) -> gen_server:call(Pid, {dropout_client, ClientId}). @@ -226,7 +226,7 @@ handle_call({assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr0, HostName}, _Fr lager:debug("[sdlan_network] alloc_ip, network_id: ~p, ips: ~p, client_id: ~p, mac: ~p, net_addr: ~p", [NetworkId, Ips, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(NetAddr0)]), - case client_model:alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0) of + case client_model:alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0, HostName) of {ok, Ip} -> %% 关闭之前的channel maybe_close_channel(maps:get(Mac, UsedMap, undefined)), @@ -296,9 +296,12 @@ handle_call({dropout_client, ClientId}, _From, State = #state{network_id = Netwo is_reference(MRef) andalso demonitor(MRef), NUsedMap = maps:remove(Mac, UsedMap), %% 从数据库删除 - client_model:delete_client(NetworkId, ClientId), - - {reply, {ok, ChannelPid}, State#state{used_map = NUsedMap}}; + case client_model:delete_client(NetworkId, ClientId) of + {ok, #client{host_name = HostName}} -> + {reply, {ok, ChannelPid, HostName}, State#state{used_map = NUsedMap}}; + {error, _} -> + {reply, error, State} + end; false -> {reply, error, State} end;