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

Fixed bug: initial state of an epoll eid for listener socket not set #2444

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
134 changes: 101 additions & 33 deletions docs/API/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,41 +629,109 @@ the listener socket to accept group connections
SRTSOCKET srt_accept(SRTSOCKET lsn, struct sockaddr* addr, int* addrlen);
```

Accepts a pending connection, then creates and returns a new socket or
group ID that handles this connection. The group and socket can be
distinguished by checking the `SRTGROUP_MASK` bit on the returned ID.

* `lsn`: the listener socket previously configured by [`srt_listen`](#srt_listen)
* `addr`: the IP address and port specification for the remote party
Extracts the first connection request on the queue of pending connections for
the listening socket, `lsn`, then creates and returns a new socket or group ID
that handles this connection. The group and socket can be distinguished by
checking the `SRTGROUP_MASK` bit on the returned ID. Note that by default group
connections will be rejected - this feature can be only enabled on demand (see
below).

* `lsn`: the listening socket
* `addr`: a location to store the remote IP address and port for the connection
* `addrlen`: INPUT: size of `addr` pointed object. OUTPUT: real size of the
returned object

**NOTE:** `addr` is allowed to be NULL, in which case it's understood that the
application is not interested in the address from which the connection originated.
Otherwise `addr` should specify an object into which the address will be written,
and `addrlen` must also specify a variable to contain the object size. Note also
that in the case of group connection only the initial connection that
establishes the group connection is returned, together with its address. As
member connections are added or broken within the group, you can obtain this
information through [`srt_group_data`](#srt_group_data) or the data filled by
[`srt_sendmsg2`](#srt_sendmsg) and [`srt_recvmsg2`](#srt_recvmsg2).

If the `lsn` listener socket is configured for blocking mode
([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) set to true, default),
the call will block until the incoming connection is ready. Otherwise, the
call always returns immediately. The `SRT_EPOLL_IN` epoll event should be
checked on the `lsn` socket prior to calling this function in that case.

If the pending connection is a group connection (initiated on the peer side by
calling the connection function using a group ID, and permitted on the listener
socket by the [`SRTO_GROUPCONNECT`](API-socket-options.md#SRTO_GROUPCONNECT)
flag), then the value returned is a group ID. This function then creates a new
group, as well as a new socket for this connection, that will be added to the
group. Once the group is created this way, further connections within the same
group, as well as sockets for them, will be created in the background. The
[`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) event is raised on the `lsn` socket when
a new background connection is attached to the group, although it's usually for
internal use only.
General requirements for a parameter correctness:

