Skip to content

Commit

Permalink
[core] Detect reusable bindings and binding conflicts correctly (#1588).
Browse files Browse the repository at this point in the history
Introduced new SRT socket error SRT_EBINDCONFLICT.
  • Loading branch information
ethouris authored May 28, 2021
1 parent 44eb6ce commit e2a00aa
Show file tree
Hide file tree
Showing 10 changed files with 672 additions and 90 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ matrix:
- make
- cd ..
env: BUILD_TYPE=Release

# Power jobs
- os: linux
arch: ppc64le
Expand All @@ -69,6 +69,7 @@ matrix:
- BUILD_TYPE=Release
- BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON'
script:
- TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*:ReuseAddr.ProtocolVersion" ; # Tests to skip due to lack of IPv6 support
- if [ "$TRAVIS_COMPILER" == "x86_64-w64-mingw32-g++" ]; then
export CC="x86_64-w64-mingw32-gcc";
export CXX="x86_64-w64-mingw32-g++";
Expand All @@ -91,7 +92,7 @@ script:
make -j$(nproc);
fi
- if [ "$TRAVIS_COMPILER" != "x86_64-w64-mingw32-g++" ]; then
./test-srt --gtest_filter="-TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*";
./test-srt --gtest_filter="-$TESTS_IPv6";
fi
- if (( "$RUN_CODECOV" )); then
source ./scripts/collect-gcov.sh;
Expand Down
86 changes: 68 additions & 18 deletions docs/API/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,14 @@ connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose.
| `SRT_ERROR` | (-1) on error, otherwise 0 |
| <img width=240px height=1px/> | <img width=710px height=1px/> |

| Errors | |
|:----------------------------------- |:-------------------------------------------------------------------- |
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket |
| [`SRT_EINVOP`](#srt_einvop) | Socket already bound |
| [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed |
| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed |
| <img width=240px height=1px/> | <img width=710px height=1px/> |
| Errors | |
|:---------------------------------------- |:-------------------------------------------------------------------- |
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket |
| [`SRT_EINVOP`](#srt_einvop) | Socket already bound |
| [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed |
| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed |
| [`SRT_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one |
| <img width=240px height=1px/> | <img width=710px height=1px/> |


[:arrow_up: &nbsp; Back to List of Functions & Structures](#srt-api-functions)
Expand Down Expand Up @@ -841,18 +842,19 @@ first on the automatically created socket for the connection.
| `SRT_ERROR` | (-1) in case of error |
| 0 | In case when used for [`u`](#u) socket |
| Socket ID | Created for connection for [`u`](#u) group |
| <img width=240px height=1px/> | <img width=710px height=1px/> |
| <img width=240px height=1px/> | <img width=710px height=1px/> |

| Errors | |
|:------------------------------------- |:-------------------------------------------------------- |
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket |
| [`SRT_EINVOP`](#srt_einvop) | Socket already bound |
| [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed |
| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed |
| [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | Internal error ([`srt_connect`](#srt_connect) should not report it after [`srt_bind`](#srt_bind) was called) |
| [`SRT_ECONNSOCK`](#srt_econnsock) | Socket [`u`](#u) is already connected |
| [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected |
| <img width=240px height=1px/> | <img width=710px height=1px/> |
| Errors | |
|:---------------------------------------- |:-------------------------------------------------------- |
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket |
| [`SRT_EINVOP`](#srt_einvop) | Socket already bound |
| [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed |
| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed |
| [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | Internal error ([`srt_connect`](#srt_connect) should not report it after [`srt_bind`](#srt_bind) was called) |
| [`SRT_ECONNSOCK`](#srt_econnsock) | Socket [`u`](#u) is already connected |
| [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected |
| [`SRT_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one |
| <img width=240px height=1px/> | <img width=710px height=1px/> |


**IMPORTANT**: It's not allowed to bind and connect the same socket to two
Expand Down Expand Up @@ -3225,6 +3227,54 @@ by setting the `SRT_EPOLL_ENABLE_EMPTY` flag, which may be useful when
you use multiple threads and start waiting without subscribed sockets, so that
you can subscribe them later from another thread.


#### `SRT_EBINDCONFLICT`

The binding you are attempting to set up a socket with cannot be completed because
it conflicts with another existing binding. This is because an intersecting binding
was found that cannot be reused according to the specification in `srt_bind` call.

A binding is considered intersecting if the existing binding has the same port
and covers at least partially the range as that of the attempted binding. These
ranges can be split in three groups:

1. An explicitly specified IP address (both IPv4 and IPv6) covers this address only.
2. An IPv4 wildcard 0.0.0.0 covers all IPv4 addresses (but not IPv6).
3. An IPv6 wildcard :: covers:
* if `SRTO_IPV6ONLY` is true - all IPv6 addresses (but not IPv4)
* if `SRTO_IPV6ONLY` is false - all IP addresses.

Example 1:

* Socket 1: bind to IPv4 0.0.0.0
* Socket 2: bind to IPv6 :: with `SRTO_IPV6ONLY` = true
* Result: NOT intersecting

Example 2:

* Socket 1: bind to IPv4 1.2.3.4
* Socket 2: bind to IPv4 0.0.0.0
* Result: intersecting (and conflicting)

Example 3:

* Socket 1: bind to IPv4 1.2.3.4
* Socket 2: bind to IPv6 :: with `SRTO_IPV6ONLY` = false
* Result: intersecting (and conflicting)

If any common range coverage is found between the attempted binding specification
(in `srt_bind` call) and the found existing binding with the same port number,
then all of the following conditions must be satisfied between them:

1. The `SRTO_REUSEADDR` must be true (default) in both.

2. The IP address specification (in case of IPv6, also including the value of
`SRTO_IPV6ONLY` flag) must be exactly identical.

3. The UDP-specific settings must be identical.

If any of these conditions isn't satisfied, the `srt_bind` function results
in conflict and report this error.

#### SRT_EASYNCFAIL

Expand Down
18 changes: 8 additions & 10 deletions scripts/generate-error-types.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ set code_minor {
XSIZE 12
EIDINVAL 13
EEMPTY 14
BUSYPORT 15

WRAVAIL 1
RDAVAIL 2
Expand Down Expand Up @@ -121,7 +122,7 @@ set errortypes {
XSIZE "Message is too large to send (it must be less than the SRT send buffer size)"
EIDINVAL "Invalid epoll ID"
EEMPTY "All sockets removed from epoll, waiting would deadlock"

BUSYPORT "Another socket is bound to that port and is not reusable for requested settings"
}

AGAIN "Non-blocking call failure" {
Expand All @@ -142,11 +143,10 @@ set main_array_item {
const char** strerror_array_major [] = {
$minor_array_list
};

}

set major_size_item {
size_t strerror_array_sizes [] = {
const size_t strerror_array_sizes [] = {
$minor_array_sizes
};
}
Expand All @@ -155,11 +155,9 @@ set minor_array_item {
const char* strerror_msgs_$majorlc [] = {
$minor_message_items
};

}

set strerror_function {

const char* strerror_get_message(size_t major, size_t minor)
{
static const char* const undefined = "UNDEFINED ERROR";
Expand Down Expand Up @@ -228,16 +226,17 @@ proc Generate:imp {} {
puts [subst -nobackslashes -nocommands $::minor_array_item]

append minor_array_list " strerror_msgs_$majorlc, // MJ_$mt = $majitem\n"
append minor_array_sizes " [expr {$minitem}],\n"
#append minor_array_sizes " [expr {$minitem}],\n"
append minor_array_sizes " SRT_ARRAY_SIZE(strerror_msgs_$majorlc) - 1,\n"
incr majitem
}
append minor_array_list " NULL\n"
append minor_array_sizes " 0\n"
append minor_array_list " NULL"
append minor_array_sizes " 0"

puts [subst -nobackslashes -nocommands $::main_array_item]
puts {#define SRT_ARRAY_SIZE(ARR) sizeof(ARR) / sizeof(ARR[0])}
puts [subst -nobackslashes -nocommands $::major_size_item]

puts ""
puts $::strerror_function

puts "\} // namespace srt"
Expand All @@ -250,4 +249,3 @@ if {[lindex $argv 0] != ""} {
}

Generate:$defmode

Loading

0 comments on commit e2a00aa

Please sign in to comment.