GNOME Bugzilla – Bug 533619
udpsink dies when Linux fails (for no reason) sendto() with non-posix errno
Last modified: 2008-05-21 11:38:38 UTC
Please describe the problem: I don't know why, perhaps it is when my firewall-scripts (using iptables/netfilter) are restarting, Linux fails udp sendto() and sets errno to EPERM, which is NOT conforming to POSIX. This errno shouldn't be used for sendto(). I've tried to see why this happens, but found nothing wrong in the udp implementation in Linux, but the IO syscalls are filtered in a rather messy way in Linux, to "secure" syscalls, for instance with SELinux (which I am NOT using btw). Well, EPERM is set anyway, and I'm using a plain vanilla kernel. The problem is, when this happens, the stream dies. I'm streaming over network to a set-top-box connected to my TV. When sendto() fails, this is not visible/noticeable, so to just ignore the few hundred (at most) failing sendto()'s is fine, whenever it happens. The attached patches fixes this issue, by ignoring sendo() failures where errno is non-POSIX EPERM. The 'talking' patch prints a warning the first time this happens. The 'silent' patch just fixes the problem. Please use any of the patches (preferably the silent one). Steps to reproduce: 1. Run Linux and make sure it sets errno to EPERM (don't ask me how) 2. Use udpsink Actual results: Stream dies Expected results: I don't really know what to expect when Linux doesn't conform to POSIX, but reasonably "try as good as you can". This patch makes sure udpsink really tries. Does this happen every time? Yes Other information:
Created attachment 111070 [details] [review] The patch
Created attachment 111071 [details] [review] The patch (printing a warning)
If you block some outgoing ports with iptables and try to send from them you'll get EPERM but IMHO udpsink should simply fail then. Is there any reason why it should continue to send data although it is blocked by the kernel?
Yes there is. When my computer gets a new IP from my ISP, or when my DHCP lease expires although I might regain the same IP (this happens frequently), my firewall scripts restarts. This affects *no* applications that I have experienced over the last 10 years. However, during these microseconds, if udpsink dies, an entire stream will end. This means, I cannot watch movies through gstreamer, simply because during a few microseconds of FW reconfiguring, udpsink will die. I have streamed movies from a variety of RTSP servers (which use RTP over UDP for the payload) from the same machine, and I have never experienced that a stream ends/fails. It simply never happens. I've also tried simple udp streamers, with the same result. With gstreamer's udpsink however, the stream dies after 10-20 minutes every single time. I don't understand why gstreamer needs to be so extremely afraid of EPERM as to kill the entire stream (which obviously no other software does). What is the purpose of killing the stream? Is it really up to udpsink to kill a stream on (what I would) loose grounds like these? From what I have understood, software usually don't care about results from sendto() for UDP payloads, only TCP. Perhaps a patch which tests the first sendto() and fails if the first packet got EPERM, but ignores EPERM after a successful sendto() would be better. Please tell me, and I can write that.
Or simply emit a warning instead of an error? Failing on the first EPERM does not seem to be reliable if you're unlucky. You could maybe also fail after N consecutive EPERM errors? or if it lasts longer than N seconds? I agree that the current behaviour is over sensitive to these little glitches.
I was thinking about that - counting consecutive EPERM's and failing after a "decent" number of them. But then it stroke me; Why fail at all? If someone streams, but wants to halt (long or perhaps continous, think webcam) a stream from being streamed for a few minutes by temporarily telling its OS (through iptables for instance) to not allow the packets, but then change back to accept them, shouldn't gstreamer allow that? Should gstreamer really be "afraid" of EPERM's at all? Most UDP applications are hard to find the error for when there's a firewall issue, simply because they don't "fail", the packets gets lost in the FW, but again; They don't fail. Even worse, udpsink is basically (from what I could see of the source code) an alias for multiudpsink with only 1 destination. But what if you have several destinations, but then want to disallow one of them for a while. All other streams end! I think my patch is the only reasonable solution; basically ignoring EPERM, just like most other software seems to be doing.
Yes, I'll apply the patch to ignore the errors.
Patch by: Gustaf Räntilä <g dot rantila at gmail dot com> * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_render): Ignore EPERM errors from sendto. Fixes #533619.