Failed to attach socket protocol , iOS 14 beta issue

We are having iPhone application which is communicating with apple watch application using network classes. We are using NWConnection and NWListener for peer to peer communication.

We have created UdpClient which is using bonjour service "camera.udp"

please check the code below UDPClient.swift

Code Block
import Foundation
import Network
import WatchKit
protocol UDPClientDelegate {
    func connectionDone()
    func dataSendSuccesfully()
    func socketConnectionStoped()
    func receivedReplyWithDict(dict : [String : Any])
}
enum ConnectionState {
    case settingUP
    case started
    case dataBeingSent
    case disconnected
}
class UDPClient {
var count : Int = 0
var udpDelegate: UDPClientDelegate?
var connection : NWConnection?
var queue : DispatchQueue = DispatchQueue.global(qos: .userInitiated)
var serviceName : String?
var connectedState : ConnectionState = .disconnected
var dataArray : Array<Any>
static let sharedInstance: UDPClient = {
        let instance = UDPClient()
        return instance
    }()
init(){
     dataArray = Array()
    }
    func setupConnection(name: String){
        serviceName = name
        let parameters = NWParameters.udp
        // Create the connection
        connection = NWConnection(to: .service(name: name, type: "_camera._udp", domain: "local", interface: nil), using: parameters)
        // Set the state update handler
        connection?.stateUpdateHandler = { (newState) in
            switch (newState){
            case .ready:
                print("Ready To Send")
            case .failed(let error):
                print("Connection State: \(error)")
            case .preparing:
                print("Preparing...")
            case .waiting(let error):
                print("Waiting: \(error)")
            default:
                print("def")
                break
            }
        }
        connectedState = .settingUP
        setupReceive()
    }
    func startConnection() {
        // Start the connection
        if(connectedState == .settingUP){
            connection?.start(queue: queue)
            connectedState = .started
        }
    }
    func stopConnection(){
        sendDisconnectACK()
        connection?.cancelCurrentEndpoint()
        connectedState = .disconnected
        connection = nil
        print("Stopped")
    }
    //MARK:- Receive Data
    func setupReceive() {
        if connection != nil{
            connection?.receiveMessage { (content, context, isComplete, error) in
                if content != nil{
                    self.processReplyFromIOS(content: content!)
                }
                self.setupReceive()
            }
        }else{
            return
        }
    }
    func processReplyFromIOS(content : Data){
        var receivedData = [:] as [String : Any]
        do{
            if let oppData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(content){
            receivedData = oppData as! [String : Any]
            }
        }catch let error{
            print(error)
        }
        if receivedData["Connected"] != nil{
            print("Got Connected")
            self.connectedState = .dataBeingSent
        }else{
        }
    }
//MARK:- Send Data
// Send Connection data
    func sendConnectionRequest(){
WKInterfaceDevice.current().isBatteryMonitoringEnabled = true
let dic = ["ConnetionRequest":"Request","batteryLevel":watchBatteryPercentage] as [String : Any]
        let dataExample: Data = NSKeyedArchiver.archivedData(withRootObject: dic)
        connection?.send(content: dataExample, completion: .contentProcessed({ (error) in
            if let error = error{
                print("Send error \(error)")
            }
        }))
    }
    var watchBatteryPercentage:Int {
        return Int(roundf(WKInterfaceDevice.current().batteryLevel * 100))
    }
func sendData(dic :[String : Any]){
        let data: Data = NSKeyedArchiver.archivedData(withRootObject: dic)   connection?.send(content: data, completion: .idempotent)
    }
    // Send Disconnection Ack
    func sendDisconnectACK(){
        let disconnectionData = ["Disconnected" : true] as [String : Any]
        let dataExample: Data = NSKeyedArchiver.archivedData(withRootObject: disconnectionData)
        connection?.send(content: dataExample, completion: .contentProcessed({ (error) in
            if let error = error{
                print("Send error \(error)")
            }
        }))
    }
}

Replies

