Blob Blame History Raw
From f0180ce1f7d8dff10caba7baa5f3854297b65b12 Mon Sep 17 00:00:00 2001
From: Danil Zagoskin <stolen@yandex-team.ru>
Date: Sat, 2 May 2015 00:40:53 +0300
Subject: [PATCH] kernel: inet6_tcp_dist: reuse inet_tcp_dist code

inet6_tcp_dist module is an old copy of inet_tcp_dist with changed
address family.
New features (such as listening port range, interface and generic
options) are implemented in inet_tcp_dist only, inet6_tcp_dist looks
abandoned (it does not even have tests).
This patch makes inet_tcp_dist internals work with abstract driver,
and inet6_tcp_dist becomes just a thin wrapper for it.
---
 lib/kernel/src/inet6_tcp.erl      |  19 ++
 lib/kernel/src/inet6_tcp_dist.erl | 365 +-------------------------------------
 lib/kernel/src/inet_tcp.erl       |  16 +-
 lib/kernel/src/inet_tcp_dist.erl  | 197 ++++++++++++--------
 4 files changed, 159 insertions(+), 438 deletions(-)

diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index c714b2b..b31f05b 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -24,10 +24,29 @@
 -export([controlling_process/2]).
 -export([fdopen/2]).
 
+-export([family/0, mask/2, parse_address/1]).
 -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
 
 -include("inet_int.hrl").
 
+%% my address family
+family() -> inet6.
+
+%% Apply netmask on address
+mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
+    {M1 band IP1,
+     M2 band IP2,
+     M3 band IP3,
+     M4 band IP4,
+     M5 band IP5,
+     M6 band IP6,
+     M7 band IP7,
+     M8 band IP8 }.
+
+%% Parse address string
+parse_address(Host) ->
+    inet_parse:ipv6strict_address(Host).
+
 %% inet_tcp port lookup
 getserv(Port) when is_integer(Port) -> {ok, Port};
 getserv(Name) when is_atom(Name)    -> inet:getservbyname(Name,tcp).
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
index 2cb0e10..1488bf4 100644
--- a/lib/kernel/src/inet6_tcp_dist.erl
+++ b/lib/kernel/src/inet6_tcp_dist.erl
@@ -23,28 +23,6 @@
 -export([listen/1, accept/1, accept_connection/5,
          setup/5, close/1, select/1, is_node_name/1]).
 
-%% internal exports
-
--export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]).
-
--import(error_logger,[error_msg/2]).
-
--include("net_address.hrl").
-
-
-
--define(to_port(Socket, Data, Opts),
-        case inet6_tcp:send(Socket, Data, Opts) of
-            {error, closed} ->
-                self() ! {tcp_closed, Socket},
-                {error, closed};
-            R ->
-                R
-        end).
-
-
--include("dist.hrl").
--include("dist_util.hrl").
 
 %% ------------------------------------------------------------
 %%  Select this protocol based on node name
@@ -52,14 +30,7 @@
 %% ------------------------------------------------------------
 
 select(Node) ->
-    case split_node(atom_to_list(Node), $@, []) of
-        [_, Host] ->
-            case inet:getaddr(Host,inet6) of
-                {ok,_} -> true;
-                _ -> false
-            end;
-        _ -> false
-    end.
+    inet_tcp_dist:gen_select(inet6_tcp, Node).
 
 %% ------------------------------------------------------------
 %% Create the listen socket, i.e. the port that this erlang
@@ -67,59 +38,14 @@ select(Node) ->
 %% ------------------------------------------------------------
 
 listen(Name) ->
-    case inet6_tcp:listen(0, [{active, false}, {packet,2}]) of
-        {ok, Socket} ->
-            TcpAddress = get_tcp_address(Socket),
-            {_,Port} = TcpAddress#net_address.address,
-            case erl_epmd:register_node(Name, Port) of
-                {ok, Creation} ->
-                    {ok, {Socket, TcpAddress, Creation}};
-                Error ->
-                    Error
-            end;
-        Error ->
-            Error
-    end.
+    inet_tcp_dist:gen_listen(inet6_tcp, Name).
 
 %% ------------------------------------------------------------
 %% Accepts new connection attempts from other Erlang nodes.
 %% ------------------------------------------------------------
 
 accept(Listen) ->
