]> granicus.if.org Git - ejabberd/commitdiff
* src/ejabberd_config.erl: Option outgoing_s2s_options to define
authorBadlop <badlop@process-one.net>
Fri, 26 Dec 2008 11:45:08 +0000 (11:45 +0000)
committerBadlop <badlop@process-one.net>
Fri, 26 Dec 2008 11:45:08 +0000 (11:45 +0000)
s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan
Maka)(EJAB-665)
* src/ejabberd_s2s_out.erl: Likewise
* src/ejabberd_socket.erl: Likewise
* src/ejabberd.cfg.example: Likewise
* doc/guide.tex: Likewise
* doc/guide.html: Likewise

SVN Revision: 1756

ChangeLog
doc/guide.html
doc/guide.tex
src/ejabberd.cfg.example
src/ejabberd_config.erl
src/ejabberd_s2s_out.erl
src/ejabberd_socket.erl

index 4688874c983d948941045842a454f36153b5814a..fe1367479aa38b490a0abdfa54507ad39c5dd087 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-12-26  Badlop  <badlop@process-one.net>
+
+       * src/ejabberd_config.erl: Option outgoing_s2s_options to define
+       s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan
+       Maka)(EJAB-665)
+       * src/ejabberd_s2s_out.erl: Likewise
+       * src/ejabberd_socket.erl: Likewise
+       * src/ejabberd.cfg.example: Likewise
+       * doc/guide.tex: Likewise
+       * doc/guide.html: Likewise
+
 2008-12-26  Evgeniy Khramtsov <ekhramtsov@process-one.net>
 
        * src/odbc/ejabberd_odbc.erl: get rid of SERIALIZABLE isolation
@@ -10,7 +21,7 @@
 2008-12-24  Badlop  <badlop@process-one.net>
 
        * src/aclocal.m4: Fixes in configure script: fix
-       disable-disable_zlib and disable-pam; in case of problems, PAM
+       disable-ejabberd_zlib and disable-pam; in case of problems, PAM
        verification aborts with error instead of warning. (EJAB-787)
        * src/configure.ac: Likewise
        * src/configure: Likewise
index 2982f355d33ac1cd66f764526fd15279d3d7e7d8..6d143c335e24ddeb334385d34c91112f3ed8047e 100644 (file)
@@ -745,6 +745,10 @@ use STARTTLS for s2s connections.
 file containing a SSL certificate.
 </DD><DT CLASS="dt-description"><B><TT>{domain_certfile, Domain, Path}</TT></B></DT><DD CLASS="dd-description"> 
 Full path to the file containing the SSL certificate for a specific domain.
+</DD><DT CLASS="dt-description"><B><TT>{outgoing_s2s_options, Methods, Timeout}</TT></B></DT><DD CLASS="dd-description"> 
+Specify which address families to try, in what order, and connect timeout in milliseconds.
+By default it first tries connecting with IPv4, if that fails it tries using IPv6,
+with a timeout of 10000 milliseconds.
 </DD><DT CLASS="dt-description"><B><TT>{s2s_default_policy, allow|deny}</TT></B></DT><DD CLASS="dd-description">
 The default policy for incoming and outgoing s2s connections to other Jabber servers.
 The default value is <TT>allow</TT>.
