Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Calculate correctly max payload size per UDP packet #2677

Open
wants to merge 44 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b53a091
[FIX] Calculate correctly max payload size per UDP packet
Mar 1, 2023
a8b9104
Applied verification of the payload size fit. Added tests. Updated do…
Mar 3, 2023
56fdfdb
Withdrawn quotes for option names
Mar 3, 2023
d7f32d0
Fixed links in the socket option table
Mar 3, 2023
70de763
Fixed minimum MSS to 116. Fixed some other bux
Mar 6, 2023
2eb1159
Replaced rand_r with std c++ random
Mar 6, 2023
9f48d3c
Fixed usage of C++14 literals in the test (build failures)
Mar 6, 2023
edbb608
[MAINT] Upgraded CI: ubuntu to version 20.04
Mar 6, 2023
26a7be6
Fixed test logics (printing after closing)
Mar 6, 2023
3d387a2
Attempted fix for a deadlock in test, added some tracking
Mar 6, 2023
03717f3
Merge branch 'dev-upgrade-ci-ubuntu' into dev-fix-ipv6-payloadsize
Mar 6, 2023
3eef592
Added expect and tracking to close socket in ReuseAddr test (Travis p…
Mar 6, 2023
e2ab5f6
Used relaxed signaling for the sake of Travis
Mar 6, 2023
d081e50
Lock debug fix for tests
ethouris Mar 7, 2023
ba5f962
Added timeout for lock-CV to avoid Travis problem
ethouris Mar 7, 2023
320a79b
Attempted more debug for test ipv6 for Travis
ethouris Mar 7, 2023
1b3ccd7
More debug for Travis
ethouris Mar 7, 2023
90b13b1
Fixed test ipv6 to use promise-future for synchronization
Mar 7, 2023
bc4059c
Fixed filtering-out IPv6 tests for Travis
Mar 7, 2023
11574a0
Fixed wrong comment
Mar 9, 2023
fabb85f
Updated with upstream and fixed
Apr 28, 2023
7cc801f
Updated and fixed
Sep 8, 2023
7658145
Fixed a bug introduced during upstream merge
Sep 11, 2023
41a86bf
Fixed tests that should require IPv6 enabled
Sep 11, 2023
45809bd
Pre-refax of change-independent parts for 2677
Sep 18, 2023
c782bf7
Merge branch 'dev-fix-ipv6-payloadsize-prefax' into dev-fix-ipv6-payl…
Sep 18, 2023
848857b
Merge branch 'master' into dev-fix-ipv6-payloadsize
Sep 18, 2023
0c3abe0
A fix from code review
Sep 18, 2023
ce2a043
Apply SOME suggestions from the doc review (others pending)
ethouris Sep 19, 2023
ccfb0b6
Updated and fixed
Sep 19, 2023
422cbed
Merge branch 'master' into dev-fix-ipv6-payloadsize
Sep 19, 2023
fa40417
Some more explanatory comments to enforce checkin
Sep 19, 2023
5c2c876
Apply suggestions from doc review (still pending)
ethouris Sep 19, 2023
0403820
Update doc review (still pending)
ethouris Sep 19, 2023
e02d85a
Apply suggestions from doc review (complete)
ethouris Sep 19, 2023
6074f21
Added extra v6-to-v6 test to check correct payload size
Oct 2, 2023
33de3eb
Fixed rejection code naming
Oct 16, 2023
dc7f437
Added an API function to control the payload size
Oct 17, 2023
49346a2
Removed BytesPacketsCount. Shifted header size to a function parameter
Oct 18, 2023
7644107
Updated
Oct 18, 2023
f34776d
Remaining bugfix
Oct 19, 2023
e1262cc
Added documentation for srt_getmaxpayloadsize
Oct 19, 2023
8072420
Fixed warn-error build break on mac
Oct 30, 2023
d1e2540
Updated and fixed
Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions apps/srt-file-transmit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ int parse_args(FileTransmitConfig &cfg, int argc, char** argv)
return 2;
}