-    spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
-
-accept_loop(Kernel, Listen) ->
-    case inet6_tcp:accept(Listen) of
-        {ok, Socket} ->
-            Kernel ! {accept,self(),Socket,inet6,tcp},
-            controller(Kernel, Socket),
-            accept_loop(Kernel, Listen);
-        Error ->
-            exit(Error)
-    end.
-
-controller(Kernel, Socket) ->
-    receive
-        {Kernel, controller, Pid} ->
-            flush_controller(Pid, Socket),
-            inet6_tcp:controlling_process(Socket, Pid),
-            flush_controller(Pid, Socket),
-            Pid ! {self(), controller};
-        {Kernel, unsupported_protocol} ->
-            exit(unsupported_protocol)
-    end.
-
-flush_controller(Pid, Socket) ->
-    receive
-        {tcp, Socket, Data} ->
-            Pid ! {tcp, Socket, Data},
-            flush_controller(Pid, Socket);
-        {tcp_closed, Socket} ->
-            Pid ! {tcp_closed, Socket},
-            flush_controller(Pid, Socket)
-    after 0 ->
-            ok
-    end.
+    inet_tcp_dist:gen_accept(inet6_tcp, Listen).
 
 %% ------------------------------------------------------------
 %% Accepts a new connection attempt from another Erlang node.
@@ -127,85 +53,7 @@ flush_controller(Pid, Socket) ->
 %% ------------------------------------------------------------
 
 accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
-    spawn_opt(?MODULE, do_accept,
-	      [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
-	      [link, {priority, max}]).
-
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
-    receive
-        {AcceptPid, controller} ->
-            Timer = dist_util:start_timer(SetupTime),
-            case check_ip(Socket) of
-                true ->
-                    HSData = #hs_data{
-                      kernel_pid = Kernel,
-                      this_node = MyNode,
-                      socket = Socket,
-                      timer = Timer,
-                      this_flags = 0,
-                      allowed = Allowed,
-                      f_send = fun(S,D) -> inet6_tcp:send(S,D) end,
-                      f_recv = fun(S,N,T) -> inet6_tcp:recv(S,N,T) 
-                               end,
-                      f_setopts_pre_nodeup = 
-                      fun(S) ->
-                              inet:setopts(S, 
-                                           [{active, false},
-                                            {packet, 4},
-                                            nodelay()])
-                      end,
-                      f_setopts_post_nodeup = 
-                      fun(S) ->
-                              inet:setopts(S, 
-                                           [{active, true},
-                                            {deliver, port},
-                                            {packet, 4},
-                                            nodelay()])
-                      end,
-                      f_getll = fun(S) ->
-                                        inet:getll(S)
-                                end,
-                      f_address = fun get_remote_id/2,
-                      mf_tick = fun ?MODULE:tick/1,
-                      mf_getstat = fun ?MODULE:getstat/1
-                     },
-                    dist_util:handshake_other_started(HSData);
-                {false,IP} ->
-                    error_msg("** Connection attempt from "
-                              "disallowed IP ~w ** ~n", [IP]),
-                    ?shutdown(no_node)
-            end
-    end.
-
-
-%% we may not always want the nodelay behaviour
-%% for performance reasons
-
-nodelay() ->
-    case application:get_env(kernel, dist_nodelay) of
-        undefined ->
-            {nodelay, true};
-        {ok, true} ->
-            {nodelay, true};
-        {ok, false} ->
-            {nodelay, false};
-        _ ->
-            {nodelay, true}
-    end.
-            
-
-%% ------------------------------------------------------------
-%% Get remote information about a Socket.
-%% ------------------------------------------------------------
-
-get_remote_id(Socket, Node) ->
-    {ok, Address} = inet:peername(Socket),
-    [_, Host] = split_node(atom_to_list(Node), $@, []),
-    #net_address {
-                  address = Address,
-                  host = Host,
-                  protocol = tcp,
-                  family = inet6 }.
+    inet_tcp_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
 
 %% ------------------------------------------------------------
 %% Setup a new connection to another Erlang node.
@@ -213,214 +61,13 @@ get_remote_id(Socket, Node) ->
 %% ------------------------------------------------------------
 
 setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
