8cca5e259b
* Do not ask certificate for client (c2s) * Check digest-uri in SASL digest authentication * Use send timeout to avoid locking on gen_tcp:send * Fix ejabberd reconnection to database * HTTP-Bind: handle wrong order of packets * MUC: Improved traffic regulation management * PubSub: Several bugfixes and improvements for best coverage of XEP-0060 v1.12 * Shared Roster Groups: push immediately membership changes * Rotate also sasl.log on "reopen-log" command
205 lines
6 KiB
Text
205 lines
6 KiB
Text
$NetBSD: patch-ag,v 1.2 2009/02/03 12:07:26 martti Exp $
|
|
|
|
Modified to use IPv6/v4 patch (https://support.process-one.net/browse/EJAB-389)
|
|
|
|
--- src/ejabberd_listener.erl.orig 2009-01-14 11:54:15.000000000 +0200
|
|
+++ src/ejabberd_listener.erl 2009-02-03 08:21:35.000000000 +0200
|
|
@@ -32,6 +32,7 @@
|
|
init_ssl/4,
|
|
start_listener/3,
|
|
stop_listener/1,
|
|
+ parse_listener_portip/2,
|
|
add_listener/3,
|
|
delete_listener/1
|
|
]).
|
|
@@ -50,8 +51,7 @@
|
|
undefined ->
|
|
ignore;
|
|
Ls ->
|
|
- {ok, {{one_for_one, 10, 1},
|
|
- lists:map(
|
|
+ Ls2 = lists:map(
|
|
fun({Port, Module, Opts}) ->
|
|
{Port,
|
|
{?MODULE, start, [Port, Module, Opts]},
|
|
@@ -59,7 +59,20 @@
|
|
brutal_kill,
|
|
worker,
|
|
[?MODULE]}
|
|
- end, Ls)}}
|
|
+ end, Ls),
|
|
+ report_duplicated_portips(Ls),
|
|
+ {ok, {{one_for_one, 10, 1}, Ls2}}
|
|
+ end.
|
|
+
|
|
+report_duplicated_portips(L) ->
|
|
+ LKeys = [Port || {Port, _, _} <- L],
|
|
+ LNoDupsKeys = proplists:get_keys(L),
|
|
+ case LKeys -- LNoDupsKeys of
|
|
+ [] -> ok;
|
|
+ Dups ->
|
|
+ ?CRITICAL_MSG("In the ejabberd configuration there are duplicated "
|
|
+ "Port number + IP address:~n ~p",
|
|
+ [Dups])
|
|
end.
|
|
|
|
|
|
@@ -84,7 +97,11 @@
|
|
end
|
|
end.
|
|
|
|
-init(Port, Module, Opts) ->
|
|
+init(PortIP, Module, Opts1) ->
|
|
+ {Port, IPT, IPS, IPV, OptsClean} = parse_listener_portip(PortIP, Opts1),
|
|
+ %% The first inet|inet6 and the last {ip, _} work,
|
|
+ %% so overriding those in Opts
|
|
+ Opts = [IPV | OptsClean] ++ [{ip, IPT}],
|
|
SockOpts = lists:filter(fun({ip, _}) -> true;
|
|
(inet6) -> true;
|
|
(inet) -> true;
|
|
@@ -103,11 +120,77 @@
|
|
{ok, ListenSocket} ->
|
|
accept(ListenSocket, Module, Opts);
|
|
{error, Reason} ->
|
|
- ?ERROR_MSG("Failed to open socket for ~p: ~p",
|
|
- [{Port, Module, Opts}, Reason]),
|
|
- error
|
|
+ ReasonT = case Reason of
|
|
+ eaddrnotavail -> "IP address not available: " ++ IPS;
|
|
+ _ -> atom_to_list(Reason)
|
|
+ end,
|
|
+ ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s",
|
|
+ [{Port, Module, SockOpts}, ReasonT]),
|
|
+ {error, ReasonT}
|
|
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) ->
|
|
+ {IPOpt, Opts2} = strip_ip_option(Opts),
|
|
+ {IPVOpt, OptsClean} = case lists:member(inet6, Opts2) of
|
|
+ true -> {inet6, Opts2 -- [inet6]};
|
|
+ false -> {inet, Opts2}
|
|
+ end,
|
|
+ {Port, IPT, IPS} = case PortIP of
|
|
+ P when is_integer(P) ->
|
|
+ T = get_ip_tuple(IPOpt, IPVOpt),
|
|
+ S = inet_parse:ntoa(T),
|
|
+ {P, T, S};
|
|
+ {P, T} when is_integer(P) and is_tuple(T) ->
|
|
+ S = inet_parse:ntoa(T),
|
|
+ {P, T, S};
|
|
+ {P, S} when is_integer(P) and is_list(S) ->
|
|
+ [S | _] = string:tokens(S, "/"),
|
|
+ {ok, T} = inet_parse:address(S),
|
|
+ {P, T, S}
|
|
+ end,
|
|
+ IPV = case size(IPT) of
|
|
+ 4 -> inet;
|
|
+ 8 -> inet6
|
|
+ end,
|
|
+ {Port, IPT, IPS, IPV, OptsClean}.
|
|
+
|
|
+strip_ip_option(Opts) ->
|
|
+ {IPL, OptsNoIP} = lists:partition(
|
|
+ fun({ip, _}) -> true;
|
|
+ (_) -> false
|
|
+ end,
|
|
+ Opts),
|
|
+ case IPL of
|
|
+ %% Only the first ip option is considered
|
|
+ [{ip, T1} | _] when is_tuple(T1) ->
|
|
+ {T1, OptsNoIP};
|
|
+ [] ->
|
|
+ {no_ip_option, OptsNoIP}
|
|
+ end.
|
|
+
|
|
+get_ip_tuple(no_ip_option, inet) ->
|
|
+ {0, 0, 0, 0};
|
|
+get_ip_tuple(no_ip_option, inet6) ->
|
|
+ {0, 0, 0, 0, 0, 0, 0, 0};
|
|
+get_ip_tuple(IPOpt, _IPVOpt) ->
|
|
+ IPOpt.
|
|
+
|
|
accept(ListenSocket, Module, Opts) ->
|
|
case gen_tcp:accept(ListenSocket) of
|
|
{ok, Socket} ->
|
|
@@ -182,6 +265,7 @@
|
|
end.
|
|
|
|
|
|
+%% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error}
|
|
start_listener(Port, Module, Opts) ->
|
|
ChildSpec = {Port,
|
|
{?MODULE, start, [Port, Module, Opts]},
|
|
@@ -195,26 +279,49 @@
|
|
supervisor:terminate_child(ejabberd_listeners, Port),
|
|
supervisor:delete_child(ejabberd_listeners, Port).
|
|
|
|
-add_listener(Port, Module, Opts) ->
|
|
+%% @spec (PortIP, Module, Opts) -> {ok, Pid} | {error, Error}
|
|
+%% where
|
|
+%% PortIP = {Port, IPT | IPS}
|
|
+%% Port = integer()
|
|
+%% IPT = tuple()
|
|
+%% IPS = string()
|
|
+%% IPV = inet | inet6
|
|
+%% Module = atom()
|
|
+%% Opts = [IPV | {ip, IPT} | atom() | tuple()]
|
|
+%% @doc Add a listener and store in config if success
|
|
+add_listener(PortIP, Module, Opts) ->
|
|
+ case start_listener(PortIP, Module, Opts) of
|
|
+ {ok, _Pid} ->
|
|
Ports = case ejabberd_config:get_local_option(listen) of
|
|
undefined ->
|
|
[];
|
|
Ls ->
|
|
Ls
|
|
end,
|
|
- Ports1 = lists:keydelete(Port, 1, Ports),
|
|
- Ports2 = [{Port, Module, Opts} | Ports1],
|
|
+ Ports1 = lists:keydelete(PortIP, 1, Ports),
|
|
+ Ports2 = [{PortIP, Module, Opts} | Ports1],
|
|
ejabberd_config:add_local_option(listen, Ports2),
|
|
- start_listener(Port, Module, Opts).
|
|
+ ok;
|
|
+ {error, {already_started, _Pid}} ->
|
|
+ {error, {already_started, PortIP}};
|
|
+ {error, Error} ->
|
|
+ {error, Error}
|
|
+ end.
|
|
|
|
-delete_listener(Port) ->
|
|
+%% @spec (PortIP) -> ok
|
|
+%% where
|
|
+%% PortIP = {Port, IPT | IPS}
|
|
+%% Port = integer()
|
|
+%% IPT = tuple()
|
|
+%% IPS = string()
|
|
+delete_listener(PortIP) ->
|
|
Ports = case ejabberd_config:get_local_option(listen) of
|
|
undefined ->
|
|
[];
|
|
Ls ->
|
|
Ls
|
|
end,
|
|
- Ports1 = lists:keydelete(Port, 1, Ports),
|
|
+ Ports1 = lists:keydelete(PortIP, 1, Ports),
|
|
ejabberd_config:add_local_option(listen, Ports1),
|
|
- stop_listener(Port).
|
|
+ stop_listener(PortIP).
|
|
|