Same way we have created UDPListerner class.
Code Block
import Foundation
import Network
protocol UDPServerDelegate {
    func dataToController(dic: [String : Any])
}
enum ListnerState {
    case started
    case stoped
    case settingUp
}
class UDPServer {
var udpDelegate: UDPServerDelegate?
    var dataToTransferViaSocket : [Data]?
    var listner : NWListener?
    var isConnected : Bool = false
    var connection : NWConnection?
var queue = DispatchQueue.global(qos: .userInteractive)
    var listnerState: ListnerState = .stoped
static let sharedInstance: UDPServer = {
        let instance = UDPServer()
        return instance
    }()
fileprivate func setupListnerName(_ name: String) {
        if let iphoneName = (UserDefaults.standard.object(forKey: "iPhoneName") as? String){
            if name != iphoneName{
                UserDefaults.standard.set(name, forKey: "iPhoneName")
                if !self.isConnected{
                }
            }
        }else{
            UserDefaults.standard.set(name, forKey: "iPhoneName")
            if !self.isConnected{        
            }
        }
    }
  func setupListner(delegate : UDPServerDelegate){
        isConnected = false
        listnerState = .settingUp
        udpDelegate = delegate
         // Create The Listner
        if let port = NWEndpoint.Port(rawValue: 55000){
            listner = try! NWListener(using: .udp, on: port)
        }else{
            let udpOption = NWProtocolUDP.Options()
            let params = NWParameters(dtls: nil, udp: udpOption)
            params.includePeerToPeer = true            
            listner = try! NWListener(using: params)
        }
        // Setup the listnerwith the service
        listner?.service = NWListener.Service(name: "MinderService",type: "_camera._udp",domain: "local")
        listner?.parameters.includePeerToPeer = true
        listner?.parameters.allowLocalEndpointReuse = true
        listner?.parameters.acceptLocalOnly = true
        // Handle Incoming sonnections
        listner?.newConnectionHandler = { (newConnection) in
            print("newConnectionHandler")
            self.connection = newConnection
            self.isConnected = false
            self.sendConnectionACK()
            newConnection.start(queue: .main)
            self.receiveUDP()
        }
// Handle listner state changes
        listner?.stateUpdateHandler = { [weak self] (newState) in
            switch (newState){
            case .setup:
                print("stateUpdateHandler setup")
            case .waiting(let error):
                print("stateUpdateHandler error \(error)")
            case .cancelled:
                print("stateUpdateHandler cancelled")
            case .ready:
                print("Listning on Port \(String(describing: self?.listner?.port))")
            case .failed(let error):
                print("stateUpdateHandler Failed: \(error)")
            default:
                print("stateUpdateHandler default")
                return
            }
           print("Listner State: \(self?.listnerState)")
        }
    }
func stopListner(){
        stopConnection()
        listner?.cancel()
        listner = nil
        listnerState = .stoped
        print("Stoped Listner")
    }
func stopConnection(){
        connection?.cancel()
        self.isConnected = false
        connection = nil
    }
func startListner(){
        listner?.start(queue: queue)
        listnerState = .started
        print("Started Listner")
    }
     // Receive packets from other side
    fileprivate func sendConnectionACK() {
        do{
            let connectionData = ["Connected":true] as [String : Any]
            let dataExample: Data = try NSKeyedArchiver.archivedData(withRootObject: connectionData, requiringSecureCoding: false)
            if ((self.connection?.send(content: dataExample, completion: .idempotent)) != nil){
                self.isConnected = true
            }
        }catch let error{
            print(error)
        }
    }
     func sendDataViaSocket() {
        if self.dataToTransferViaSocket != nil && self.dataToTransferViaSocket?.count != 0{
            self.connection?.send(content: self.dataToTransferViaSocket?.first, completion: .idempotent)
            self.dataToTransferViaSocket?.removeFirst()
            if self.dataToTransferViaSocket != nil && self.dataToTransferViaSocket?.count != 0{
                sendDataViaSocket()
            }
        }
        else{
            return
        }
    }
     func receiveUDP() {
        self.connection?.receiveMessage { (data, context, isComplete, error) in
                if data != nil{
                    let dictionary: Dictionary? = NSKeyedUnarchiver.unarchiveObject(with: data!) as? [String : Any]
                    if dictionary != nil{
                        if dictionary!["Disconnected"] != nil{
//                            self.stopConnection()
                        }else{
                            self.udpDelegate?.dataToController(dic: dictionary!)
                        }
                    }
                }
            self.receiveUDP()
        }
    }
}

```

Above code working perfectly fine with iOS 13 and watch OS 6 , But not working in IOS 14 beta and Watch 7 Beta.


We are getting error as dataSend Extension[562:369291] [connection] nwendpointflowattachprotocols [C1.1
fd74:6572:6d6e:7573:d:8ea4:c65a:3cd3.62742 in_progress socket-flow (satisfied (Path is satisfied), interface: ipsec2, scoped, ipv4,
ipv6)] Failed to attach socket protocol

We have taken following measures as suggested in WWDC2020 video on changes in privacy settings
WWDC2020 video
  • Added Privacy - Local Network Usage Description in info plist

  • Bonjour Services -> in array added the Service as camera.udp in info plist


Please let us know if we are missing something .