-    spawn_opt(?MODULE, do_setup, 
-	      [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
-	      [link, {priority, max}]).
-
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
-    ?trace("~p~n",[{?MODULE,self(),setup,Node}]),
-    [Name, Address] = splitnode(Node, LongOrShortNames),
-    case inet:getaddr(Address, inet6) of
-        {ok, Ip} ->
-            Timer = dist_util:start_timer(SetupTime),
-            case erl_epmd:port_please(Name, Ip) of
-                {port, TcpPort, Version} ->
-                    ?trace("port_please(~p) -> version ~p~n", 
-                           [Node,Version]),
-                    dist_util:reset_timer(Timer),
-                    case inet6_tcp:connect(Ip, TcpPort, 
-                                          [{active, false}, 
-                                           {packet,2}]) of
-                        {ok, Socket} ->
-                            HSData = #hs_data{
-                              kernel_pid = Kernel,
-                              other_node = Node,
-                              this_node = MyNode,
-                              socket = Socket,
-                              timer = Timer,
-                              this_flags = 0,
-                              other_version = Version,
-			      f_send = fun inet6_tcp:send/2,
-			      f_recv = fun inet6_tcp:recv/3,
-                              f_setopts_pre_nodeup = 
-                              fun(S) ->
-                                      inet:setopts
-                                        (S, 
-                                         [{active, false},
-                                          {packet, 4},
-                                          nodelay()])
-                              end,
-                              f_setopts_post_nodeup = 
-                              fun(S) ->
-                                      inet:setopts
-                                        (S, 
-                                         [{active, true},
-                                          {deliver, port},
-                                          {packet, 4},
-                                          nodelay()])
-                              end,
-			      f_getll = fun inet:getll/1,
-                              f_address = 
-                              fun(_,_) ->
-                                      #net_address {
-                                   address = {Ip,TcpPort},
-                                   host = Address,
-                                   protocol = tcp,
-                                   family = inet6}
-                              end,
-			      mf_tick = fun ?MODULE:tick/1,
-			      mf_getstat = fun ?MODULE:getstat/1,
-			      request_type = Type
-                             },
-                            dist_util:handshake_we_started(HSData);
-                        _ ->
-                            %% Other Node may have closed since 
-                            %% port_please !
-                            ?trace("other node (~p) "
-                                   "closed since port_please.~n", 
-                                   [Node]),
-                            ?shutdown(Node)
-                    end;
-                _ ->
-                    ?trace("port_please (~p) "
-                           "failed.~n", [Node]),
-                    ?shutdown(Node)
-            end;
-        __Other ->
-            ?trace("inet_getaddr(~p) "
-                   "failed (~p).~n", [Node,__Other]),
-            ?shutdown(Node)
-    end.
+    inet_tcp_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
 
 %%
 %% Close a socket.
 %%
 close(Socket) ->
     inet6_tcp:close(Socket).
-
-
-%% If Node is illegal terminate the connection setup!!
-splitnode(Node, LongOrShortNames) ->
-    case split_node(atom_to_list(Node), $@, []) of
-        [Name|Tail] when Tail =/= [] ->
-            Host = lists:append(Tail),
-            case split_node(Host, $., []) of
-                [_] when LongOrShortNames =:= longnames ->
-                    case inet_parse:ipv6strict_address(Host) of
-                        {ok, _} ->
-                            [Name, Host];
-                        _ ->
-                            error_msg("** System running to use "
-                                      "fully qualified "
-                                      "hostnames **~n"
-                                      "** Hostname ~s is illegal **~n",
-                                      [Host]),
-                            ?shutdown(Node)
-                    end;
-                L when length(L) > 1, LongOrShortNames =:= shortnames ->
-                    error_msg("** System NOT running to use fully qualified "
-                              "hostnames **~n"
-                              "** Hostname ~s is illegal **~n",
-                              [Host]),
-                    ?shutdown(Node);
-                _ ->
-                    [Name, Host]
-            end;
-        [_] ->
-            error_msg("** Nodename ~p illegal, no '@' character **~n",
-                      [Node]),
-            ?shutdown(Node);
-        _ ->
-            error_msg("** Nodename ~p illegal **~n", [Node]),
-            ?shutdown(Node)
-    end.
-
-split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
-split_node([H|T], Chr, Ack)   -> split_node(T, Chr, [H|Ack]);
-split_node([], _, Ack)        -> [lists:reverse(Ack)].
-
-%% ------------------------------------------------------------
-%% Fetch local information about a Socket.
-%% ------------------------------------------------------------
-get_tcp_address(Socket) ->
-    {ok, Address} = inet:sockname(Socket),
-    {ok, Host} = inet:gethostname(),
-    #net_address {
-                  address = Address,
-                  host = Host,
-                  protocol = tcp,
-                  family = inet6
-                 }.
-
-%% ------------------------------------------------------------
-%% Do only accept new connection attempts from nodes at our
-%% own LAN, if the check_ip environment parameter is true.
-%% ------------------------------------------------------------
-check_ip(Socket) ->
-    case application:get_env(check_ip) of
-        {ok, true} ->
-            case get_ifs(Socket) of
-                {ok, IFs, IP} ->
-                    check_ip(IFs, IP);
-                _ ->
-                    ?shutdown(no_node)
-            end;
-        _ ->
-            true
-    end.
-
-get_ifs(Socket) ->
-    case inet:peername(Socket) of
-        {ok, {IP, _}} ->
-            case inet:getif(Socket) of
-                {ok, IFs} -> {ok, IFs, IP};
-                Error     -> Error
-            end;
-        Error ->
-            Error
-    end.
-
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
-    case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
-        {M, M} -> true;
-        _      -> check_ip(IFs, PeerIP)
-    end;
-check_ip([], PeerIP) ->
-    {false, PeerIP}.
     
-mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
-    {M1 band IP1,
-     M2 band IP2,
-     M3 band IP3,
-     M4 band IP4,
-     M5 band IP5,
-     M6 band IP6,
-     M7 band IP7,
-     M8 band IP8 }.
-
 is_node_name(Node) when is_atom(Node) ->
-    case split_node(atom_to_list(Node), $@, []) of
-        [_,_Host] -> true;
-        _ -> false
-    end;
-is_node_name(_Node) ->
-    false.
-tick(Sock) ->
-    ?to_port(Sock,[],[force]).
-getstat(Socket) ->
-    case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
-        {ok, Stat} ->
-            split_stat(Stat,0,0,0);
-        Error ->
-            Error
-    end.
-
-split_stat([{recv_cnt, R}|Stat], _, W, P) ->
-    split_stat(Stat, R, W, P);
-split_stat([{send_cnt, W}|Stat], R, _, P) ->
-    split_stat(Stat, R, W, P);
-split_stat([{send_pend, P}|Stat], R, W, _) ->
-    split_stat(Stat, R, W, P);
-split_stat([], R, W, P) ->
-    {ok, R, W, P}.
-
+    inet_tcp_dist:is_node_name(Node).
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index 4c2db16..71d35ca 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -26,11 +26,25 @@
 -export([controlling_process/2]).
 -export([fdopen/2]).
 
+-export([family/0, mask/2, parse_address/1]).
 -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
 
-
 -include("inet_int.hrl").
 
+%% my address family
+family() -> inet.
+
+%% Apply netmask on address
+mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
+    {M1 band IP1,
+     M2 band IP2,
+     M3 band IP3,
+     M4 band IP4}.
+
+%% Parse address string
+parse_address(Host) ->
+    inet_parse:ipv4strict_address(Host).
+
 %% inet_tcp port lookup
 getserv(Port) when is_integer(Port) -> {ok, Port};
 getserv(Name) when is_atom(Name)    -> inet:getservbyname(Name,tcp).
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index 8005eff..0739cf3 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -23,9 +23,13 @@
 -export([listen/1, accept/1, accept_connection/5,
 	 setup/5, close/1, select/1, is_node_name/1]).
 
+%% Generalized dist API
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
+	 gen_setup/6, gen_select/2]).
+
 %% internal exports
 
--export([accept_loop/2,do_accept/6,do_setup/6,getstat/1,tick/1]).
+-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]).
 
 -import(error_logger,[error_msg/2]).
 
@@ -33,15 +37,6 @@
 
 
 
--define(to_port(Socket, Data, Opts),
-	case inet_tcp:send(Socket, Data, Opts) of
-	    {error, closed} ->
-		self() ! {tcp_closed, Socket},
-	        {error, closed};
-	    R ->
-	        R
-        end).
-
 
 -include("dist.hrl").
 -include("dist_util.hrl").
@@ -52,8 +47,15 @@
 %% ------------------------------------------------------------
 
 select(Node) ->
