3

Based on the premise that UDP is a connectionless protocol I had presumed that whether a host is up or down would be irrelevant.

However, now that I'm doing testing I've discovered that when I have "connected" my UDP client socket, a write to that socket returns an error because the server has sent back a ICMP Port Unreachable error ..

The purpose of "connecting" the UDP port (According to Stevens Unix Network Programming) is to basically caches the entry from the routing table, rather than creating a new one for each packet, which is supposed to have performance benefits.

However, this ICMP packet is causing me to lose my client socket, which is very annoying.

Can anybody shed any light on why this could be? Are there any known workarounds?

I'm using a 3p java library that doesn't account for this and just disconnects and I'll probably have to hack it to reconnect, but before I do I was kind of hoping there was something I could do at the (Linux) operating system level maybe to prevent this happening ... all investigations into socket options etc. have turned out to be unfruitful.

EDIT

In summary this isn't possible and fixing the code is the only way to do this.

The only possibility appears to be configuring iptables to block the ICMP responses but that's a bit of a sledgehammer to crack this particular nut.

robert
  • 4,612
  • 2
  • 29
  • 39
  • That said, I'm not sure I understand your question. You've attempted to connect a socket to an end point that isn't available, and got an ICMP error. Why _wouldn't_ you get an error when you then try to `write` to it? – Alnitak Feb 03 '17 at 10:40
  • Because it's *connectionless* - indeed if I hadn't connected then I would not get this error. Don't be mislead by the word connected, just cause that's what it's not what it means in a datagram context. Like I say, Stevens even appears mystified. – robert Feb 03 '17 at 10:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/134756/discussion-between-alnitak-and-robert). – Alnitak Feb 03 '17 at 10:46
  • @EJP in further discussion with the OP, the underlying problem is a really crappy implementation of the `UDPAppender` in log4j, which uses connected sockets, but provides no means for recovery if the far end disappears. https://bz.apache.org/bugzilla/show_bug.cgi?id=57891 – Alnitak Feb 03 '17 at 11:42
  • No, he says, and admittedly I'm paraphrasing *"it is unclear why they took this particular approach"*. – robert Feb 03 '17 at 11:42
  • Exact quote *"Why this design decision was made when sockets were first implemented is rarely understood."* See 8.10 of the book. – robert Feb 03 '17 at 11:47
  • I think you've misread that. My reading is that it's not understood why the API was designed so that _only_ connected sockets get error messages, and that unconnected ones don't. – Alnitak Feb 03 '17 at 11:48
  • That makes more sense since he goes on to explain why in the next paragraph ... – robert Feb 03 '17 at 11:49
  • @EJP and really come on *"Stevens isn't mystified. You are"* is gratuitously rude. If I wasn't mystified, I wouldn't be on here asking this question. Sap. – robert Feb 03 '17 at 11:51
  • 1
    The text in the next paragraph appears to be incorrect. It says _"The only piece of information that recvfrom can return is an errno value; recvfrom has no way of returning the destination IP address and destination UDP port number of the datagram in error"_. That's odd, because that's precisely what the `address` field could be used for, it just seems that the BSD folks decided not to fill it in if there's an ICMP error. WRS is no longer with us, but I know one of the co-authors and could ask him about it. – Alnitak Feb 03 '17 at 11:53

2 Answers2

6

Whilst your UDP socket is not strictly "connected", making a connect() call does create local "state" for that socket.

This state not only allows the system to cache the current routing entry for the destination, but also means that all subsequent output operations don't need to specify the destination - they'll use the one specified in the connect() call. It also ensures that the kernel will throw away inbound packets destined for your socket that don't come from the "connected" party.

This connected state also allows the kernel to deliver errors relating to that socket (signalled via ICMP) to the application - unconnected sockets don't get these - they're "fire and forget".

In the case of the log4j code that you've pointed me at offline, the problem appears to be entirely in user space code. The log4j UDPAppender just unilaterally throws away the socket when it gets an IOException on a write call, and provides no means to detect that condition so that you can fix it.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
-2

Well, UDP sits on top of IP. And the message you get, is from that layer. See https://en.wikipedia.org/wiki/User_Datagram_Protocol and https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol

So it's connection-less in the sense, that you don't have a persistent tunnel, so it won't be guaranteed that your packets arrive in order, and stuff. Or you won't necessarily recognise right away if there's an error.

But you still need to be able to connect to something, to start with. It just happens on a lower level.

But the kernel will still keep track of the socket, so it might notify you about ICMP packets it receives, let's say from routers along the way. The point is, that ICMP is a layer below.

UPDATE: By the way, I think, you could have the problem the other way around. Your router, or whatever sits inbetween could just ignore the fact, that it doesn't know where to connect forward the packet to, and just silently drop the packet, instead of replying with an ICMP error message.

Dan
  • 630
  • 5
  • 8
  • Thanks for your insight Dan. I've actually come on a good bit now on this issue and it looks like we're going to have to rewrite the code. Check this out for a description of how the 'connected' state applies to UDP http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch08lev1sec11.html – robert Feb 03 '17 at 11:36
  • You don't need to connect a UDP socket. Your last paragraph doesn't make sense. – user207421 Feb 03 '17 at 11:36
  • 1
    Ok, let me rephrase that slightly... :) – Dan Feb 03 '17 at 11:41