Improve listener errors formatting
This commit is contained in:
parent
5b3af9d4cd
commit
395d2e86bc
|
@ -92,15 +92,15 @@ start_dependent(Port, Module, Opts) ->
|
||||||
proc_lib:start_link(?MODULE, init, [Port, Module, Opts]).
|
proc_lib:start_link(?MODULE, init, [Port, Module, Opts]).
|
||||||
|
|
||||||
init(PortIP, Module, RawOpts) ->
|
init(PortIP, Module, RawOpts) ->
|
||||||
{Port, IPT, IPS, IPV, Proto, OptsClean} = parse_listener_portip(PortIP, RawOpts),
|
{Port, IPT, IPV, Proto, OptsClean} = parse_listener_portip(PortIP, RawOpts),
|
||||||
{Opts, SockOpts} = prepare_opts(IPT, IPV, OptsClean),
|
{Opts, SockOpts} = prepare_opts(IPT, IPV, OptsClean),
|
||||||
if Proto == udp ->
|
if Proto == udp ->
|
||||||
init_udp(PortIP, Module, Opts, SockOpts, Port, IPS);
|
init_udp(PortIP, Module, Opts, SockOpts, Port);
|
||||||
true ->
|
true ->
|
||||||
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS)
|
init_tcp(PortIP, Module, Opts, SockOpts, Port)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
|
init_udp(PortIP, Module, Opts, SockOpts, Port) ->
|
||||||
case gen_udp:open(Port, [binary,
|
case gen_udp:open(Port, [binary,
|
||||||
{active, false},
|
{active, false},
|
||||||
{reuseaddr, true} |
|
{reuseaddr, true} |
|
||||||
|
@ -126,34 +126,38 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
|
||||||
udp_recv(Socket, Module, NewOpts)
|
udp_recv(Socket, Module, NewOpts)
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
{error, Reason} ->
|
{error, Reason} = Err ->
|
||||||
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
|
report_socket_error(Reason, PortIP, Module),
|
||||||
|
proc_lib:init_ack(Err)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
|
init_tcp(PortIP, Module, Opts, SockOpts, Port) ->
|
||||||
ListenSocket = listen_tcp(PortIP, Module, SockOpts, Port, IPS),
|
case listen_tcp(PortIP, Module, SockOpts, Port) of
|
||||||
%% Inform my parent that this port was opened successfully
|
{ok, ListenSocket} ->
|
||||||
proc_lib:init_ack({ok, self()}),
|
proc_lib:init_ack({ok, self()}),
|
||||||
application:ensure_started(ejabberd),
|
application:ensure_started(ejabberd),
|
||||||
start_module_sup(Port, Module),
|
start_module_sup(Port, Module),
|
||||||
?INFO_MSG("Start accepting TCP connections at ~s for ~p",
|
?INFO_MSG("Start accepting TCP connections at ~s for ~p",
|
||||||
[format_portip(PortIP), Module]),
|
[format_portip(PortIP), Module]),
|
||||||
case erlang:function_exported(Module, tcp_init, 2) of
|
case erlang:function_exported(Module, tcp_init, 2) of
|
||||||
false ->
|
false ->
|
||||||
accept(ListenSocket, Module, Opts);
|
|
||||||
true ->
|
|
||||||
case catch Module:tcp_init(ListenSocket, Opts) of
|
|
||||||
{'EXIT', _} = Err ->
|
|
||||||
?ERROR_MSG("failed to process callback function "
|
|
||||||
"~p:~s(~p, ~p): ~p",
|
|
||||||
[Module, tcp_init, ListenSocket, Opts, Err]),
|
|
||||||
accept(ListenSocket, Module, Opts);
|
accept(ListenSocket, Module, Opts);
|
||||||
NewOpts ->
|
true ->
|
||||||
accept(ListenSocket, Module, NewOpts)
|
case catch Module:tcp_init(ListenSocket, Opts) of
|
||||||
end
|
{'EXIT', _} = Err ->
|
||||||
|
?ERROR_MSG("failed to process callback function "
|
||||||
|
"~p:~s(~p, ~p): ~p",
|
||||||
|
[Module, tcp_init, ListenSocket, Opts, Err]),
|
||||||
|
accept(ListenSocket, Module, Opts);
|
||||||
|
NewOpts ->
|
||||||
|
accept(ListenSocket, Module, NewOpts)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
{error, _} = Err ->
|
||||||
|
proc_lib:init_ack(Err)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
listen_tcp(PortIP, Module, SockOpts, Port, IPS) ->
|
listen_tcp(PortIP, Module, SockOpts, Port) ->
|
||||||
Res = gen_tcp:listen(Port, [binary,
|
Res = gen_tcp:listen(Port, [binary,
|
||||||
{packet, 0},
|
{packet, 0},
|
||||||
{active, false},
|
{active, false},
|
||||||
|
@ -165,52 +169,34 @@ listen_tcp(PortIP, Module, SockOpts, Port, IPS) ->
|
||||||
SockOpts]),
|
SockOpts]),
|
||||||
case Res of
|
case Res of
|
||||||
{ok, ListenSocket} ->
|
{ok, ListenSocket} ->
|
||||||
ListenSocket;
|
{ok, ListenSocket};
|
||||||
{error, Reason} ->
|
{error, Reason} = Err ->
|
||||||
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
|
report_socket_error(Reason, PortIP, Module),
|
||||||
|
Err
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean}
|
|
||||||
%% where
|
|
||||||
%% PortIP = Port | {Port, IPT | IPS}
|
|
||||||
%% Port = integer()
|
|
||||||
%% IPT = tuple()
|
|
||||||
%% IPS = string()
|
|
||||||
%% IPV = inet | inet6
|
|
||||||
%% Opts = [IPV | {ip, IPT} | atom() | tuple()]
|
|
||||||
%% OptsClean = [atom() | tuple()]
|
|
||||||
%% @doc Parse any kind of ejabberd listener specification.
|
|
||||||
%% The parsed options are returned in several formats.
|
|
||||||
%% OptsClean does not include inet/inet6 or ip options.
|
|
||||||
%% Opts can include the options inet6 and {ip, Tuple},
|
|
||||||
%% but they are only used when no IP address was specified in the PortIP.
|
|
||||||
%% The IP version (either IPv4 or IPv6) is inferred from the IP address type,
|
|
||||||
%% so the option inet/inet6 is only used when no IP is specified at all.
|
|
||||||
parse_listener_portip(PortIP, Opts) ->
|
parse_listener_portip(PortIP, Opts) ->
|
||||||
{IPOpt, Opts2} = strip_ip_option(Opts),
|
{IPOpt, Opts2} = strip_ip_option(Opts),
|
||||||
{IPVOpt, OptsClean} = case proplists:get_bool(inet6, Opts2) of
|
{IPVOpt, OptsClean} = case proplists:get_bool(inet6, Opts2) of
|
||||||
true -> {inet6, proplists:delete(inet6, Opts2)};
|
true -> {inet6, proplists:delete(inet6, Opts2)};
|
||||||
false -> {inet, Opts2}
|
false -> {inet, Opts2}
|
||||||
end,
|
end,
|
||||||
{Port, IPT, IPS, Proto} =
|
{Port, IPT, Proto} =
|
||||||
case add_proto(PortIP, Opts) of
|
case add_proto(PortIP, Opts) of
|
||||||
{P, Prot} ->
|
{P, Prot} ->
|
||||||
T = get_ip_tuple(IPOpt, IPVOpt),
|
T = get_ip_tuple(IPOpt, IPVOpt),
|
||||||
S = misc:ip_to_list(T),
|
{P, T, Prot};
|
||||||
{P, T, S, Prot};
|
|
||||||
{P, T, Prot} when is_integer(P) and is_tuple(T) ->
|
{P, T, Prot} when is_integer(P) and is_tuple(T) ->
|
||||||
S = misc:ip_to_list(T),
|
{P, T, Prot};
|
||||||
{P, T, S, Prot};
|
|
||||||
{P, S, Prot} when is_integer(P) and is_binary(S) ->
|
{P, S, Prot} when is_integer(P) and is_binary(S) ->
|
||||||
[S | _] = str:tokens(S, <<"/">>),
|
|
||||||
{ok, T} = inet_parse:address(binary_to_list(S)),
|
{ok, T} = inet_parse:address(binary_to_list(S)),
|
||||||
{P, T, S, Prot}
|
{P, T, Prot}
|
||||||
end,
|
end,
|
||||||
IPV = case tuple_size(IPT) of
|
IPV = case tuple_size(IPT) of
|
||||||
4 -> inet;
|
4 -> inet;
|
||||||
8 -> inet6
|
8 -> inet6
|
||||||
end,
|
end,
|
||||||
{Port, IPT, IPS, IPV, Proto, OptsClean}.
|
{Port, IPT, IPV, Proto, OptsClean}.
|
||||||
|
|
||||||
prepare_opts(IPT, IPV, OptsClean) ->
|
prepare_opts(IPT, IPV, OptsClean) ->
|
||||||
%% The first inet|inet6 and the last {ip, _} work,
|
%% The first inet|inet6 and the last {ip, _} work,
|
||||||
|
@ -437,19 +423,9 @@ normalize_proto(UnknownProto) ->
|
||||||
[UnknownProto]),
|
[UnknownProto]),
|
||||||
tcp.
|
tcp.
|
||||||
|
|
||||||
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS) ->
|
report_socket_error(Reason, PortIP, Module) ->
|
||||||
ReasonT = case Reason of
|
?ERROR_MSG("Failed to open socket at ~s for ~s: ~s",
|
||||||
eaddrnotavail ->
|
[format_portip(PortIP), Module, format_error(Reason)]).
|
||||||
"IP address not available: " ++ binary_to_list(IPS);
|
|
||||||
eaddrinuse ->
|
|
||||||
"IP address and port number already used: "
|
|
||||||
++binary_to_list(IPS)++" "++integer_to_list(Port);
|
|
||||||
_ ->
|
|
||||||
format_error(Reason)
|
|
||||||
end,
|
|
||||||
?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s",
|
|
||||||
[{Port, Module, SockOpts}, ReasonT]),
|
|
||||||
throw({Reason, PortIP}).
|
|
||||||
|
|
||||||
format_error(Reason) ->
|
format_error(Reason) ->
|
||||||
case inet:format_error(Reason) of
|
case inet:format_error(Reason) of
|
||||||
|
|
Loading…
Reference in New Issue