Read ICMP error messages instead of looping
When we are dealing with connected sockets shared between a udpsrc and a udpsink we might receive ICMP connection refused error messages in udpsrc that will cause it to go into a bursty loop because the poll returns right away without a message to read. Instead of looping, read the error message from the error queue in udpsrc. Fixes #567857.
This commit is contained in:
parent
04359c8382
commit
969622b439
@ -357,6 +357,35 @@ gst_udpsrc_getcaps (GstBaseSrc * src)
|
|||||||
return gst_caps_new_any ();
|
return gst_caps_new_any ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read a message from the error queue */
|
||||||
|
static void
|
||||||
|
clear_error (GstUDPSrc * udpsrc)
|
||||||
|
{
|
||||||
|
struct msghdr cmsg;
|
||||||
|
char cbuf[128];
|
||||||
|
char msgbuf[CMSG_SPACE (128)];
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
/* Flush ERRORS from fd so next poll will not return at once */
|
||||||
|
/* No need for address : We look for local error */
|
||||||
|
cmsg.msg_name = NULL;
|
||||||
|
cmsg.msg_namelen = 0;
|
||||||
|
|
||||||
|
/* IOV */
|
||||||
|
memset (&cbuf, 0, sizeof (cbuf));
|
||||||
|
iov.iov_base = cbuf;
|
||||||
|
iov.iov_len = sizeof (cbuf);
|
||||||
|
cmsg.msg_iov = &iov;
|
||||||
|
cmsg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
/* msg_control */
|
||||||
|
memset (&msgbuf, 0, sizeof (msgbuf));
|
||||||
|
cmsg.msg_control = &msgbuf;
|
||||||
|
cmsg.msg_controllen = sizeof (msgbuf);
|
||||||
|
|
||||||
|
recvmsg (udpsrc->sock.fd, &cmsg, MSG_ERRQUEUE);
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
@ -434,8 +463,10 @@ retry:
|
|||||||
* woken up by activity on the socket but it was not a read. We know someone
|
* woken up by activity on the socket but it was not a read. We know someone
|
||||||
* will also do something with the socket so that we don't go into an infinite
|
* will also do something with the socket so that we don't go into an infinite
|
||||||
* loop in the select(). */
|
* loop in the select(). */
|
||||||
if (G_UNLIKELY (!readsize))
|
if (G_UNLIKELY (!readsize)) {
|
||||||
|
clear_error (udpsrc);
|
||||||
goto retry;
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
no_select:
|
no_select:
|
||||||
GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize);
|
GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize);
|
||||||
@ -447,10 +478,11 @@ no_select:
|
|||||||
len = sizeof (struct sockaddr);
|
len = sizeof (struct sockaddr);
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize,
|
ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize,
|
||||||
|
0, (struct sockaddr *) &tmpaddr, &len);
|
||||||
#else
|
#else
|
||||||
ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize,
|
ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize,
|
||||||
#endif
|
|
||||||
0, (struct sockaddr *) &tmpaddr, &len);
|
0, (struct sockaddr *) &tmpaddr, &len);
|
||||||
|
#endif
|
||||||
if (G_UNLIKELY (ret < 0)) {
|
if (G_UNLIKELY (ret < 0)) {
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
/* WSAECONNRESET for a UDP socket means that a packet sent with udpsink
|
/* WSAECONNRESET for a UDP socket means that a packet sent with udpsink
|
||||||
@ -730,6 +762,7 @@ static gboolean
|
|||||||
gst_udpsrc_start (GstBaseSrc * bsrc)
|
gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
{
|
{
|
||||||
guint bc_val;
|
guint bc_val;
|
||||||
|
guint err_val;
|
||||||
gint reuse;
|
gint reuse;
|
||||||
int port;
|
int port;
|
||||||
GstUDPSrc *src;
|
GstUDPSrc *src;
|
||||||
@ -821,6 +854,15 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
|||||||
g_strerror (errno), errno));
|
g_strerror (errno), errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Accept ERRQUEUE to get and flush icmp errors */
|
||||||
|
err_val = 1;
|
||||||
|
if ((ret = setsockopt (src->sock.fd, IPPROTO_IP, IP_RECVERR, &err_val,
|
||||||
|
sizeof (err_val))) < 0) {
|
||||||
|
GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
|
||||||
|
("could not configure socket for IP_RECVERR %d: %s (%d)", ret,
|
||||||
|
g_strerror (errno), errno));
|
||||||
|
}
|
||||||
|
|
||||||
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
|
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
|
||||||
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group);
|
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group);
|
||||||
ret = gst_udp_join_group (src->sock.fd, &src->myaddr);
|
ret = gst_udp_join_group (src->sock.fd, &src->myaddr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user