+    gen_select(inet_tcp, Node).
+
+gen_select(Driver, Node) ->
     case split_node(atom_to_list(Node), $@, []) of
-	[_,_Host] -> true;
+	[_, Host] ->
+	    case inet:getaddr(Host, Driver:family()) of
+                {ok,_} -> true;
+                _ -> false
+            end;
 	_ -> false
     end.
 
@@ -63,9 +65,12 @@ select(Node) ->
 %% ------------------------------------------------------------
 
 listen(Name) ->
-    case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of
+    gen_listen(inet_tcp, Name).
+
+gen_listen(Driver, Name) ->
+    case do_listen(Driver, [{active, false}, {packet,2}, {reuseaddr, true}]) of
 	{ok, Socket} ->
-	    TcpAddress = get_tcp_address(Socket),
+	    TcpAddress = get_tcp_address(Driver, Socket),
 	    {_,Port} = TcpAddress#net_address.address,
 	    case erl_epmd:register_node(Name, Port) of
 		{ok, Creation} ->
@@ -77,7 +82,7 @@ listen(Name) ->
 	    Error
     end.
 
-do_listen(Options0) ->
+do_listen(Driver, Options) ->
     {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
 		       {ok,N} when is_integer(N) ->
 			   case application:get_env(kernel,
@@ -90,46 +95,60 @@ do_listen(Options0) ->
 		       _ ->
 			   {0,0}
 		   end,
-    Options = case application:get_env(kernel, inet_dist_use_interface) of
-		   {ok, Ip} ->
-		       [{ip, Ip} | Options0];
-		   _ ->
-		       Options0
-	       end,
-    do_listen(First, Last, [{backlog,128}|Options]).
-
-do_listen(First,Last,_) when First > Last ->
+    do_listen(Driver, First, Last, listen_options([{backlog,128}|Options])).
+
+do_listen(_Driver, First,Last,_) when First > Last ->
     {error,eaddrinuse};
-do_listen(First,Last,Options) ->
-    case inet_tcp:listen(First, Options) of
+do_listen(Driver, First,Last,Options) ->
+    case Driver:listen(First, Options) of
 	{error, eaddrinuse} ->
-	    do_listen(First+1,Last,Options);
+	    do_listen(Driver, First+1,Last,Options);
 	Other ->
 	    Other
     end.
 
+listen_options(Opts0) ->
+    Opts1 =
+	case application:get_env(kernel, inet_dist_use_interface) of
+	    {ok, Ip} ->
+		[{ip, Ip} | Opts0];
+	    _ ->
+		Opts0
+	end,
+    case application:get_env(kernel, inet_dist_listen_options) of
+	{ok,ListenOpts} ->
+	    erlang:display({inet_dist_listen_options, ListenOpts}),
+	    ListenOpts ++ Opts1;
+	_ ->
+	    Opts1
+    end.
+
+
 %% ------------------------------------------------------------
 %% Accepts new connection attempts from other Erlang nodes.
 %% ------------------------------------------------------------
 
 accept(Listen) ->
-    spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
+    gen_accept(inet_tcp, Listen).
 
-accept_loop(Kernel, Listen) ->
-    case inet_tcp:accept(Listen) of
+gen_accept(Driver, Listen) ->
+    spawn_opt(?MODULE, accept_loop, [Driver, self(), Listen], [link, {priority, max}]).
+
+accept_loop(Driver, Kernel, Listen) ->
+    case Driver:accept(Listen) of
 	{ok, Socket} ->
-	    Kernel ! {accept,self(),Socket,inet,tcp},
-	    controller(Kernel, Socket),
-	    accept_loop(Kernel, Listen);
+	    Kernel ! {accept,self(),Socket,Driver:family(),tcp},
+	    _ = controller(Driver, Kernel, Socket),
+	    accept_loop(Driver, Kernel, Listen);
 	Error ->
 	    exit(Error)
     end.
 
-controller(Kernel, Socket) ->
+controller(Driver, Kernel, Socket) ->
     receive
 	{Kernel, controller, Pid} ->
 	    flush_controller(Pid, Socket),
-	    inet_tcp:controlling_process(Socket, Pid),
+	    Driver:controlling_process(Socket, Pid),
 	    flush_controller(Pid, Socket),
 	    Pid ! {self(), controller};
 	{Kernel, unsupported_protocol} ->
@@ -154,15 +173,18 @@ flush_controller(Pid, Socket) ->
 %% ------------------------------------------------------------
 
 accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+    gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
+
+gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
     spawn_opt(?MODULE, do_accept,
-	      [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
+	      [Driver, self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
 	      [link, {priority, max}]).
 
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
     receive
 	{AcceptPid, controller} ->
 	    Timer = dist_util:start_timer(SetupTime),
-	    case check_ip(Socket) of
+	    case check_ip(Driver, Socket) of
 		true ->
 		    HSData = #hs_data{
 		      kernel_pid = Kernel,
@@ -171,9 +193,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
 		      timer = Timer,
 		      this_flags = 0,
 		      allowed = Allowed,
-		      f_send = fun(S,D) -> inet_tcp:send(S,D) end,
-		      f_recv = fun(S,N,T) -> inet_tcp:recv(S,N,T) 
-			       end,
+		      f_send = fun Driver:send/2,
+		      f_recv = fun Driver:recv/3,
 		      f_setopts_pre_nodeup = 
 		      fun(S) ->
 			      inet:setopts(S, 
@@ -192,8 +213,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
 		      f_getll = fun(S) ->
 					inet:getll(S)
 				end,
-		      f_address = fun get_remote_id/2,
-		      mf_tick = fun ?MODULE:tick/1,
+		      f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end,
+		      mf_tick = fun(S) -> tick(Driver, S) end,
 		      mf_getstat = fun ?MODULE:getstat/1
 		     },
 		    dist_util:handshake_other_started(HSData);
@@ -224,13 +245,13 @@ nodelay() ->
 %% ------------------------------------------------------------
 %% Get remote information about a Socket.
 %% ------------------------------------------------------------
-get_remote_id(Socket, Node) ->
+get_remote_id(Driver, Socket, Node) ->
     case inet:peername(Socket) of
 	{ok,Address} ->
 	    case split_node(atom_to_list(Node), $@, []) of
 		[_,Host] ->
 		    #net_address{address=Address,host=Host,
-				 protocol=tcp,family=inet};
+				 protocol=tcp,family=Driver:family()};
 		_ ->
 		    %% No '@' or more than one '@' in node name.
 		    ?shutdown(no_node)
@@ -245,14 +266,18 @@ get_remote_id(Socket, Node) ->
 %% ------------------------------------------------------------
 
 setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+    gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
+
+gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
     spawn_opt(?MODULE, do_setup, 
-	      [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
+	      [Driver, self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
 	      [link, {priority, max}]).
 
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
     ?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]),
-    [Name, Address] = splitnode(Node, LongOrShortNames),
-    case inet:getaddr(Address, inet) of
+    [Name, Address] = splitnode(Driver, Node, LongOrShortNames),
+    AddressFamily = Driver:family(),
+    case inet:getaddr(Address, AddressFamily) of
 	{ok, Ip} ->
 	    Timer = dist_util:start_timer(SetupTime),
 	    case erl_epmd:port_please(Name, Ip) of
@@ -260,9 +285,11 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
 		    ?trace("port_please(~p) -> version ~p~n", 
 			   [Node,Version]),
 		    dist_util:reset_timer(Timer),
-		    case inet_tcp:connect(Ip, TcpPort, 
-					  [{active, false}, 
-					   {packet,2}]) of
+		    case
+			Driver:connect(
+			  Ip, TcpPort,
+			  connect_options([{active, false}, {packet, 2}]))
+		    of
 			{ok, Socket} ->
 			    HSData = #hs_data{
 			      kernel_pid = Kernel,
@@ -272,8 +299,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
 			      timer = Timer,
 			      this_flags = 0,
 			      other_version = Version,
-			      f_send = fun inet_tcp:send/2,
-			      f_recv = fun inet_tcp:recv/3,
+			      f_send = fun Driver:send/2,
+			      f_recv = fun Driver:recv/3,
 			      f_setopts_pre_nodeup = 
 			      fun(S) ->
 				      inet:setopts
@@ -298,9 +325,9 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
 				   address = {Ip,TcpPort},
 				   host = Address,
 				   protocol = tcp,
-				   family = inet}
+				   family = AddressFamily}
 			      end,
