NWConnection how to force ipv4 ?

I have the following code to force the connectivity over cellular and it works perfectly

Code Block
let tcpOptions = NWProtocolTCP.Options()
    tcpOptions.connectionTimeout = 5
    var tlsOptions: NWProtocolTLS.Options?
    var port = 80
    if (url.scheme!.starts(with:"https")) {
      port = 443
      tlsOptions = .init()
    }
    /*force network connection to cellular only*/
    let params = NWParameters(tls: tlsOptions , tcp: tcpOptions)
    params.requiredInterfaceType = .cellular
    params.prohibitExpensivePaths = false
    params.prohibitedInterfaceTypes = [.wifi]
    /* create network connection */
    connection = NWConnection(host: NWEndpoint.Host(url.host!), port: NWEndpoint.Port(rawValue: UInt16(port))!, using: params)


Now I'm looking to force the connection to use ipv4 (even if the phone has an ipv6 available) because the targeted server has a broken ipv6 support and I don't have control over it (it belongs to a mobile operator)

Any idea?
E



Replies

Now I'm looking to force the connection to use ipv4

That’d be the version property.

Share and Enjoy

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

How exactly would I set the desired IP protocol version on a connection? I followed the link to find NWProtocolIP.Options.Version which is an enum having v4 as one of its cases. But for the life of me I can't figure out how to pass this as an option. I tried lots of things with NWParameters and so on. The documentation does not really help. Could you please provide a working code fragment and explain it? I think it would also be "educational" to understand how the Apple frameworks expect the various parameters and options specified - I am talking to you, eskimo1 😉

Thanks in advance, Giulio

This is one of those places where the general-purpose nature of Network framework makes it harder to see what’s going on. Within an NWParameters value, there’s a defaultProtocolStack property that has a bunch of different properties like internetProtocol. That’s declared to be of type NWProtocolOptions but at runtime it’s actually a subclass value, with the type NWProtocolIP.Options. You have to force cast it to get at the version property.

For example:

import Foundation
import Network

func main() {
    let params = NWParameters.tcp
    let ip = params.defaultProtocolStack.internetProtocol! as! NWProtocolIP.Options
    ip.version = .v4
    let conn = NWConnection(to: .hostPort(host: "localhost", port: 12345), using: params)
    withExtendedLifetime(conn) {
        conn.stateUpdateHandler = { newState in
            print(newState)
        }
        let message = Data("Hello Cruel World!\r\n\(Date())\r\n".utf8)
        conn.send(content: message, completion: .contentProcessed({ error in
            print(error)
        }))
        conn.start(queue: .main)
        dispatchMain()
    }
}

main()

Put this in a new tool project. Then open a Terminal window and run this command:

% nc -l 12345

Then run your tool from Xcode, and you’ll see something like this in Terminal:

% nc -l 12345
Hello Cruel World!
2021-11-22 11:57:29 +0000

Share and Enjoy

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

Hi Eskimo, Thanks for your example. This works great on Simulator but on Real Device i always get only IPV6 address for the same code base and the same server. Do you know what can be the reason ?

Btw: Instead of direct ip/port for connection i'm using a NWEndpoint that is created by a NWBrowser .bonjour instance and listening for browseResultsChangedHandler from where i get NWEndpoint .

Any idea why ? Thanks!

Instead of direct ip/port for connection i'm using a NWEndpoint that is created by a NWBrowser

So, you get your NWEndpoint from Bonjour and you create your NWConnection from that? With code like this:

let ep: NWEndpoint = … from NWBrowser …
let params = NWParameters.tcp
let ip = params.defaultProtocolStack.internetProtocol! as! NWProtocolIP.Options
ip.version = .v4
let conn = NWConnection(to: ep, using: params)

Share and Enjoy

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