cfg.chunk_size = stoul(Option<OutString>(params, "1456", o_chunk));
cfg.chunk_size = stoul(Option<OutString>(params, "0", o_chunk));
cfg.skip_flushing = Option<OutBool>(params, false, o_no_flush);
cfg.bw_report = stoi(Option<OutString>(params, "0", o_bwreport));
cfg.stats_report = stoi(Option<OutString>(params, "0", o_statsrep));
Expand Down Expand Up @@ -681,8 +681,11 @@ int main(int argc, char** argv)
//
// Set global config variables
//
if (cfg.chunk_size != SRT_LIVE_MAX_PLSIZE)
if (cfg.chunk_size != 0)
transmit_chunk_size = cfg.chunk_size;
else
transmit_chunk_size = SRT_MAX_PLSIZE_AF_INET;

transmit_stats_writer = SrtStatsWriterFactory(cfg.stats_pf);
transmit_bw_report = cfg.bw_report;
transmit_stats_report = cfg.stats_report;
Expand Down
74 changes: 71 additions & 3 deletions apps/transmitmedia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ bool g_stats_are_printed_to_stdout = false;
bool transmit_total_stats = false;
unsigned long transmit_bw_report = 0;
unsigned long transmit_stats_report = 0;
unsigned long transmit_chunk_size = SRT_LIVE_MAX_PLSIZE;
unsigned long transmit_chunk_size = SRT_MAX_PLSIZE_AF_INET6;

class FileSource: public Source
{
Expand Down Expand Up @@ -179,6 +179,40 @@ void SrtCommon::InitParameters(string host, map<string,string> par)
m_adapter = host;
}

unsigned int max_payload_size = 0;

// Try to interpret host and adapter first
sockaddr_any host_sa, adapter_sa;

if (host != "")
{
host_sa = CreateAddr(host);
if (host_sa.family() == AF_UNSPEC)
Error("Failed to interpret 'host' spec: " + host);

if (host_sa.family() == AF_INET)
max_payload_size = SRT_MAX_PLSIZE_AF_INET;
}

if (adapter != "" && adapter != host)
{
adapter_sa = CreateAddr(adapter);

if (adapter_sa.family() == AF_UNSPEC)
Error("Failed to interpret 'adapter' spec: " + adapter);

if (host_sa.family() != AF_UNSPEC && host_sa.family() != adapter_sa.family())
{
Error("Both host and adapter specified and they use different IP versions");
}

if (max_payload_size == 0 && host_sa.family() == AF_INET)
max_payload_size = SRT_MAX_PLSIZE_AF_INET;
}

if (!max_payload_size)
max_payload_size = SRT_MAX_PLSIZE_AF_INET6;

if (par.count("tsbpd") && false_names.count(par.at("tsbpd")))
{
m_tsbpdmode = false;
Expand All @@ -195,11 +229,17 @@ void SrtCommon::InitParameters(string host, map<string,string> par)
if ((par.count("transtype") == 0 || par["transtype"] != "file")
&& transmit_chunk_size > SRT_LIVE_DEF_PLSIZE)
{
if (transmit_chunk_size > SRT_LIVE_MAX_PLSIZE)
throw std::runtime_error("Chunk size in live mode exceeds 1456 bytes; this is not supported");
if (transmit_chunk_size > max_payload_size)
Error(Sprint("Chunk size in live mode exceeds ", max_payload_size, " bytes; this is not supported"));

par["payloadsize"] = Sprint(transmit_chunk_size);
}
else
{
// set it so without making sure that it was set to "file".
// worst case it will be rejected in settings
m_transtype = SRTT_FILE;
}

// Assign the others here.
m_options = par;
Expand Down Expand Up @@ -263,6 +303,21 @@ bool SrtCommon::AcceptNewClient()
Error("srt_accept");
}

int maxsize = srt_getmaxpayloadsize(m_sock);
if (maxsize == SRT_ERROR)
{
srt_close(m_bindsock);
srt_close(m_sock);
Error("srt_getmaxpayloadsize");
}

if (m_transtype == SRTT_LIVE && transmit_chunk_size > size_t(maxsize))
{
srt_close(m_bindsock);
srt_close(m_sock);
Error(Sprint("accepted connection's payload size ", maxsize, " is too small for required ", transmit_chunk_size, " chunk size"));
}

// we do one client connection at a time,
// so close the listener.
srt_close(m_bindsock);
Expand Down Expand Up @@ -431,6 +486,19 @@ void SrtCommon::ConnectClient(string host, int port)
Error("srt_connect");
}

int maxsize = srt_getmaxpayloadsize(m_sock);
if (maxsize == SRT_ERROR)
{
srt_close(m_sock);
Error("srt_getmaxpayloadsize");
}

