diff options
author | Serge Aleynikov <[email protected]> | 2015-12-30 13:29:34 -0500 |
---|---|---|
committer | Serge Aleynikov <[email protected]> | 2016-01-12 11:18:12 -0500 |
commit | e293ad1b08b2f937555a102e6f3b4336574773c8 (patch) | |
tree | b2eb8a92e8386e9d9589503929b2cf8afac13068 | |
parent | 1237669f7c59714f0c27d3df748241dfd655c0be (diff) | |
download | otp-e293ad1b08b2f937555a102e6f3b4336574773c8.tar.gz otp-e293ad1b08b2f937555a102e6f3b4336574773c8.tar.bz2 otp-e293ad1b08b2f937555a102e6f3b4336574773c8.zip |
Assign externally open fd to gen_tcp (UDS support)
When a AF_LOCAL file descriptor is created externally (e.g. Unix
Domain Socket) and passed to `gen_tcp:listen(0, [{fd, FD}])`, the
implementation incorrectly assigned the address family to be equal
to `inet`, which in the inet_drv driver translated to AF_INET instead
of AF_LOCAL (or AF_UNIX), and an `einval` error code was returned.
This patch fixes this problem such that the file descriptors of the
`local` address family are supported in the inet:fdopen/5,
gen_tcp:connect/3, gen_tcp:listen/2, gen_udp:open/2 calls
-rw-r--r-- | erts/configure.in | 2 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 161 | ||||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 17 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_tcp.xml | 7 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_udp.xml | 7 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 20 | ||||
-rw-r--r-- | lib/kernel/src/inet_int.hrl | 6 | ||||
-rw-r--r-- | lib/kernel/src/inet_tcp.erl | 11 | ||||
-rw-r--r-- | lib/kernel/src/inet_udp.erl | 8 |
9 files changed, 210 insertions, 29 deletions
diff --git a/erts/configure.in b/erts/configure.in index 4fb725ff00..68ead3285b 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -2238,7 +2238,7 @@ fi dnl Need by run_erl. AC_CHECK_FUNCS([openpty]) -AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h) +AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h) AC_CHECK_FUNCS([getifaddrs]) dnl Checks for variables in6addr_any and in6addr_loopback, diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89011d89ad..bd4543f831 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -58,6 +58,9 @@ #ifdef HAVE_NETPACKET_PACKET_H #include <netpacket/packet.h> #endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -747,6 +750,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_AF_INET6 2 #define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */ #define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */ +#define INET_AF_LOCAL 5 /* open and INET_REQ_GETTYPE enumeration */ #define INET_TYPE_STREAM 1 @@ -1032,19 +1036,29 @@ typedef union { #ifdef HAVE_IN6 struct sockaddr_in6 sai6; #endif +#ifdef HAVE_SYS_UN_H + struct sockaddr_un sal; +#endif } inet_address; /* for AF_INET & AF_INET6 */ #define inet_address_port(x) ((x)->sai.sin_port) +#ifdef HAVE_SYS_UN_H +#define localaddrlen(family, data) \ + ((family == AF_LOCAL) ? *(unsigned char*)(data) : 0) +#else + 0 +#endif + #if defined(HAVE_IN6) && defined(AF_INET6) -#define addrlen(family) \ +#define addrlen(family, data) \ ((family == AF_INET) ? sizeof(struct in_addr) : \ - ((family == AF_INET6) ? sizeof(struct in6_addr) : 0)) + ((family == AF_INET6) ? sizeof(struct in6_addr) : localaddrlen(family, data))) #else -#define addrlen(family) \ - ((family == AF_INET) ? sizeof(struct in_addr) : 0) +#define addrlen(family, data) \ + ((family == AF_INET) ? sizeof(struct in_addr) : localaddrlen(family, data)) #endif typedef struct _multi_timer_data { @@ -1728,6 +1742,12 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) spec[i++] = 8; } #endif +#ifdef HAVE_SYS_UN_H + else if (family == AF_LOCAL) { + int len = *(unsigned char*)buf++; + i = LOAD_STRING(spec, i, buf, len); + } +#endif else { spec[i++] = ERL_DRV_TUPLE; spec[i++] = 0; @@ -3573,10 +3593,11 @@ static int tcp_error_message(tcp_descriptor* desc, int err) #ifdef HAVE_UDP /* ** active mode message: -** {udp, S, IP, Port, [H1,...Hsz | Data]} or -** {sctp, S, IP, Port, {[AncilData], Event_or_Data}} +** {udp, S, IP, Port, [H1,...Hsz | Data]} or +** {sctp, S, IP, Port, {[AncilData], Event_or_Data}} ** where ** [H1,...,HSz] are msg headers (without IP/Port, UDP only), +** [AddrLen, H2,...,HSz] are msg headers for UDP AF_LOCAL only ** Data : List() | Binary() */ static int packet_binary_message @@ -3586,6 +3607,7 @@ static int packet_binary_message ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN]; int i = 0; int alen; + char* data = bin->orig_bytes+offs; DEBUGF(("packet_binary_message(%ld): len = %d\r\n", (long)desc->port, len)); @@ -3596,10 +3618,15 @@ static int packet_binary_message # endif i = LOAD_PORT(spec, i, desc->dport); /* S */ - alen = addrlen(desc->sfamily); - i = load_ip_address(spec, i, desc->sfamily, bin->orig_bytes+offs+3); - i = load_ip_port(spec, i, bin->orig_bytes+offs+1); /* IP, Port */ + alen = addrlen(desc->sfamily, data+3); + i = load_ip_address(spec, i, desc->sfamily, data+3); + i = load_ip_port(spec, i, data+1); /* IP, Port */ +# ifdef HAVE_SYS_UN_H + /* AF_LOCAL addresses have a prefix byte containing address length */ + if (desc->sfamily == AF_LOCAL) + alen++; +# endif offs += (alen + 3); len -= (alen + 3); @@ -4152,6 +4179,16 @@ static char* inet_set_address(int family, inet_address* dst, return src + 2+16; } #endif +#ifdef HAVE_SYS_UN_H + else if ((family == AF_LOCAL) && (*len >= 3+sizeof(struct sockaddr_un))) { + int n = *((unsigned char*)src+2); + dst->sal.sun_family = family; + sys_memcpy(dst->sal.sun_path, src+3, n); + dst->sal.sun_path[n-1] = '\0'; + *len = n; + return src + 3 + n; + } +#endif return NULL; } @@ -4160,7 +4197,7 @@ static char* inet_set_address(int family, inet_address* dst, ** or from argument if source data specifies constant address. ** ** src = [TAG,P1,P0] when TAG = INET_AF_ANY | INET_AF_LOOPBACK -** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 +** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL */ static char *inet_set_faddress(int family, inet_address* dst, char *src, ErlDrvSizeT* len) { @@ -4178,6 +4215,21 @@ static char *inet_set_faddress(int family, inet_address* dst, family = AF_INET6; break; # endif +# ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: { + int n; + if (*len || *len < 3) return NULL; + family = AF_LOCAL; + /* Next two bytes are the length of the local path (< 256) */ + src++; + n = *(unsigned char*)src++; + if (n+3 > *len) return NULL; + dst->sal.sun_family = family; + sys_memcpy(dst->sal.sun_path, src, n); + *len = n; + break; + } +# endif case INET_AF_ANY: case INET_AF_LOOPBACK: { int port; @@ -4241,7 +4293,6 @@ static char *inet_set_faddress(int family, inet_address* dst, return inet_set_address(family, dst, src, len); } - /* Get a inaddr structure ** src = inaddr structure ** *len is the lenght of structure @@ -4274,9 +4325,54 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) return 0; } #endif +#ifdef HAVE_SYS_UN_H + else if ((family == AF_LOCAL) && *len > 0) { + int n = *len - 4; + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + if (n == 0 || n >= sizeof(src->sal.sun_path)) { + *(dst+3) = 0; + *len = 3+1; + } else { + *(dst+3) = n; + sys_memcpy(dst+4, src->sal.sun_path, n); + *len = 3+1+n; + } + return 0; + } +#endif return -1; } +static int inet_family_get_address(inet_descriptor* desc, char* dst, inet_address* src, unsigned int* len) +{ +#ifdef HAVE_SYS_UN_H + if (desc->sfamily == AF_LOCAL) { + int n = *len - 4; + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + if (n <= 0 || n >= sizeof(src->sal.sun_path)) { + if (desc->name_ptr) { + char* p = desc->name_ptr->sal.sun_path; + n = strlen(p); + *(dst+3) = n; + sys_memcpy(dst+4, p, n); + *len = 3+1+n; + } else { + *(dst+3) = 0; + *len = 3+1; + } + } else { + *(dst+3) = n; + sys_memcpy(dst+4, src->sal.sun_path, n); + *len = 3+1+n; + } + return 0; + } +#endif + return inet_get_address(dst, src, len); +} + /* Same as the above, but take family from the address structure, ** and advance the address pointer to the next address ** according to the size of the current, @@ -4307,6 +4403,19 @@ static int inet_address_to_erlang(char *dst, inet_address **src) { (*src) = (inet_address *) (&(*src)->sai6 + 1); return 1 + 2 + 16; #endif +#ifdef HAVE_SYS_UN_H + case AF_LOCAL: { + int n = strlen((*src)->sal.sun_path); + if (dst) { + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + *(dst+3) = n; + sys_memcpy(dst+1+2+1, (*src)->sal.sun_path, n); + } + (*src) = (inet_address *) (&(*src)->sal + 1); + return 1+2+1+n; + } +#endif default: return -1; } @@ -4402,7 +4511,8 @@ static void desc_close_read(inet_descriptor* desc) static int erl_inet_close(inet_descriptor* desc) { free_subscribers(&desc->empty_out_q_subs); - if ((desc->prebound == 0) && (desc->state & INET_F_OPEN)) { + if ((desc->prebound == 0 || desc->sfamily == AF_LOCAL) && + (desc->state & INET_F_OPEN)) { desc_close(desc); desc->state = INET_STATE_CLOSED; } else if (desc->prebound && (desc->s != INVALID_SOCKET)) { @@ -4582,6 +4692,13 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); +#ifdef HAVE_SYS_UN_H + if (domain == AF_LOCAL) { + sys_memcpy(&desc->name_addr, &name, sizeof(desc->name_addr)); + if (desc->name_ptr == NULL) + desc->name_ptr = &desc->name_addr; + } +#endif } #ifdef __OSE__ /* for fdopen duplicating the sd will allow to uniquely identify @@ -8571,6 +8688,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, put_int32(INET_AF_INET6, &tbuf[0]); } #endif +#ifdef HAVE_SYS_UN_H + else if (desc->sfamily == AF_LOCAL) { + put_int32(INET_AF_LOCAL, &tbuf[0]); + } +#endif else return ctl_error(EINVAL, rbuf, rsize); @@ -9256,6 +9378,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_xerror("eafnosupport", rbuf, rsize); break; #endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: + domain = AF_LOCAL; + break; +#endif default: return ctl_error(EINVAL, rbuf, rsize); } @@ -9282,6 +9409,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_xerror("eafnosupport", rbuf, rsize); break; #endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: + domain = AF_LOCAL; + break; +#endif default: return ctl_error(EINVAL, rbuf, rsize); } @@ -11344,6 +11476,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, return ctl_xerror("eafnosupport", rbuf, rsize); break; #endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: af = AF_LOCAL; break; +#endif default: return ctl_error(EINVAL, rbuf, rsize); } @@ -11955,7 +12090,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) inet_input_count(desc, n); udesc->i_ptr += n; - inet_get_address(abuf, &other, &len); + inet_family_get_address(desc, abuf, &other, &len); /* Copy formatted address to the buffer allocated; "len" is the actual length which must be <= than the original reserved. This means that the addr + data in the buffer are contiguous, diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index bd74831bb7..4659448221 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -70,6 +70,8 @@ open(Protocol, Family, Type) -> open(Protocol, Family, Type, Opts) -> open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []). +%% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer()) + fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> fdopen(Protocol, Family, Type, Fd, true). @@ -104,8 +106,9 @@ open(Protocol, Family, Type, Opts, Req, Data) -> error:system_limit -> {error, system_limit} end. -enc_family(inet) -> ?INET_AF_INET; -enc_family(inet6) -> ?INET_AF_INET6. +enc_family(inet) -> ?INET_AF_INET; +enc_family(inet6) -> ?INET_AF_INET6; +enc_family(local) -> ?INET_AF_LOCAL. enc_type(stream) -> ?INET_TYPE_STREAM; enc_type(dgram) -> ?INET_TYPE_DGRAM; @@ -1619,6 +1622,8 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; +enc_value_2(addr, {File,0}) when is_list(File) -> + [?INET_AF_LOCAL,0,0,length(File)|File]; enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs; enc_value_2(sockaddr, any) -> [?INET_AF_ANY]; @@ -1628,6 +1633,8 @@ enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 -> [?INET_AF_INET|ip4_to_bytes(IP)]; enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6|ip6_to_bytes(IP)]; +enc_value_2(sockaddr, File) when is_list(File) -> + [?INET_AF_LOCAL,0,0,length(File)|File]; enc_value_2(linkaddr, Linkaddr) -> [?int16(length(Linkaddr)),Linkaddr]; enc_value_2(sctp_assoc_id, Val) -> ?int32(Val); @@ -2265,8 +2272,10 @@ get_addrs([F,P1,P0|Addr]) -> {IP,Addrs} = get_ip(F, Addr), [{IP,?u16(P1, P0)}|get_addrs(Addrs)]. -get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); -get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr). +get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); +get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr); +get_ip(?INET_AF_LOCAL, [0]) -> {[], []}; +get_ip(?INET_AF_LOCAL, [N | Addr]) -> lists:split(N, Addr). get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}. diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 6a19e76c4f..20a13782ca 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -132,6 +132,13 @@ do_recv(Sock, Bs) -> <p>Set up the socket for IPv6.</p> </item> + <tag><c>local</c></tag> + <item> + <p>Set up the socket for local address family. This option is only + valid together with <c>{fd, integer()}</c> when the file descriptor + is of local address family (e.g. a Unix Domain Socket)</p> + </item> + <tag><c>{port, Port}</c></tag> <item> <p>Specify which local port number to use.</p> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 79cd87dcef..72f25d8d3f 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -101,6 +101,13 @@ <p>Set up the socket for IPv4.</p> </item> + <tag><c>local</c></tag> + <item> + <p>Set up the socket for local address family. This option is only + valid together with <c>{fd, integer()}</c> when the file descriptor + is of local address family (e.g. a Unix Domain Socket)</p> + </item> + <tag><c>{udp_module, module()}</c></tag> <item> <p> Override which callback module is used. Defaults to diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index b573112445..8840f05fa1 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -40,7 +40,7 @@ -export([i/0, i/1, i/2]). --export([getll/1, getfd/1, open/8, fdopen/6]). +-export([getll/1, getfd/1, open/8, fdopen/6, getfamily/1]). -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). @@ -133,7 +133,7 @@ '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 stat_option() :: @@ -711,6 +711,7 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) -> {tcp_module,_} -> con_opt(Opts, R, As); inet -> con_opt(Opts, R, As); inet6 -> con_opt(Opts, R, As); + local -> con_opt(Opts, R#connect_opts { family = local }, As); {netns,NS} -> BinNS = filename2binary(NS), case prim_inet:is_sockopt_val(netns, BinNS) of @@ -783,6 +784,7 @@ list_opt([Opt | Opts], #listen_opts{} = R, As) -> {tcp_module,_} -> list_opt(Opts, R, As); inet -> list_opt(Opts, R, As); inet6 -> list_opt(Opts, R, As); + local -> list_opt(Opts, R#listen_opts { family = local }, As); {netns,NS} -> BinNS = filename2binary(NS), case prim_inet:is_sockopt_val(netns, BinNS) of @@ -839,8 +841,9 @@ udp_opt([Opt | Opts], #udp_opts{} = R, 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); + inet -> udp_opt(Opts, R, As); + inet6 -> udp_opt(Opts, R, As); + local -> udp_opt(Opts, R#udp_opts { family = local }, As); {netns,NS} -> BinNS = filename2binary(NS), case prim_inet:is_sockopt_val(netns, BinNS) of @@ -1318,7 +1321,7 @@ fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) -> Bound = Port == 0 andalso IsAnyAddr, case prim_inet:fdopen(Protocol, Family, Type, Fd, Bound) of {ok, S} -> - case prim_inet:setopts(S, Opts) of + case prim_inet:setopts(S, Opts -- [local]) of ok -> case if Bound -> @@ -1345,6 +1348,13 @@ fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) -> Error -> Error end. +-spec getfamily(list()) -> atom(). +getfamily(Options) when is_list(Options) -> + case lists:member(local, Options) of + true -> local; + false -> inet + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% socket stat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index e7c6cf8ae2..0a2201298a 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -29,6 +29,7 @@ -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 %% type codes to open and gettype - INET_REQ_GETTYPE -define(INET_TYPE_STREAM, 1). @@ -378,7 +379,8 @@ { 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 + family = inet, %% address family opts = [] %% [{active,true}] added in inet:connect_options }). @@ -388,6 +390,7 @@ port = 0, %% bind to port (default is dynamic port) backlog = ?LISTEN_BACKLOG, %% backlog fd = -1, %% %% fd >= 0 => already bound + family = inet, %% address family opts = [] %% [{active,true}] added in %% inet:listen_options }). @@ -397,6 +400,7 @@ ifaddr = any, port = 0, fd = -1, + family = inet, opts = [{active,true}] }). diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index f551af9709..ad0a6159fe 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -108,9 +108,10 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) -> {ok, #connect_opts{fd=Fd, ifaddr=BAddr={Ab,Bb,Cb,Db}, port=BPort, + family=Family, 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,tcp,Family,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, {A,B,C,D}, Port, Time) of ok -> {ok,S}; @@ -130,9 +131,10 @@ listen(Port, Opts) -> {ok, #listen_opts{fd=Fd, ifaddr=BAddr={A,B,C,D}, port=BPort, + family=Family, 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,tcp,Family,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -165,4 +167,7 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE). + fdopen(Fd, inet:getfamily(Opts), Opts). + +fdopen(Fd, Family, Opts) -> + inet:fdopen(Fd, Opts, tcp, Family, stream, ?MODULE). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 5b2e5120c9..74b2874d5b 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -52,8 +52,9 @@ open(Port, Opts) -> {ok, #udp_opts{fd=Fd, ifaddr=BAddr={A,B,C,D}, port=BPort, + family=Family, opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,Family,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -92,9 +93,12 @@ controlling_process(Socket, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> + fdopen(Fd, inet:getfamily(Opts), Opts). + +fdopen(Fd, Family, Opts) -> inet:fdopen(Fd, optuniquify([{recbuf, ?RECBUF} | Opts]), - udp, inet, dgram, ?MODULE). + udp, Family, dgram, ?MODULE). %% Remove all duplicate options from an option list. |