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

Implemented and exposed rejection reason #720

Merged
merged 11 commits into from
Aug 14, 2019
110 changes: 110 additions & 0 deletions docs/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,10 @@ rendezvous socket, but rendezvous sockets must be explicitly bound to a local
interface prior to connecting. Non-rendezvous sockets (caller sockets) can be
left without binding - the call to `srt_connect` will bind them automatically.
* `SRT_ECONNSOCK`: Socket `u` is already connected
* `SRT_ECONNREJ`: Connection has been rejected

In case when `SRT_ECONNREJ` error was reported, you can get the reason for
a rejected connection from `srt_getrejectreason`.

### srt_connect_debug

Expand Down Expand Up @@ -874,6 +878,112 @@ void srt_clearlasterror(void);
This function clears the last error. After this call, the `srt_getlasterror` will
report a "successful" code.

### srt_getrejectreason

```
enum SRT_REJECT_REASON srt_getrejectreason(SRTSOCKET sock);
```

This function shall be called after a connecting function (such as `srt_connect`)
has returned an error, which's code was `SRT_ECONNREJ`. It allows to get a more
detailed rejection reason. This function returns a numeric code, which can be
translated into a message by `srt_rejectreason_str`. The following codes are
currently reported:

#### SRT_REJ_UNKNOWN

A fallback value for cases when there was no connection rejected.

#### SRT_REJ_SYSTEM

One of system function reported a failure. Usually this means some system
error or lack of system resources to complete the task.

#### SRT_REJ_PEER

The connection has been rejected by peer, but no further details are available.
This usually means that the peer doesn't support rejection reason reporting.

#### SRT_REJ_RESOURCE

A problem with resource allocation (usually memory).

#### SRT_REJ_ROGUE

The data sent by one party to another cannot be properly interpreted. This
should not happen during normal usage, unless it's a bug, or some weird
events are happening on the network.

#### SRT_REJ_BACKLOG

The listener's backlog has exceeded (there are many other callers waiting for
the opportunity of being connected and wait in the queue, which has reached
its limit).

#### SRT_REJ_IPE

Internal Program Error. This should not happen during normal usage and it
usually means a bug in the software (although this can be reported by both
local and foreign host).

#### SRT_REJ_CLOSE

The listener socket was able to receive your request, but at this moment it
is being closed. It's likely that your next attempt will result with timeout.

#### SRT_REJ_VERSION

Any party of the connection has set up minimum version that is required for
that connection, and the other party didn't satisfy this requirement.

#### SRT_REJ_RDVCOOKIE

Rendezvous cookie collision. This normally should never happen, or the
probability that this will really happen is negligible. However this can
be also a result of a misconfiguration that you are trying to make a
rendezvous connection where both parties try to bind to the same IP
address, or both are local addresses of the same host - in which case
the sent handshake packets are returning to the same host as if they
were sent by the peer, who is this party itself. When this happens,
this reject reason will be reported by every attempt.

#### SRT_REJ_BADSECRET

Both parties have defined a passprhase for connection and they differ.

#### SRT_REJ_UNSECURE

Only one connection party has set up a password. See also
`SRTO_STRICTENC` flag in API.md.

#### SRT_REJ_MESSAGEAPI

The value for `SRTO_MESSAGEAPI` flag is different on both connection
parties.

#### SRT_REJ_CONGESTION

The `SRTO_CONGESTION` option has been set up differently on both
connection parties.

#### SRT_REJ_FILTER

The `SRTO_FILTER` option has been set differently on both connection
parties (NOTE: this flag may not exist yet in this version).


### srt_rejectreason_str

```
const char* srt_rejectreason_str(enum SRT_REJECT_REASON id);
```

Returns a constant string for the reason of the connection rejected,
as per given code id. Alternatively you can use the `srt_rejectreason_msg`
array. This function additionally handles the case for unknown id by
reporting `SRT_REJ_UNKNOWN` in such case.


Performance tracking
--------------------

Expand Down
6 changes: 6 additions & 0 deletions docs/handshake.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,12 @@ indicates the handshake message type.
Note that the **Rendezvous** process is different in HSv4 and HSv5, as the latter
is based on a state machine.

In case when the connection process has failed when the party was about to
send the `URQ_CONCLUSION` handshake, this field will contain appropriate
error value. This value starts from 1000 (see `UDTRequestType` in `handshake.h`,
since `URQ_FAILURE_TYPES` symbol) added with the value of the rejection
reason (see `SRT_REJECT_REASON` in `srt.h`).

