summaryrefslogtreecommitdiffstats
path: root/gst/udp/gstudpsrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/udp/gstudpsrc.c')
-rw-r--r--gst/udp/gstudpsrc.c78
1 files changed, 63 insertions, 15 deletions
diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c
index bcdbc359..8d92241e 100644
--- a/gst/udp/gstudpsrc.c
+++ b/gst/udp/gstudpsrc.c
@@ -357,13 +357,50 @@ gst_udpsrc_getcaps (GstBaseSrc * src)
return gst_caps_new_any ();
}
+/* read a message from the error queue */
+static void
+clear_error (GstUDPSrc * udpsrc)
+{
+#if defined (MSG_ERRQUEUE)
+ 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);
+#endif
+}
+
static GstFlowReturn
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
GstUDPSrc *udpsrc;
GstNetBuffer *outbuf;
- struct sockaddr_storage tmpaddr;
- socklen_t len;
+ union gst_sockaddr
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+ struct sockaddr_in6 sa_in6;
+ struct sockaddr_storage sa_stor;
+ } sa;
+ socklen_t slen;
guint8 *pktdata;
gint pktsize;
#ifdef G_OS_UNIX
@@ -434,8 +471,10 @@ retry:
* 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
* loop in the select(). */
- if (G_UNLIKELY (!readsize))
+ if (G_UNLIKELY (!readsize)) {
+ clear_error (udpsrc);
goto retry;
+ }
no_select:
GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize);
@@ -444,13 +483,13 @@ no_select:
pktsize = readsize;
while (TRUE) {
- len = sizeof (struct sockaddr);
+ slen = sizeof (sa);
#ifdef G_OS_WIN32
- ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize,
+ ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize, 0, &sa.sa,
+ &slen);
#else
- ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize,
+ ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize, 0, &sa.sa, &slen);
#endif
- 0, (struct sockaddr *) &tmpaddr, &len);
if (G_UNLIKELY (ret < 0)) {
#ifdef G_OS_WIN32
/* WSAECONNRESET for a UDP socket means that a packet sent with udpsink
@@ -486,22 +525,19 @@ no_select:
GST_BUFFER_DATA (outbuf) = pktdata;
GST_BUFFER_SIZE (outbuf) = ret;
- switch (tmpaddr.ss_family) {
+ switch (sa.sa.sa_family) {
case AF_INET:
{
- gst_netaddress_set_ip4_address (&outbuf->from,
- ((struct sockaddr_in *) &tmpaddr)->sin_addr.s_addr,
- ((struct sockaddr_in *) &tmpaddr)->sin_port);
+ gst_netaddress_set_ip4_address (&outbuf->from, sa.sa_in.sin_addr.s_addr,
+ sa.sa_in.sin_port);
}
break;
case AF_INET6:
{
guint8 ip6[16];
- memcpy (ip6, &((struct sockaddr_in6 *) &tmpaddr)->sin6_addr,
- sizeof (ip6));
- gst_netaddress_set_ip6_address (&outbuf->from, ip6,
- ((struct sockaddr_in *) &tmpaddr)->sin_port);
+ memcpy (ip6, &sa.sa_in6.sin6_addr, sizeof (ip6));
+ gst_netaddress_set_ip6_address (&outbuf->from, ip6, sa.sa_in6.sin6_port);
}
break;
default:
@@ -730,6 +766,7 @@ static gboolean
gst_udpsrc_start (GstBaseSrc * bsrc)
{
guint bc_val;
+ guint err_val;
gint reuse;
int port;
GstUDPSrc *src;
@@ -821,6 +858,17 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
g_strerror (errno), errno));
}
+ /* Accept ERRQUEUE to get and flush icmp errors */
+ err_val = 1;
+#if defined (IP_RECVERR)
+ 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));
+ }
+#endif
+
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group);
ret = gst_udp_join_group (src->sock.fd, &src->myaddr);