-			      mf_tick = fun ?MODULE:tick/1,
+			      mf_tick = fun(S) -> tick(Driver, S) end,
 			      mf_getstat = fun ?MODULE:getstat/1,
 			      request_type = Type
 			     },
@@ -324,6 +351,15 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
 	    ?shutdown(Node)
     end.
 
+connect_options(Opts) ->
+    case application:get_env(kernel, inet_dist_connect_options) of
+	{ok,ConnectOpts} ->
+	    erlang:display({inet_dist_connect_options, ConnectOpts}),
+	    ConnectOpts ++ Opts;
+	_ ->
+	    Opts
+    end.
+
 %%
 %% Close a socket.
 %%
@@ -332,18 +368,23 @@ close(Socket) ->
 
 
 %% If Node is illegal terminate the connection setup!!
-splitnode(Node, LongOrShortNames) ->
+splitnode(Driver, Node, LongOrShortNames) ->
     case split_node(atom_to_list(Node), $@, []) of
 	[Name|Tail] when Tail =/= [] ->
 	    Host = lists:append(Tail),
 	    case split_node(Host, $., []) of
 		[_] when LongOrShortNames =:= longnames ->
-		    error_msg("** System running to use "
-			      "fully qualified "
-			      "hostnames **~n"
-			      "** Hostname ~s is illegal **~n",
-			      [Host]),
-		    ?shutdown(Node);
+                    case Driver:parse_address(Host) of
+                        {ok, _} ->
+                            [Name, Host];
+                        _ ->
+                            error_msg("** System running to use "
+                                      "fully qualified "
+                                      "hostnames **~n"
+                                      "** Hostname ~s is illegal **~n",
+                                      [Host]),
+                            ?shutdown(Node)
+                    end;
 		L when length(L) > 1, LongOrShortNames =:= shortnames ->
 		    error_msg("** System NOT running to use fully qualified "
 			      "hostnames **~n"
@@ -369,26 +410,26 @@ split_node([], _, Ack)        -> [lists:reverse(Ack)].
 %% ------------------------------------------------------------
 %% Fetch local information about a Socket.
 %% ------------------------------------------------------------
-get_tcp_address(Socket) ->
+get_tcp_address(Driver, Socket) ->
     {ok, Address} = inet:sockname(Socket),
     {ok, Host} = inet:gethostname(),
     #net_address {
 		  address = Address,
 		  host = Host,
 		  protocol = tcp,
-		  family = inet
+		  family = Driver:family()
 		 }.
 
 %% ------------------------------------------------------------
 %% Do only accept new connection attempts from nodes at our
 %% own LAN, if the check_ip environment parameter is true.
 %% ------------------------------------------------------------
