aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2016-06-09 09:27:05 +0200
committerRaimo Niskanen <[email protected]>2016-06-09 09:27:05 +0200
commit2da08a037e4315a1010769b22610ca81462d813d (patch)
treece14def3320bcbdf897a4a7a4a52f65db490c8d4
parent7f2a5750d896febf39a51c488f57c4235e34a040 (diff)
parent16e895198a541ccbbbe6c970bd9572cf347a9c77 (diff)
downloadotp-2da08a037e4315a1010769b22610ca81462d813d.tar.gz
otp-2da08a037e4315a1010769b22610ca81462d813d.tar.bz2
otp-2da08a037e4315a1010769b22610ca81462d813d.zip
Merge branch 'raimo/uds-support/OTP-13643'
* raimo/uds-support/OTP-13643: Document the local (unix) address family Remove internal state BOUND from inet_drv
-rw-r--r--erts/emulator/drivers/common/inet_drv.c81
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin76292 -> 76348 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl4
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml21
-rw-r--r--lib/kernel/doc/src/gen_udp.xml19
-rw-r--r--lib/kernel/doc/src/inet.xml53
-rw-r--r--lib/kernel/src/gen_tcp.erl12
-rw-r--r--lib/kernel/src/gen_udp.erl10
-rw-r--r--lib/kernel/src/inet.erl91
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/local_tcp.erl10
-rw-r--r--lib/kernel/src/local_udp.erl9
12 files changed, 207 insertions, 104 deletions
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 06dfb2dd10..93ea9f5dcb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -627,6 +627,7 @@ static int is_nonzero(const char *s, size_t n)
*/
/* general address encode/decode tag */
+#define INET_AF_UNSPEC 0
#define INET_AF_INET 1
#define INET_AF_INET6 2
#define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */
@@ -655,7 +656,7 @@ static int is_nonzero(const char *s, size_t n)
/* INET_REQ_GETSTATUS enumeration */
#define INET_F_OPEN 0x0001
-#define INET_F_BOUND 0x0002
+/* INET_F_BOUND removed - renumber when there comes a bigger rewrite */
#define INET_F_ACTIVE 0x0004
#define INET_F_LISTEN 0x0008
#define INET_F_CON 0x0010
@@ -853,19 +854,15 @@ static int is_nonzero(const char *s, size_t n)
#define INET_STATE_CLOSED (0)
#define INET_STATE_OPEN (INET_F_OPEN)
-#define INET_STATE_BOUND (INET_STATE_OPEN | INET_F_BOUND)
-#define INET_STATE_CONNECTED (INET_STATE_BOUND | INET_F_ACTIVE)
-#define INET_STATE_LISTENING (INET_STATE_BOUND | INET_F_LISTEN)
-#define INET_STATE_CONNECTING (INET_STATE_BOUND | INET_F_CON)
+#define INET_STATE_CONNECTED (INET_STATE_OPEN | INET_F_ACTIVE)
+#define INET_STATE_LISTENING (INET_STATE_OPEN | INET_F_LISTEN)
+#define INET_STATE_CONNECTING (INET_STATE_OPEN | INET_F_CON)
#define INET_STATE_ACCEPTING (INET_STATE_LISTENING | INET_F_ACC)
#define INET_STATE_MULTI_ACCEPTING (INET_STATE_ACCEPTING | INET_F_MULTI_CLIENT)
#define IS_OPEN(d) \
(((d)->state & INET_F_OPEN) == INET_F_OPEN)
-#define IS_BOUND(d) \
- (((d)->state & INET_F_BOUND) == INET_F_BOUND)
-
#define IS_CONNECTED(d) \
(((d)->state & INET_STATE_CONNECTED) == INET_STATE_CONNECTED)
@@ -1287,6 +1284,7 @@ static int async_ref = 0; /* async reference id generator */
static ErlDrvTermData am_ok;
static ErlDrvTermData am_undefined;
+static ErlDrvTermData am_unspec;
static ErlDrvTermData am_tcp;
static ErlDrvTermData am_error;
static ErlDrvTermData am_einval;
@@ -1553,10 +1551,18 @@ static int load_address(ErlDrvTermData* spec, int i, char* buf)
break;
}
#endif
- default: { /* INET_AF_UNDEFINED */
- i = LOAD_ATOM(spec, i, am_undefined);
+ case INET_AF_UNSPEC: {
+ i = LOAD_ATOM(spec, i, am_unspec);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
+ spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
spec[i++] = ERL_DRV_INT;
spec[i++] = 0;
+ break;
+ }
+ default: { /* INET_AF_UNDEFINED */
+ i = LOAD_ATOM(spec, i, am_undefined);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
spec[i++] = ERL_DRV_TUPLE;
spec[i++] = 2;
spec[i++] = ERL_DRV_INT;
@@ -3823,6 +3829,7 @@ static int inet_init()
INIT_ATOM(ok);
INIT_ATOM(undefined);
+ INIT_ATOM(unspec);
INIT_ATOM(tcp);
#ifdef HAVE_UDP
INIT_ATOM(udp);
@@ -4149,6 +4156,10 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
return 0;
}
#endif
+ else if (family == AF_UNSPEC) {
+ dst[0] = INET_AF_UNSPEC;
+ *len = 1;
+ }
else {
dst[0] = INET_AF_UNDEFINED;
*len = 1;
@@ -4419,10 +4430,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
{
inet_address name;
- unsigned int sz = sizeof(name);
+ unsigned int sz;
if (bound) {
/* check that it is a socket and that the socket is bound */
+ sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
if (name.sa.sa_family != domain)
@@ -4437,10 +4450,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
driver_select(desc->port, desc->event, ERL_DRV_READ, 1);
#endif
- if (bound)
- desc->state = INET_STATE_BOUND;
- else
- desc->state = INET_STATE_OPEN;
+ desc->state = INET_STATE_OPEN;
if (type == SOCK_STREAM) { /* check if connected */
sz = sizeof(name);
@@ -8448,7 +8458,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getpaddrs) {
@@ -8524,7 +8533,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getladdrs) {
@@ -8546,6 +8554,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
int i;
sz = sizeof(addr);
+ sys_memzero((char *) &addr, sz);
i = sock_name(desc->s, (struct sockaddr *) &addr, &sz);
return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz);
}
@@ -8559,15 +8568,13 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
DEBUGF(("inet_ctl(%ld): NAME\r\n", (long)desc->port));
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize); /* address is not valid */
-
if ((ptr = desc->name_ptr) != NULL) {
sz = desc->name_addr_len;
}
else {
ptr = &name;
sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
if (IS_SOCKET_ERROR
(sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
@@ -8612,11 +8619,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len)))
return ctl_error(sock_errno(), rbuf, rsize);
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
port = inet_address_port(&local);
if (port == 0) {
SOCKLEN_T adrlen = sizeof(local);
+ sys_memzero((char *) &local, adrlen);
sock_name(desc->s, &local.sa, &adrlen);
port = inet_address_port(&local);
}
@@ -9136,8 +9144,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(INETP(desc)))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
backlog = get_int16(buf);
@@ -9160,8 +9166,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (IS_CONNECTED(INETP(desc)))
return ctl_error(EISCONN, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (IS_CONNECTING(INETP(desc)))
return ctl_error(EINVAL, rbuf, rsize);
if (len < 6)
@@ -9262,6 +9266,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
} else {
n = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, n);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &n);
if (s == INVALID_SOCKET) {
if (sock_errno() == ERRNO_BLOCK) {
@@ -10147,6 +10152,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
inet_async_op *this_op = desc->inet.opt;
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, just a ghost trigger from poll,
@@ -10213,6 +10219,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, keep the last return code */
@@ -10653,7 +10660,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(struct sockaddr*) &desc->inet.remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), sock_errno());
goto done;
}
@@ -10666,7 +10673,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), error);
goto done;
}
@@ -11075,8 +11082,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc)) {
inet_address remote;
@@ -11163,8 +11168,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
@@ -11211,7 +11214,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_error(sock_errno(), rbuf, rsize);
}
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -11228,8 +11231,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (! p_sctp_peeloff)
return ctl_error(ENOTSUP, rbuf, rsize);
@@ -11270,8 +11271,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* INPUT: Timeout(4), Length(4) */
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize);
if (desc->active || (len != 8))
return ctl_error(EINVAL, rbuf, rsize);
timeout = get_int32(buf);
@@ -11336,10 +11335,6 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
inet_reply_error(desc, EINVAL);
return;
}
- if (!IS_BOUND(desc)) {
- inet_reply_error(desc, EINVAL);
- return;
- }
#ifdef HAVE_SCTP
if (IS_SCTP(desc))
@@ -11470,6 +11465,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
while(packet_count--) {
unsigned int len = sizeof(other);
+ sys_memzero((char *) &other, sizeof(other));
+
/* udesc->i_buf is only kept between SCTP fragments */
if (udesc->i_buf == NULL) {
udesc->i_bufsz = desc->bufsz + len;
@@ -11665,7 +11662,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(struct sockaddr*) &desc->remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, sock_errno());
goto done;
}
@@ -11678,7 +11675,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, error);
goto done;
}
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index edb86d35a6..fdf8bbf4e2 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 71dbfbd0a7..560810d222 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1746,8 +1746,8 @@ enc_value_2(addr, {inet6,{IP,Port}}) ->
[?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
enc_value_2(addr, {local,Addr}) ->
%% A binary is passed as is, but anything else will be
- %% regarded as a filename and therefore UTF-8 encoded
- %% if the system filename encoding flag so dictates.
+ %% regarded as a filename and therefore encoded according to
+ %% the current system filename encoding mode.
Bin =
if
is_binary(Addr) ->
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index b75d42d198..88135ea43d 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -153,17 +153,17 @@ do_recv(Sock, Bs) ->
<c><anno>Address</anno></c> can be a hostname or an IP address.</p>
<p>The following options are available:</p>
<taglist>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to use.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to use.</p>
</item>
<tag><c>{fd, integer() >= 0}</c></tag>
<item><p>If a socket has somehow been connected without using
<c>gen_tcp</c>, use this option to pass the file descriptor
- for it. If <c>{ip, ip_address()}</c> and/or
+ for it. If <c>{ip, Address}</c> and/or
<c>{port, port_number()}</c> is combined with this option, the
<c>fd</c> is bound to the specified interface and port before
connecting. If these options are not specified, it is assumed that
@@ -175,9 +175,10 @@ do_recv(Sock, Bs) ->
<tag><c>local</c></tag>
<item>
<p>
- Sets 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)
+ Sets up a Unix Domain Socket. See
+ <seealso marker="inet#type-local_address">
+ <c>inet:local_address()</c>
+ </seealso>
</p>
</item>
<tag><c>{port, Port}</c></tag>
@@ -254,7 +255,7 @@ do_recv(Sock, Bs) ->
<item><p><c>B</c> is an integer &gt;= <c>0</c>. The backlog value
defines the maximum length that the queue of pending connections
can grow to. Defaults to <c>5</c>.</p></item>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to listen on.</p></item>
<tag><c>{port, Port}</c></tag>
@@ -263,8 +264,8 @@ do_recv(Sock, Bs) ->
<item><p>If a socket has somehow been connected without using
<c>gen_tcp</c>, use this option to pass the file
descriptor for it.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to use.</p>
</item>
<tag><c>inet6</c></tag>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index ca9d9c978c..3f88a0272d 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -85,11 +85,11 @@
<item><p>Received <c>Packet</c> is delivered as a list.</p></item>
<tag><c>binary</c></tag>
<item><p>Received <c>Packet</c> is delivered as a binary.</p></item>
- <tag><c>{ip, ip_address()}</c></tag>
+ <tag><c>{ip, Address}</c></tag>
<item><p>If the host has many network interfaces, this option
specifies which one to use.</p></item>
- <tag><c>{ifaddr, ip_address()}</c></tag>
- <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many
+ <tag><c>{ifaddr, Address}</c></tag>
+ <item><p>Same as <c>{ip, Address}</c>. If the host has many
network interfaces, this option specifies which one to
use.</p></item>
<tag><c>{fd, integer() >= 0}</c></tag>
@@ -107,9 +107,10 @@
<tag><c>local</c></tag>
<item>
<p>
- Sets 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)
+ Sets up a Unix Domain Socket. See
+ <seealso marker="inet#type-local_address">
+ <c>inet:local_address()</c>
+ </seealso>
</p>
</item>
<tag><c>{udp_module, module()}</c></tag>
@@ -184,8 +185,10 @@
<name name="send" arity="4"/>
<fsummary>Send a packet.</fsummary>
<desc>
- <p>Sends a packet to the specified address and port. Argument
- <c><anno>Address</anno></c> can be a hostname or an IP address.</p>
+ <p>
+ Sends a packet to the specified address and port. Argument
+ <c><anno>Address</anno></c> can be a hostname or a socket address.
+ </p>
</desc>
</func>
</funcs>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 5ff167bcb3..c0dce2f50c 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -118,6 +118,59 @@ fe80::204:acff:fe17:bf38
<name name="port_number"/>
</datatype>
<datatype>
+ <name name="local_address"/>
+ <desc>
+ <p>
+ This address family only works on Unix-like systems.
+ </p>
+ <p>
+ <c><anno>File</anno></c> is normally a file pathname
+ in a local filesystem. It is limited in length by the
+ operating system, traditionally to 108 bytes.
+ </p>
+ <p>
+ A <c>binary()</c> is passed as is to the operating system,
+ but a <c>string()</c> is encoded according to the
+ <seealso marker="file#native_name_encoding/0">
+ system filename encoding mode.
+ </seealso>
+ </p>
+ <p>
+ Other addresses are possible, for example Linux implements
+ "Abstract Addresses". See the documentation for
+ Unix Domain Sockets on your system,
+ normally <c>unix</c> in manual section 7.
+ </p>
+ <p>
+ In most API functions where you can use
+ this address family the port number must be <c>0</c>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="socket_address"/>
+ </datatype>
+ <datatype>
+ <name name="returned_non_ip_address"/>
+ <desc>
+ <p>
+ Addresses besides
+ <seealso marker="#type-ip_address">
+ <c>ip_address()</c>
+ </seealso>
+ ones that are returned from socket API functions.
+ See in particular
+ <seealso marker="#type-local_address">
+ <c>local_address()</c>.
+ </seealso>
+ The <c>unspec</c> family corresponds to AF_UNSPEC and can
+ occur if the other side has no socket address.
+ The <c>undefined</c> family can only occur in the unlikely
+ event of an address family that the VM does not recognize.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 2b3afcd44c..1a21541b7c 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -96,17 +96,17 @@
tos |
ipv6_v6only.
-type connect_option() ::
- {ip, inet:ip_address()} |
+ {ip, inet:socket_address()} |
{fd, Fd :: non_neg_integer()} |
- {ifaddr, inet:ip_address()} |
+ {ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{tcp_module, module()} |
option().
-type listen_option() ::
- {ip, inet:ip_address()} |
+ {ip, inet:socket_address()} |
{fd, Fd :: non_neg_integer()} |
- {ifaddr, inet:ip_address()} |
+ {ifaddr, inet:socket_address()} |
inet:address_family() |
{port, inet:port_number()} |
{backlog, B :: non_neg_integer()} |
@@ -122,7 +122,7 @@
%%
-spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Options :: [connect_option()],
Socket :: socket(),
@@ -133,7 +133,7 @@ connect(Address, Port, Opts) ->
-spec connect(Address, Port, Options, Timeout) ->
{ok, Socket} | {error, Reason} when
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Options :: [connect_option()],
Timeout :: timeout(),
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 2227bb3562..98d2f0bcfb 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -92,9 +92,9 @@ open(Port) ->
-spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when
Port :: inet:port_number(),
Opts :: [Option],
- Option :: {ip, inet:ip_address()}
+ Option :: {ip, inet:socket_address()}
| {fd, non_neg_integer()}
- | {ifaddr, inet:ip_address()}
+ | {ifaddr, inet:socket_address()}
| inet:address_family()
| {port, inet:port_number()}
| option(),
@@ -114,7 +114,7 @@ close(S) ->
-spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when
Socket :: socket(),
- Address :: inet:ip_address() | inet:hostname(),
+ Address :: inet:socket_address() | inet:hostname(),
Port :: inet:port_number(),
Packet :: iodata(),
Reason :: not_owner | inet:posix().
@@ -148,7 +148,7 @@ send(S, Packet) when is_port(S) ->
{ok, {Address, Port, Packet}} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
- Address :: inet:ip_address(),
+ Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -166,7 +166,7 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
- Address :: inet:ip_address(),
+ Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index de43ea792b..20c64a39ca 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -73,8 +73,9 @@
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
- ip6_address/0, ip_address/0, posix/0, socket/0,
- port_number/0]).
+ ip6_address/0, ip_address/0, port_number/0,
+ local_address/0, socket_address/0, returned_non_ip_address/0,
+ posix/0, socket/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -98,6 +99,11 @@
0..65535,0..65535,0..65535,0..65535}.
-type ip_address() :: ip4_address() | ip6_address().
-type port_number() :: 0..65535.
+-type local_address() :: {local, File :: binary() | string()}.
+-type returned_non_ip_address() ::
+ {local, binary()} |
+ {unspec, <<>>} |
+ {undefined, any()}.
-type posix() :: exbadport | exbadseq | file:posix().
-type socket() :: port().
@@ -138,7 +144,7 @@
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
-type socket_address() ::
- ip_address() | {address_family(), any()} | 'any' | 'loopback'.
+ ip_address() | 'any' | 'loopback' | local_address().
-type stat_option() ::
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
@@ -163,26 +169,33 @@ close(Socket) ->
end.
--spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec peername(Socket :: socket()) ->
+ {ok,
+ {ip_address(), port_number()} |
+ returned_non_ip_address()} |
+ {error, posix()}.
peername(Socket) ->
prim_inet:peername(Socket).
--spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
- 'ok' | {'error', any()}.
+-spec setpeername(
+ Socket :: socket(),
+ Address ::
+ {ip_address() | 'any' | 'loopback',
+ port_number()} |
+ socket_address()) ->
+ 'ok' | {'error', any()}.
setpeername(Socket, {IP,Port}) ->
prim_inet:setpeername(Socket, {IP,Port});
setpeername(Socket, undefined) ->
prim_inet:setpeername(Socket, undefined).
--spec peernames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec peernames(Socket :: socket()) ->
+ {ok,
+ [{ip_address(), port_number()} |
+ returned_non_ip_address()]} |
+ {error, posix()}.
peernames(Socket) ->
prim_inet:peernames(Socket).
@@ -198,15 +211,21 @@ peernames(Socket, Assoc) ->
prim_inet:peernames(Socket, Assoc).
--spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec sockname(Socket :: socket()) ->
+ {ok,
+ {ip_address(), port_number()} |
+ returned_non_ip_address()} |
+ {error, posix()}.
sockname(Socket) ->
prim_inet:sockname(Socket).
--spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) ->
+-spec setsockname(
+ Socket :: socket(),
+ Address ::
+ {ip_address() | 'any' | 'loopback',
+ port_number()} |
+ socket_address()) ->
'ok' | {'error', any()}.
setsockname(Socket, {IP,Port}) ->
@@ -214,10 +233,11 @@ setsockname(Socket, {IP,Port}) ->
setsockname(Socket, undefined) ->
prim_inet:setsockname(Socket, undefined).
--spec socknames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when
- Socket :: socket(),
- Address :: ip_address(),
- Port :: non_neg_integer().
+-spec socknames(Socket :: socket()) ->
+ {ok,
+ [{ip_address(), port_number()} |
+ returned_non_ip_address()]} |
+ {error, posix()}.
socknames(Socket) ->
prim_inet:socknames(Socket).
@@ -1296,7 +1316,17 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
end.
-spec open(Fd_or_OpenOpts :: integer() | list(),
- Addr :: socket_address(),
+ Addr ::
+ socket_address() |
+ {ip_address() | 'any' | 'loopback', % Unofficial
+ port_number()} |
+ {inet, % Unofficial
+ {ip4_address() | 'any' | 'loopback',
+ port_number()}} |
+ {inet6, % Unofficial
+ {ip6_address() | 'any' | 'loopback',
+ port_number()}} |
+ undefined, % Internal - no bind()
Port :: port_number(),
Opts :: [socket_setopt()],
Protocol :: socket_protocol(),
@@ -1316,11 +1346,16 @@ open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module)
{ok,S} ->
case prim_inet:setopts(S, Opts) of
ok ->
- case if is_list(Addr) ->
- bindx(S, Addr, Port);
- true ->
- prim_inet:bind(S, Addr, Port)
- end of
+ case
+ case Addr of
+ undefined ->
+ {ok, undefined};
+ _ when is_list(Addr) ->
+ bindx(S, Addr, Port);
+ _ ->
+ prim_inet:bind(S, Addr, Port)
+ end
+ of
{ok, _} ->
inet_db:register_socket(S, Module),
{ok,S};
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 32d09fb63c..c8a8962e78 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -25,6 +25,7 @@
%%
%% family codes to open
+-define(INET_AF_UNSPEC, 0).
-define(INET_AF_INET, 1).
-define(INET_AF_INET6, 2).
-define(INET_AF_ANY, 3). % Fake for ANY in any address family
diff --git a/lib/kernel/src/local_tcp.erl b/lib/kernel/src/local_tcp.erl
index 64085ec42e..e3c67dfbb7 100644
--- a/lib/kernel/src/local_tcp.erl
+++ b/lib/kernel/src/local_tcp.erl
@@ -107,8 +107,14 @@ do_connect(Addr = {?FAMILY, _}, 0, Opts, Time) ->
when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
BAddr =:= any ->
case inet:open(
- Fd, BAddr, 0, SockOpts,
- ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
+ Fd,
+ case BAddr of
+ any ->
+ undefined;
+ _ ->
+ BAddr
+ end,
+ 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
{ok, S} ->
case prim_inet:connect(S, Addr, 0, Time) of
ok -> {ok,S};
diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl
index ebb4d2b33f..481a8c4910 100644
--- a/lib/kernel/src/local_udp.erl
+++ b/lib/kernel/src/local_udp.erl
@@ -59,7 +59,14 @@ open(0, Opts) ->
when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY;
BAddr =:= any ->
inet:open(
- Fd, BAddr, 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
+ Fd,
+ case BAddr of
+ any ->
+ undefined;
+ _ ->
+ BAddr
+ end,
+ 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE);
{ok, _} -> exit(badarg)
end.