if (m_transtype == SRTT_LIVE && transmit_chunk_size > size_t(maxsize))
{
srt_close(m_sock);
Error(Sprint("accepted connection's payload size ", maxsize, " is too small for required ", transmit_chunk_size, " chunk size"));
}

stat = ConfigurePost(m_sock);
if ( stat == SRT_ERROR )
Error("ConfigurePost");
Expand Down
1 change: 1 addition & 0 deletions apps/transmitmedia.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class SrtCommon
string m_mode;
string m_adapter;
map<string, string> m_options; // All other options, as provided in the URI
SRT_TRANSTYPE m_transtype = SRTT_LIVE;
SRTSOCKET m_sock = SRT_INVALID_SOCK;
SRTSOCKET m_bindsock = SRT_INVALID_SOCK;
bool IsUsable() { SRT_SOCKSTATUS st = srt_getsockstate(m_sock); return st > SRTS_INIT && st < SRTS_BROKEN; }
Expand Down
82 changes: 76 additions & 6 deletions docs/API/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
| [srt_bind_acquire](#srt_bind_acquire) | Acquires a given UDP socket instead of creating one |
| [srt_getsockstate](#srt_getsockstate) | Gets the current status of the socket |
| [srt_getsndbuffer](#srt_getsndbuffer) | Retrieves information about the sender buffer |
| [srt_getmaxpayloadsize](#srt_getmaxpayloadsize) | Retrieves the information about the maximum payload size in a single packet |
| [srt_close](#srt_close) | Closes the socket or group and frees all used resources |
| <img width=290px height=1px/> | <img width=720px height=1px/> |

Expand All @@ -28,7 +29,7 @@
|:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- |
| [srt_listen](#srt_listen) | Sets up the listening state on a socket |
| [srt_accept](#srt_accept) | Accepts a connection; creates/returns a new socket or group ID |
| [srt_accept_bond](#srt_accept_bond) | Accepts a connection pending on any sockets passed in the `listeners` array <br/> of `nlisteners` size |
| [srt_accept_bond](#srt_accept_bond) | Accepts a connection pending on any sockets passed in the `listeners` array <br/> of `nlisteners` size |
| [srt_listen_callback](#srt_listen_callback) | Installs/executes a callback hook on a socket created to handle the incoming connection <br/> on a listening socket |
| [srt_connect](#srt_connect) | Connects a socket or a group to a remote party with a specified address and port |
| [srt_connect_bind](#srt_connect_bind) | Same as [`srt_bind`](#srt_bind) then [`srt_connect`](#srt_connect) if called with socket [`u`](#u) |
Expand Down Expand Up @@ -166,13 +167,14 @@ Since SRT v1.5.0.
| [SRT_REJ_VERSION](#SRT_REJ_VERSION) | 1.3.4 | A party did not satisfy the minimum version requirement that had been set up for a connection |
| [SRT_REJ_RDVCOOKIE](#SRT_REJ_RDVCOOKIE) | 1.3.4 | Rendezvous cookie collision |
| [SRT_REJ_BADSECRET](#SRT_REJ_BADSECRET) | 1.3.4 | Both parties have defined a passphrase for connection and they differ |
| [SRT_REJ_UNSECURE](#SRT_REJ_UNSECURE) | 1.3.4 | Only one connection party has set up a password |
| [SRT_REJ_UNSECURE](#SRT_REJ_UNSECURE) | 1.3.4 | Only one connection party has set up a password |
| [SRT_REJ_MESSAGEAPI](#SRT_REJ_MESSAGEAPI) | 1.3.4 | The value for [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag is different on both connection parties |
| [SRT_REJ_FILTER](#SRT_REJ_FILTER) | 1.3.4 | The [`SRTO_PACKETFILTER`](API-socket-options.md#SRTO_PACKETFILTER) option has been set differently on both connection parties |
| [SRT_REJ_GROUP](#SRT_REJ_GROUP) | 1.4.2 | The group type or some group settings are incompatible for both connection parties |
| [SRT_REJ_TIMEOUT](#SRT_REJ_TIMEOUT) | 1.4.2 | The connection wasn't rejected, but it timed out |
| [SRT_REJ_CRYPTO](#SRT_REJ_CRYPTO) | 1.5.2 | The connection was rejected due to an unsupported or mismatching encryption mode |
| <img width=290px height=1px/> | | |
| [SRT_REJ_GROUP](#SRT_REJ_GROUP) | 1.4.2 | The group type or some group settings are incompatible for both connection parties |
| [SRT_REJ_TIMEOUT](#SRT_REJ_TIMEOUT) | 1.4.2 | The connection wasn't rejected, but it timed out |
| [SRT_REJ_CRYPTO](#SRT_REJ_CRYPTO) | 1.5.2 | The connection was rejected due to an unsupported or mismatching encryption mode |
| [SRT_REJ_CONFIG](#SRT_REJ_CONFIG) | 1.6.0 | The connection was rejected because settings on both parties are in collision and cannot negotiate common values |
| <img width=290px height=1px/> | | |

See the full list in [Rejection Reason Codes](./rejection-codes.md).

Expand Down Expand Up @@ -294,6 +296,7 @@ This means that if you call [`srt_startup`](#srt_startup) multiple times, you ne
* [srt_bind_acquire](#srt_bind_acquire)
* [srt_getsockstate](#srt_getsockstate)
* [srt_getsndbuffer](#srt_getsndbuffer)
* [srt_getmaxpayloadsize](#srt_getmaxpayloadsize)
* [srt_close](#srt_close)


Expand Down Expand Up @@ -541,6 +544,58 @@ This function can be used for diagnostics. It is especially useful when the
socket needs to be closed asynchronously.


[:arrow_up: &nbsp; Back to List of Functions & Structures](#srt-api-functions)

---

### srt_getmaxpayloadsize

```
int srt_getmaxpayloadsize(SRTSOCKET u);
```

Returns the maximum number of bytes that fit in a single packet. Useful only in
live mode (when `SRTO_TSBPDMODE` is true). The socket must be bound (see
[srt_bind](#srt_bind)) or connected (see [srt_connect](#srt_connect))
to use this function. Note that in case when the socket is bound to an IPv6
wildcard address and it is dual-stack (`SRTO_IPV6ONLY` is set to false), this
function returns the correct value only if the socket is connected, otherwise
it will return the value always as if the connection was made from an IPv6 peer
(including when you call it on a listening socket).

This function is only useful for the application to check if it is able to use
a payload of certain size in the live mode, or after connection, if the application
can send payloads of certain size. This is useful only in assertions, as if the
[`SRTO_PAYLOADSIZE`](API_socket-options.md#SRTO_PAYLOADSIZE) option is to be
set to a non-default value (for which the one returned by this function is the
maximum value), this option should be modified before connection and on both
parties, regarding the settings applied on the socket.

The returned value is the maximum number of bytes that can be put in a single
packet regarding:

* The current MTU size (`SRTO_MSS`)
* The IP version (IPv4 or IPv6)
* The `SRTO_CRYPTOMODE` setting (bytes reserved for AEAD authentication tag)
* The `SRTO_PACKETFILTER` setting (bytes reserved for extra field in a FEC control packet)

With default options this value should be 1456 for IPv4 and 1444 for IPv6.


| Returns | |
|:----------------------------- |:------------------------------------------------- |
| The maximum payload size (>0) | If succeeded |
| `SRT_ERROR` | Usage error |
| <img width=240px height=1px/> | <img width=710px height=1px/> |

| Errors | |
|:--------------------------------------- |:----------------------------------------------- |
| [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID |
| [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) | Socket [`u`](#u) is not bound |
| <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 @@ -3071,6 +3126,21 @@ and above is reserved for "predefined codes" (`SRT_REJC_PREDEFINED` value plus
adopted HTTP codes). Values above `SRT_REJC_USERDEFINED` are freely defined by
the application.

#### SRT_REJ_CRYPTO

Settings for `SRTO_CRYPTOMODE` on both parties are not compatible with one another.
See [`SRTO_CRYPTOMODE`](API-socket-options.md#SRTO_CRYPTOMODE) for details.

#### SRT_REJ_CONFIG

Settings for various transmission parameters that are supposed to be negotiated
during the handshake (in order to agree upon a common value) are under restrictions
that make finding common values for them impossible. Cases include:

* `SRTO_PAYLOADSIZE`, which is nonzero in live mode, is set to a value that
exceeds the free space in a single packet that results from the value of the
negotiated MSS value


[:arrow_up: &nbsp; Back to List of Functions & Structures](#srt-api-functions)

Expand Down
Loading
Loading