-check_ip(Socket) ->
+check_ip(Driver, Socket) ->
     case application:get_env(check_ip) of
 	{ok, true} ->
 	    case get_ifs(Socket) of
 		{ok, IFs, IP} ->
-		    check_ip(IFs, IP);
+		    check_ip(Driver, IFs, IP);
 		_ ->
 		    ?shutdown(no_node)
 	    end;
@@ -407,20 +448,14 @@ get_ifs(Socket) ->
 	    Error
     end.
 
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
-    case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
+check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) ->
+    case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of
 	{M, M} -> true;
-	_      -> check_ip(IFs, PeerIP)
+	_      -> check_ip(Driver, IFs, PeerIP)
     end;
-check_ip([], PeerIP) ->
+check_ip(_Driver, [], PeerIP) ->
     {false, PeerIP}.
     
-mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
-    {M1 band IP1,
-     M2 band IP2,
-     M3 band IP3,
-     M4 band IP4}.
-
 is_node_name(Node) when is_atom(Node) ->
     case split_node(atom_to_list(Node), $@, []) of
 	[_, _Host] -> true;
@@ -429,8 +464,14 @@ is_node_name(Node) when is_atom(Node) ->
 is_node_name(_Node) ->
     false.
 
-tick(Sock) ->
-    ?to_port(Sock,[],[force]).
+tick(Driver, Socket) ->
+    case Driver:send(Socket, [], [force]) of
+	{error, closed} ->
+	    self() ! {tcp_closed, Socket},
+	    {error, closed};
+	R ->
+	    R
+    end.
 
 getstat(Socket) ->
     case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
-- 
2.5.0