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

[core][apps] Implemented the socket close reason feature #2747

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
203 changes: 192 additions & 11 deletions docs/API/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
| [srt_getsockstate](#srt_getsockstate) | Gets the current status of the socket |
| [srt_getsndbuffer](#srt_getsndbuffer) | Retrieves information about the sender buffer |
| [srt_close](#srt_close) | Closes the socket or group and frees all used resources |
| [srt_close_withreason](#srt_close_withreason) | Closes the socket or group and frees all used resources (with setting the reason code) |
| <img width=290px height=1px/> | <img width=720px height=1px/> |

<h3 id="connecting">Connecting</h3>
Expand Down Expand Up @@ -149,6 +150,7 @@ Since SRT v1.5.0.
| [srt_rejectreason_str](#srt_rejectreason_str) | Returns a constant string for the reason of the connection rejected, as per given code ID |
| [srt_setrejectreason](#srt_setrejectreason) | Sets the rejection code on the socket |
| [srt_getrejectreason](#srt_getrejectreason) | Provides a detailed reason for a failed connection attempt |
| [srt_close_getreason](#srt_close_getreason) | Provides a detailed reason for closing a socket |
| <img width=290px height=1px/> | <img width=720px height=1px/> |

<h4 id="rejection-reasons">Rejection Reasons</h4>
Expand Down Expand Up @@ -295,6 +297,7 @@ This means that if you call [`srt_startup`](#srt_startup) multiple times, you ne
* [srt_getsockstate](#srt_getsockstate)
* [srt_getsndbuffer](#srt_getsndbuffer)
* [srt_close](#srt_close)
* [srt_close_withreason](#srt_close_withreason)


### srt_socket
Expand Down Expand Up @@ -545,16 +548,22 @@ socket needs to be closed asynchronously.

---

### srt_close
### srt_close, srt_close_withreason

```
int srt_close(SRTSOCKET u);
int srt_close_withreason(SRTSOCKET u, int reason);
```

Closes the socket or group and frees all used resources. Note that underlying
UDP sockets may be shared between sockets, so these are freed only with the
last user closed.

**Arguments**:

* `u`: Socket or group to close
* `reason`: Reason code for closing. You should use numbers from `SRT_CLSC_USER` up.

| Returns | |
|:----------------------------- |:--------------------------------------------------------- |
| `SRT_ERROR` | (-1) in case of error, otherwise 0 |
Expand Down Expand Up @@ -2801,6 +2810,7 @@ to timestamp packets submitted to SRT is not recommended and must be done with a
* [srt_getrejectreason](#srt_getrejectreason)
* [srt_rejectreason_str](#srt_rejectreason_str)
* [srt_setrejectreason](#srt_setrejectreason)
* [srt_close_getreason](#srt_close_getreason)

General notes concerning the `getlasterror` diagnostic functions: when an API
function ends up with error, this error information is stored in a thread-local
Expand Down Expand Up @@ -2945,6 +2955,38 @@ a numeric code, which can be translated into a message by
[`srt_rejectreason_str`](#srt_rejectreason_str).


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

---

### srt_close_getreason

```
int srt_close_getreason(SRTSOCKET u, SRT_CLOSE_INFO* info);
```

Retrieves the reason code for closing the socket. This designates the
very first reason of closing the socket or group (if there could have
been multiple reasons for closing it, only the first one counts).

Note that this information may be retrieved even if the socket is already
physically closed, but only for up to 10 seconds after that happens (more
precisely, 10 cycles of GC, which run every 1 second) and only up to 10 such
records are remembered (newer closed ones push off the oldest one).

**Arguments**:

* `u`: Socket or group that you believe is closed or broken
* `info`: The structure where the reason is written, see [`SRT_CLOSE_INFO`](#srt_close_info)

Returns 0 in case of success. Returns `SRT_ERROR` (-1) in case of error,
which may be because:

* `info` is a NULL pointer
* `u` is an `SRT_INVALID_SOCK` value
* `u` designates a socket that has expired more than 10 seconds ago


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

---
Expand Down Expand Up @@ -3072,6 +3114,136 @@ adopted HTTP codes). Values above `SRT_REJC_USERDEFINED` are freely defined by
the application.


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

---

### `SRT_CLOSE_INFO`

This structure can be used to get the closing reason (simplified definition):

```
struct SRT_CLOSE_INFO
{
SRT_CLOSE_REASON agent;
SRT_CLOSE_REASON peer;
int64_t time;
};
```

Where:

* `agent`: The reason code set on the agent ("this machine") side of the connection
if the very first reason of closing has happened on the agent. If the closing was
initiated by the peer, this field contains `SRT_CLS_PEER` value

* `peer`: If `agent` == `SRT_CLS_PEER`, then closing was initiated by peer and this
field contains the value of this reason

* `time`: Time when closing has happened, in the same convention as the time value
supplied by [`srt_time_now`](#srt_time_now)

The values for `agent` and `peer` can be internal, out of the below shown list, or
it can be a user code, if the value is at least `SRT_CLSC_USER`.


### Closing reasons

#### SRT_CLS_UNKNOWN

The reason not set. The value is used as a fallback if the reason wasn't properly set.

#### SRT_CLS_INTERNAL

Closed by internal reasons during connection attempt.

#### SRT_CLS_PEER

Closed by the peer (the value is to be used on agent). This happens when the closing
action has been initiated by peer through sending the `UMSG_SHUTDOWN` message.

#### SRT_CLS_RESOURCE

A problem with resource allocation.

#### SRT_CLS_ROGUE

Received wrong data in the packet. This happens when the socket was closed
due to security reasons, when the data in the packet do not match the expected
protocol specification.

#### SRT_CLS_OVERFLOW

Emergency close due to receiver buffer's double overflow that has lead to
an irrecoverable situation. This happens when too slow reading data by the
application has caused that first, incoming packets cannot be inserted into
the buffer because the position in the buffer mapped to their sequence number
locates them outside the buffer. If this situation isn't quickly recovered
from, it causes eventually that the sequence number distance between the last
packet still stored in the buffer and the newly incoming packet exceeds the
size of the receiver buffer. This is then an irrecoverable situation and in
result the socket is closed with this code as a reason.

#### SRT_CLS_IPE

Internal program error. Currently used if the incoming acknowledge packet
represents the sequence number that has never been sent, or the value is
out of any valid range.

#### SRT_CLS_API

The socket has been closed by the API call of `srt_close()`. This code
is set also if the reason value used in `srt_close_withreason()` is
less than `SRT_CLSC_USER`.

#### SRT_CLS_FALLBACK

This value is set on the `peer` field in case when the peer runs the SRT
version that does not support this feature. If this feature is supported,
then the peer should send `UMSG_SHUTDOWN` message with the reason value,
which will be then set on the `peer` field.

#### SRT_CLS_LATE

Accepted-socket late-rejection or in-handshake rollback. The late rejection
is something that may happen when the listener side responds to the caller
with a proper handshake message, but the caller rejects that message by
some reason. This way, the caller gets closed with a rejection reason, but
at this moment the accepted socket on the listener side considers itself
connected. Therefore the caller socket in this situation sends first
the `UMSG_SHUTDOWN` message to the peer (that is, the accepted socket)
and in result the accepted socket gets closed with this reason code.

#### SRT_CLS_CLEANUP

All sockets are being closed due to srt_cleanup() call.

#### SRT_CLS_DEADLSN

This is an accepted socket off a dead listener. If the listener
socket has been closed before the accepted socket could be completed,
the socket can be returned as valid, but could not be used due to
having the listener socket closed too early.

#### SRT_CLS_PEERIDLE

Peer didn't send any packet for a time of `SRTO_PEERIDLETIMEO`. This
means that the peer idle timeout has been reached while waiting for
any packet incoming from the peer.

#### SRT_CLS_UNSTABLE

Requested to be broken as unstable in Backup group. This happens
exclusively in the group of type `SRT_GTYPE_BACKUP` in case when
the link that was used so far for transmission, has become too
slowly responsive, which caused activation of one of the backup
links, and then this link didn't get back to stability in a given
time (the minimum is configured in `SRTO_GROUPMINSTABLETIMEO`),
which caused that the newly activated link has taken over transmission
and the socket using the unstable link has been closed with this
reason code.


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

---
Expand Down Expand Up @@ -3341,9 +3513,18 @@ 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.
The binding you are attempting to set up a socket with, using the `srt_bind`
call, cannot be completed because it conflicts with another existing binding.

An attempt of binding a socket, in the conditions of having some other socket already
bound to the same port number, can result in one of three possibilities:

1. The binding is separate to the existing one (succeeds).
2. The binding intersects with the exiting one (fails).
3. The binding is exactly identical to the existing one (see below).

See the [`srt_bind`](#srt_bind) for a reference about what kinds of binding
addresses can coexist without conflicts.

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
Expand All @@ -3359,7 +3540,7 @@ Example 1:

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

Example 2:

Expand All @@ -3373,14 +3554,14 @@ Example 3:
* 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:
A binding, that is identical with existing one, is allowed, as long as all
of the following conditions are satisfied:

1. The `SRTO_REUSEADDR` must be true (default) in both.
1. The `SRTO_REUSEADDR` must be true (default) in both the attempted and
existing bindings.

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

3. The UDP-specific settings must be identical.

Expand Down
Loading
Loading