fix
This commit is contained in:
parent
d64cb4235f
commit
c9adbb5e16
@ -24,32 +24,6 @@ handle_request("POST", "/node/disable", _, #{<<"network_id">> := NetworkId, <<"c
|
|||||||
{ok, 200, sdlan_util:json_data(<<"success">>)}
|
{ok, 200, sdlan_util:json_data(<<"success">>)}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_request("POST", "/node/move", _, #{<<"client_id">> := ClientId, <<"from_network_id">> := FromNetworkId, <<"to_network_id">> := ToNetworkId, <<"timeout">> := Timeout}) ->
|
|
||||||
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, HostName} ->
|
|
||||||
Ref = sdlan_channel:move_network(ChannelPid, self(), ToPid, HostName),
|
|
||||||
receive
|
|
||||||
{command_reply, Ref, {error, Reason}} ->
|
|
||||||
logger:warning("[node_handler] client_id: ~p, move network from: ~p, to: ~p, get error: ~p", [ClientId, FromPid, ToPid, Reason]),
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"move failed">>)};
|
|
||||||
{command_reply, Ref, #sdl_command_ack{status = true}} ->
|
|
||||||
{ok, 200, sdlan_util:json_data(<<"success">>)};
|
|
||||||
{command_reply, Ref, #sdl_command_ack{status = false, message = ErrorMsg}} when is_binary(ErrorMsg) ->
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"move failed: ", ErrorMsg/binary>>)}
|
|
||||||
after Timeout * 1000 ->
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"move timeout">>)}
|
|
||||||
end;
|
|
||||||
error ->
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"dropout from from_network error">>)}
|
|
||||||
end;
|
|
||||||
{FromPid, undefined} when is_pid(FromPid) ->
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"to_network not found">>)};
|
|
||||||
{undefined, ToPid} when is_pid(ToPid) ->
|
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"from_network not found">>)}
|
|
||||||
end;
|
|
||||||
|
|
||||||
handle_request(_, Path, _, _) ->
|
handle_request(_, Path, _, _) ->
|
||||||
Path1 = list_to_binary(Path),
|
Path1 = list_to_binary(Path),
|
||||||
{ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
|
{ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
|
||||||
@ -22,7 +22,6 @@ start(_StartType, _StartArgs) ->
|
|||||||
dns_pending_wheel:start(),
|
dns_pending_wheel:start(),
|
||||||
|
|
||||||
start_http_server(),
|
start_http_server(),
|
||||||
start_tcp_server(),
|
|
||||||
sdlan_sup:start_link().
|
sdlan_sup:start_link().
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
@ -58,24 +57,3 @@ start_http_server() ->
|
|||||||
{ok, Pid} = cowboy:start_clear(http_listener, TransOpts, #{env => #{dispatch => Dispatcher}}),
|
{ok, Pid} = cowboy:start_clear(http_listener, TransOpts, #{env => #{dispatch => Dispatcher}}),
|
||||||
|
|
||||||
logger:debug("[iot_app] the http server start at: ~p, pid is: ~p", [Port, Pid]).
|
logger:debug("[iot_app] the http server start at: ~p, pid is: ~p", [Port, Pid]).
|
||||||
|
|
||||||
%% 启动tcp服务
|
|
||||||
start_tcp_server() ->
|
|
||||||
{ok, Props} = application:get_env(sdlan, tcp_server),
|
|
||||||
Acceptors = proplists:get_value(acceptors, Props, 50),
|
|
||||||
MaxConnections = proplists:get_value(max_connections, Props, 10240),
|
|
||||||
Backlog = proplists:get_value(backlog, Props, 1024),
|
|
||||||
Port = proplists:get_value(port, Props),
|
|
||||||
|
|
||||||
TransOpts = #{
|
|
||||||
num_acceptors => Acceptors,
|
|
||||||
max_connections => MaxConnections,
|
|
||||||
socket_opts => [
|
|
||||||
{port, Port},
|
|
||||||
{nodelay, false},
|
|
||||||
{backlog, Backlog}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ok, _} = ranch:start_listener('sdlan/tcp_server', ranch_tcp, TransOpts, sdlan_channel, []),
|
|
||||||
|
|
||||||
logger:debug("[sdlan_app] the tcp server start at: ~p", [Port]).
|
|
||||||
@ -1,382 +0,0 @@
|
|||||||
%%%-------------------------------------------------------------------
|
|
||||||
%%% @author licheng5
|
|
||||||
%%% @copyright (C) 2020, <COMPANY>
|
|
||||||
%%% @doc
|
|
||||||
%%%
|
|
||||||
%%% @end
|
|
||||||
%%% Created : 10. 12月 2020 上午11:17
|
|
||||||
%%%-------------------------------------------------------------------
|
|
||||||
-module(sdlan_channel).
|
|
||||||
-author("licheng5").
|
|
||||||
-behaviour(gen_server).
|
|
||||||
|
|
||||||
-include("sdlan.hrl").
|
|
||||||
-include("sdlan_pb.hrl").
|
|
||||||
|
|
||||||
%% 心跳包监测机制
|
|
||||||
-define(PING_TICKER, 15000).
|
|
||||||
|
|
||||||
%% 注册失败的的错误码
|
|
||||||
|
|
||||||
%% token不存在
|
|
||||||
-define(NAK_INVALID_TOKEN, 1).
|
|
||||||
%% 节点被禁用
|
|
||||||
-define(NAK_NODE_DISABLE, 2).
|
|
||||||
%% 没有IP地址可以用
|
|
||||||
-define(NAK_NO_IP, 3).
|
|
||||||
%% 网络错误
|
|
||||||
-define(NAK_NETWORK_FAULT, 4).
|
|
||||||
%% 内部错误
|
|
||||||
-define(NAK_INTERNAL_FAULT, 5).
|
|
||||||
%% hostname被占用
|
|
||||||
-define(NAK_HOSTNAME_USED, 6).
|
|
||||||
|
|
||||||
%% 升级策略
|
|
||||||
-define(UPGRADE_NONE, 0).
|
|
||||||
-define(UPGRADE_NORMAL, 1).
|
|
||||||
-define(UPGRADE_FORCE, 2).
|
|
||||||
|
|
||||||
%% API
|
|
||||||
-export([start_link/4]).
|
|
||||||
-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]).
|
|
||||||
|
|
||||||
-record(state, {
|
|
||||||
transport,
|
|
||||||
socket,
|
|
||||||
|
|
||||||
client_id :: undefined | binary(),
|
|
||||||
pub_key :: undefined | binary(),
|
|
||||||
token :: undefined | binary(),
|
|
||||||
|
|
||||||
%% 分配的ip地址
|
|
||||||
assign_ip :: undefined | integer(),
|
|
||||||
%% 网络相关信息id
|
|
||||||
network_pid :: undefined | pid(),
|
|
||||||
%% mac地址
|
|
||||||
mac :: undefined | binary(),
|
|
||||||
|
|
||||||
%% 标记是否已经注册
|
|
||||||
is_registered = false,
|
|
||||||
|
|
||||||
%% 记录ping的次数
|
|
||||||
ping_counter = 0,
|
|
||||||
|
|
||||||
%% 发送消息对应的id
|
|
||||||
packet_id = 1 :: integer(),
|
|
||||||
%% 请求响应的对应关系
|
|
||||||
inflight = #{}
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% 向通道中写入消息
|
|
||||||
-spec publish_command(Pid :: pid(), ReceiverPid :: pid(), CommandType :: integer(), Msg :: binary()) -> Ref :: reference().
|
|
||||||
publish_command(Pid, ReceiverPid, CommandType, Msg) when is_pid(Pid), is_pid(ReceiverPid), is_integer(CommandType), is_binary(Msg) ->
|
|
||||||
Ref = make_ref(),
|
|
||||||
Pid ! {publish_command, ReceiverPid, Ref, CommandType, Msg},
|
|
||||||
Ref.
|
|
||||||
|
|
||||||
%% 网络迁移是一种特殊的指令信息,需要单独处理
|
|
||||||
-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, HostName},
|
|
||||||
Ref.
|
|
||||||
|
|
||||||
%% 向通道中写入消息
|
|
||||||
-spec send_event(Pid :: pid(), EventType :: integer(), Event :: binary()) -> no_return().
|
|
||||||
send_event(Pid, EventType, Event) when is_pid(Pid), is_integer(EventType), is_binary(Event) ->
|
|
||||||
Pid ! {send_event, EventType, Event}.
|
|
||||||
|
|
||||||
%% 关闭方法
|
|
||||||
-spec stop(Pid :: pid(), Reason :: any()) -> no_return().
|
|
||||||
stop(undefined, _Reason) ->
|
|
||||||
ok;
|
|
||||||
stop(Pid, Reason) when is_pid(Pid) ->
|
|
||||||
Pid ! {stop, Reason}.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% esockd callback
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
start_link(Ref, _Socket, Transport, Opts) ->
|
|
||||||
{ok, proc_lib:spawn_link(?MODULE, init, [[Ref, Transport, Opts]])}.
|
|
||||||
|
|
||||||
init([Ref, Transport, _Opts = []]) ->
|
|
||||||
{ok, Socket} = ranch:handshake(Ref),
|
|
||||||
logger:debug("[sdlan_channel] get a new connection: ~p", [Socket]),
|
|
||||||
Transport:setopts(Socket, [{active, true}, {packet, 2}]),
|
|
||||||
erlang:start_timer(?PING_TICKER, self(), ping_ticker),
|
|
||||||
gen_server:enter_loop(?MODULE, [], #state{transport = Transport, socket = Socket}).
|
|
||||||
|
|
||||||
handle_call(_Request, _From, State) ->
|
|
||||||
{reply, ok, State}.
|
|
||||||
|
|
||||||
handle_cast(_Msg, State) ->
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
%% 带上token或者网络id来注册
|
|
||||||
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, dev_addr = #sdl_dev_addr{mac = Mac}, network_code = NetworkCode, token = Token, pub_key = PubKey} = sdlan_pb:decode_msg(Body, sdl_register_super),
|
|
||||||
|
|
||||||
%% 参数检查
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, public_key: ~p, token: ~p, network_code: ~p", [ClientId, PubKey, Token, NetworkCode]),
|
|
||||||
true = (Mac =/= <<>> andalso PubKey =/= <<>> andalso ClientId =/= <<>>),
|
|
||||||
%% Mac地址不能是广播地址
|
|
||||||
true = not (sdlan_util:is_multicast_mac(Mac) orelse sdlan_util:is_broadcast_mac(Mac)),
|
|
||||||
|
|
||||||
AuthResult = if
|
|
||||||
Token /= <<>> ->
|
|
||||||
logger:debug("[sdlan_channel] auth token: ~p", [Token]),
|
|
||||||
sdlan_api:auth_token(ClientId, Token, Version);
|
|
||||||
NetworkCode /= <<>> ->
|
|
||||||
logger:debug("[sdlan_channel] auth network code: ~p", [NetworkCode]),
|
|
||||||
sdlan_api:auth_network_code(ClientId, NetworkCode, Version)
|
|
||||||
end,
|
|
||||||
|
|
||||||
case AuthResult of
|
|
||||||
{ok, #{<<"result">> := #{<<"network_id">> := NetworkId, <<"upgrade_type">> := UpgradeType, <<"upgrade_prompt">> := UpgradePrompt, <<"upgrade_address">> := UpgradeAddress}}} when is_integer(NetworkId) ->
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, mac: ~p, token: ~p, version: ~p, registerd, alloc network_id: ~p", [ClientId, sdlan_util:format_mac(Mac), Token, Version, NetworkId]),
|
|
||||||
%% 建立到network的对应关系
|
|
||||||
case sdlan_network:get_pid(NetworkId) of
|
|
||||||
NetworkPid when is_pid(NetworkPid) ->
|
|
||||||
try sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac) of
|
|
||||||
{ok, Domain, NetAddr, NetBitLen, AesKey} ->
|
|
||||||
RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey),
|
|
||||||
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
|
|
||||||
|
|
||||||
RegisterSuperAck = sdlan_pb:encode_msg(#sdl_register_super_ack {
|
|
||||||
dev_addr = #sdl_dev_addr{
|
|
||||||
network_id = NetworkId,
|
|
||||||
net_addr = NetAddr,
|
|
||||||
mac = Mac,
|
|
||||||
net_bit_len = NetBitLen,
|
|
||||||
network_domain = Domain
|
|
||||||
},
|
|
||||||
aes_key = EncodedAesKey,
|
|
||||||
upgrade_type = UpgradeType,
|
|
||||||
upgrade_prompt = UpgradePrompt,
|
|
||||||
upgrade_address = UpgradeAddress
|
|
||||||
}),
|
|
||||||
|
|
||||||
%% 发送确认信息
|
|
||||||
Reply = <<PacketId:32, ?PACKET_REGISTER_SUPER_ACK, RegisterSuperAck/binary>>,
|
|
||||||
Transport:send(Sock, Reply),
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, mac: ~p, alloc ip: ~p, register will send ack, aes_key: ~p, enc_aes_key: ~p",
|
|
||||||
[ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(NetAddr), AesKey, EncodedAesKey]),
|
|
||||||
|
|
||||||
%% 设置节点的在线状态
|
|
||||||
Result = sdlan_api:node_online(ClientId, NetworkId, sdlan_ipaddr:int_to_ipv4(NetAddr)),
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, set none online, result is: ~p", [ClientId, Result]),
|
|
||||||
case UpgradeType =:= ?UPGRADE_FORCE of
|
|
||||||
true ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, need upgrade force!", [ClientId]),
|
|
||||||
{stop, normal, State};
|
|
||||||
false ->
|
|
||||||
{noreply, State#state{client_id = ClientId, mac = Mac, assign_ip = NetAddr, network_pid = NetworkPid, pub_key = PubKey, is_registered = true}}
|
|
||||||
end;
|
|
||||||
{error, no_ip} ->
|
|
||||||
logger: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} ->
|
|
||||||
logger: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} ->
|
|
||||||
logger: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">>)),
|
|
||||||
{stop, normal, State}
|
|
||||||
catch _:Error:Stack ->
|
|
||||||
logger:warning("[sdlan_channel] get error: ~p, stack: ~p", [Error, Stack])
|
|
||||||
end;
|
|
||||||
undefined ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: network not found", [ClientId, Token]),
|
|
||||||
Transport:send(Sock, register_nak_reply(PacketId, ?NAK_INTERNAL_FAULT, <<"Internal Error">>)),
|
|
||||||
|
|
||||||
{stop, normal, State}
|
|
||||||
end;
|
|
||||||
{ok, #{<<"error">> := #{<<"code">> := 1, <<"message">> := Message}}} ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~ts, error_code: 1", [ClientId, Token, Message]),
|
|
||||||
Transport:send(Sock, register_nak_reply(PacketId, ?NAK_INVALID_TOKEN, Message)),
|
|
||||||
{stop, normal, State};
|
|
||||||
|
|
||||||
{ok, #{<<"error">> := #{<<"code">> := 2, <<"message">> := Message}}} ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p, error_code: 2", [ClientId, Token, Message]),
|
|
||||||
Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, Message)),
|
|
||||||
{stop, normal, State};
|
|
||||||
|
|
||||||
{error, Reason} ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p", [ClientId, Token, Reason]),
|
|
||||||
Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NETWORK_FAULT, <<"Network Error">>)),
|
|
||||||
{stop, normal, State}
|
|
||||||
end;
|
|
||||||
|
|
||||||
handle_info({tcp, Sock, <<PacketId:32, ?PACKET_QUERY_INFO, Body/binary>>}, State = #state{transport = Transport, socket = Sock, network_pid = NetworkPid, mac = SrcMac, is_registered = true}) when is_pid(NetworkPid) ->
|
|
||||||
#sdl_query_info{dst_mac = DstMac} = sdlan_pb:decode_msg(Body, sdl_query_info),
|
|
||||||
case sdlan_network:peer_info(NetworkPid, SrcMac, DstMac) of
|
|
||||||
error ->
|
|
||||||
logger:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer not found",
|
|
||||||
[sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]),
|
|
||||||
|
|
||||||
Transport:send(Sock, <<PacketId:32, ?PACKET_EMPTY>>),
|
|
||||||
{noreply, State};
|
|
||||||
{ok, {NatPeer = {{Ip0, Ip1, Ip2, Ip3}, NatPort}, NatType}, V6Info} ->
|
|
||||||
logger:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer: ~p",
|
|
||||||
[sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), NatPeer]),
|
|
||||||
|
|
||||||
PeerInfo = sdlan_pb:encode_msg(#sdl_peer_info{
|
|
||||||
dst_mac = DstMac,
|
|
||||||
v4_info = #sdl_v4_info {
|
|
||||||
port = NatPort,
|
|
||||||
v4 = <<Ip0, Ip1, Ip2, Ip3>>,
|
|
||||||
nat_type = NatType
|
|
||||||
},
|
|
||||||
v6_info = V6Info
|
|
||||||
}),
|
|
||||||
Transport:send(Sock, <<PacketId:32, ?PACKET_PEER_INFO, PeerInfo/binary>>),
|
|
||||||
{noreply, State}
|
|
||||||
end;
|
|
||||||
|
|
||||||
handle_info({tcp, _Sock, <<0:32, ?PACKET_PING>>}, State = #state{transport = Transport, socket = Sock, ping_counter = PingCounter}) ->
|
|
||||||
%logger:debug("[sdlan_channel] client_id: ~p, get ping", [ClientId]),
|
|
||||||
Transport:send(Sock, <<0:32, ?PACKET_PONG>>),
|
|
||||||
{noreply, State#state{ping_counter = PingCounter + 1}};
|
|
||||||
|
|
||||||
handle_info({timeout, _, ping_ticker}, State = #state{client_id = ClientId, ping_counter = PingCounter}) ->
|
|
||||||
%% 等待下一次的心跳检测
|
|
||||||
erlang:start_timer(?PING_TICKER, self(), ping_ticker),
|
|
||||||
case PingCounter > 0 of
|
|
||||||
true ->
|
|
||||||
{noreply, State#state{ping_counter = 0}};
|
|
||||||
false ->
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, ping losted", [ClientId]),
|
|
||||||
{stop, normal, State#state{ping_counter = 0}}
|
|
||||||
end;
|
|
||||||
|
|
||||||
%% 重新加入网络
|
|
||||||
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) of
|
|
||||||
{ok, Domain, NetAddr, NetBitLen, AesKey} ->
|
|
||||||
RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey),
|
|
||||||
EncodedAesKey = rsa_encode(AesKey, RsaPubKey),
|
|
||||||
|
|
||||||
{ok, NetworkId} = sdlan_network:get_network_id(NetworkPid),
|
|
||||||
%% 发送确认信息
|
|
||||||
ChangeNetworkCommand = sdlan_pb:encode_msg(#sdl_change_network_command {
|
|
||||||
dev_addr = #sdl_dev_addr {
|
|
||||||
network_id = NetworkId,
|
|
||||||
net_addr = NetAddr,
|
|
||||||
net_bit_len = NetBitLen,
|
|
||||||
network_domain = Domain
|
|
||||||
},
|
|
||||||
aes_key = EncodedAesKey
|
|
||||||
}),
|
|
||||||
Command = <<PacketId:32, ?PACKET_COMMAND, ?PACKET_COMMAND_CHANGE_NETWORK, ChangeNetworkCommand/binary>>,
|
|
||||||
Transport:send(Sock, Command),
|
|
||||||
|
|
||||||
%% 设置节点的在线状态
|
|
||||||
sdlan_api:node_online(ClientId, NetworkId, sdlan_ipaddr:int_to_ipv4(NetAddr)),
|
|
||||||
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, move_network will send command: ~p", [ClientId, Command]),
|
|
||||||
{noreply, State#state{packet_id = PacketId + 1, assign_ip = NetAddr, network_pid = NetworkPid, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}};
|
|
||||||
{error, Reason} ->
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, move_network get error: ~p", [ClientId, Reason]),
|
|
||||||
Transport:send(Sock, register_nak_reply(0, ?NAK_NO_IP, <<"No Ip address">>)),
|
|
||||||
ReceiverPid ! {command_reply, Ref, {error, <<"assign_ip error, no ip free">>}},
|
|
||||||
{noreply, State}
|
|
||||||
end;
|
|
||||||
|
|
||||||
%% 发送指令信息
|
|
||||||
handle_info({send_event, EventType, Event}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, is_registered = true}) ->
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, will send eventType: ~p, event: ~p", [ClientId, EventType, Event]),
|
|
||||||
Transport:send(Sock, <<0:32, ?PACKET_EVENT, EventType, Event/binary>>),
|
|
||||||
{noreply, State};
|
|
||||||
|
|
||||||
%% 网络流量统计
|
|
||||||
handle_info({tcp, _Sock, <<0:32, ?PACKET_FLOW_TRACER, Body/binary>>}, State = #state{client_id = ClientId, network_pid = NetworkPid, is_registered = true}) when is_pid(NetworkPid) ->
|
|
||||||
#sdl_flows{forward_num = ForwardNum, p2p_num = P2PNum, inbound_num = InboundNum} = sdlan_pb:decode_msg(Body, sdl_flows),
|
|
||||||
{ok, NetworkId} = sdlan_network:get_network_id(NetworkPid),
|
|
||||||
ReportResult = sdlan_api:flow_report(ClientId, NetworkId, ForwardNum, P2PNum, InboundNum),
|
|
||||||
logger:debug("[sdlan_channel] flow_tracer, forward: ~p, p2p: ~p, inbound: ~p, result: ~p", [ClientId, ForwardNum, P2PNum, InboundNum, ReportResult]),
|
|
||||||
{noreply, State};
|
|
||||||
|
|
||||||
%% 取消注册
|
|
||||||
handle_info({tcp, _Sock, <<0:32, ?PACKET_UNREGISTER>>}, State = #state{client_id = ClientId, network_pid = NetworkPid, is_registered = true}) when is_pid(NetworkPid) ->
|
|
||||||
logger:warning("[sdlan_channel] unregister client_id: ~p", [ClientId]),
|
|
||||||
% sdlan_network:unregister(NetworkPid, ClientId),
|
|
||||||
{stop, normal, State};
|
|
||||||
|
|
||||||
%% 发送指令信息
|
|
||||||
handle_info({publish_command, ReceiverPid, Ref, CommandType, Msg}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, packet_id = PacketId, inflight = Inflight, is_registered = true}) ->
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, will publish: ~p, message: ~p", [ClientId, CommandType, Msg]),
|
|
||||||
Transport:send(Sock, <<PacketId:32, ?PACKET_COMMAND, CommandType, Msg/binary>>),
|
|
||||||
{noreply, State#state{packet_id = PacketId + 1, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}};
|
|
||||||
|
|
||||||
%% 主机端的消息响应
|
|
||||||
handle_info({tcp, _Sock, <<PacketId:32, ?PACKET_COMMAND_ACK, Body/binary>>}, State = #state{client_id = ClientId, inflight = Inflight}) when PacketId > 0 ->
|
|
||||||
CommandAck = #sdl_command_ack{} = sdlan_pb:decode_msg(Body, sdl_command_ack),
|
|
||||||
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, get publish response message: ~p, packet_id: ~p", [ClientId, CommandAck, PacketId]),
|
|
||||||
case maps:take(PacketId, Inflight) of
|
|
||||||
error ->
|
|
||||||
logger:warning("[sdlan_channel] get unknown publish response message: ~p, packet_id: ~p", [CommandAck, PacketId]),
|
|
||||||
{ok, State};
|
|
||||||
{{ReceiverPid, Ref}, NInflight} ->
|
|
||||||
case is_pid(ReceiverPid) andalso is_process_alive(ReceiverPid) of
|
|
||||||
true ->
|
|
||||||
ReceiverPid ! {command_reply, Ref, CommandAck};
|
|
||||||
false ->
|
|
||||||
logger:warning("[sdlan_channel] get publish response message: ~p, packet_id: ~p, but receiver_pid is deaded", [CommandAck, PacketId])
|
|
||||||
end,
|
|
||||||
{noreply, State#state{inflight = NInflight}}
|
|
||||||
end;
|
|
||||||
|
|
||||||
handle_info({tcp_error, Sock, Reason}, State = #state{socket = Sock, client_id = ClientId}) ->
|
|
||||||
logger:notice("[sdlan_channel] client_id: ~p, tcp_error: ~p", [ClientId, Reason]),
|
|
||||||
{stop, normal, State};
|
|
||||||
|
|
||||||
handle_info({tcp_closed, Sock}, State = #state{socket = Sock, client_id = ClientId}) ->
|
|
||||||
logger:notice("[sdlan_channel] client_id: ~p, tcp_closed", [ClientId]),
|
|
||||||
{stop, normal, State};
|
|
||||||
|
|
||||||
%% 关闭当前通道
|
|
||||||
handle_info({stop, Reason}, State) ->
|
|
||||||
{stop, Reason, State};
|
|
||||||
|
|
||||||
handle_info(Info, State) ->
|
|
||||||
logger:warning("[sdlan_channel] get a unknown message: ~p, channel will closed", [Info]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
terminate(Reason, #state{client_id = ClientId, network_pid = NetworkPid}) ->
|
|
||||||
case ClientId /= undefined andalso is_pid(NetworkPid) of
|
|
||||||
true ->
|
|
||||||
{ok, NetworkId} = sdlan_network:get_network_id(NetworkPid),
|
|
||||||
Result = sdlan_api:node_offline(ClientId, NetworkId),
|
|
||||||
logger:debug("[sdlan_channel] client_id: ~p, set none offline, result is: ~p", [ClientId, Result]);
|
|
||||||
false ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
logger:warning("[sdlan_channel] client_id: ~p, stop with reason: ~p", [ClientId, Reason]),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
code_change(_OldVsn, State, _Extra) ->
|
|
||||||
{ok, State}.
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
%% helper methods
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
-spec register_nak_reply(PacketId :: integer(), ErrorCode :: integer(), ErrorMsg :: binary()) -> binary().
|
|
||||||
register_nak_reply(PacketId, ErrorCode, ErrorMsg) when is_integer(PacketId), is_integer(ErrorCode), is_binary(ErrorMsg) ->
|
|
||||||
RegisterNakReply = sdlan_pb:encode_msg(#sdl_register_super_nak {
|
|
||||||
error_code = ErrorCode,
|
|
||||||
error_message = ErrorMsg
|
|
||||||
}),
|
|
||||||
<<PacketId:32, ?PACKET_REGISTER_SUPER_NAK, RegisterNakReply/binary>>.
|
|
||||||
|
|
||||||
rsa_encode(PlainText, RsaPubKey) when is_binary(PlainText) ->
|
|
||||||
iolist_to_binary(sdlan_cipher:rsa_encrypt(PlainText, RsaPubKey)).
|
|
||||||
@ -187,7 +187,7 @@ init([Id]) when is_integer(Id) ->
|
|||||||
{stop, Reason :: term(), NewState :: #state{}}).
|
{stop, Reason :: term(), NewState :: #state{}}).
|
||||||
%% 给客户端分配ip地址
|
%% 给客户端分配ip地址
|
||||||
handle_call({attach, Peer, ClientId, Mac, Ip, Hostname}, _From,
|
handle_call({attach, Peer, ClientId, Mac, Ip, Hostname}, _From,
|
||||||
State = #state{network_id = NetworkId, domain = Domain, endpoints = Endpoints, mask_len = MaskLen, aes_key = AesKey}) ->
|
State = #state{network_id = NetworkId, domain = Domain, endpoints = Endpoints, aes_key = AesKey}) ->
|
||||||
%% 分配ip地址的时候,以mac地址为唯一基准
|
%% 分配ip地址的时候,以mac地址为唯一基准
|
||||||
logger:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, ip_addr: ~p",
|
logger:debug("[sdlan_network] alloc_ip, network_id: ~p, client_id: ~p, mac: ~p, ip_addr: ~p",
|
||||||
[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)]),
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
send_packet(Peer, Packet) ->
|
send_packet(Peer, Packet) ->
|
||||||
gen_server:cast(?SERVER, {send_packet, Peer, Packet}).
|
gen_server:cast(?SERVER, {send_packet, Peer, Packet}).
|
||||||
|
|
||||||
-spec send_packet(Peers :: [{Ip :: inet:ip4_address(), Port :: integer()}], Packet :: binary()) -> no_return().
|
-spec send_packets(Peers :: [{Ip :: inet:ip4_address(), Port :: integer()}], Packet :: binary()) -> no_return().
|
||||||
send_packets(Peers, Packet) when is_list(Peers), is_binary(Packet) ->
|
send_packets(Peers, Packet) when is_list(Peers), is_binary(Packet) ->
|
||||||
gen_server:cast(?SERVER, {send_packets, Peers, Packet}).
|
gen_server:cast(?SERVER, {send_packets, Peers, Packet}).
|
||||||
|
|
||||||
|
|||||||
@ -98,17 +98,15 @@ handle_call(register, _From, State = #state{socket = Socket, client_id = ClientI
|
|||||||
},
|
},
|
||||||
|
|
||||||
Register = #sdl_register_super {
|
Register = #sdl_register_super {
|
||||||
version = 1,
|
version = 0,
|
||||||
installed_channel = <<"macos">>,
|
|
||||||
client_id = ClientId,
|
client_id = ClientId,
|
||||||
dev_addr = #sdl_dev_addr {
|
network_id = 8,
|
||||||
network_id = 0,
|
|
||||||
mac = <<11, 12, 13, 14, 15, 16>>,
|
mac = <<11, 12, 13, 14, 15, 16>>,
|
||||||
net_addr = 0,
|
ip = 0,
|
||||||
net_bit_len = 0
|
mask_len = 0,
|
||||||
},
|
hostname = <<"mysql1">>,
|
||||||
pub_key = <<>>,
|
pub_key = <<>>,
|
||||||
token = <<"1234567890">>
|
access_token = <<"access_token1234">>
|
||||||
},
|
},
|
||||||
|
|
||||||
logger:debug("register is: ~p", [Register]),
|
logger:debug("register is: ~p", [Register]),
|
||||||
|
|||||||
@ -8,13 +8,6 @@
|
|||||||
{backlog, 10240}
|
{backlog, 10240}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
{tcp_server, [
|
|
||||||
{port, 18083},
|
|
||||||
{acceptors, 500},
|
|
||||||
{max_connections, 10240},
|
|
||||||
{backlog, 10240}
|
|
||||||
]},
|
|
||||||
|
|
||||||
%% 网络带宽, 单位为: kb
|
%% 网络带宽, 单位为: kb
|
||||||
{band_width, 2048},
|
{band_width, 2048},
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,6 @@
|
|||||||
{backlog, 10240}
|
{backlog, 10240}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
{tcp_server, [
|
|
||||||
{port, 18083},
|
|
||||||
{acceptors, 500},
|
|
||||||
{max_connections, 10240},
|
|
||||||
{backlog, 10240}
|
|
||||||
]},
|
|
||||||
|
|
||||||
%% 网络带宽, 单位为: kb
|
%% 网络带宽, 单位为: kb
|
||||||
{band_width, 2048},
|
{band_width, 2048},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user