UDP port unreachable and nw_connection_receive*

I'm trying to use Network framework for a UDP connection. It works, I get traffic flowing both ways when UDP server is responding, however when the server is down and box sends ICMP port unreachable completion blocks from
Code Block
nw_connection_receive_message() nw_connection_receive()
are not getting called.
State and viability change handlers are also not getting called.
In my app console though I see message
Code Block
[connection] nw_socket_get_input_frames [C1:1] recvmsg(fd 4, 9216 bytes) [61: Connection refused]

So somewhere inside of the API it actually gets the ICMP and knows that connection is refused, but how exactly do I get notified about this? This surely beats waiting on connection and timing out if host is nice enough to tell you that port is closed right away.
I discussed this with some folks here and we’re of the opinion that the failure should be reported to you somehow (via one of the two mechanisms you outlined). Can you file a bug about this? Make sure to attach a sysdiagnose log. If you can also attach:
  • A small test project that reproduces the issue

  • A packet trace

that’d be grand.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Ok, FB9000160.
Hi,

I have a similar problem and I don't know if I'm doing something wrong or if it's a bug.

I have a client on iOS that sends a UDP message to a server programmed in Java.
Once the server receives the message it responds with a UDP message. The client gets the message and all is well.

But when I run the following scenario, I get an error message:
1. I start the client and an instance of NWConnection is created.
2. the connection is started with connection.start(...)
3. directly after the start I execute the command: connection.receiveMessage(...)
4. the server is NOT started
5. the created NWConnection is in "Ready" state
6. i send a message
7. the passed "NWConnection.SendCompletion" is called without error. Otherwise nothing happens here. No errors.
8. i start the server
9. i send a message again
10. the message arrives at the server. Then the server sends a UDP response.
11. On the client I now get the following message in the console = "2021-04-10 12:30:43.660695+0200 MySocketClient[27462:5157187] [connection] nw_read_request_report [C1] Receive failed with error "Connection refused""
12. my response handler is called "(data: Data?, context: NWConnection.ContentContext?, isComplete: Bool, error: NWError? )". Interestingly, I get an error = POSIXErrorCode: Connection refused. But at the same time data contains the correct content sent by the server.
13. If I now send further messages from the client to the server everything runs as described from step 6 to step 12.

Am I doing something wrong here? If not, maybe my description can help.

This behaviour matches BSD Sockets pretty well — where a connected UDP socket monitors ICMP responses and simulates ECONNREFUSED errors — but clearly the result is less than ideal. I don’t think you’re doing anything wrong here; rather, NWConnection should provide better semantics here. I encourage you to file a bug about this. Make sure to reference the bug number that hardloafz posted, because these are similar issues.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Was this enhancement to the NWConnection framework ever considered? We also have the requirement to understand when a connection fails and the target emits an ICMP error message to be able to parse this message and failure state. Does this otherwise force us back to implementing the same using BSD sockets so both a TCP connection and the potential resulting ICMP messages can be processed?

Was this enhancement to the [Network] framework ever considered?

Your timing is excellent in that I was discussing this with the Network framework team… like… yesterday.

Sadly, I don’t have a lot of concrete info to share, other than to say that the more we look at this the more weird edge cases we discover (r. 107319681)-:

If this is causing you grief in some specific case, please do file a bug about that. I’d appreciate you posting your bug number here, just for the record.

Does this otherwise force us back to implementing the same using BSD sockets so both a TCP connection and the potential resulting ICMP messages can be processed?

Did you mean UDP here? Because TCP port unreachable failures are reported via a different mechanism, and that is reliably reported via the connection’s state update handler.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your follow up Quinn and happy to hear our timing on this issue is spot on.

Just to clarify our use case is related to the original post in our lack of ability to be notified / process ICMP messages but it does differ in the fact we are currently using a TCP connection and wanting to process any potential TTL exceeded ICMP packets that are returned in transit to our target host. Currently our only way to know this situation has occurred is the receipt of the following error state which is not very deterministic:

error: The operation couldn’t be completed. (Network.NWError error 0.)

Ideally we need to be notified on the receipt of (and type of) the ICMP packet along with the details of the source host to responded with the TTL exceeded in our case.

I have included more detail in the suggested bug ticket I just raised. (FB12118366).

Thanks!

I have included more detail in the suggested bug ticket I just raised. (FB12118366).

Thanks.

The TCP case isn’t something that’s currently on our radar (so to speak) so it’s good to have a bug for that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Great appreciate the team's consideration. How can we stay in the loop of any progress on the UDP / ICMP support as if this is likely to drop sooner we could look at this as an interim step?

With UDP you can achieve reasonable results today using BSD Sockets. You just have to make sure that you use a connected UDP socket.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Great to hear. Do you have a pointers to any sample code that handles BSD socket connections that are able to process both the UDP datagrams and potential returned ICMP packets? Are you suggesting we could achieve the same for TCP connections at the BSD socket level as an interim solution until they are addressed in the Network Framework?

Do you have a pointers to any sample code that handles BSD socket connections that are able to process both the UDP datagrams and potential returned ICMP packets?

My go-to reference for BSD Sockets is UNIX Network Programming by Stevens et al.

http://www.unpbook.com

If you create a connected UDP socket, the system automatically translates incoming ICMP messages relevant to that connection [1] to errors on the socket.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well… flow.

UDP port unreachable and nw_connection_receive*
 
 
Q