Understanding '.waiting' state in NWConnection.State for UDP

While going through the documentation for NWConnection, there seems to be state known as .waiting which means that the connection is waiting for a path change. For TCP, the state is understandable and can occur under some scenarios. But for the case of UDP, I have following queries:

  1. Why do we need .waiting state for the case of UDP?
  2. Even if we do need .waiting state for UDP, when all does this state occurs?
Answered by DTS Engineer in 882405022

NWConnection is quite generic, so you shouldn’t be surprised that not all of its options make sense for all connection types [1]. However, in this case the .waiting state does make sense for UDP. Consider a connection created like this:

let connection = NWConnection(to: .hostPort(host: "example.com", port: 80), using: .udp)

If you run this on a device with Airplane Mode enabled, the connection will enter the .waiting state. That’s because it’s waiting for DNS to come online so that it can resolve example.com to find out what addresses it should attempt to ‘connect’ to.

But that’s just an example. I suspect that are a number of other cases where you’ll see this.

Share and Enjoy

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

[1] The new NetworkConnection API improves this situation, using the Swift type system to vary the operations supported on the connection based on the underlying protocol. However, there are limits to how much you can improve this. Like with onions, the finer you chop, the more likely it is that things will end it tears (-:

Accepted Answer

NWConnection is quite generic, so you shouldn’t be surprised that not all of its options make sense for all connection types [1]. However, in this case the .waiting state does make sense for UDP. Consider a connection created like this:

let connection = NWConnection(to: .hostPort(host: "example.com", port: 80), using: .udp)

If you run this on a device with Airplane Mode enabled, the connection will enter the .waiting state. That’s because it’s waiting for DNS to come online so that it can resolve example.com to find out what addresses it should attempt to ‘connect’ to.

But that’s just an example. I suspect that are a number of other cases where you’ll see this.

Share and Enjoy

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

[1] The new NetworkConnection API improves this situation, using the Swift type system to vary the operations supported on the connection based on the underlying protocol. However, there are limits to how much you can improve this. Like with onions, the finer you chop, the more likely it is that things will end it tears (-:

I wanted to consolidate my understanding of the states delivered via NWListener.stateUpdateHandler for ConnectedUDP and verify if this interpretation is correct. From what I understand, the following states can occur:

  • .setup

This state occurs immediately after creating the NWListener instance and persists until start(queue:) is called.

  • .waiting

This occurs when the listener is unable to bind or become ready at that moment, but may recover. Typical scenarios include:

  1. Required network interface is temporarily unavailable
  2. Port is temporarily unavailable (e.g., already in use but may be released)
  3. Local network permission has not yet been granted
  • .ready

This occurs when the listener has successfully bound to a port and selected a viable interface/path. At this point, it is ready to receive incoming traffic.

  • .failed

This represents a non-recoverable error that prevents the listener from functioning. Typical scenarios include:

  1. Invalid parameters during initialization (e.g., EINVAL)
  2. Binding to an invalid or unavailable address (EADDRNOTAVAIL)
  3. Permission explicitly denied (EACCES)
  4. Port in use by another long-lived process (EADDRINUSE)
  • .cancelled

This occurs after cancel() is explicitly called on the listener and represents a terminal state.

State Transition Understanding

Based on this, my current understanding is:

  • Once the listener transitions out of .setup, it does not return to .setup.
  • In the normal (“happy path”) case, the state progression is: .setup.ready.cancelled
  • .waiting is a recoverable state, whereas .failed is non-recoverable. In other words, once the listener enters .failed, it will not transition to any other state except .cancelled.
Understanding '.waiting' state in NWConnection.State for UDP
 
 
Q