aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2016-06-02 07:52:28 +0200
committerRaimo Niskanen <[email protected]>2016-06-02 08:00:57 +0200
commit30a202a41eb51f74d44e25667780136507395713 (patch)
treebf322dbdd67a56b2d521e8c8f37f00197ffae3a4 /lib/kernel/src
parentfaa62026143e37f80dbbb5f895715d1b8a369a9a (diff)
parent0f1a85ef0373f2b5767579a30a6dc29eeb16438a (diff)
downloadotp-30a202a41eb51f74d44e25667780136507395713.tar.gz
otp-30a202a41eb51f74d44e25667780136507395713.tar.bz2
otp-30a202a41eb51f74d44e25667780136507395713.zip
Merge branch 'saleyn/uds/PR-612/OTP-13572'
* saleyn/uds/PR-612/OTP-13572: Rewrite inet* for address family 'local' Rewrite inet_drv for AF_LOCAL Assign externally open fd to gen_tcp (UDS support) Conflicts: erts/preloaded/ebin/prim_inet.beam lib/kernel/doc/src/gen_tcp.xml lib/kernel/doc/src/gen_udp.xml lib/kernel/src/inet6_sctp.erl lib/kernel/test/inet_SUITE.erl
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/Makefile4
-rw-r--r--lib/kernel/src/gen_sctp.erl33
-rw-r--r--lib/kernel/src/gen_tcp.erl38
-rw-r--r--lib/kernel/src/gen_udp.erl36
-rw-r--r--lib/kernel/src/inet.erl101
-rw-r--r--lib/kernel/src/inet6_sctp.erl26
-rw-r--r--lib/kernel/src/inet6_tcp.erl88
-rw-r--r--lib/kernel/src/inet6_udp.erl42
-rw-r--r--lib/kernel/src/inet_int.hrl4
-rw-r--r--lib/kernel/src/inet_sctp.erl19
-rw-r--r--lib/kernel/src/inet_tcp.erl86
-rw-r--r--lib/kernel/src/inet_udp.erl52
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/local_tcp.erl172
-rw-r--r--lib/kernel/src/local_udp.erl99
15 files changed, 555 insertions, 247 deletions
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 8bf02afec9..2b72f78dcf 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -104,6 +104,8 @@ MODULES = \
inet_sctp \
kernel \
kernel_config \
+ local_udp \
+ local_tcp \
net \
net_adm \
net_kernel \
@@ -244,6 +246,8 @@ $(EBIN)/inet_tcp.beam: inet_int.hrl
$(EBIN)/inet_udp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl
$(EBIN)/inet_udp.beam: inet_int.hrl
$(EBIN)/inet_sctp.beam: inet_int.hrl ../include/inet_sctp.hrl
+$(EBIN)/local_udp.beam: inet_int.hrl
+$(EBIN)/local_tcp.beam: inet_int.hrl
$(EBIN)/net_kernel.beam: ../include/net_address.hrl
$(EBIN)/os.beam: ../include/file.hrl
$(EBIN)/ram_file.beam: ../include/file.hrl
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index d00ed828a7..b133e6fed4 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -124,8 +124,8 @@ open() ->
SockType :: seqpacket | stream,
Socket :: sctp_socket().
-open(Opts) when is_list(Opts) ->
- Mod = mod(Opts, undefined),
+open(Opts0) when is_list(Opts0) ->
+ {Mod, Opts} = inet:sctp_module(Opts0),
case Mod:open(Opts) of
{error,badarg} ->
erlang:error(badarg, [Opts]);
@@ -445,32 +445,3 @@ controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
controlling_process(S, Pid) ->
erlang:error(badarg, [S,Pid]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Utilites
-%%
-
-%% Get the SCTP module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:sctp_module() of
- inet_sctp when tuple_size(Address) =:= 8 ->
- inet6_sctp;
- Mod ->
- Mod
- end.
-
-%% Get the SCTP module, but option sctp_module|inet|inet6 overrides
-mod([{sctp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_sctp;
-mod([inet6|_], _Address) ->
- inet6_sctp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 1f0d44b8e1..2b3afcd44c 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -151,8 +151,8 @@ connect(Address, Port, Opts, Time) ->
Error -> Error
end.
-connect1(Address,Port,Opts,Timer) ->
- Mod = mod(Opts, Address),
+connect1(Address, Port, Opts0, Timer) ->
+ {Mod, Opts} = inet:tcp_module(Opts0, Address),
case Mod:getaddrs(Address,Timer) of
{ok,IPs} ->
case Mod:getserv(Port) of
@@ -185,8 +185,8 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) ->
ListenSocket :: socket(),
Reason :: system_limit | inet:posix().
-listen(Port, Opts) ->
- Mod = mod(Opts, undefined),
+listen(Port, Opts0) ->
+ {Mod, Opts} = inet:tcp_module(Opts0),
case Mod:getserv(Port) of
{ok,TP} ->
Mod:listen(TP, Opts);
@@ -335,32 +335,6 @@ controlling_process(S, NewOwner) ->
%%
%% Create a port/socket from a file descriptor
%%
-fdopen(Fd, Opts) ->
- Mod = mod(Opts, undefined),
+fdopen(Fd, Opts0) ->
+ {Mod, Opts} = inet:tcp_module(Opts0),
Mod:fdopen(Fd, Opts).
-
-%% Get the tcp_module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:tcp_module() of
- inet_tcp when tuple_size(Address) =:= 8 ->
- inet6_tcp;
- Mod ->
- Mod
- end.
-
-%% Get the tcp_module, but option tcp_module|inet|inet6 overrides
-mod([{tcp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_tcp;
-mod([inet6|_], _Address) ->
- inet6_tcp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
-
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 5e85c61dd9..2227bb3562 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -101,9 +101,9 @@ open(Port) ->
Socket :: socket(),
Reason :: inet:posix().
-open(Port, Opts) ->
- Mod = mod(Opts, undefined),
- {ok,UP} = Mod:getserv(Port),
+open(Port, Opts0) ->
+ {Mod, Opts} = inet:udp_module(Opts0),
+ {ok, UP} = Mod:getserv(Port),
Mod:open(UP, Opts).
-spec close(Socket) -> ok when
@@ -203,32 +203,6 @@ controlling_process(S, NewOwner) ->
%%
%% Create a port/socket from a file descriptor
%%
-fdopen(Fd, Opts) ->
- Mod = mod(Opts, undefined),
+fdopen(Fd, Opts0) ->
+ {Mod,Opts} = inet:udp_module(Opts0),
Mod:fdopen(Fd, Opts).
-
-
-%% Get the udp_module, but IPv6 address overrides default IPv4
-mod(Address) ->
- case inet_db:udp_module() of
- inet_udp when tuple_size(Address) =:= 8 ->
- inet6_udp;
- Mod ->
- Mod
- end.
-
-%% Get the udp_module, but option udp_module|inet|inet6 overrides
-mod([{udp_module,Mod}|_], _Address) ->
- Mod;
-mod([inet|_], _Address) ->
- inet_udp;
-mod([inet6|_], _Address) ->
- inet6_udp;
-mod([{ip, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([{ifaddr, Address}|Opts], _) ->
- mod(Opts, Address);
-mod([_|Opts], Address) ->
- mod(Opts, Address);
-mod([], Address) ->
- mod(Address).
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 713a9cf725..de43ea792b 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -37,6 +37,7 @@
parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, ntoa/1]).
-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
+-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]).
-export([i/0, i/1, i/2]).
@@ -133,9 +134,11 @@
'running' | 'multicast' | 'loopback']} |
{'hwaddr', ether_address()}.
--type address_family() :: 'inet' | 'inet6'.
+-type address_family() :: 'inet' | 'inet6' | 'local'.
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
+-type socket_address() ::
+ ip_address() | {address_family(), any()} | 'any' | 'loopback'.
-type stat_option() ::
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
@@ -681,7 +684,7 @@ connect_options() ->
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
show_econnreset].
-connect_options(Opts, Family) ->
+connect_options(Opts, Mod) ->
BaseOpts =
case application:get_env(kernel, inet_default_connect_options) of
{ok,List} when is_list(List) ->
@@ -698,7 +701,7 @@ connect_options(Opts, Family) ->
{ok, R} ->
{ok, R#connect_opts {
opts = lists:reverse(R#connect_opts.opts),
- ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#connect_opts.ifaddr)
}};
Error -> Error
end.
@@ -713,9 +716,6 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) ->
{fd,Fd} -> con_opt(Opts, R#connect_opts { fd = Fd }, As);
binary -> con_add(mode, binary, R, Opts, As);
list -> con_add(mode, list, R, Opts, As);
- {tcp_module,_} -> con_opt(Opts, R, As);
- inet -> con_opt(Opts, R, As);
- inet6 -> con_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -752,7 +752,7 @@ listen_options() ->
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
packet_size, raw, show_econnreset].
-listen_options(Opts, Family) ->
+listen_options(Opts, Mod) ->
BaseOpts =
case application:get_env(kernel, inet_default_listen_options) of
{ok,List} when is_list(List) ->
@@ -769,7 +769,7 @@ listen_options(Opts, Family) ->
{ok, R} ->
{ok, R#listen_opts {
opts = lists:reverse(R#listen_opts.opts),
- ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#listen_opts.ifaddr)
}};
Error -> Error
end.
@@ -785,9 +785,6 @@ list_opt([Opt | Opts], #listen_opts{} = R, As) ->
{backlog,BL} -> list_opt(Opts, R#listen_opts { backlog = BL }, As);
binary -> list_add(mode, binary, R, Opts, As);
list -> list_add(mode, list, R, Opts, As);
- {tcp_module,_} -> list_opt(Opts, R, As);
- inet -> list_opt(Opts, R, As);
- inet6 -> list_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -812,6 +809,19 @@ list_add(Name, Val, #listen_opts{} = R, Opts, As) ->
Error -> Error
end.
+tcp_module(Opts) ->
+ tcp_module_1(Opts, undefined).
+
+tcp_module(Opts, Addr) ->
+ Address = {undefined,Addr},
+ %% Address has to be a 2-tuple but the first element is ignored
+ tcp_module_1(Opts, Address).
+
+tcp_module_1(Opts, Address) ->
+ mod(
+ Opts, tcp_module, Address,
+ #{inet => inet_tcp, inet6 => inet6_tcp, local => local_tcp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Available options for udp:open
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -823,12 +833,12 @@ udp_options() ->
high_msgq_watermark, low_msgq_watermark].
-udp_options(Opts, Family) ->
+udp_options(Opts, Mod) ->
case udp_opt(Opts, #udp_opts { }, udp_options()) of
{ok, R} ->
{ok, R#udp_opts {
opts = lists:reverse(R#udp_opts.opts),
- ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
+ ifaddr = Mod:translate_ip(R#udp_opts.ifaddr)
}};
Error -> Error
end.
@@ -843,9 +853,6 @@ udp_opt([Opt | Opts], #udp_opts{} = R, As) ->
{fd,Fd} -> udp_opt(Opts, R#udp_opts { fd = Fd }, As);
binary -> udp_add(mode, binary, R, Opts, As);
list -> udp_add(mode, list, R, Opts, As);
- {udp_module,_} -> udp_opt(Opts, R, As);
- inet -> udp_opt(Opts, R, As);
- inet6 -> udp_opt(Opts, R, As);
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -870,6 +877,11 @@ udp_add(Name, Val, #udp_opts{} = R, Opts, As) ->
Error -> Error
end.
+udp_module(Opts) ->
+ mod(
+ Opts, udp_module, undefined,
+ #{inet => inet_udp, inet6 => inet6_udp, local => local_udp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Available options for sctp:open
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -926,9 +938,6 @@ sctp_opt([Opt|Opts], Mod, #sctp_opts{} = R, As) ->
sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As);
binary -> sctp_opt (Opts, Mod, R, As, mode, binary);
list -> sctp_opt (Opts, Mod, R, As, mode, list);
- {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with
- inet -> sctp_opt (Opts, Mod, R, As); % Done with
- inet6 -> sctp_opt (Opts, Mod, R, As); % Done with
{netns,NS} ->
BinNS = filename2binary(NS),
case prim_inet:is_sockopt_val(netns, BinNS) of
@@ -970,6 +979,11 @@ sctp_opt_ifaddr(Opts, Mod, #sctp_opts{ifaddr=IfAddr}=R, As, Addr) ->
_ -> [IP,IfAddr]
end}, As).
+sctp_module(Opts) ->
+ mod(
+ Opts, sctp_module, undefined,
+ #{inet => inet_sctp, inet6 => inet6_sctp}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Util to check and insert option in option list
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1028,6 +1042,53 @@ translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0};
translate_ip(loopback, inet6) -> {0,0,0,0,0,0,0,1};
translate_ip(IP, _) -> IP.
+mod(Opts, Tag, Address, Map) ->
+ mod(Opts, Tag, Address, Map, undefined, []).
+%%
+mod([{Tag, M}|Opts], Tag, Address, Map, Mod, Acc) ->
+ mod(Opts, Tag, Address, Map, Mod, Acc, M);
+mod([{T, _} = Opt|Opts], Tag, _Address, Map, Mod, Acc)
+ when T =:= ip; T =:= ifaddr->
+ mod(Opts, Tag, Opt, Map, Mod, [Opt|Acc]);
+mod([Family|Opts], Tag, Address, Map, Mod, Acc) when is_atom(Family) ->
+ case Map of
+ #{Family := M} ->
+ mod(Opts, Tag, Address, Map, Mod, Acc, M);
+ #{} ->
+ mod(Opts, Tag, Address, Map, Mod, [Family|Acc])
+ end;
+mod([Opt|Opts], Tag, Address, Map, Mod, Acc) ->
+ mod(Opts, Tag, Address, Map, Mod, [Opt|Acc]);
+mod([], Tag, Address, Map, undefined, Acc) ->
+ {case Address of
+ {_, {local, _}} ->
+ case Map of
+ #{local := Mod} ->
+ Mod;
+ #{} ->
+ inet_db:Tag()
+ end;
+ {_, IP} when tuple_size(IP) =:= 8 ->
+ #{inet := IPv4Mod} = Map,
+ %% Get the mod, but IPv6 address overrides default IPv4
+ case inet_db:Tag() of
+ IPv4Mod ->
+ #{inet6 := IPv6Mod} = Map,
+ IPv6Mod;
+ Mod ->
+ Mod
+ end;
+ _ ->
+ inet_db:Tag()
+ end, lists:reverse(Acc)};
+mod([], _Tag, _Address, _Map, Mod, Acc) ->
+ {Mod, lists:reverse(Acc)}.
+%%
+mod(Opts, Tag, Address, Map, undefined, Acc, M) ->
+ mod(Opts, Tag, Address, Map, M, Acc);
+mod(Opts, Tag, Address, Map, Mod, Acc, _M) ->
+ mod(Opts, Tag, Address, Map, Mod, Acc).
+
getaddrs_tm({A,B,C,D} = IP, Fam, _) ->
%% Only "syntactic" validation and check of family.
@@ -1235,7 +1296,7 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
end.
-spec open(Fd_or_OpenOpts :: integer() | list(),
- Addr :: ip_address(),
+ Addr :: socket_address(),
Port :: port_number(),
Opts :: [socket_setopt()],
Protocol :: socket_protocol(),
diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl
index cc98bc0ccb..a5503f6f54 100644
--- a/lib/kernel/src/inet6_sctp.erl
+++ b/lib/kernel/src/inet6_sctp.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
-%%
+%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
@@ -14,13 +14,12 @@
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% SCTP protocol contribution by Leonid Timochouk and Serge Aleynikov.
%% See also: $ERL_TOP/lib/kernel/AUTHORS
%%
-%%
-module(inet6_sctp).
%% This module provides functions for communicating with
@@ -31,6 +30,7 @@
-include("inet_sctp.hrl").
-include("inet_int.hrl").
+-define(PROTO, sctp).
-define(FAMILY, inet6).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
@@ -39,25 +39,19 @@
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) ->
- inet:getservbyname(Name, sctp);
-getserv(_) ->
- {error,einval}.
-
-getaddr(Address) ->
- inet:getaddr(Address, ?FAMILY).
-getaddr(Address, Timer) ->
- inet:getaddr_tm(Address, ?FAMILY, Timer).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO);
+getserv(_) -> {error,einval}.
-translate_ip(IP) ->
- inet:translate_ip(IP, ?FAMILY).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
{ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
+ inet:open(Fd, Addr, Port, SOs, ?PROTO, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index 3dfe5dfc86..a0d5d3df70 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -25,13 +25,18 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([family/0, mask/2, parse_address/1]).
+-export([family/0, mask/2, parse_address/1]). % inet_tcp_dist
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet6).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
%% my address family
-family() -> inet6.
+family() -> ?FAMILY.
%% Apply netmask on address
mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
@@ -50,15 +55,18 @@ parse_address(Host) ->
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_tcp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet6).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet6, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
%% inet_tcp address lookup
-getaddrs(Address) -> inet:getaddrs(Address, inet6).
-getaddrs(Address,Timer) -> inet:getaddrs_tm(Address,inet6,Timer).
+getaddrs(Address) -> inet:getaddrs(Address, ?FAMILY).
+getaddrs(Address, Timer) -> inet:getaddrs_tm(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
%%
%% Send data on a socket
@@ -73,11 +81,6 @@ recv(Socket, Length) -> prim_inet:recv(Socket, Length).
recv(Socket, Length, Timeout) -> prim_inet:recv(Socket, Length, Timeout).
unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
-%%
-%% Close a socket (async)
-%%
-close(Socket) ->
- inet:tcp_close(Socket).
%%
%% Shutdown one end of a socket
@@ -86,6 +89,12 @@ shutdown(Socket, How) ->
prim_inet:shutdown(Socket, How).
%%
+%% Close a socket (async)
+%%
+close(Socket) ->
+ inet:tcp_close(Socket).
+
+%%
%% Set controlling process
%% FIXME: move messages to new owner!!!
%%
@@ -100,24 +109,28 @@ connect(Address, Port, Opts) ->
connect(Address, Port, Opts, infinity) ->
do_connect(Address, Port, Opts, infinity);
-connect(Address, Port, Opts, Timeout) when is_integer(Timeout),
- Timeout >= 0 ->
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
do_connect(Address, Port, Opts, Timeout).
-do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when
- ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
- case inet:connect_options(Opts, inet6) of
+do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time)
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
+ case inet:connect_options(Opts, ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #connect_opts{fd=Fd,
- ifaddr=BAddr={Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr = {Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb},
+ port = BPort,
+ opts = SockOpts}}
when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:connect(S, Addr, Port, Time) of
- ok -> {ok,S};
- Error -> prim_inet:close(S), Error
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
end;
Error -> Error
end;
@@ -128,14 +141,18 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when
%% Listen
%%
listen(Port, Opts) ->
- case inet:listen_options([{port,Port} | Opts], inet6) of
+ case inet:listen_options([{port,Port} | Opts], ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #listen_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D,E,F,G,H},
- port=BPort,
- opts=SockOpts}=R}
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D,E,F,G,H},
+ port = BPort,
+ opts = SockOpts} = R}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -156,18 +173,17 @@ accept(L) ->
{ok,S};
Error -> Error
end.
-
-accept(L,Timeout) ->
- case prim_inet:accept(L,Timeout) of
+
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
-
+
%%
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE).
-
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl
index eb6945f60a..71db0357cd 100644
--- a/lib/kernel/src/inet6_udp.erl
+++ b/lib/kernel/src/inet6_udp.erl
@@ -24,29 +24,44 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([getserv/1, getaddr/1, getaddr/2]).
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet6).
+-define(PROTO, udp).
+-define(TYPE, dgram).
+
+
%% inet_udp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_udp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet6).
-getaddr(Address,Timer) -> inet:getaddr(Address, inet6, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
+-spec open(_) -> {ok, inet:socket()} | {error, atom()}.
open(Port) -> open(Port, []).
+-spec open(_, _) -> {ok, inet:socket()} | {error, atom()}.
open(Port, Opts) ->
- case inet:udp_options([{port,Port} | Opts], inet6) of
+ case inet:udp_options(
+ [{port,Port} | Opts],
+ ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #udp_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D,E,F,G,H},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D,E,F,G,H},
+ port = BPort,
+ opts = SockOpts}}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE);
+ inet:open(
+ Fd, BAddr, BPort, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
{ok, _} -> exit(badarg)
end.
@@ -61,12 +76,13 @@ connect(S, Addr = {A,B,C,D,E,F,G,H}, P)
when ?ip6(A,B,C,D,E,F,G,H), ?port(P) ->
prim_inet:connect(S, Addr, P).
-recv(S,Len) ->
+recv(S, Len) ->
prim_inet:recvfrom(S, Len).
-recv(S,Len,Time) ->
+recv(S, Len, Time) ->
prim_inet:recvfrom(S, Len, Time).
+-spec close(inet:socket()) -> ok.
close(S) ->
inet:udp_close(S).
@@ -85,4 +101,4 @@ controlling_process(Socket, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE).
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 65d78b66c9..32d09fb63c 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -29,6 +29,8 @@
-define(INET_AF_INET6, 2).
-define(INET_AF_ANY, 3). % Fake for ANY in any address family
-define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family
+-define(INET_AF_LOCAL, 5). % For Unix Domain address family
+-define(INET_AF_UNDEFINED, 6). % For any unknown address family
%% type codes to open and gettype - INET_REQ_GETTYPE
-define(INET_TYPE_STREAM, 1).
@@ -378,7 +380,7 @@
{
ifaddr = any, %% bind to interface address
port = 0, %% bind to port (default is dynamic port)
- fd = -1, %% fd >= 0 => already bound
+ fd = -1, %% fd >= 0 => already bound
opts = [] %% [{active,true}] added in inet:connect_options
}).
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index 60677cb7de..8569cacb29 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -30,6 +30,7 @@
-include("inet_sctp.hrl").
-include("inet_int.hrl").
+-define(PROTO, sctp).
-define(FAMILY, inet).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
@@ -38,25 +39,19 @@
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) ->
- inet:getservbyname(Name, sctp);
-getserv(_) ->
- {error,einval}.
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO);
+getserv(_) -> {error,einval}.
-getaddr(Address) ->
- inet:getaddr(Address, ?FAMILY).
-getaddr(Address, Timer) ->
- inet:getaddr_tm(Address, ?FAMILY, Timer).
-
-translate_ip(IP) ->
- inet:translate_ip(IP, ?FAMILY).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
{ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
+ inet:open(Fd, Addr, Port, SOs, ?PROTO, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index ee885af3b0..dac6b3119d 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -27,13 +27,18 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([family/0, mask/2, parse_address/1]).
+-export([family/0, mask/2, parse_address/1]). % inet_tcp_dist
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
%% my address family
-family() -> inet.
+family() -> ?FAMILY.
%% Apply netmask on address
mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
@@ -48,16 +53,19 @@ parse_address(Host) ->
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_tcp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
%% inet_tcp address lookup
-getaddrs(Address) -> inet:getaddrs(Address, inet).
-getaddrs(Address,Timer) -> inet:getaddrs_tm(Address,inet,Timer).
-
+getaddrs(Address) -> inet:getaddrs(Address, ?FAMILY).
+getaddrs(Address, Timer) -> inet:getaddrs_tm(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
+
%%
%% Send data on a socket
%%
@@ -77,7 +85,7 @@ unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
%%
shutdown(Socket, How) ->
prim_inet:shutdown(Socket, How).
-
+
%%
%% Close a socket (async)
%%
@@ -88,7 +96,7 @@ close(Socket) ->
%% Set controlling process
%%
controlling_process(Socket, NewOwner) ->
- inet:tcp_controlling_process(Socket, NewOwner).
+ inet:tcp_controlling_process(Socket, NewOwner).
%%
%% Connect
@@ -98,23 +106,28 @@ connect(Address, Port, Opts) ->
connect(Address, Port, Opts, infinity) ->
do_connect(Address, Port, Opts, infinity);
-connect(Address, Port, Opts, Timeout) when is_integer(Timeout),
- Timeout >= 0 ->
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
do_connect(Address, Port, Opts, Timeout).
-do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) ->
- case inet:connect_options(Opts, inet) of
+do_connect(Addr = {A,B,C,D}, Port, Opts, Time)
+ when ?ip(A,B,C,D), ?port(Port) ->
+ case inet:connect_options(Opts, ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #connect_opts{fd=Fd,
- ifaddr=BAddr={Ab,Bb,Cb,Db},
- port=BPort,
- opts=SockOpts}}
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr = {Ab,Bb,Cb,Db},
+ port = BPort,
+ opts = SockOpts}}
when ?ip(Ab,Bb,Cb,Db), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
- case prim_inet:connect(S, {A,B,C,D}, Port, Time) of
- ok -> {ok,S};
- Error -> prim_inet:close(S), Error
+ case prim_inet:connect(S, Addr, Port, Time) of
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
end;
Error -> Error
end;
@@ -125,14 +138,18 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) ->
%% Listen
%%
listen(Port, Opts) ->
- case inet:listen_options([{port,Port} | Opts], inet) of
- {error,Reason} -> exit(Reason);
- {ok, #listen_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D},
- port=BPort,
- opts=SockOpts}=R}
+ case inet:listen_options([{port,Port} | Opts], ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D},
+ port = BPort,
+ opts = SockOpts} = R}
when ?ip(A,B,C,D), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
+ case inet:open(
+ Fd, BAddr, BPort, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -146,23 +163,24 @@ listen(Port, Opts) ->
%%
%% Accept
%%
-accept(L) ->
+accept(L) ->
case prim_inet:accept(L) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
-
-accept(L,Timeout) ->
- case prim_inet:accept(L,Timeout) of
+
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+
%%
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE).
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 7e8d9cdb72..8a8aa8ecca 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -24,21 +24,26 @@
-export([controlling_process/2]).
-export([fdopen/2]).
--export([getserv/1, getaddr/1, getaddr/2]).
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
-include("inet_int.hrl").
+-define(FAMILY, inet).
+-define(PROTO, udp).
+-define(TYPE, dgram).
-define(RECBUF, (8*1024)).
-
%% inet_udp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
-getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp).
+getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
%% inet_udp address lookup
-getaddr(Address) -> inet:getaddr(Address, inet).
-getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer).
+getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
+getaddr(Address, Timer) -> inet:getaddr(Address, ?FAMILY, Timer).
+
+%% inet_udp special this side addresses
+translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
-spec open(_) -> {ok, inet:socket()} | {error, atom()}.
open(Port) -> open(Port, []).
@@ -47,33 +52,38 @@ open(Port) -> open(Port, []).
open(Port, Opts) ->
case inet:udp_options(
[{port,Port}, {recbuf, ?RECBUF} | Opts],
- inet) of
+ ?MODULE) of
{error, Reason} -> exit(Reason);
- {ok, #udp_opts{fd=Fd,
- ifaddr=BAddr={A,B,C,D},
- port=BPort,
- opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE);
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr = {A,B,C,D},
+ port = BPort,
+ opts = SockOpts}}
+ when ?ip(A,B,C,D), ?port(BPort) ->
+ inet:open(
+ Fd, BAddr, BPort, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
{ok, _} -> exit(badarg)
end.
-send(S,{A,B,C,D},P,Data) when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:sendto(S, {A,B,C,D}, P, Data).
+send(S, {A,B,C,D} = Addr, P, Data)
+ when ?ip(A,B,C,D), ?port(P) ->
+ prim_inet:sendto(S, Addr, P, Data).
send(S, Data) ->
prim_inet:sendto(S, {0,0,0,0}, 0, Data).
-connect(S, {A,B,C,D}, P) when ?ip(A,B,C,D), ?port(P) ->
- prim_inet:connect(S, {A,B,C,D}, P).
+connect(S, Addr = {A,B,C,D}, P)
+ when ?ip(A,B,C,D), ?port(P) ->
+ prim_inet:connect(S, Addr, P).
-recv(S,Len) ->
+recv(S, Len) ->
prim_inet:recvfrom(S, Len).
-recv(S,Len,Time) ->
+recv(S, Len, Time) ->
prim_inet:recvfrom(S, Len, Time).
-spec close(inet:socket()) -> ok.
-
close(S) ->
inet:udp_close(S).
@@ -92,9 +102,9 @@ controlling_process(Socket, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd,
- optuniquify([{recbuf, ?RECBUF} | Opts]),
- udp, inet, dgram, ?MODULE).
+ inet:fdopen(
+ Fd, optuniquify([{recbuf, ?RECBUF} | Opts]),
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
%% Remove all duplicate options from an option list.
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 1acd6803b2..56d1699656 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -55,6 +55,8 @@
inet_tcp_dist,
kernel,
kernel_config,
+ local_tcp,
+ local_udp,
net,
net_adm,
net_kernel,
diff --git a/lib/kernel/src/local_tcp.erl b/lib/kernel/src/local_tcp.erl
new file mode 100644
index 0000000000..64085ec42e
--- /dev/null
+++ b/lib/kernel/src/local_tcp.erl
@@ -0,0 +1,172 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(local_tcp).
+
+%% Socket server for TCP/IP
+
+-export([connect/3, connect/4, listen/2, accept/1, accept/2, close/1]).
+-export([send/2, send/3, recv/2, recv/3, unrecv/2]).
+-export([shutdown/2]).
+-export([controlling_process/2]).
+-export([fdopen/2]).
+
+-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
+-export([translate_ip/1]).
+
+-include("inet_int.hrl").
+
+-define(FAMILY, local).
+-define(PROTO, tcp).
+-define(TYPE, stream).
+
+%% port lookup
+getserv(0) -> {ok, 0}.
+
+%% no address lookup
+getaddr({?FAMILY, _} = Address) -> {ok, Address}.
+getaddr({?FAMILY, _} = Address, _Timer) -> {ok, Address}.
+
+%% no address lookup
+getaddrs({?FAMILY, _} = Address) -> {ok, [Address]}.
+getaddrs({?FAMILY, _} = Address, _Timer) -> {ok, [Address]}.
+
+%% special this side addresses
+translate_ip(IP) -> IP.
+
+%%
+%% Send data on a socket
+%%
+send(Socket, Packet, Opts) -> prim_inet:send(Socket, Packet, Opts).
+send(Socket, Packet) -> prim_inet:send(Socket, Packet, []).
+
+%%
+%% Receive data from a socket (inactive only)
+%%
+recv(Socket, Length) -> prim_inet:recv(Socket, Length).
+recv(Socket, Length, Timeout) -> prim_inet:recv(Socket, Length, Timeout).
+
+unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
+
+%%
+%% Shutdown one end of a socket
+%%
+shutdown(Socket, How) ->
+ prim_inet:shutdown(Socket, How).
+
+%%
+%% Close a socket (async)
+%%
+close(Socket) ->
+ inet:tcp_close(Socket).
+
+%%
+%% Set controlling process
+%% FIXME: move messages to new owner!!!
+%%
+controlling_process(Socket, NewOwner) ->
+ inet:tcp_controlling_process(Socket, NewOwner).
+
+%%
+%% Connect
+%%
+connect(Address, Port, Opts) ->
+ do_connect(Address, Port, Opts, infinity).
+%%
+connect(Address, Port, Opts, infinity) ->
+ do_connect(Address, Port, Opts, infinity);
+connect(Address, Port, Opts, Timeout)
+ when is_integer(Timeout), Timeout >= 0 ->
+ do_connect(Address, Port, Opts, Timeout).
+
+do_connect(Addr = {?FAMILY, _}, 0, Opts, Time) ->
+ case inet:connect_options(Opts, ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #connect_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts}}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ case inet:open(
+ Fd, BAddr, 0, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
+ {ok, S} ->
+ case prim_inet:connect(S, Addr, 0, Time) of
+ ok -> {ok,S};
+ Error -> prim_inet:close(S), Error
+ end;
+ Error -> Error
+ end;
+ {ok, _} -> exit(badarg)
+ end.
+
+%%
+%% Listen
+%%
+listen(0, Opts) ->
+ case inet:listen_options([{port,0} | Opts], ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #listen_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts} = R}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ case inet:open(
+ Fd, BAddr, 0, SockOpts,
+ ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
+ {ok, S} ->
+ case prim_inet:listen(S, R#listen_opts.backlog) of
+ ok -> {ok, S};
+ Error -> prim_inet:close(S), Error
+ end;
+ Error -> Error
+ end;
+ {ok, _} -> exit(badarg)
+ end.
+
+%%
+%% Accept
+%%
+accept(L) ->
+ case prim_inet:accept(L) of
+ {ok, S} ->
+ inet_db:register_socket(S, ?MODULE),
+ {ok,S};
+ Error -> Error
+ end.
+%%
+accept(L, Timeout) ->
+ case prim_inet:accept(L, Timeout) of
+ {ok, S} ->
+ inet_db:register_socket(S, ?MODULE),
+ {ok,S};
+ Error -> Error
+ end.
+
+%%
+%% Create a port/socket from a file descriptor
+%%
+fdopen(Fd, Opts) ->
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl
new file mode 100644
index 0000000000..ebb4d2b33f
--- /dev/null
+++ b/lib/kernel/src/local_udp.erl
@@ -0,0 +1,99 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(local_udp).
+
+-export([open/1, open/2, close/1]).
+-export([send/2, send/4, recv/2, recv/3, connect/3]).
+-export([controlling_process/2]).
+-export([fdopen/2]).
+
+-export([getserv/1, getaddr/1, getaddr/2, translate_ip/1]).
+
+-include("inet_int.hrl").
+
+-define(FAMILY, local).
+-define(PROTO, udp).
+-define(TYPE, dgram).
+
+
+%% port lookup
+getserv(0) -> {ok, 0}.
+
+%% no address lookup
+getaddr({?FAMILY, _} = Address) -> {ok, Address}.
+getaddr({?FAMILY, _} = Address, _Timer) -> {ok, Address}.
+
+%% special this side addresses
+translate_ip(IP) -> IP.
+
+open(0) -> open(0, []).
+%%
+open(0, Opts) ->
+ case inet:udp_options(
+ [{port,0} | Opts],
+ ?MODULE) of
+ {error, Reason} -> exit(Reason);
+ {ok,
+ #udp_opts{
+ fd = Fd,
+ ifaddr = BAddr,
+ port = 0,
+ opts = SockOpts}}
+ when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
+ BAddr =:= any ->
+ inet:open(
+ Fd, BAddr, 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
+ {ok, _} -> exit(badarg)
+ end.
+
+send(S, Addr = {?FAMILY,_}, 0, Data) ->
+ prim_inet:sendto(S, Addr, 0, Data).
+%%
+send(S, Data) ->
+ prim_inet:sendto(S, {?FAMILY,<<>>}, 0, Data).
+
+connect(S, Addr = {?FAMILY,_}, 0) ->
+ prim_inet:connect(S, Addr, 0).
+
+recv(S, Len) ->
+ prim_inet:recvfrom(S, Len).
+%%
+recv(S, Len, Time) ->
+ prim_inet:recvfrom(S, Len, Time).
+
+close(S) ->
+ inet:udp_close(S).
+
+%%
+%% Set controlling process:
+%% 1) First sync socket into a known state
+%% 2) Move all messages onto the new owners message queue
+%% 3) Commit the owner
+%% 4) Wait for ack of new Owner (since socket does some link and unlink)
+%%
+
+controlling_process(Socket, NewOwner) ->
+ inet:udp_controlling_process(Socket, NewOwner).
+
+%%
+%% Create a port/socket from a file descriptor
+%%
+fdopen(Fd, Opts) ->
+ inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).