Age | Commit message (Collapse) | Author |
|
ingela/merge-294
* ingela/raimo/udp-send-TOS/ERIERL-294/OTP-15747:
Introduce udp send ancillary data argument down to inet_drv
Fix old warnings
|
|
|
|
* `open/1-2` can return `{error, system_limit}`
* `recv/3` can return `{error, timeout}`
|
|
Implement socket options recvtclass, recvtos, recvttl and pktoptions.
Document the implemented socket options, new types and message formats.
The options recvtclass, recvtos and recvttl are boolean options that
when activated (true) for a socket will cause ancillary data to be
received through recvmsg(). That is for packet oriented sockets
(UDP and SCTP).
The required options for this feature were recvtclass and recvtos,
and recvttl was only added to test that the ancillary data parsing
handled multiple data items in one message correctly.
These options does not work on Windows since ancillary data
is not handled by the Winsock2 API.
For stream sockets (TCP) there is no clear connection between
a received packet and what is returned when reading data from
the socket, so recvmsg() is not useful. It is possible to get
the same ancillary data through a getsockopt() call with
the IPv6 socket option IPV6_PKTOPTIONS, on Linux named
IPV6_2292PKTOPTIONS after the now obsoleted RFC where it originated.
(unfortunately RFC 3542 that obsoletes it explicitly undefines
this way to get packet ancillary data from a stream socket)
Linux also has got a way to get packet ancillary data for IPv4
TCP sockets through a getsockopt() call with IP_PKTOPTIONS,
which appears to be Linux specific.
This implementation uses a flag field in the inet_drv.c socket
internal data that records if any setsockopt() call with recvtclass,
recvtos or recvttl (IPV6_RECVTCLASS, IP_RECVTOS or IP_RECVTTL)
has been activated. If so recvmsg() is used instead of recvfrom().
Ancillary data is delivered to the application by a new return
tuple format from gen_udp:recv/2,3 containing a list of
ancillary data tuples [{tclass,TCLASS} | {tos,TOS} | {ttl,TTL}],
as returned by recvmsg(). For a socket in active mode a new
message format, containing the ancillary data list, delivers
the data in the same way.
For gen_sctp the ancillary data is delivered in the same way,
except that the gen_sctp return tuple format already contained
an ancillary data list so there are just more possible elements
when using these socket options. Note that the active mode
message format has got an extra tuple level for the ancillary
data compared to what is now implemented gen_udp.
The gen_sctp active mode format was considered to be the odd one
- now all tuples containing ancillary data are flat,
except for gen_sctp active mode.
Note that testing has not shown that Linux SCTP sockets deliver
any ancillary data for these socket options, so it is probably
not implemented yet. Remains to be seen what FreeBSD does...
For gen_tcp inet:getopts([pktoptions]) will deliver the latest
received ancillary data for any activated socket option recvtclass,
recvtos or recvttl, on platforms where IP_PKTOPTIONS is defined
for an IPv4 socket, or where IPV6_PKTOPTIONS or IPV6_2292PKTOPTIONS
is defined for an IPv6 socket. It will be delivered as a
list of ancillary data items in the same way as for gen_udp
(and gen_sctp).
On some platforms, e.g the BSD:s, when you activate IP_RECVTOS
you get ancillary data tagged IP_RECVTOS with the TOS value,
but on Linux you get ancillary data tagged IP_TOS with the
TOS value. Linux follows the style of RFC 2292, and the BSD:s
use an older notion. For RFC 2292 that defines the IP_PKTOPTIONS
socket option it is more logical to tag the items with the
tag that is the item's, than with the tag that defines that you
want the item. Therefore this implementation translates all
BSD style ancillary data tags to the corresponding Linux style
data tags, so the application will only see the tags 'tclass',
'tos' and 'ttl' on all platforms.
|
|
|
|
Some networking functions accept the options netns (to switch network
namespaces) and bind_to_device (to bind to a device with
SO_BINDTODEVICE), but these functions are not annotated to accept these
options, which causes dialyzer to raise issues.
This patch applies these type specs to the options for
gen_tcp:connect/3,4, gen_tcp:listen/2, gen_udp:open/1,2, and
gen_sctp:open/0,1,2, as these are the documented functions which accept
the netns and bind_to_device options.
|
|
For gen_tcp, gen_udp and gen_sctp controlling_process/2 can return
badarg if erlang:port_connect/2 fails with badarg. This can easily
happen if the new owner is not alive but in some race condition also
when the socket is closed right before port_connect/2 (and after the
previous socket function)
This commit documents this behaviour.
|
|
|
|
|
|
|
|
|
|
Add the {active,N} socket option, where N is an integer in the range
-32768..32767, to allow a caller to specify the number of data messages to
be delivered to the controlling process. Once the socket's delivered
message count either reaches 0 or is explicitly set to 0 with
inet:setopts/2 or by including {active,0} as an option when the socket is
created, the socket transitions to passive ({active, false}) mode and the
socket's controlling process receives a message to inform it of the
transition. TCP sockets receive {tcp_passive,Socket}, UDP sockets receive
{udp_passive,Socket} and SCTP sockets receive {sctp_passive,Socket}.
The socket's delivered message counter defaults to 0, but it can be set
using {active,N} via any gen_tcp, gen_udp, or gen_sctp function that takes
socket options as arguments, or via inet:setopts/2. New N values are added
to the socket's current counter value, and negative numbers can be used to
reduce the counter value. Specifying a number that would cause the socket's
counter value to go above 32767 causes an einval error. If a negative
number is specified such that the counter value would become negative, the
socket's counter value is set to 0 and the socket transitions to passive
mode. If the counter value is already 0 and inet:setopts(Socket,
[{active,0}]) is specified, the counter value remains at 0 but the
appropriate passive mode transition message is generated for the socket.
This commit contains a modified preloaded prim_inet.beam due to changes in
prim_inet.erl.
Add tests for {active,N} mode for TCP, UDP, and SCTP sockets.
Add documentation for {active,N} mode for inet, gen_tcp, gen_udp, and
gen_sctp.
|
|
|
|
|
|
|
|
|
|
Add case to handle the situation when someone call
{gen_tcp,gen_udp}:controlling_process(Port, self()). Also improve spec
and doc from gen_udp and gen_sctp for controlling_process/2.
To reproduce the issue, open an UDP port:
4> {ok,Port} = gen_udp:open(9000, [binary]).
{ok,#Port<0.587>}
5> gen_udp:controlling_process(Port, self()).
ok
Simulate error:
6> 1=2.
** exception error: no match of right hand side value 2
Here is the leak:
7> inet:i().
Port Module Recv Sent Owner Local Address Foreign Address State
Type
581 inet_udp 0 0 <0.31.0> *:cslistener *:* BOUND
DGRAM
ok
|
|
The type is marked as a binary() or a string() but in practice it can
be an iodata(). The test suite was updated to confirm the gen_tcp/2
and gen_udp:send/4 functions accept iodata() (iolists) packets.
|
|
|
|
|
|
Currently an 8-tuple representing an IPv6 address is not accepted by
gen_tcp:listen/2, gen_tcp:connect/3,4, gen_udp:open/2, or
gen_sctp:open/1,2, unless the 'inet6' option is also given. This means
that an application that has obtained the address, e.g. from
configuration that allows for either IPv4 or IPv6, must always check the
type of the address before passing it to these functions. Letting the
functions infer 'inet6' from the 8-tuple, in case other options do not
override this choice, improves usability.
|
|
|