[Return to top of page](#srt-handshake)


Expand Down
25 changes: 23 additions & 2 deletions srtcore/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,13 @@ SRTSOCKET CUDTUnited::newSocket(int af, int)
return ns->m_SocketID;
}

int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt)
int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt,
ref_t<SRT_REJECT_REASON> r_error)
{
CUDTSocket* ns = NULL;

*r_error = SRT_REJ_IPE;

// Can't manage this error through an exception because this is
// running in the listener loop.
CUDTSocket* ls = locate(listen);
Expand Down Expand Up @@ -376,6 +379,7 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHan
// exceeding backlog, refuse the connection request
if (ls->m_pQueuedSockets->size() >= ls->m_uiBackLog)
{
*r_error = SRT_REJ_BACKLOG;
LOGC(mglog.Error, log << "newConnection: listen backlog=" << ls->m_uiBackLog << " EXCEEDED");
return -1;
}
Expand All @@ -401,6 +405,7 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHan
}
catch (...)
{
*r_error = SRT_REJ_RESOURCE;
delete ns;
LOGC(mglog.Error, log << "IPE: newConnection: unexpected exception (probably std::bad_alloc)");
return -1;
Expand All @@ -419,6 +424,10 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHan

int error = 0;

// Set the error code for all prospective problems below.
// It won't be interpreted when result was successful.
*r_error = SRT_REJ_RESOURCE;

// These can throw exception only when the memory allocation failed.
// CUDT::connect() translates exception into CUDTException.
// CUDT::open() may only throw original std::bad_alloc from new.
Expand Down Expand Up @@ -453,6 +462,8 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHan
}
catch (...)
{
// Extract the error that was set in this new failed entity.
*r_error = ns->m_pUDT->m_RejectReason;
error = 1;
goto ERR_ROLLBACK;
}
Expand Down Expand Up @@ -499,7 +510,12 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr* peer, CHan
if (error > 0)
{
#if ENABLE_LOGGING
static const char* why [] = {"?", "ACCEPT ERROR", "IPE when mapping a socket", "IPE when inserting a socket" };
static const char* why [] = {
"UNKNOWN ERROR",
"CONNECTION REJECTED",
"IPE when mapping a socket",
"IPE when inserting a socket"
};
LOGC(mglog.Error, log << CONID(ns->m_SocketID) << "newConnection: connection rejected due to: " << why[error]);
#endif
SRTSOCKET id = ns->m_SocketID;
Expand Down Expand Up @@ -3181,4 +3197,9 @@ SRT_API std::string getstreamid(SRTSOCKET u)
return CUDT::getstreamid(u);
}

SRT_REJECT_REASON getrejectreason(SRTSOCKET u)
{
return CUDT::rejectReason(u);
}

} // namespace UDT
3 changes: 2 additions & 1 deletion srtcore/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ friend class CRendezvousQueue;
/// @param [in,out] hs handshake information from peer side (in), negotiated value (out);
/// @return If the new connection is successfully created: 1 success, 0 already exist, -1 error.

int newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt);
int newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt,
ref_t<SRT_REJECT_REASON> r_error);

int installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq);

Expand Down
32 changes: 27 additions & 5 deletions srtcore/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,11 +608,6 @@ const char* CUDTException::getErrorMessage()
m_strMsg += ": " + SysStrError(m_iErrno);
}

// period
#ifndef _WIN32
m_strMsg += ".";
#endif

return m_strMsg.c_str();
}

Expand Down Expand Up @@ -843,6 +838,33 @@ std::string TransmissionEventStr(ETransmissionEvent ev)
return vals[ev];
}

extern const char* const srt_rejectreason_msg [] = {
"Unknown or erroneous",
"Error in system calls",
"Peer rejected connection",
"Resource allocation failure",
"Rogue peer or incorrect parameters",
"Listener's backlog exceeded",
"Internal Program Error",
"Socket is being closed",
"Peer version too old",
"Rendezvous-mode cookie collision",
"Incorrect passphrase",
"Password required or unexpected",
"MessageAPI/StreamAPI collision",
"Congestion controller type collision",
"Packet Filter type collision"
};

const char* srt_rejectreason_str(SRT_REJECT_REASON rid)
{
int id = rid;
static const size_t ra_size = Size(srt_rejectreason_msg);
if (size_t(id) >= ra_size)
return srt_rejectreason_msg[0];
return srt_rejectreason_msg[id];
}

// Some logging imps
#if ENABLE_LOGGING

Expand Down
Loading