* `lsn` must be first [bound](#srt_bind) and [listening](#srt_listen)

* `addr` may be NULL, or otherwise it must be a pointer to an object
that can be treated as an instance of `sockaddr_in` or `sockaddr_in6`

* `addrlen` should be a pointer to a variable set to the size of the object
specified in `addr`, if `addr` is not NULL. Otherwise it's ignored.

If `addr` is not NULL, the information about the source IP address and
port of the peer will be written into this object. Note that whichever
type of object is expected here (`sockaddr_in` or `sockaddr_in6`), it
depends on the address type used in the `srt_bind` call for `lsn`.
If unsure in a particular situation, it is recommended that you use
`sockaddr_storage` or `srt::sockaddr_any`.

If the `lsn` listener socket is in the blocking mode (if
[`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) is set to true,
which is default), the call will block until the incoming connection is ready
for extraction. Otherwise, the call always returns immediately, possibly with
failure, if there was no pending connection waiting on the listening socket
`lsn`.

The listener socket can be checked for any pending connections prior to calling
`srt_accept` by checking the `SRT_EPOLL_ACCEPT` epoll event (which is an alias
to `SRT_EPOLL_IN`). This event might be spurious in certain cases though, for
example, when the connection has been closed by the peer or broken before the
application extracts it. The call to `srt_accept` would then still fail in
such a case.

In order to allow the listening socket `lsn` to accept a group connection,
the [`SRTO_GROUPCONNECT`](API-socket-options.md#SRTO_GROUPCONNECT) socket option
for the listening socket must be set to 1. Note that single socket connections
can still be reported to that socket. The application can distinguish the socket
and group connection by checking the `SRTGROUP_MASK` bit on the returned
successful value. There are some important differences to single socket
connections:

1. Accepting a group connection can be done only once per connection, even
though particular member connections can get broken or established while
the group is connected. The actual connection reporter (listener) is a socket,
like before, but once you call `srt_accept` and receive this group ID, it is
the group considered connected, and any member connections of the same group
will be handled in the background.

2. If a group was extracted from the `srt_accept` call, the address reported in
`addr` parameter is still the address of the connection that has triggered the
group connection extraction. The information about all member links in the
group at the moment can be obtained at any time through
[`srt_group_data`](#srt_group_data) or the data filled by
[`srt_sendmsg2`](#srt_sendmsg2) and [`srt_recvmsg2`](#srt_recvmsg2)
in the [`SRT_MSGCTRL`](#SRT_MSGCTRL) structure.

3. Listening sockets are not bound to groups anyhow. You can allow multiple
listening sockets to accept group connections and the connection extracted
from the listener, if it is declared to be a group member, will join its
group, no matter which of the listening sockets has received the connection
request. This feature is prone to more tricky rules, however:

* If you use multiple listener sockets, all of them in blocking mode,
allowed for group connections, and receiving connection requests for
the same group at the moment, and you run one thread per `srt_accept`
call, it is undefined, which of them will extract the group ID
for the connection, but still only one will, while the others will
continue blocking. If you want to use only one thread for accepting
connections from potentially multiple listening sockets in the blocking
mode, you should use [`srt_accept_bond`](#srt_accept_bond) instead.
Note though that this function is actually a wrapper that changes locally
to the nonblocking mode on all these listeners and uses epoll internally.

* If at the moment multiple listener sockets have received connection
request and you query them all for readiness epoll flags (by calling
an epoll waiting function), all of them will get the `SRT_EPOLL_ACCEPT`
flag set, but still only one of them will return the group ID from the
`srt_accept` call. After this call, from all listener sockets in the
whole application the `SRT_EPOLL_ACCEPT` flag, that was set by the reason
of a pending connection for the same group, will be withdrawn (that is,
it will be cleared if there are no other pending connections). This is
then yet another situation when this flag can be spurious.

4. If you query a listening socket for epoll flags after the `srt_accept`
function has once returned the group ID, the listening sockets that have
received new member connection requests within that group will report only the
[`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) flag. This flag is edge-triggered-only
because there is no operation you can perform in response in order to clear
this flag. This flag is mostly used internally and the application may use it
if it would like to trigger updating the current group information due to
having one newly added member connection.



| Returns | |
|:----------------------------- |:----------------------------------------------------------------------- |
Expand All @@ -673,7 +741,7 @@ internal use only.

| Errors | |
|:--------------------------------- |:----------------------------------------------------------------------- |
| [`SRT_EINVPARAM`](#srt_einvparam) | NULL specified as `addrlen`, when `addr` is not NULL |
| [`SRT_EINVPARAM`](#srt_einvparam) | Invalid `addr` or `addrlen` (see requirements in the begininng) |
| [`SRT_EINVSOCK`](#srt_einvsock) | `lsn` designates no valid socket ID. |
| [`SRT_ENOLISTEN`](#srt_enolisten) | `lsn` is not set up as a listener ([`srt_listen`](#srt_listen) not called). |
| [`SRT_EASYNCRCV`](#srt_easyncrcv) | No connection reported so far. This error is reported only in the non-blocking mode |
Expand Down
5 changes: 5 additions & 0 deletions docs/API/API-socket-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ allowed must take this into consideration. It's up to the caller of this
function to make this distinction and to take appropriate action depending on
the type of entity returned.

Note: this flag should be altered **before** calling `srt_listen`. If you do
this after this call, you might have some pending group connections in the
meantime that will be rejected because group connections are not **yet**
allowed on this listener socket.

When this flag is set to 1 on an accepted socket that is passed to the
listener callback handler, it means that this socket is created for a group
connection and it will become a member of a group. Note that in this case
Expand Down
Loading
Loading