fix network
This commit is contained in:
parent
a4f2ed8428
commit
eb11c05ba5
@ -15,23 +15,6 @@
|
|||||||
%% API
|
%% API
|
||||||
-export([handle_request/4]).
|
-export([handle_request/4]).
|
||||||
|
|
||||||
handle_request("POST", "/node/list", _, #{<<"network_id">> := NetworkId}) when NetworkId > 0 ->
|
|
||||||
Pid = sdlan_network:get_pid(NetworkId),
|
|
||||||
UsedMap = sdlan_network:get_used_map(Pid),
|
|
||||||
|
|
||||||
Clients = client_model:get_clients(NetworkId),
|
|
||||||
ClientInfos = lists:map(fun(#client{client_id = ClientId, mac = Mac, ip = Ip, status = Status}) ->
|
|
||||||
Info = #{
|
|
||||||
<<"client_id">> => ClientId,
|
|
||||||
<<"mac">> => Mac,
|
|
||||||
<<"ip">> => sdlan_ipaddr:int_to_ipv4(Ip),
|
|
||||||
<<"status">> => atom_to_binary(Status)
|
|
||||||
},
|
|
||||||
maps:merge(Info, maps:get(Mac, UsedMap, #{}))
|
|
||||||
end, Clients),
|
|
||||||
|
|
||||||
{ok, 200, sdlan_util:json_data(ClientInfos)};
|
|
||||||
|
|
||||||
handle_request("POST", "/node/disable", _, #{<<"network_id">> := NetworkId, <<"client_id">> := ClientId}) when NetworkId > 0 ->
|
handle_request("POST", "/node/disable", _, #{<<"network_id">> := NetworkId, <<"client_id">> := ClientId}) when NetworkId > 0 ->
|
||||||
case sdlan_network:get_pid(NetworkId) of
|
case sdlan_network:get_pid(NetworkId) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/2]).
|
-export([start_link/2]).
|
||||||
-export([get_name/1, get_pid/1, lookup_pid/1, attach/6, peer_info/3, unregister/3, debug_info/1, get_network_id/1, get_used_map/1, arp_query/2]).
|
-export([get_name/1, get_pid/1, lookup_pid/1, attach/6, peer_info/3, unregister/3, debug_info/1, get_network_id/1, arp_query/2]).
|
||||||
-export([forward/5, update_hole/6, disable_client/2, dropout_client/2]).
|
-export([forward/5, update_hole/6, disable_client/2, dropout_client/2]).
|
||||||
-export([test_event/1]).
|
-export([test_event/1]).
|
||||||
|
|
||||||
@ -38,6 +38,7 @@
|
|||||||
%% ip的使用信息, 记录Node的运行时状态信息
|
%% ip的使用信息, 记录Node的运行时状态信息
|
||||||
-record(endpoint, {
|
-record(endpoint, {
|
||||||
client_id :: binary(),
|
client_id :: binary(),
|
||||||
|
mac :: binary(),
|
||||||
ip :: integer(),
|
ip :: integer(),
|
||||||
hostname :: binary(),
|
hostname :: binary(),
|
||||||
hole :: #hole{},
|
hole :: #hole{},
|
||||||
@ -51,18 +52,13 @@
|
|||||||
domain :: binary(),
|
domain :: binary(),
|
||||||
ipaddr :: binary(),
|
ipaddr :: binary(),
|
||||||
mask_len :: integer(),
|
mask_len :: integer(),
|
||||||
owner_id :: integer(),
|
|
||||||
|
|
||||||
%% 设置网络带宽
|
%% 设置网络带宽
|
||||||
throttle_key :: atom(),
|
throttle_key :: atom(),
|
||||||
|
|
||||||
%% 转发流量统计
|
%% 转发流量统计
|
||||||
forward_bytes = 0,
|
forward_bytes = 0,
|
||||||
|
|
||||||
%% 同一个网络下公用的密钥, 采用AES-256加密算法;随机生成
|
%% 同一个网络下公用的密钥, 采用AES-256加密算法;随机生成
|
||||||
aes_key :: binary(),
|
aes_key :: binary(),
|
||||||
|
%% 记录已经使用了的ip, #{mac => #endpoint{}}
|
||||||
%% 记录已经使用了的ip, #{mac :: integer() => #endpoint{}}
|
|
||||||
endpoints = #{}
|
endpoints = #{}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
@ -122,7 +118,7 @@ forward(Pid, Sock, SrcMac, DstMac, Packet) when is_pid(Pid), is_binary(SrcMac),
|
|||||||
update_hole(Pid, ClientId, Mac, Peer, NatType, V6Info) when is_pid(Pid), is_binary(ClientId), is_binary(Mac), is_integer(NatType) ->
|
update_hole(Pid, ClientId, Mac, Peer, NatType, V6Info) when is_pid(Pid), is_binary(ClientId), is_binary(Mac), is_integer(NatType) ->
|
||||||
gen_server:cast(Pid, {update_hole, ClientId, Mac, Peer, NatType, V6Info}).
|
gen_server:cast(Pid, {update_hole, ClientId, Mac, Peer, NatType, V6Info}).
|
||||||
|
|
||||||
-spec disable_client(Pid :: pid(), ClientId :: binary()) -> ok | error.
|
-spec disable_client(Pid :: pid(), ClientId :: binary()) -> ok.
|
||||||
disable_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) ->
|
disable_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) ->
|
||||||
gen_server:call(Pid, {disable_client, ClientId}).
|
gen_server:call(Pid, {disable_client, ClientId}).
|
||||||
|
|
||||||
@ -135,12 +131,6 @@ dropout_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) ->
|
|||||||
debug_info(Pid) when is_pid(Pid) ->
|
debug_info(Pid) when is_pid(Pid) ->
|
||||||
gen_server:call(Pid, debug_info).
|
gen_server:call(Pid, debug_info).
|
||||||
|
|
||||||
-spec get_used_map(Pid :: pid()) -> map().
|
|
||||||
get_used_map(Pid) when is_pid(Pid) ->
|
|
||||||
gen_server:call(Pid, get_used_map);
|
|
||||||
get_used_map(undefined) ->
|
|
||||||
#{}.
|
|
||||||
|
|
||||||
%% @doc Spawns the server and registers the local name (unique)
|
%% @doc Spawns the server and registers the local name (unique)
|
||||||
-spec(start_link(Name :: atom(), Id :: integer()) ->
|
-spec(start_link(Name :: atom(), Id :: integer()) ->
|
||||||
{ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
|
{ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
|
||||||
@ -160,7 +150,7 @@ init([Id]) when is_integer(Id) ->
|
|||||||
case sdlan_api:get_network(Id) of
|
case sdlan_api:get_network(Id) of
|
||||||
{ok, #{<<"ipaddr">> := Null}} when Null == <<"null">>; Null == <<"NULL">> ->
|
{ok, #{<<"ipaddr">> := Null}} when Null == <<"null">>; Null == <<"NULL">> ->
|
||||||
ignore;
|
ignore;
|
||||||
{ok, #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} ->
|
{ok, #{<<"id">> := Id, <<"name">> := Name, <<"domain">> := Domain, <<"ipaddr">> := IpAddr0}} ->
|
||||||
{IpAddr, MaskLen} = parse_ipaddr(IpAddr0),
|
{IpAddr, MaskLen} = parse_ipaddr(IpAddr0),
|
||||||
AesKey = sdlan_util:rand_byte(32),
|
AesKey = sdlan_util:rand_byte(32),
|
||||||
|
|
||||||
@ -173,8 +163,7 @@ 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),
|
||||||
sdlan_domain_regedit:insert(Domain),
|
sdlan_domain_regedit:insert(Domain),
|
||||||
|
|
||||||
{ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, owner_id = OwnerId,
|
{ok, #state{network_id = Id, name = Name, domain = Domain, ipaddr = IpAddr, mask_len = MaskLen, aes_key = AesKey, throttle_key = ThrottleKey}};
|
||||||
mask_len = MaskLen, aes_key = AesKey, throttle_key = ThrottleKey}};
|
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
logger:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]),
|
logger:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]),
|
||||||
ignore
|
ignore
|
||||||
@ -198,43 +187,17 @@ handle_call({attach, Peer, ClientId, Mac, Ip, Hostname}, _From,
|
|||||||
[NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(Ip)]),
|
[NetworkId, ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(Ip)]),
|
||||||
%% 添加域名->ip的映射关系
|
%% 添加域名->ip的映射关系
|
||||||
sdlan_hostname_regedit:insert(Hostname, Domain, Ip),
|
sdlan_hostname_regedit:insert(Hostname, Domain, Ip),
|
||||||
NEndpoints = maps:put(Mac, #endpoint{client_id = ClientId, ip = Ip, hostname = Hostname, hole = #hole{peer = Peer, nat_type = 0}}, Endpoints),
|
Endpoint = #endpoint{client_id = ClientId, mac = Mac, ip = Ip, hostname = Hostname, hole = #hole{peer = Peer, nat_type = 0}},
|
||||||
|
|
||||||
{reply, {ok, Domain, MaskLen, AesKey}, State#state{endpoints = NEndpoints}};
|
{reply, {ok, Domain, MaskLen, AesKey}, State#state{endpoints = maps:put(Mac, Endpoint, Endpoints)}};
|
||||||
|
|
||||||
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}} ->
|
|
||||||
#{
|
|
||||||
<<"nat_ip">> => sdlan_ipaddr:int_to_ipv4(sdlan_ipaddr:ipv4_to_int(NatIp)),
|
|
||||||
<<"nat_port">> => NatPort
|
|
||||||
};
|
|
||||||
_ ->
|
|
||||||
#{}
|
|
||||||
end,
|
|
||||||
|
|
||||||
V6Map = case V6Info of
|
|
||||||
#sdl_v6_info{v6 = IpV6, port = Port} ->
|
|
||||||
#{
|
|
||||||
<<"v6_ip">> => sdlan_ipaddr:ipv6_bytes_to_binary(IpV6),
|
|
||||||
<<"v6_port">> => Port
|
|
||||||
};
|
|
||||||
_ ->
|
|
||||||
#{}
|
|
||||||
end,
|
|
||||||
#{<<"hole">> => HoleMap, <<"v6_info">> => V6Map}
|
|
||||||
end, Endpoints),
|
|
||||||
|
|
||||||
{reply, {ok, UsedInfos}, State};
|
|
||||||
|
|
||||||
%% client设置为禁止状态,不允许重连
|
%% client设置为禁止状态,不允许重连
|
||||||
handle_call({disable_client, ClientId}, _From, State = #state{endpoints = Endpoints}) ->
|
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
|
case search_endpoint(fun(_, #endpoint{client_id = ClientId0}) -> ClientId =:= ClientId0 end, Endpoints) of
|
||||||
{value, {Mac, #endpoint{}}} ->
|
{ok, Mac, _} ->
|
||||||
{reply, ok, State#state{endpoints = maps:remove(Mac, Endpoints)}};
|
{reply, ok, State#state{endpoints = maps:remove(Mac, Endpoints)}};
|
||||||
false ->
|
error ->
|
||||||
{reply, error, State}
|
{reply, ok, State}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_call(get_network_id, _From, State = #state{network_id = NetworkId}) ->
|
handle_call(get_network_id, _From, State = #state{network_id = NetworkId}) ->
|
||||||
@ -265,19 +228,18 @@ handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{endpoints = Endpo
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_SEND_REGISTER, Event/binary>>,
|
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_SEND_REGISTER, Event/binary>>,
|
||||||
sdlan_stun_pool:send_packets([{DstNatPeer, EventPacket}])
|
sdlan_stun_pool:send_packet(DstNatPeer, EventPacket)
|
||||||
end,
|
end,
|
||||||
{reply, {ok, {DstNatPeer, DstNatType}, DstV6Info}, State};
|
{reply, {ok, {DstNatPeer, DstNatType}, DstV6Info}, State};
|
||||||
_ ->
|
_ ->
|
||||||
{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, endpoints = Endpoints}) ->
|
handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, endpoints = Endpoints}) ->
|
||||||
Reply = #{
|
Reply = #{
|
||||||
<<"network_id">> => NetworkId,
|
<<"network_id">> => NetworkId,
|
||||||
<<"ipaddr">> => IpAddr,
|
<<"ipaddr">> => IpAddr,
|
||||||
<<"mask_len">> => MaskLen,
|
<<"mask_len">> => MaskLen,
|
||||||
<<"owner_id">> => OwnerId,
|
|
||||||
<<"used_ips">> => lists:map(fun format_endpoint/1, maps:to_list(Endpoints))
|
<<"used_ips">> => lists:map(fun format_endpoint/1, maps:to_list(Endpoints))
|
||||||
},
|
},
|
||||||
{reply, Reply, State}.
|
{reply, Reply, State}.
|
||||||
@ -326,15 +288,9 @@ handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id =
|
|||||||
true ->
|
true ->
|
||||||
PacketBytes = byte_size(Packet),
|
PacketBytes = byte_size(Packet),
|
||||||
%% 消息广播
|
%% 消息广播
|
||||||
broadcast(fun(#endpoint{hole = Hole}) ->
|
broadcast(fun(#endpoint{hole = #hole{peer = {NatIp, NatPort}}}) ->
|
||||||
case Hole of
|
gen_udp:send(Sock, NatIp, NatPort, Packet)
|
||||||
#hole{peer = {NatIp, NatPort}} ->
|
|
||||||
gen_udp:send(Sock, NatIp, NatPort, Packet);
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end
|
|
||||||
end, [SrcMac], Endpoints),
|
end, [SrcMac], Endpoints),
|
||||||
|
|
||||||
%% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat
|
%% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat
|
||||||
logger:debug("[sdlan_network] broadcast data networkd_id: ~p, src_mac: ~p, dst_mac: ~p",
|
logger:debug("[sdlan_network] broadcast data networkd_id: ~p, src_mac: ~p, dst_mac: ~p",
|
||||||
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
|
[NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
|
||||||
@ -354,35 +310,25 @@ handle_cast({forward, _Sock, SrcMac, DstMac, _Packet}, State = #state{network_id
|
|||||||
%% 删除ip的占用并关闭channel
|
%% 删除ip的占用并关闭channel
|
||||||
handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId, endpoints = Endpoints}) ->
|
handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId, endpoints = Endpoints}) ->
|
||||||
logger:debug("[sdlan_network] networkd_id: ~p, unregister Mac: ~p", [NetworkId, sdlan_util:format_mac(Mac)]),
|
logger:debug("[sdlan_network] networkd_id: ~p, unregister Mac: ~p", [NetworkId, sdlan_util:format_mac(Mac)]),
|
||||||
case maps:take(Mac, Endpoints) of
|
{noreply, State#state{endpoints = maps:remove(Mac, Endpoints)}};
|
||||||
error ->
|
|
||||||
{noreply, State};
|
|
||||||
{#endpoint{monitor_ref = MRef}, NEndpoints} ->
|
|
||||||
is_reference(MRef) andalso demonitor(MRef),
|
|
||||||
{noreply, State#state{endpoints = NEndpoints}}
|
|
||||||
end;
|
|
||||||
|
|
||||||
%% 需要判断,client是属于当前网络的
|
%% 需要判断,client是属于当前网络的
|
||||||
handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{endpoints = Endpoints}) ->
|
handle_cast({update_hole, ClientId, Mac, Peer, NatType, V6Info}, State = #state{endpoints = Endpoints}) ->
|
||||||
case maps:find(Mac, Endpoints) of
|
case maps:find(Mac, Endpoints) of
|
||||||
{ok, Endpoint0 = #endpoint{client_id = ClientId0, ip = Ip, hole = OldHole}} when ClientId =:= ClientId0 ->
|
{ok, Endpoint0 = #endpoint{ip = Ip, client_id = ClientId0, hole = OldHole}} when ClientId =:= ClientId0 ->
|
||||||
case OldHole =:= undefined orelse (OldHole#hole.peer =/= Peer orelse OldHole#hole.nat_type =/= NatType) of
|
NHole = #hole{peer = Peer, nat_type = NatType},
|
||||||
true ->
|
maybe
|
||||||
|
true ?= same_hole(OldHole, NHole),
|
||||||
NatChangedEvent = sdlan_pb:encode_msg(#sdl_nat_changed_event{
|
NatChangedEvent = sdlan_pb:encode_msg(#sdl_nat_changed_event{
|
||||||
mac = Mac,
|
mac = Mac,
|
||||||
ip = Ip
|
ip = Ip
|
||||||
}),
|
}),
|
||||||
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_NAT_CHANGED, NatChangedEvent>>,
|
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_NAT_CHANGED, NatChangedEvent/binary>>,
|
||||||
|
|
||||||
broadcast(fun(#endpoint{hole = #hole{peer = Peer}}) ->
|
EndpointPeers = endpoint_peers([Mac], Endpoints),
|
||||||
sdlan_stun_pool:send_packet(Peer, EventPacket)
|
sdlan_stun_pool:send_packets(EndpointPeers, EventPacket)
|
||||||
end, [Mac], Endpoints);
|
|
||||||
false ->
|
|
||||||
ok
|
|
||||||
end,
|
end,
|
||||||
Endpoint = Endpoint0#endpoint{hole = #hole{peer = Peer, nat_type = NatType}, v6_info = V6Info},
|
{noreply, State#state{endpoints = maps:put(Mac, Endpoint0#endpoint{hole = NHole, v6_info = V6Info}, Endpoints)}};
|
||||||
|
|
||||||
{noreply, State#state{endpoints = maps:put(Mac, Endpoint, Endpoints)}};
|
|
||||||
_ ->
|
_ ->
|
||||||
{noreply, State}
|
{noreply, State}
|
||||||
end.
|
end.
|
||||||
@ -411,10 +357,9 @@ terminate(Reason, #state{network_id = NetworkId, endpoints = Endpoints}) ->
|
|||||||
NetworkShutdownEvent = sdlan_pb:encode_msg(#sdl_network_shutdown_event {
|
NetworkShutdownEvent = sdlan_pb:encode_msg(#sdl_network_shutdown_event {
|
||||||
message = <<"Network shutdown">>
|
message = <<"Network shutdown">>
|
||||||
}),
|
}),
|
||||||
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_NETWORK_SHUTDOWN, NetworkShutdownEvent>>,
|
EventPacket = <<?PACKET_EVENT, ?PACKET_EVENT_NETWORK_SHUTDOWN, NetworkShutdownEvent/binary>>,
|
||||||
broadcast(fun(#endpoint{hole = #hole{peer = Peer}}) ->
|
EndpointPeers = endpoint_peers([], Endpoints),
|
||||||
sdlan_stun_pool:send_packet(Peer, EventPacket)
|
sdlan_stun_pool:send_packets(EndpointPeers, EventPacket),
|
||||||
end, Endpoints),
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
@ -443,10 +388,6 @@ limiting_check(ThrottleKey) ->
|
|||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec broadcast(Fun :: binary(), Endpoints :: map()) -> no_return().
|
|
||||||
broadcast(Fun, Endpoints) when is_function(Fun, 1), is_map(Endpoints) ->
|
|
||||||
broadcast(Fun, [], Endpoints).
|
|
||||||
|
|
||||||
-spec broadcast(Fun :: binary(), ExcludeMacs :: [binary()], Endpoints :: map()) -> no_return().
|
-spec broadcast(Fun :: binary(), ExcludeMacs :: [binary()], Endpoints :: map()) -> no_return().
|
||||||
broadcast(Fun, ExcludeMacs, Endpoints) when is_function(Fun, 1), is_map(Endpoints), is_list(ExcludeMacs) ->
|
broadcast(Fun, ExcludeMacs, Endpoints) when is_function(Fun, 1), is_map(Endpoints), is_list(ExcludeMacs) ->
|
||||||
maps:foreach(fun(Mac, Endpoint) ->
|
maps:foreach(fun(Mac, Endpoint) ->
|
||||||
@ -458,17 +399,6 @@ broadcast(Fun, ExcludeMacs, Endpoints) when is_function(Fun, 1), is_map(Endpoint
|
|||||||
end
|
end
|
||||||
end, Endpoints).
|
end, Endpoints).
|
||||||
|
|
||||||
-spec broadcast_peers(Fun :: binary(), ExcludeMacs :: [binary()], Endpoints :: map()) -> no_return().
|
|
||||||
broadcast_peers(Fun, ExcludeMacs, Endpoints) when is_function(Fun, 1), is_map(Endpoints), is_list(ExcludeMacs) ->
|
|
||||||
maps:filtermap(fun(Mac, Endpoint) ->
|
|
||||||
case lists:member(Mac, ExcludeMacs) of
|
|
||||||
true ->
|
|
||||||
ok;
|
|
||||||
false ->
|
|
||||||
Fun(Endpoint)
|
|
||||||
end
|
|
||||||
end, Endpoints).
|
|
||||||
|
|
||||||
%% 解析IpAddr: <<"192.168.172/24">>
|
%% 解析IpAddr: <<"192.168.172/24">>
|
||||||
-spec parse_ipaddr(IpAddr0 :: binary()) -> {IpAddr :: binary(), MaskLen :: integer()}.
|
-spec parse_ipaddr(IpAddr0 :: binary()) -> {IpAddr :: binary(), MaskLen :: integer()}.
|
||||||
parse_ipaddr(IpAddr0) when is_binary(IpAddr0) ->
|
parse_ipaddr(IpAddr0) when is_binary(IpAddr0) ->
|
||||||
@ -523,3 +453,20 @@ search_endpoint0(F, Iter) when is_function(F, 1) ->
|
|||||||
'none' ->
|
'none' ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec same_hole(Hole :: #hole{}, Hole :: #hole{}) -> boolean().
|
||||||
|
same_hole(#hole{peer = OldPeer, nat_type = OldNatType}, #hole{peer = Peer, nat_type = NatType}) when OldPeer =:= Peer, OldNatType =:= NatType ->
|
||||||
|
true;
|
||||||
|
same_hole(_, _) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
-spec endpoint_peers(ExcludeMacs :: list(), Endpoints :: map()) -> Peers :: list().
|
||||||
|
endpoint_peers(ExcludeMacs, Endpoints) when is_list(ExcludeMacs), is_map(Endpoints) ->
|
||||||
|
maps:values(maps:filtermap(fun(Mac, #endpoint{hole = #hole{peer = Peer}}) ->
|
||||||
|
case lists:member(Mac, ExcludeMacs) of
|
||||||
|
true ->
|
||||||
|
false;
|
||||||
|
false ->
|
||||||
|
{true, Peer}
|
||||||
|
end
|
||||||
|
end, Endpoints)).
|
||||||
@ -16,7 +16,7 @@
|
|||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([start_link/0, send_packets/1, send_packet/2]).
|
-export([start_link/0, send_packets/2, send_packet/2]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
||||||
@ -33,11 +33,13 @@
|
|||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
|
-spec send_packet(Peer :: {Ip :: inet:ip4_address(), Port :: integer()}, Packet :: binary()) -> no_return().
|
||||||
send_packet(Peer, Packet) ->
|
send_packet(Peer, Packet) ->
|
||||||
gen_server:cast(?SERVER, {send_packet, Peer, Packet}).
|
gen_server:cast(?SERVER, {send_packet, Peer, Packet}).
|
||||||
|
|
||||||
send_packets(Packets) when is_list(Packets) ->
|
-spec send_packet(Peers :: [{Ip :: inet:ip4_address(), Port :: integer()}], Packet :: binary()) -> no_return().
|
||||||
gen_server:cast(?SERVER, {send_packets, Packets}).
|
send_packets(Peers, Packet) when is_list(Peers), is_binary(Packet) ->
|
||||||
|
gen_server:cast(?SERVER, {send_packets, Peers, Packet}).
|
||||||
|
|
||||||
%% @doc Spawns the server and registers the local name (unique)
|
%% @doc Spawns the server and registers the local name (unique)
|
||||||
-spec(start_link() ->
|
-spec(start_link() ->
|
||||||
@ -103,9 +105,9 @@ handle_cast({send_packet, {Ip, Port}, Packet}, State = #state{workers = Workers,
|
|||||||
NewIdx = (Idx rem Num) + 1,
|
NewIdx = (Idx rem Num) + 1,
|
||||||
{noreply, State#state{idx = NewIdx}};
|
{noreply, State#state{idx = NewIdx}};
|
||||||
|
|
||||||
handle_cast({send_packets, Packets}, State = #state{workers = Workers, idx = Idx, num = Num}) ->
|
handle_cast({send_packets, Peers, Packet}, State = #state{workers = Workers, idx = Idx, num = Num}) ->
|
||||||
{Sock, _} = element(Idx, Workers),
|
{Sock, _} = element(Idx, Workers),
|
||||||
lists:foreach(fun({{Ip, Port}, Data}) -> gen_udp:send(Sock, Ip, Port, Data) end, Packets),
|
lists:foreach(fun({Ip, Port}) -> gen_udp:send(Sock, Ip, Port, Packet) end, Peers),
|
||||||
NewIdx = (Idx rem Num) + 1,
|
NewIdx = (Idx rem Num) + 1,
|
||||||
{noreply, State#state{idx = NewIdx}}.
|
{noreply, State#state{idx = NewIdx}}.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user