pkgsrc/chat/ejabberd/patches/patch-ag
martti 8cca5e259b Updated chat/ejabberd to 2.0.3
* 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
2009-02-03 12:07:26 +00:00

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).