diff options
Diffstat (limited to 'gst/udp/gstudpsrc.c')
-rw-r--r-- | gst/udp/gstudpsrc.c | 78 |
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); |