@@ -1032,6 +1036,10 @@ declarations of ACLs in the configuration file have the following syntax:
 </PRE></DD><DT CLASS="dt-description"><B><TT>{resource, &lt;resource&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any JID with a resource
 <TT>&lt;resource&gt;</TT>. Example:
 <PRE CLASS="verbatim">{acl, mucklres, {resource, "muckl"}}.
+</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, &lt;groupname&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT>&lt;groupname&gt;</TT> in the virtual host. Example:
+<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam"}}.
+</PRE></DD><DT CLASS="dt-description"><B><TT>{shared_group, &lt;groupname&gt;, &lt;server&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any member of a Shared Roster Group with name <TT>&lt;groupname&gt;</TT> in the virtual host <TT>&lt;server&gt;</TT>. Example:
+<PRE CLASS="verbatim">{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.
 </PRE></DD><DT CLASS="dt-description"><B><TT>{user_regexp, &lt;regexp&gt;}</TT></B></DT><DD CLASS="dd-description"> Matches any local user with a name that
 matches <TT>&lt;regexp&gt;</TT> on local virtual hosts. Example:
 <PRE CLASS="verbatim">{acl, tests, {user_regexp, "^test[0-9]*$"}}.
index 9501c0cc5e46696de889256f6cf1253bcccec95b..afc63a3ffb10c30fcac894666f04f7a06e517ed6 100644 (file)
@@ -870,6 +870,10 @@ There are some additional global options:
   file containing a SSL certificate.
   \titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile}
   Full path to the file containing the SSL certificate for a specific domain.
+  \titem{\{outgoing\_s2s\_options, Methods, Timeout\}} \ind{options!outgoing\_s2s\_options}
+  Specify which address families to try, in what order, and connect timeout in milliseconds.
+  By default it first tries connecting with IPv4, if that fails it tries using IPv6,
+  with a timeout of 10000 milliseconds.
   \titem{\{s2s\_default\_policy, allow|deny\}}
   The default policy for incoming and outgoing s2s connections to other Jabber servers.
   The default value is \term{allow}.
index 6a6b52494eed4a2fea52127cc51cae7954a35c6c..046db942b545b53ab06d22f592fde3f301d22ae1 100644 (file)
 %%{{s2s_host, "goodhost.org"}, allow}.
 %%{{s2s_host, "badhost.org"}, deny}.
 
+%%
+%% Outgoing S2S options
+%%
+%% Preferred address families (which to try first) and connect timeout
+%% in milliseconds.
+%%
+%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
 
 %%%   ==============
 %%%   AUTHENTICATION
index 6ee0fa528e443b0ae7bfc80dd23aa5ab0030431b..a5083424b36dbb44db40706c89a21f59ef745fd8 100644 (file)
@@ -330,6 +330,8 @@ process_term(Term, State) ->
            add_option(language, Val, State);
        {outgoing_s2s_port, Port} ->
            add_option(outgoing_s2s_port, Port, State);
+       {outgoing_s2s_options, Methods, Timeout} ->
+           add_option(outgoing_s2s_options, {Methods, Timeout}, State);
        {s2s_use_starttls, Port} ->
            add_option(s2s_use_starttls, Port, State);
        {s2s_certfile, CertFile} ->
index aa4c7ed96f4e329944f3615a4d920056277127fc..5f5d905f81ee6e94738744b92f2d52ccbc64e035 100644 (file)
 -define(INVALID_XML_ERR,
        xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
 
+-define(SOCKET_DEFAULT_RESULT, {error, badarg}).
+
 %%%----------------------------------------------------------------------
 %%% API
 %%%----------------------------------------------------------------------
@@ -206,7 +208,7 @@ open_socket(init, StateData) ->
                                 _ ->
                                     open_socket1(Addr, Port)
                             end
-                    end, {error, badarg}, AddrList) of
+                    end, ?SOCKET_DEFAULT_RESULT, AddrList) of
        {ok, Socket} ->
            Version = if
                          StateData#state.use_v10 ->
@@ -239,34 +241,40 @@ open_socket(_, StateData) ->
     {next_state, open_socket, StateData}.
 
 %%----------------------------------------------------------------------
-open_socket1(Addr, Port) ->
-    ?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]),
-    Res = case catch ejabberd_socket:connect(
-                      Addr, Port,
-                      [binary, {packet, 0},
-                       {active, false}]) of
-             {ok, _Socket} = R -> R;
-             {error, Reason1} ->
-                 ?DEBUG("s2s_out: connect return ~p~n", [Reason1]),
-                 catch ejabberd_socket:connect(
-                         Addr, Port,
-                         [binary, {packet, 0},
-                          {active, false}, inet6]);
-             {'EXIT', Reason1} ->
-                 ?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]),
-                 catch ejabberd_socket:connect(
-                         Addr, Port,
-                         [binary, {packet, 0},
-                          {active, false}, inet6])
-         end,
-    case Res of
-       {ok, Socket} ->
-           {ok, Socket};
-       {error, Reason} ->
-           ?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
-           {error, Reason};
+%% IPv4
+open_socket1({_,_,_,_} = Addr, Port) ->
+    open_socket2(inet, Addr, Port);
+
+%% IPv6
+open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) ->
+    open_socket2(inet6, Addr, Port);
+
+%% Hostname
+open_socket1(Host, Port) ->
+    lists:foldl(fun(_Family, {ok, _Socket} = R) ->
+                       R;
+                  (Family, _) ->
+                       Addrs = get_addrs(Host, Family),
+                       lists:foldl(fun(_Addr, {ok, _Socket} = R) ->
+                                           R;
+                                      (Addr, _) ->
+                                           open_socket1(Addr, Port)
+                                   end, ?SOCKET_DEFAULT_RESULT, Addrs)
+               end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()).
+
+open_socket2(Type, Addr, Port) ->
+    ?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
+    Timeout = outgoing_s2s_timeout(),
+    case (catch ejabberd_socket:connect(Addr, Port,
+                                       [binary, {packet, 0},
+                                        {active, false}, Type],
+                                       Timeout)) of
+       {ok, _Socket} = R -> R;
+       {error, Reason} = R ->
+           ?DEBUG("s2s_out: connect return ~p~n", [Reason]),
+           R;
        {'EXIT', Reason} ->
