* src/ejabberd_app.erl: In a Windows machine, explicitly add the
authorBadlop <badlop@process-one.net>
Thu, 5 Mar 2009 20:03:18 +0000 (20:03 +0000)
committerBadlop <badlop@process-one.net>
Thu, 5 Mar 2009 20:03:18 +0000 (20:03 +0000)
nameservers, as it seems Erlang does not do itself (EJAB-860)
* src/win32_dns.erl: Get name servers from Windows registy (thanks
to Geoff Cant)

SVN Revision: 1968

ChangeLog
src/ejabberd_app.erl
src/win32_dns.erl [new file with mode: 0644]

index a0cd37d7732bd04741ce5ca07d232cd66dc950fa..03b41b8039df39efb5d0f7ffc79c94a7e340e515 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2009-03-05  Badlop  <badlop@process-one.net>
 
+       * src/ejabberd_app.erl: In a Windows machine, explicitly add the
+       nameservers, as it seems Erlang does not do itself (EJAB-860)
+       * src/win32_dns.erl: Get name servers from Windows registy (thanks
+       to Geoff Cant)
+
        * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877)
        * doc/guide.html: Likewise
 
index 35746b37037aebc577738e5bae4d42f48973d231..b774bacb539b387f914113f663aa71427ace7305 100644 (file)
@@ -63,6 +63,7 @@ start(normal, _Args) ->
     %eprof:start(),
     %eprof:profile([self()]),
     %fprof:trace(start, "/tmp/fprof"),
+    maybe_add_nameservers(),
     start_modules(),
     ejabberd_listener:start_listeners(),
     ?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
@@ -180,3 +181,16 @@ get_log_path() ->
                    Path
            end
     end.
+
+
+%% If ejabberd is running on some Windows machine, get nameservers and add to Erlang
+maybe_add_nameservers() ->
+    case os:type() of
+       {win32, _} -> add_windows_nameservers();
+       _ -> ok
+    end.
+
+add_windows_nameservers() ->
+    IPTs = win32_dns_test:get_nameservers(),
+    ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]),
+    lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
diff --git a/src/win32_dns.erl b/src/win32_dns.erl
new file mode 100644 (file)
index 0000000..79725cb
--- /dev/null
@@ -0,0 +1,122 @@
+%%%----------------------------------------------------------------------
+%%% File    : win32_dns.erl
+%%% Author  : Geoff Cant
+%%% Purpose : Get name servers in a Windows machine
+%%% Created : 5 Mar 2009 by Geoff Cant
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2009   ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with this program; if not, write to the Free Software
+%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+%%% 02111-1307 USA
+%%%
+%%%----------------------------------------------------------------------
+
+-module(win32_dns).
+-export([get_nameservers/0]).
+
+-define(IF_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces").
+-define(TOP_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters").
+
+get_nameservers() ->
+    {_, Config} = pick_config(),
+    IPTs = get_value(["NameServer"], Config),
+    lists:filter(fun(IPTuple) -> is_good_ns(IPTuple) end, IPTs).
+
+is_good_ns(Addr) ->
+    element(1,
+           inet_res:nnslookup("a.root-servers.net", in, any, [{Addr,53}],
+                              timer:seconds(5)
+                             )
+          ) =:= ok.
+
+reg() ->
+    {ok, R} = win32reg:open([read]),
+    R.
+
+interfaces(R) ->
+    ok = win32reg:change_key(R, ?IF_KEY),
+    {ok, I} = win32reg:sub_keys(R),
+    I.
+config_keys(R, Key) ->
+    ok = win32reg:change_key(R, Key),
+    [ {K,
+       case win32reg:value(R, K) of
+           {ok, V} -> translate(K, V);
+           _ -> undefined
+       end
+      } || K <- ["Domain", "DhcpDomain",
+                 "NameServer", "DhcpNameServer", "SearchList"]].
+
+translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" ->
+    IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, ",")],
+    [ list_to_tuple([list_to_integer(String) || String <- IpStrings])
+      || IpStrings <- IPsStrings];
+translate(_, V) -> V.
+
+interface_configs(R) ->
+    [{If, config_keys(R, ?IF_KEY ++ "\\" ++ If)}
+     || If <- interfaces(R)].
+
+sort_configs(Configs) ->
+    lists:sort(fun ({_, A}, {_, B}) ->
+                       ANS = proplists:get_value("NameServer", A),
+                       BNS = proplists:get_value("NameServer", B),
+                       if ANS =/= undefined, BNS =:= undefined -> false;
+                          true -> count_undef(A) < count_undef(B)
+                       end
+               end,
+              Configs).
+
+count_undef(L) when is_list(L) ->
+    lists:foldl(fun ({_K, undefined}, Acc) -> Acc +1;
+                    ({_K, []}, Acc) -> Acc +1;
+                    (_, Acc) -> Acc
+                end, 0, L).
+
+all_configs() ->
+    R = reg(),
+    TopConfig = config_keys(R, ?TOP_KEY),
+    Configs = [{top, TopConfig}
+               | interface_configs(R)],
+    win32reg:close(R),
+    {TopConfig, Configs}.
+
+pick_config() ->
+    {TopConfig, Configs} = all_configs(),
+    NSConfigs = [{If, C} || {If, C} <- Configs,
+                           get_value(["DhcpNameServer","NameServer"], C)
+                               =/= undefined],
+    case get_value(["DhcpNameServer","NameServer"],
+                   TopConfig) of
+        %% No top level nameserver to pick interface with
+        undefined ->
+            hd(sort_configs(NSConfigs));
+        %% Top level has a nameserver - use this to select an interface.
+        NS ->
+            Cs = [ {If, C}
+                   || {If, C} <- Configs,
+                     lists:member(NS,
+                                  [get_value(["NameServer"], C),
+                                   get_value(["DhcpNameServer"], C)])],
+            hd(sort_configs(Cs))
+    end.
+
+get_value([], _Config) -> undefined;
+get_value([K|Keys], Config) ->
+    case proplists:get_value(K, Config) of
+        undefined -> get_value(Keys, Config);
+        V -> V
+    end.