Compare commits
2 Commits
c89091c205
...
8d94244689
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d94244689 | |||
| be855d6985 |
@ -15,7 +15,7 @@
|
|||||||
-export([get_all_networks/0, get_network/1]).
|
-export([get_all_networks/0, get_network/1]).
|
||||||
-export([auth_token/3, node_online/3, node_offline/2, flow_report/5, network_forward_report/2, auth_network_code/3]).
|
-export([auth_token/3, node_online/3, node_offline/2, flow_report/5, network_forward_report/2, auth_network_code/3]).
|
||||||
|
|
||||||
-export([assign_ip_address/5]).
|
-export([assign_ip_address/3]).
|
||||||
|
|
||||||
-spec get_all_networks() -> {ok, [NetworkId :: integer()]} | {error, Reason :: any()}.
|
-spec get_all_networks() -> {ok, [NetworkId :: integer()]} | {error, Reason :: any()}.
|
||||||
get_all_networks() ->
|
get_all_networks() ->
|
||||||
@ -78,19 +78,25 @@ auth_network_code(ClientId, NetworkCode, Version) when is_binary(ClientId), is_b
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
%% 请求ip地址的分配
|
%% 请求ip地址的分配
|
||||||
assign_ip_address(NetworkId, ClientId, Mac, RetainIp, HostName) when is_integer(NetworkId), is_binary(ClientId), is_binary(Mac), is_integer(RetainIp), is_binary(HostName) ->
|
-spec assign_ip_address(NetworkId :: integer(), ClientId :: binary(), Mac :: binary()) -> {ok, map()} | {error, Reason :: any()}.
|
||||||
|
assign_ip_address(NetworkId, ClientId, Mac) when is_integer(NetworkId), is_binary(ClientId), is_binary(Mac) ->
|
||||||
Params = #{
|
Params = #{
|
||||||
<<"network_id">> => NetworkId,
|
<<"network_id">> => NetworkId,
|
||||||
<<"client_id">> => ClientId,
|
<<"client_id">> => ClientId,
|
||||||
<<"mac">> => Mac,
|
<<"mac">> => Mac
|
||||||
<<"retain_ip">> => RetainIp,
|
|
||||||
<<"host_name">> => HostName
|
|
||||||
},
|
},
|
||||||
case catch do_post("assign_ip_address", Params) of
|
case catch do_post("assign_ip_address", Params) of
|
||||||
{ok, Resp} ->
|
{ok, Resp} ->
|
||||||
case catch jiffy:decode(Resp, [return_maps]) of
|
case catch jiffy:decode(Resp, [return_maps]) of
|
||||||
Result when is_map(Result) ->
|
Json when is_map(Json) ->
|
||||||
|
case Json of
|
||||||
|
#{<<"result">> := Result} ->
|
||||||
{ok, Result};
|
{ok, Result};
|
||||||
|
#{<<"error">> := #{<<"message">> := Message}} ->
|
||||||
|
{error, Message};
|
||||||
|
_ ->
|
||||||
|
{error, <<"invalid response">>}
|
||||||
|
end;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
|
|||||||
@ -117,7 +117,7 @@ handle_cast(_Msg, State) ->
|
|||||||
|
|
||||||
%% 带上token或者网络id来注册
|
%% 带上token或者网络id来注册
|
||||||
handle_info({tcp, Sock, <<PacketId:32, ?PACKET_REGISTER_SUPER, Body/binary>>}, State=#state{transport = Transport, socket = Sock}) ->
|
handle_info({tcp, Sock, <<PacketId:32, ?PACKET_REGISTER_SUPER, Body/binary>>}, State=#state{transport = Transport, socket = Sock}) ->
|
||||||
#sdl_register_super{version = Version, client_id = ClientId, hostname = HostName, dev_addr = #sdl_dev_addr{net_addr = NetAddr0, mac = Mac}, network_code = NetworkCode, token = Token, pub_key = PubKey} = sdlan_pb:decode_msg(Body, sdl_register_super),
|
#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),
|
||||||
|
|
||||||
%% 参数检查
|
%% 参数检查
|
||||||
lager:debug("[sdlan_channel] client_id: ~p, public_key: ~p, token: ~p, network_code: ~p", [ClientId, PubKey, Token, NetworkCode]),
|
lager:debug("[sdlan_channel] client_id: ~p, public_key: ~p, token: ~p, network_code: ~p", [ClientId, PubKey, Token, NetworkCode]),
|
||||||
@ -140,7 +140,7 @@ handle_info({tcp, Sock, <<PacketId:32, ?PACKET_REGISTER_SUPER, Body/binary>>}, S
|
|||||||
%% 建立到network的对应关系
|
%% 建立到network的对应关系
|
||||||
case sdlan_network:get_pid(NetworkId) of
|
case sdlan_network:get_pid(NetworkId) of
|
||||||
NetworkPid when is_pid(NetworkPid) ->
|
NetworkPid when is_pid(NetworkPid) ->
|
||||||
try sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac, NetAddr0, HostName) of
|
try sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac) of
|
||||||
{ok, Domain, NetAddr, NetBitLen, AesKey} ->
|
{ok, Domain, NetAddr, NetBitLen, AesKey} ->
|
||||||
RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey),
|
RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey),
|
||||||
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
|
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/2]).
|
-export([start_link/2]).
|
||||||
-export([get_name/1, get_pid/1, assign_ip_addr/6, peer_info/3, unregister/3, debug_info/1, get_network_id/1, get_used_map/1]).
|
-export([get_name/1, get_pid/1, assign_ip_addr/4, peer_info/3, unregister/3, debug_info/1, get_network_id/1, get_used_map/1]).
|
||||||
-export([forward/5, update_hole/6, disable_client/2, get_channel/2, dropout_client/2, reload/1]).
|
-export([forward/5, update_hole/6, disable_client/2, get_channel/2, dropout_client/2]).
|
||||||
-export([test_event/1]).
|
-export([test_event/1]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
@ -33,9 +33,10 @@
|
|||||||
nat_type :: integer()
|
nat_type :: integer()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%% ip的使用信息, 记录主机的动态信息
|
%% ip的使用信息, 记录Node的运行时状态信息
|
||||||
-record(host, {
|
-record(endpoint, {
|
||||||
client_id :: binary(),
|
client_id :: binary(),
|
||||||
|
ip :: integer(),
|
||||||
channel_pid :: undefined | pid(),
|
channel_pid :: undefined | pid(),
|
||||||
monitor_ref :: undefined | reference(),
|
monitor_ref :: undefined | reference(),
|
||||||
hole :: undefined | #hole{},
|
hole :: undefined | #hole{},
|
||||||
@ -60,11 +61,7 @@
|
|||||||
%% 同一个网络下公用的密钥, 采用AES-256加密算法;随机生成
|
%% 同一个网络下公用的密钥, 采用AES-256加密算法;随机生成
|
||||||
aes_key :: binary(),
|
aes_key :: binary(),
|
||||||
|
|
||||||
%% ip分配器
|
%% 记录已经使用了的ip, #{mac :: integer() => #endpoint{}}
|
||||||
%% 记录当前网络下的全部ip地址
|
|
||||||
ips = [] :: [Ip :: integer()],
|
|
||||||
|
|
||||||
%% 记录已经使用了的ip, #{mac :: integer() => Host :: #host{}}
|
|
||||||
used_map = #{}
|
used_map = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
@ -84,14 +81,10 @@ get_pid(Id) when is_integer(Id) ->
|
|||||||
get_name(Id) when is_integer(Id) ->
|
get_name(Id) when is_integer(Id) ->
|
||||||
list_to_atom("sdlan_network:" ++ integer_to_list(Id)).
|
list_to_atom("sdlan_network:" ++ integer_to_list(Id)).
|
||||||
|
|
||||||
-spec reload(Pid :: pid()) -> ok | {error, Reason :: any()}.
|
-spec assign_ip_addr(Pid :: pid(), ChannelPid :: pid(), ClientId :: binary(), Mac :: binary()) ->
|
||||||
reload(Pid) when is_pid(Pid) ->
|
|
||||||
gen_server:call(Pid, reload).
|
|
||||||
|
|
||||||
-spec assign_ip_addr(Pid :: pid(), ChannelPid :: pid(), ClientId :: binary(), Mac :: binary(), NetAddr :: integer(), HostName :: binary()) ->
|
|
||||||
{ok, Domain :: binary(), NetAddr :: integer(), MaskLen :: integer(), AesKey :: binary()} | {error, Reason :: any()}.
|
{ok, Domain :: binary(), NetAddr :: integer(), MaskLen :: integer(), AesKey :: binary()} | {error, Reason :: any()}.
|
||||||
assign_ip_addr(Pid, ChannelPid, ClientId, Mac, NetAddr, HostName) when is_pid(Pid), is_pid(ChannelPid), is_binary(ClientId), is_binary(Mac), is_integer(NetAddr) ->
|
assign_ip_addr(Pid, ChannelPid, ClientId, Mac) when is_pid(Pid), is_pid(ChannelPid), is_binary(ClientId), is_binary(Mac) ->
|
||||||
gen_server:call(Pid, {assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr, HostName}).
|
gen_server:call(Pid, {assign_ip_addr, ChannelPid, ClientId, Mac}).
|
||||||
|
|
||||||
-spec get_network_id(Pid :: pid()) -> {ok, NetworkId :: integer()}.
|
-spec get_network_id(Pid :: pid()) -> {ok, NetworkId :: integer()}.
|
||||||
get_network_id(Pid) when is_pid(Pid) ->
|
get_network_id(Pid) when is_pid(Pid) ->
|
||||||
@ -160,8 +153,8 @@ init([Id]) when is_integer(Id) ->
|
|||||||
ignore;
|
ignore;
|
||||||
{ok, #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} ->
|
{ok, #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} ->
|
||||||
{IpAddr, MaskLen} = parse_ipaddr(IpAddr0),
|
{IpAddr, MaskLen} = parse_ipaddr(IpAddr0),
|
||||||
Ips = sdlan_ipaddr:ips(IpAddr, MaskLen),
|
|
||||||
AesKey = sdlan_util:rand_byte(32),
|
AesKey = sdlan_util:rand_byte(32),
|
||||||
|
|
||||||
%% 限流key
|
%% 限流key
|
||||||
ThrottleKey = list_to_atom("network_throttle:" ++ integer_to_list(Id)),
|
ThrottleKey = list_to_atom("network_throttle:" ++ integer_to_list(Id)),
|
||||||
%% 绑定到资源协调器
|
%% 绑定到资源协调器
|
||||||
@ -169,15 +162,9 @@ init([Id]) when is_integer(Id) ->
|
|||||||
|
|
||||||
%% 每分钟汇报一次转发的流量
|
%% 每分钟汇报一次转发的流量
|
||||||
erlang:start_timer(?FLOW_REPORT_INTERVAL, self(), flow_report_ticker),
|
erlang:start_timer(?FLOW_REPORT_INTERVAL, self(), flow_report_ticker),
|
||||||
|
|
||||||
%% 创建数据库表
|
|
||||||
create_mnesia_table(Id),
|
|
||||||
|
|
||||||
lager:debug("[sdlan_network] network: ~p, ips: ~p", [Id, lists:map(fun sdlan_ipaddr:int_to_ipv4/1, Ips)]),
|
|
||||||
|
|
||||||
sdlan_domain_regedit:insert(Domain),
|
sdlan_domain_regedit:insert(Domain),
|
||||||
|
|
||||||
{ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, owner_id = OwnerId, mask_len = MaskLen, ips = Ips, aes_key = AesKey, throttle_key = ThrottleKey}};
|
{ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, owner_id = OwnerId, mask_len = MaskLen, aes_key = AesKey, throttle_key = ThrottleKey}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
lager:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]),
|
lager:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]),
|
||||||
ignore
|
ignore
|
||||||
@ -193,58 +180,23 @@ init([Id]) when is_integer(Id) ->
|
|||||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||||
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
|
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
|
||||||
{stop, Reason :: term(), NewState :: #state{}}).
|
{stop, Reason :: term(), NewState :: #state{}}).
|
||||||
%% 重新加载网络信息
|
|
||||||
handle_call(reload, _From, State = #state{network_id = Id, ipaddr = OldIpAddr, mask_len = OldMarkLen, used_map = UsedMap}) ->
|
|
||||||
case sdlan_api:get_network(Id) of
|
|
||||||
{ok, #{<<"name">> := Name, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} ->
|
|
||||||
{IpAddr, MaskLen} = parse_ipaddr(IpAddr0),
|
|
||||||
case OldIpAddr =:= IpAddr andalso OldMarkLen =:= MaskLen of
|
|
||||||
true ->
|
|
||||||
{reply, ok, State#state{name = Name, owner_id = OwnerId}};
|
|
||||||
false ->
|
|
||||||
lager:debug("[sdlan_networkd] network_id: ~p, reload will close all channels", [Id]),
|
|
||||||
Ips = sdlan_ipaddr:ips(IpAddr, MaskLen),
|
|
||||||
%% 整个网络下的设备都需要重新连接
|
|
||||||
maps:foreach(fun(_, #host{channel_pid = ChannelPid, monitor_ref = MRef}) ->
|
|
||||||
is_reference(MRef) andalso demonitor(MRef),
|
|
||||||
is_process_alive(ChannelPid) andalso sdlan_channel:stop(ChannelPid, normal)
|
|
||||||
end, UsedMap),
|
|
||||||
%% 清理掉数据库中的数据
|
|
||||||
ok = client_model:delete_clients(Id),
|
|
||||||
|
|
||||||
{reply, ok, State#state{name = Name, ipaddr = IpAddr,
|
|
||||||
owner_id = OwnerId, mask_len = MaskLen, ips = Ips, used_map = maps:new()}}
|
|
||||||
end;
|
|
||||||
{error, Reason} ->
|
|
||||||
lager:warning("[sdlan_network] reload network: ~p, get error: ~p", [Id, Reason]),
|
|
||||||
{reply, {error, Reason}, State}
|
|
||||||
end;
|
|
||||||
|
|
||||||
%% 给客户端分配ip地址
|
%% 给客户端分配ip地址
|
||||||
handle_call({assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr0, HostName}, _From,
|
handle_call({assign_ip_addr, ChannelPid, ClientId, Mac}, _From,
|
||||||
State = #state{network_id = NetworkId, domain = Domain, ips = Ips, used_map = UsedMap, mask_len = MaskLen, aes_key = AesKey}) ->
|
State = #state{network_id = NetworkId, domain = Domain, used_map = UsedMap, mask_len = MaskLen, aes_key = AesKey}) ->
|
||||||
|
|
||||||
|
case sdlan_api:assign_ip_address(NetworkId, ClientId, Mac) of
|
||||||
|
{ok, #{<<"ip">> := Ip, <<"host_name">> := HostName}} ->
|
||||||
%% 分配ip地址的时候,以mac地址为唯一基准
|
%% 分配ip地址的时候,以mac地址为唯一基准
|
||||||
lager:debug("[sdlan_network] alloc_ip, network_id: ~p, ips: ~p, client_id: ~p, mac: ~p, net_addr: ~p",
|
lager:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, net_addr: ~p",
|
||||||
[NetworkId, Ips, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(NetAddr0)]),
|
[NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(Ip)]),
|
||||||
|
|
||||||
case client_model:alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0, HostName) of
|
|
||||||
{ok, Ip} ->
|
|
||||||
%% 关闭之前的channel
|
%% 关闭之前的channel
|
||||||
maybe_close_channel(maps:get(Mac, UsedMap, undefined)),
|
maybe_close_channel(maps:get(Mac, UsedMap, undefined)),
|
||||||
|
|
||||||
%% 添加域名->ip的映射关系
|
%% 添加域名->ip的映射关系
|
||||||
case HostName =/= <<>> of
|
sdlan_hostname_regedit:insert(HostName, Domain, Ip),
|
||||||
true ->
|
|
||||||
FullHostname = <<HostName/binary, ".", Domain/binary>>,
|
|
||||||
sdlan_hostname_regedit:insert(FullHostname, Ip);
|
|
||||||
false ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
|
|
||||||
%% 建立到新的channel之间的关系
|
%% 建立到新的channel之间的关系
|
||||||
MRef = monitor(process, ChannelPid),
|
MRef = monitor(process, ChannelPid),
|
||||||
NUsedMap = maps:put(Mac, #host{client_id = ClientId, channel_pid = ChannelPid, monitor_ref = MRef}, UsedMap),
|
NUsedMap = maps:put(Mac, #endpoint{client_id = ClientId, ip = Ip, channel_pid = ChannelPid, monitor_ref = MRef}, UsedMap),
|
||||||
|
|
||||||
{reply, {ok, Domain, Ip, MaskLen, AesKey}, State#state{used_map = NUsedMap}};
|
{reply, {ok, Domain, Ip, MaskLen, AesKey}, State#state{used_map = NUsedMap}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
@ -252,7 +204,7 @@ handle_call({assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr0, HostName}, _Fr
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) ->
|
handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) ->
|
||||||
UsedInfos = maps:map(fun(_, #host{hole = Hole, v6_info = V6Info}) ->
|
UsedInfos = maps:map(fun(_, #endpoint{hole = Hole, v6_info = V6Info}) ->
|
||||||
HoleMap = case Hole of
|
HoleMap = case Hole of
|
||||||
#hole{peer = {NatIp, NatPort}} ->
|
#hole{peer = {NatIp, NatPort}} ->
|
||||||
#{
|
#{
|
||||||
@ -279,40 +231,31 @@ handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) ->
|
|||||||
|
|
||||||
%% client设置为禁止状态,不允许重连
|
%% client设置为禁止状态,不允许重连
|
||||||
handle_call({disable_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) ->
|
handle_call({disable_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) ->
|
||||||
case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
||||||
{value, {Mac, #host{channel_pid = ChannelPid, monitor_ref = MRef}}} ->
|
{value, {Mac, #endpoint{channel_pid = ChannelPid, monitor_ref = MRef}}} ->
|
||||||
is_reference(MRef) andalso demonitor(MRef),
|
is_reference(MRef) andalso demonitor(MRef),
|
||||||
sdlan_channel:stop(ChannelPid, disable),
|
sdlan_channel:stop(ChannelPid, disable),
|
||||||
NUsedMap = maps:remove(Mac, UsedMap),
|
NUsedMap = maps:remove(Mac, UsedMap),
|
||||||
%% 将客户端设置为禁止状态
|
|
||||||
client_model:disable_client(NetworkId, ClientId),
|
|
||||||
|
|
||||||
{reply, ok, State#state{used_map = NUsedMap}};
|
{reply, ok, State#state{used_map = NUsedMap}};
|
||||||
false ->
|
false ->
|
||||||
{reply, error, State}
|
{reply, error, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call({get_channel, ClientId}, _From, State = #state{used_map = UsedMap}) ->
|
handle_call({get_channel, ClientId}, _From, State = #state{used_map = UsedMap}) ->
|
||||||
case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
||||||
{value, {_Ip, #host{channel_pid = ChannelPid}}} ->
|
{value, {_Ip, #endpoint{channel_pid = ChannelPid}}} ->
|
||||||
{reply, {ok, ChannelPid}, State};
|
{reply, {ok, ChannelPid}, State};
|
||||||
false ->
|
false ->
|
||||||
{reply, error, State}
|
{reply, error, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% 区别在于是否关闭掉channel, 这里是在网络迁移中的功能; drop的时候需要从当前网络中移除
|
%% 区别在于是否关闭掉channel, 这里是在网络迁移中的功能; drop的时候需要从当前网络中移除
|
||||||
handle_call({dropout_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) ->
|
handle_call({dropout_client, ClientId}, _From, State = #state{used_map = UsedMap}) ->
|
||||||
case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
case lists:search(fun({_, #endpoint{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of
|
||||||
{value, {Mac, #host{channel_pid = ChannelPid, monitor_ref = MRef}}} ->
|
{value, {Mac, #endpoint{channel_pid = ChannelPid, monitor_ref = MRef}}} ->
|
||||||
is_reference(MRef) andalso demonitor(MRef),
|
is_reference(MRef) andalso demonitor(MRef),
|
||||||
NUsedMap = maps:remove(Mac, UsedMap),
|
NUsedMap = maps:remove(Mac, UsedMap),
|
||||||
%% 从数据库删除
|
{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 ->
|
false ->
|
||||||
{reply, error, State}
|
{reply, error, State}
|
||||||
end;
|
end;
|
||||||
@ -323,10 +266,10 @@ handle_call(get_network_id, _From, State = #state{network_id = NetworkId}) ->
|
|||||||
%% 网络存在的nat_peer信息
|
%% 网络存在的nat_peer信息
|
||||||
handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMap}) ->
|
handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMap}) ->
|
||||||
case maps:find(DstMac, UsedMap) of
|
case maps:find(DstMac, UsedMap) of
|
||||||
{ok, #host{channel_pid = DstChannelPid, hole = #hole{peer = DstNatPeer, nat_type = DstNatType}, v6_info = DstV6Info}} ->
|
{ok, #endpoint{channel_pid = DstChannelPid, hole = #hole{peer = DstNatPeer, nat_type = DstNatType}, v6_info = DstV6Info}} ->
|
||||||
%% 让目标服务器发送sendRegister事件(2024-06-25 新增,提高打洞的成功率)
|
%% 让目标服务器发送sendRegister事件(2024-06-25 新增,提高打洞的成功率)
|
||||||
case maps:get(SrcMac, UsedMap, undefined) of
|
case maps:get(SrcMac, UsedMap, undefined) of
|
||||||
#host{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = NatType}, v6_info = SrcV6Info} ->
|
#endpoint{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = NatType}, v6_info = SrcV6Info} ->
|
||||||
Event = sdlan_pb:encode_msg(#sdl_send_register_event {
|
Event = sdlan_pb:encode_msg(#sdl_send_register_event {
|
||||||
dst_mac = SrcMac,
|
dst_mac = SrcMac,
|
||||||
nat_ip = sdlan_ipaddr:ipv4_to_int(SrcNatIp),
|
nat_ip = sdlan_ipaddr:ipv4_to_int(SrcNatIp),
|
||||||
@ -343,21 +286,13 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMa
|
|||||||
{reply, error, State}
|
{reply, error, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, ips = Ips, used_map = UsedMap}) ->
|
handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, used_map = UsedMap}) ->
|
||||||
Reply = #{
|
Reply = #{
|
||||||
<<"network_id">> => NetworkId,
|
<<"network_id">> => NetworkId,
|
||||||
<<"ipaddr">> => IpAddr,
|
<<"ipaddr">> => IpAddr,
|
||||||
<<"mask_len">> => MaskLen,
|
<<"mask_len">> => MaskLen,
|
||||||
<<"owner_id">> => OwnerId,
|
<<"owner_id">> => OwnerId,
|
||||||
<<"ips">> => lists:map(fun sdlan_ipaddr:int_to_ipv4/1, Ips),
|
<<"used_ips">> => lists:map(fun format_endpoint/1, maps:to_list(UsedMap))
|
||||||
<<"used_ips">> => lists:map(fun({_, Host = #host{client_id = ClientId}}) ->
|
|
||||||
case client_model:get_client(NetworkId, ClientId) of
|
|
||||||
error ->
|
|
||||||
#{};
|
|
||||||
{ok, #client{mac = Mac, ip = Ip}} ->
|
|
||||||
format_host(Host, Ip, Mac)
|
|
||||||
end
|
|
||||||
end, maps:to_list(UsedMap))
|
|
||||||
},
|
},
|
||||||
{reply, Reply, State}.
|
{reply, Reply, State}.
|
||||||
|
|
||||||
@ -373,29 +308,19 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id =
|
|||||||
|
|
||||||
PacketBytes = byte_size(Packet),
|
PacketBytes = byte_size(Packet),
|
||||||
case maps:find(DstMac, UsedMap) of
|
case maps:find(DstMac, UsedMap) of
|
||||||
{ok, #host{hole = #hole{peer = Peer = {Ip, Port}}}} ->
|
{ok, #endpoint{hole = #hole{peer = Peer = {Ip, Port}}}} ->
|
||||||
case throttle:check(sdlan_network, ThrottleKey) of
|
case limiting_check(ThrottleKey) of
|
||||||
{ok, _RestCount, _LeftToReset} ->
|
pass ->
|
||||||
%% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat
|
%% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat
|
||||||
lager:debug("[sdlan_network] forward data networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole: ~p",
|
lager:debug("[sdlan_network] forward data networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole: ~p",
|
||||||
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), Peer]),
|
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), Peer]),
|
||||||
|
|
||||||
gen_udp:send(Sock, Ip, Port, Packet),
|
gen_udp:send(Sock, Ip, Port, Packet),
|
||||||
{noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}};
|
{noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}};
|
||||||
{limit_exceeded, 0, _LeftToReset} ->
|
denied ->
|
||||||
%% 尝试获取其他网络是否有让渡的资源
|
|
||||||
case sdlan_network_coordinator:checkout() of
|
|
||||||
ok ->
|
|
||||||
lager:debug("[sdlan_network] use release forward data networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole: ~p",
|
|
||||||
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), Peer]),
|
|
||||||
|
|
||||||
gen_udp:send(Sock, Ip, Port, Packet),
|
|
||||||
{noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}};
|
|
||||||
error ->
|
|
||||||
lager:notice("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, rate limited, discard",
|
lager:notice("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, rate limited, discard",
|
||||||
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
|
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
|
||||||
{noreply, State}
|
{noreply, State}
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole not found",
|
lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole not found",
|
||||||
@ -408,6 +333,7 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id =
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
%% 网络数据转发, ip广播或组播, 不限流
|
%% 网络数据转发, ip广播或组播, 不限流
|
||||||
|
%% TODO 需要处理arp请求,arp请求就不要广播出去了,network是知道目标的ip信息的
|
||||||
handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, forward_bytes = ForwardBytes})
|
handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, forward_bytes = ForwardBytes})
|
||||||
when is_map_key(SrcMac, UsedMap) ->
|
when is_map_key(SrcMac, UsedMap) ->
|
||||||
%% 广播地址和组播地址,需要转发到整个网络
|
%% 广播地址和组播地址,需要转发到整个网络
|
||||||
@ -415,10 +341,9 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id =
|
|||||||
true ->
|
true ->
|
||||||
PacketBytes = byte_size(Packet),
|
PacketBytes = byte_size(Packet),
|
||||||
%% 消息广播
|
%% 消息广播
|
||||||
maps:foreach(fun(Mac, #host{hole = Hole}) ->
|
maps:foreach(fun(Mac, #endpoint{hole = Hole}) ->
|
||||||
case {Mac =/= SrcMac, Hole} of
|
case {Mac =/= SrcMac, Hole} of
|
||||||
{true, #hole{peer = {NatIp, NatPort}}} ->
|
{true, #hole{peer = {NatIp, NatPort}}} ->
|
||||||
lager:debug("[sdlan_network] call me here"),
|
|
||||||
gen_udp:send(Sock, NatIp, NatPort, Packet);
|
gen_udp:send(Sock, NatIp, NatPort, Packet);
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
@ -447,16 +372,16 @@ handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId,
|
|||||||
case maps:take(Mac, UsedMap) of
|
case maps:take(Mac, UsedMap) of
|
||||||
error ->
|
error ->
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
{#host{channel_pid = ChannelPid, monitor_ref = MRef}, NUsedMap} ->
|
{#endpoint{channel_pid = ChannelPid, monitor_ref = MRef}, NUsedMap} ->
|
||||||
is_reference(MRef) andalso demonitor(MRef),
|
is_reference(MRef) andalso demonitor(MRef),
|
||||||
sdlan_channel:stop(ChannelPid, normal),
|
sdlan_channel:stop(ChannelPid, normal),
|
||||||
{noreply, State#state{used_map = NUsedMap}}
|
{noreply, State#state{used_map = NUsedMap}}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
%% 需要判断,client是属于当前网络的
|
%% 需要判断,client是属于当前网络的
|
||||||
handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{network_id = NetworkId, used_map = UsedMap}) ->
|
handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{used_map = UsedMap}) ->
|
||||||
case {maps:find(Mac, UsedMap), client_model:get_client(NetworkId, ClientId)} of
|
case maps:find(Mac, UsedMap) of
|
||||||
{{ok, Host0 = #host{client_id = ClientId0, hole = OldHole}}, {ok, #client{ip = Ip}}} when ClientId =:= ClientId0 ->
|
{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
|
case OldHole =:= undefined orelse (OldHole#hole.peer =/= Peer orelse OldHole#hole.nat_type =/= NatType) of
|
||||||
true ->
|
true ->
|
||||||
NatChangedEvent = sdlan_pb:encode_msg(#sdl_nat_changed_event{
|
NatChangedEvent = sdlan_pb:encode_msg(#sdl_nat_changed_event{
|
||||||
@ -467,9 +392,9 @@ handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{
|
|||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
Host = Host0#host{hole = #hole{peer = Peer, nat_type = NatType}, v6_info = V6Info},
|
Endpoint = Endpoint0#endpoint{hole = #hole{peer = Peer, nat_type = NatType}, v6_info = V6Info},
|
||||||
|
|
||||||
{noreply, State#state{used_map = maps:put(Mac, Host, UsedMap)}};
|
{noreply, State#state{used_map = maps:put(Mac, Endpoint, UsedMap)}};
|
||||||
_ ->
|
_ ->
|
||||||
{noreply, State}
|
{noreply, State}
|
||||||
end.
|
end.
|
||||||
@ -492,7 +417,7 @@ handle_info({'EXIT', _Pid, shutdown}, State = #state{network_id = NetworkId, use
|
|||||||
%% Channel进程退出, hole里面的数据也需要清理
|
%% 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, used_map = UsedMap}) ->
|
||||||
lager:notice("[sdlan_network] network_id: ~p, channel_pid: ~p, close with reason: ~p", [NetworkId, ChannelPid, Reason]),
|
lager:notice("[sdlan_network] network_id: ~p, channel_pid: ~p, close with reason: ~p", [NetworkId, ChannelPid, Reason]),
|
||||||
NUsedMap = maps:filter(fun(_, #host{channel_pid = ChannelPid0}) -> ChannelPid =/= ChannelPid0 end, UsedMap),
|
NUsedMap = maps:filter(fun(_, #endpoint{channel_pid = ChannelPid0}) -> ChannelPid =/= ChannelPid0 end, UsedMap),
|
||||||
{noreply, State#state{used_map = NUsedMap}}.
|
{noreply, State#state{used_map = NUsedMap}}.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
@ -505,6 +430,11 @@ handle_info({'DOWN', _MRef, process, ChannelPid, Reason}, State = #state{network
|
|||||||
terminate(Reason, #state{network_id = NetworkId, used_map = UsedMap}) ->
|
terminate(Reason, #state{network_id = NetworkId, used_map = UsedMap}) ->
|
||||||
lager:debug("[sdlan_network] network: ~p, will terminate with reason: ~p", [NetworkId, Reason]),
|
lager:debug("[sdlan_network] network: ~p, will terminate with reason: ~p", [NetworkId, Reason]),
|
||||||
broadcast_shutdown(UsedMap),
|
broadcast_shutdown(UsedMap),
|
||||||
|
%% 整个网络下的设备都需要重新连接
|
||||||
|
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),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
@ -519,21 +449,23 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
|
|||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
%% 创建数据库表
|
-spec limiting_check(ThrottleKey :: any()) -> pass | denied.
|
||||||
-spec create_mnesia_table(NetworkId :: integer()) -> no_return().
|
limiting_check(ThrottleKey) ->
|
||||||
create_mnesia_table(NetworkId) when is_integer(NetworkId) ->
|
case throttle:check(sdlan_network, ThrottleKey) of
|
||||||
Tab = client_model:get_table_name(NetworkId),
|
{ok, _RestCount, _LeftToReset} ->
|
||||||
Tables = mnesia:system_info(tables),
|
pass;
|
||||||
case lists:member(Tab, Tables) of
|
{limit_exceeded, 0, _LeftToReset} ->
|
||||||
true ->
|
%% 尝试获取其他网络是否有让渡的资源
|
||||||
ok;
|
case sdlan_network_coordinator:checkout() of
|
||||||
false ->
|
ok ->
|
||||||
Res = client_model:create_table(Tab),
|
pass;
|
||||||
lager:debug("[sdlan_network] create table result: ~p", [Res])
|
error ->
|
||||||
|
denied
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec maybe_close_channel(undefined | #host{}) -> no_return().
|
-spec maybe_close_channel(undefined | #endpoint{}) -> no_return().
|
||||||
maybe_close_channel(#host{channel_pid = ChannelPid0, monitor_ref = MRef0}) ->
|
maybe_close_channel(#endpoint{channel_pid = ChannelPid0, monitor_ref = MRef0}) ->
|
||||||
case is_pid(ChannelPid0) andalso is_process_alive(ChannelPid0) of
|
case is_pid(ChannelPid0) andalso is_process_alive(ChannelPid0) of
|
||||||
true ->
|
true ->
|
||||||
is_reference(MRef0) andalso demonitor(MRef0),
|
is_reference(MRef0) andalso demonitor(MRef0),
|
||||||
@ -546,7 +478,7 @@ maybe_close_channel(_) ->
|
|||||||
|
|
||||||
-spec broadcast(EventType :: integer(), Event :: binary(), ExcludeMac :: binary(), UsedMap :: map()) -> no_return().
|
-spec broadcast(EventType :: integer(), Event :: binary(), ExcludeMac :: binary(), UsedMap :: map()) -> no_return().
|
||||||
broadcast(EventType, Event, ExcludeMac, UsedMap) when is_map(UsedMap), is_binary(ExcludeMac), is_integer(EventType), is_binary(Event) ->
|
broadcast(EventType, Event, ExcludeMac, UsedMap) when is_map(UsedMap), is_binary(ExcludeMac), is_integer(EventType), is_binary(Event) ->
|
||||||
maps:foreach(fun(Mac, #host{channel_pid = ChannelPid}) ->
|
maps:foreach(fun(Mac, #endpoint{channel_pid = ChannelPid}) ->
|
||||||
case is_process_alive(ChannelPid) andalso ExcludeMac /= Mac of
|
case is_process_alive(ChannelPid) andalso ExcludeMac /= Mac of
|
||||||
true ->
|
true ->
|
||||||
sdlan_channel:send_event(ChannelPid, EventType, Event);
|
sdlan_channel:send_event(ChannelPid, EventType, Event);
|
||||||
@ -556,7 +488,7 @@ broadcast(EventType, Event, ExcludeMac, UsedMap) when is_map(UsedMap), is_binary
|
|||||||
end, UsedMap).
|
end, UsedMap).
|
||||||
|
|
||||||
broadcast_shutdown(UsedMap) when is_map(UsedMap) ->
|
broadcast_shutdown(UsedMap) when is_map(UsedMap) ->
|
||||||
maps:foreach(fun(_, #host{channel_pid = ChannelPid}) ->
|
maps:foreach(fun(_, #endpoint{channel_pid = ChannelPid}) ->
|
||||||
case is_process_alive(ChannelPid) of
|
case is_process_alive(ChannelPid) of
|
||||||
true ->
|
true ->
|
||||||
NetworkShutdownEvent = sdlan_pb:encode_msg(#sdl_network_shutdown_event {
|
NetworkShutdownEvent = sdlan_pb:encode_msg(#sdl_network_shutdown_event {
|
||||||
@ -580,8 +512,8 @@ parse_ipaddr(IpAddr0) when is_binary(IpAddr0) ->
|
|||||||
{IpAddr0, 24}
|
{IpAddr0, 24}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec format_host(Host :: #host{}, Ip :: integer(), Mac :: binary()) -> map().
|
-spec format_endpoint({Mac :: binary(), Host :: #endpoint{}}) -> map().
|
||||||
format_host(#host{client_id = ClientId, hole = Hole, v6_info = V6Info}, Ip, Mac) when is_integer(Ip), is_binary(Mac) ->
|
format_endpoint({Mac, #endpoint{client_id = ClientId, ip = Ip, hole = Hole, v6_info = V6Info}}) ->
|
||||||
HoleMap = case Hole of
|
HoleMap = case Hole of
|
||||||
undefined ->
|
undefined ->
|
||||||
#{};
|
#{};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user