-           ?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]),
+           ?DEBUG("s2s_out: connect crashed ~p~n", [Reason]),
            {error, Reason}
     end.
 
@@ -1000,6 +1008,23 @@ test_get_addr_port(Server) ->
              end
       end, [], lists:seq(1, 100000)).
 
+get_addrs(Host, Family) ->
+    Type = case Family of
+              inet4 -> a;
+              ipv4 -> a;
+              inet6 -> aaaa;
+              ipv6 -> aaaa
+          end,
+    case inet_res:getbyname(Host, Type) of
+       {ok, #hostent{h_addr_list = Addrs}} ->
+           ?DEBUG("~s of ~s resolved to: ~p~n", [Type, Host, Addrs]),
+           Addrs;
+       {error, Reason} ->
+           ?DEBUG("~s lookup of '~s' failed: ~p~n", [Type, Host, Reason]),
+           []
+    end.
+
+
 outgoing_s2s_port() ->
     case ejabberd_config:get_local_option(outgoing_s2s_port) of
        Port when is_integer(Port) ->
@@ -1008,6 +1033,36 @@ outgoing_s2s_port() ->
            5269
     end.
 
+outgoing_s2s_families() ->
+    case ejabberd_config:get_local_option(outgoing_s2s_options) of
+       {Families, _} when is_list(Families) ->
+           Families;
+       undefined ->
+           %% DISCUSSION: Why prefer IPv4 first?
+           %%
+           %% IPv4 connectivity will be available for everyone for
+           %% many years to come. So, there's absolutely no benefit
+           %% in preferring IPv6 connections which are flaky at best
+           %% nowadays.
+           %%
+           %% On the other hand content providers hesitate putting up
+           %% AAAA records for their sites due to the mentioned
+           %% quality of current IPv6 connectivity. Making IPv6 the a
+           %% `fallback' may avoid these problems elegantly.
+           [ipv4, ipv6]
+    end.
+
+outgoing_s2s_timeout() ->
+    case ejabberd_config:get_local_option(outgoing_s2s_options) of
+       {_, Timeout} when is_integer(Timeout) ->
+           Timeout;
+       {_, infinity} ->
+           infinity;
+       undefined ->
+           %% 10 seconds
+           10000
+    end.
+
 %% Human readable S2S logging: Log only new outgoing connections as INFO
 %% Do not log dialback
 log_s2s_out(false, _, _) -> ok;
index ba706e4e87ae7dc9039f062fc37d6c164aacb5b4..01e1eddcbfe4eca72f90c18162c2f41438d7c977 100644 (file)
@@ -30,6 +30,7 @@
 %% API
 -export([start/4,
         connect/3,
+        connect/4,
         starttls/2,
         starttls/3,
         compress/1,
@@ -94,7 +95,10 @@ start(Module, SockMod, Socket, Opts) ->
     end.
 
 connect(Addr, Port, Opts) ->
-    case gen_tcp:connect(Addr, Port, Opts) of
+    connect(Addr, Port, Opts, infinity).
+
+connect(Addr, Port, Opts, Timeout) ->
+    case gen_tcp:connect(Addr, Port, Opts, Timeout) of
        {ok, Socket} ->
            Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
            SocketData = #socket_state{sockmod = gen_tcp,