diff options
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 81 | ||||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 76292 -> 76348 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 4 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_tcp.xml | 21 | ||||
-rw-r--r-- | lib/kernel/doc/src/gen_udp.xml | 19 | ||||
-rw-r--r-- | lib/kernel/doc/src/inet.xml | 53 | ||||
-rw-r--r-- | lib/kernel/src/gen_tcp.erl | 12 | ||||
-rw-r--r-- | lib/kernel/src/gen_udp.erl | 10 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 91 | ||||
-rw-r--r-- | lib/kernel/src/inet_int.hrl | 1 | ||||
-rw-r--r-- | lib/kernel/src/local_tcp.erl | 10 | ||||
-rw-r--r-- | lib/kernel/src/local_udp.erl | 9 |
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 Binary files differindex edb86d35a6..fdf8bbf4e2 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam 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 >= <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. |