Skip to content

Commit 8db35de

Browse files
authored
[core] Refaxed and fixed multiplexer reusage (Haivision#2608).
Fixed ReuseAddr tests.
1 parent 6c92a13 commit 8db35de

9 files changed

+740
-142
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ matrix:
7171
- BUILD_TYPE=Release
7272
- BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON'
7373
script:
74-
- TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*:ReuseAddr.ProtocolVersion" ; # Tests to skip due to lack of IPv6 support
74+
- TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*:ReuseAddr.ProtocolVersion:ReuseAddr.*6" ; # Tests to skip due to lack of IPv6 support
7575
- if [ "$TRAVIS_COMPILER" == "x86_64-w64-mingw32-g++" ]; then
7676
export CC="x86_64-w64-mingw32-gcc";
7777
export CXX="x86_64-w64-mingw32-g++";

docs/API/API-functions.md

+84-14
Original file line numberDiff line numberDiff line change
@@ -358,27 +358,96 @@ int srt_bind(SRTSOCKET u, const struct sockaddr* name, int namelen);
358358

359359
Binds a socket to a local address and port. Binding specifies the local network
360360
interface and the UDP port number to be used for the socket. When the local
361-
address is a form of `INADDR_ANY`, then it's bound to all interfaces. When the
362-
port number is 0, then the port number will be system-allocated if necessary.
361+
address is a wildcard (`INADDR_ANY` for IPv4 or `in6addr_any` for IPv6), then
362+
it's bound to all interfaces (although see `SRTO_IPV6ONLY` and additional
363+
information below for details about the wildcard address in IPv6).
364+
365+
Binding is necessary for every socket to be used for communication. If the socket
366+
is to be used to initiate a connection to a listener socket, which can be done,
367+
for example, by the [`srt_connect`](#srt_connect) function, the socket is bound
368+
implicitly to the wildcard address according to the IP family (`INADDR_ANY` for
369+
`AF_INET` or `in6addr_any` for `AF_INET6`) and port number 0. In all other cases,
370+
a socket must be bound explicitly by using the functionality of this function first.
371+
372+
When the port number parameter is 0, then the effective port number will be
373+
system-allocated. To obtain this effective port number you can use
374+
[`srt_getsockname`](#srt_getsockname).
363375

364376
This call is obligatory for a listening socket before calling [`srt_listen`](#srt_listen)
365377
and for rendezvous mode before calling [`srt_connect`](#srt_connect); otherwise it's
366378
optional. For a listening socket it defines the network interface and the port where
367-
the listener should expect a call request. In the case of rendezvous mode (when the
368-
socket has set [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) to
369-
true both parties connect to one another) it defines the network interface and port
370-
from which packets will be sent to the peer, and the port to which the peer is
371-
expected to send packets.
372-
373-
For a connecting socket this call can set up the outgoing port to be used in the
374-
communication. It is allowed that multiple SRT sockets share one local outgoing
375-
port, as long as [`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS)
376-
is set to *true* (default). Without this call the port will be automatically
377-
selected by the system.
379+
the listener should expect a call request.
380+
381+
In the case of rendezvous mode there are two parties that connect to one another.
382+
For every party there must be chosen a local binding endpoint (local address and port)
383+
to which they expect connection from the peer. Let's say, we have a Party 1
384+
that selects an endpoint A and a Party 2 that selects an endpoint B. In this case the Party 1
385+
binds the socket to the endpoint A and then connects to the endpoint B, and the Party 2
386+
the other way around. Both sockets must be set
387+
[`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) to *true* to make
388+
this connection possible.
389+
390+
For a connecting socket the call to `srt_bind` is optional, but can be used to set up the
391+
outgoing port for communication as well as the local interface through which
392+
it should reach out to the remote endpoint, should that be necessary.
393+
394+
Whether binding is possible depends on some runtime conditions, in particular:
395+
396+
* No socket in the system has been bound to this port ("free binding"), or
397+
398+
* A socket bound to this port is bound to a certain address, and this binding is
399+
using a different non-wildcard address ("side binding"), or
400+
401+
* A socket bound to this port is bound to a wildcard address for a different IP
402+
version than the version requested for this binding ("side wildcard binding",
403+
see also `SRTO_IPV6ONLY` socket option).
404+
405+
It is also possible to bind to the already busy port as long as the existing
406+
binding ("shared binding") is possessed by an SRT socket created in the same
407+
application, and:
408+
409+
* Its binding address and UDP-related socket options match the socket to be bound.
410+
* Its [`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS) is set to *true* (default).
411+
412+
If none of the free, side and shared binding options is currently possible, this function
413+
will fail. If the socket blocking the requested endpoint is an SRT
414+
socket in the current application, it will report the `SRT_EBINDCONFLICT` error,
415+
while if it was another socket in the system, or the problem was in the system
416+
in general, it will report `SRT_ESOCKFAIL`. Here is the table that shows possible situations:
417+
418+
| Requested binding | vs. Existing bindings... | | | | |
419+
|---------------------|------------------------------|-----------|-----------------------------|---------------|---------------|
420+
| | A.B.C.D | 0.0.0.0 | ::X | :: / V6ONLY=1 | :: / V6ONLY=0 |
421+
| 1.2.3.4 | 1.2.3.4 shareable, else free | blocked | free | free | blocked |
422+
| 0.0.0.0 | blocked | shareable | free | free | blocked |
423+
| 8080::1 | free | free | 8080::1 sharable, else free | blocked | blocked |
424+
| :: / V6ONLY=1 | free | free | blocked | sharable | blocked |
425+
| :: / V6ONLY=0 | blocked | blocked | blocked | blocked | sharable |
426+
Where:
427+
* free: This binding can coexist with the requested binding.
428+
* blocked: This binding conflicts with the requested binding.
429+
* shareable: This binding can be shared with the requested binding if it's compatible.
430+
* (ADDRESS) shareable, else free: this binding is shareable if the requested binding address is
431+
equal to the given one. Otherwise it's free.
432+
If the binding is shareable, then the operation will succeed if the socket that currently
433+
occupies the binding has the `SRTO_REUSEADDR` option set to true (default) and all UDP
434+
settings are the same as in the current socket. Otherwise it will fail. Shared binding means
435+
sharing the underlying UDP socket and communication queues between SRT sockets. If
436+
all existing bindings on the same port are "free" then the requested binding will
437+
allocate a distinct UDP socket for this SRT socket ("side binding").
438+
378439

379440
**NOTE**: This function cannot be called on a socket group. If you need to
380441
have the group-member socket bound to the specified source address before
381-
connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose.
442+
connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose
443+
or set the appropriate source address using
444+
[`srt_prepare_endpoint`](#srt_prepare_endpoint).
445+
446+
**IMPORTANT information about IPv6**: If you are going to bind to the
447+
`in6addr_any` IPv6 wildcard address (known as `::`), the `SRTO_IPV6ONLY`
448+
option must be first set explicitly to 0 or 1, otherwise the binding
449+
will fail. In all other cases this option is meaningless. See `SRTO_IPV6ONLY`
450+
option for more information.
382451

383452
| Returns | |
384453
|:----------------------------- |:--------------------------------------------------------- |
@@ -389,6 +458,7 @@ connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose.
389458
|:---------------------------------------- |:-------------------------------------------------------------------- |
390459
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket |
391460
| [`SRT_EINVOP`](#srt_einvop) | Socket already bound |
461+
| [`SRT_EINVPARAM`](#srt_einvparam) | Invalid `name`/`namelen` or invalid `SRTO_IPV6ONLY` flag in `u` |
392462
| [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed |
393463
| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed |
394464
| [`SRT_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one |

docs/API/API-socket-options.md

+11-4
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,17 @@ and the actual value for connected sockets.
645645
| ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ |
646646
| `SRTO_IPV6ONLY` | 1.4.0 | pre-bind | `int32_t` | | (system) | -1..1 | RW | GSD |
647647

648-
Set system socket flag `IPV6_V6ONLY`. When set to 0 a listening socket binding an
649-
IPv6 address accepts also IPv4 clients (their addresses will be formatted as
650-
IPv4-mapped IPv6 addresses). By default (-1) this option is not set and the
651-
platform default value is used.
648+
Set system socket option level `IPPROTO_IPV6` named `IPV6_V6ONLY`. This is meaningful
649+
only when the socket is going to be bound to the IPv6 wildcard address `in6addr_any`
650+
(known also as `::`). In this case this option must be also set explicitly to 0 or 1
651+
before binding, otherwise binding will fail (this is because it is not possible to
652+
determine the default value of this above-mentioned system option in any portable or
653+
reliable way). Possible values are:
654+
655+
* -1: (default) use system-default value (can be used when not binding to IPv6 wildcard `::`)
656+
* 0: The binding to `in6addr_any` will bind to both IPv6 and IPv4 wildcard address
657+
* 1: The binding to `in6addr_any` will bind only to IPv6 and not IPv4 wildcard address
658+
652659

653660
[Return to list](#list-of-options)
654661

0 commit comments

Comments
 (0)