srtobject: detect socket errors from srt_epoll_wait()

On an error event, epoll wait puts the failed socket in both readfds and
writefds. We can take advantage of this and avoid explicitly checking
socket state before every read or write attempt.

In addition, srt_getrejectreason() will give us more detailed
description of the connection failure.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1943>
This commit is contained in:
Jakub Adam 2020-10-16 19:27:37 +02:00 committed by GStreamer Merge Bot
parent df8d29e9c3
commit ef118f3d0a

View File

@ -37,6 +37,18 @@
GST_DEBUG_CATEGORY_EXTERN (gst_debug_srtobject); GST_DEBUG_CATEGORY_EXTERN (gst_debug_srtobject);
#define GST_CAT_DEFAULT gst_debug_srtobject #define GST_CAT_DEFAULT gst_debug_srtobject
#if SRT_VERSION_VALUE > 0x10402
#define SRTSOCK_ERROR_DEBUG ("libsrt reported: %s", srt_rejectreason_str (reason))
#else
/* srt_rejectreason_str() is unavailable in libsrt 1.4.2 and prior due to
* unexported symbol. See https://github.com/Haivision/srt/pull/1728. */
#define SRTSOCK_ERROR_DEBUG ("libsrt reported reject reason code %d", reason)
#endif
#define ELEMENT_WARNING_SRTSOCK_ERROR(code, reason) \
GST_ELEMENT_WARNING (srtobject->element, RESOURCE, code, \
("Error on SRT socket. Trying to reconnect."), SRTSOCK_ERROR_DEBUG)
enum enum
{ {
PROP_URI = 1, PROP_URI = 1,
@ -1510,11 +1522,11 @@ gst_srt_object_read (GstSRTObject * srtobject,
SRTSOCKET rsock; SRTSOCKET rsock;
gint rsocklen = 1; gint rsocklen = 1;
int pollret; SRTSOCKET wsock;
gint wsocklen = 1;
pollret = srt_epoll_wait (poll_id, &rsock, if (srt_epoll_wait (poll_id, &rsock, &rsocklen, &wsock, &wsocklen,
&rsocklen, 0, 0, poll_timeout, NULL, 0, NULL, 0); poll_timeout, NULL, 0, NULL, 0) < 0) {
if (pollret < 0) {
gint srt_errno = srt_getlasterror (NULL); gint srt_errno = srt_getlasterror (NULL);
if (srt_errno != SRT_ETIMEOUT) { if (srt_errno != SRT_ETIMEOUT) {
@ -1523,34 +1535,22 @@ gst_srt_object_read (GstSRTObject * srtobject,
continue; continue;
} }
if (rsocklen < 0) { if (wsocklen == 1 && rsocklen == 1) {
GST_WARNING_OBJECT (srtobject->element, /* Socket reported in wsock AND rsock signifies an error. */
"abnormal SRT socket is detected"); gint reason = srt_getrejectreason (wsock);
srt_close (rsock);
}
switch (srt_getsockstate (rsock)) { if (connection_mode == GST_SRT_CONNECTION_MODE_LISTENER) {
case SRTS_BROKEN: /* Caller has disappeared. */
case SRTS_NONEXIST: return 0;
case SRTS_CLOSED: } else {
if (connection_mode == GST_SRT_CONNECTION_MODE_LISTENER) { ELEMENT_WARNING_SRTSOCK_ERROR (READ, reason);
/* Caller has been disappeared. */
return 0; gst_srt_object_close (srtobject);
} else { if (!gst_srt_object_open_internal (srtobject, cancellable, error)) {
GST_WARNING_OBJECT (srtobject->element, return -1;
"Invalid SRT socket. Trying to reconnect");
gst_srt_object_close (srtobject);
if (!gst_srt_object_open_internal (srtobject, cancellable, error)) {
return -1;
}
continue;
} }
case SRTS_CONNECTED: }
/* good to go */ continue;
break;
default:
/* not-ready */
continue;
} }
@ -1739,6 +1739,8 @@ gst_srt_object_write_one (GstSRTObject * srtobject,
} }
while (len < mapinfo->size) { while (len < mapinfo->size) {
SRTSOCKET rsock;
gint rsocklen = 1;
SRTSOCKET wsock; SRTSOCKET wsock;
gint wsocklen = 1; gint wsocklen = 1;
@ -1756,31 +1758,22 @@ gst_srt_object_write_one (GstSRTObject * srtobject,
break; break;
} }
if (srt_epoll_wait (srtobject->poll_id, 0, 0, &wsock, if (srt_epoll_wait (srtobject->poll_id, &rsock, &rsocklen, &wsock,
&wsocklen, poll_timeout, NULL, 0, NULL, 0) < 0) { &wsocklen, poll_timeout, NULL, 0, NULL, 0) < 0) {
continue; continue;
} }
switch (srt_getsockstate (wsock)) { if (wsocklen == 1 && rsocklen == 1) {
case SRTS_BROKEN: /* Socket reported in wsock AND rsock signifies an error. */
case SRTS_NONEXIST: gint reason = srt_getrejectreason (wsock);
case SRTS_CLOSED:
GST_ELEMENT_WARNING (srtobject->element, RESOURCE, WRITE, NULL, ELEMENT_WARNING_SRTSOCK_ERROR (WRITE, reason);
("Invalid SRT socket. Trying to reconnect. (%s)",
srt_getlasterror_str ())); gst_srt_object_close (srtobject);
gst_srt_object_close (srtobject); if (!gst_srt_object_open_internal (srtobject, cancellable, error)) {
if (!gst_srt_object_open_internal (srtobject, cancellable, error)) { return -1;
return -1; }
} continue;
continue;
case SRTS_CONNECTED:
/* good to go */
GST_LOG_OBJECT (srtobject->element, "good to go");
break;
default:
GST_WARNING_OBJECT (srtobject->element, "not ready");
/* not-ready */
continue;
} }
if (srt_getsockflag (wsock, SRTO_PAYLOADSIZE, &payload_size, &optlen)) { if (srt_getsockflag (wsock, SRTO_PAYLOADSIZE, &payload_size, &optlen)) {