CocoaMQTT icon indicating copy to clipboard operation
CocoaMQTT copied to clipboard

Connection to AWS WSS fails due to lack of implementation of urlSession(_:didReceive:completionHandler:)

Open raschiapedane opened this issue 2 years ago • 7 comments

I'm having issues connecting to AWS IoT Core using wss and CocoaMQTTWebSocket. Log reports the following error messages:

CocoaMQTT(debug): Call the SSL/TLS manually validating function
2022-03-07 15:35:44.474400+0100 WssMQTT[28978:4192468] API MISUSE: NSURLSession delegate _TtCC9CocoaMQTT18CocoaMQTTWebSocket20FoundationConnection: <_TtCC9CocoaMQTT18CocoaMQTTWebSocket20FoundationConnection: 0x600001660780> (0x600001660780)
2022-03-07 15:35:44.474500+0100 WssMQTT[28978:4192468] API MISUSE: task:didReceiveChallenge:completionHandler: completion handler not called
2022-03-07 15:37:51.479108+0100 WssMQTT[28978:4197052] [boringssl] boringssl_metrics_log_metric_block_invoke(151) Failed to log metrics
2022-03-07 15:37:51.486063+0100 WssMQTT[28978:4195086] Connection 1: received failure notification
2022-03-07 15:37:51.486210+0100 WssMQTT[28978:4195086] Connection 1: failed to connect 3:-9816, reason -1
2022-03-07 15:37:51.486264+0100 WssMQTT[28978:4195086] Connection 1: encountered error(3:-9816)
2022-03-07 15:37:51.487232+0100 WssMQTT[28978:4195086] Task <476BFBAF-77DC-460C-8018-919F9B32F232>.<1> HTTP load failed, 0/0 bytes (error code: -1200 [3:-9816])

Implementation of the following CocoaMQTTDelegate method seems to be useless...

func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) {
    completionHandler(true)
}

...method is called but the connection cannot be established after calling completionHandler both with true/false value passed as parameter. After the implementation, log doesn't display the "API MISUSE" warning but connection can't be established.

CocoaMQTT(debug): Call the SSL/TLS manually validating function
2022-03-07 16:59:21.538536+0100 WssMQTT[39613:4324980] [boringssl] boringssl_metrics_log_metric_block_invoke(151) Failed to log metrics
2022-03-07 17:00:26.614176+0100 WssMQTT[39613:4326397] Connection 1: received failure notification

I changed CocoaMQTTWebSocket.swift file to manually implement

public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {
     return (.performDefaultHandling, nil)
}

and connection is working fine

2022-03-07 15:38:14.189880+0100 WssMQTT[29564:4198291] [boringssl] boringssl_metrics_log_metric_block_invoke(151) Failed to log metrics
CocoaMQTT(debug): SEND: CONNECT(id:XXXXXXX, username: nil, password: nil, keepalive : 60, cleansess: true)
CocoaMQTT(debug): RECV: CONNACK(code: accept, sp: false)
Connected
CocoaMQTT(debug): SEND: SUBSCRIBE(id: 2, topics: [("test/pluto", qos1)])
CocoaMQTT(debug): SEND: PUBLISH(id: 1, topic: test/pippo, payload: [112, 108, 117, 116, 111])
CocoaMQTT(debug): RECV: PUBACK(id: 1)
CocoaMQTT(debug): Acknowledge frame id 1 success, acked: [PUBLISH(id: 1, topic: test/pippo, payload: [112, 108, 117, 116, 111])]
CocoaMQTT(debug): RECV: SUBACK(id: 2)
CocoaMQTT(debug): ping
CocoaMQTT(debug): SEND: PING
CocoaMQTT(debug): RECV: PONG

I believe that a manual override of func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) is a barely acceptable workaround but I'm stuck figuring out a definitive solution. Can you please help?

raschiapedane avatar Mar 07 '22 16:03 raschiapedane

hi . I will review on this🧐.

leeway1208 avatar Mar 08 '22 02:03 leeway1208

Hello, i'm encountering (i guess) the same problem. My app crashes reporting:

CocoaMQTT(debug): Call the SSL/TLS manually validating function
2022-07-15 17:43:23.560407+0200 BookIt[8527:276038] API MISUSE: NSURLSession delegate _TtCC18CocoaMQTTWebSocket18CocoaMQTTWebSocket20FoundationConnection: <_TtCC18CocoaMQTTWebSocket18CocoaMQTTWebSocket20FoundationConnection: 0x60000114fa80> (0x60000114fa80)
2022-07-15 17:43:23.560928+0200 BookIt[8527:276038] API MISUSE: task:didReceiveChallenge:completionHandler: completion handler not called

In my setup, i'm using nginx as a reverse proxy to forward the mqtt websocket request to my internal container of a docker stack. Nginx is secured with SSL.

nginx.conf

...
listen 443;
        location / mqtt{
            proxy_pass http://mosquitto:8083;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
        }
...

My setup should be fine as i can succesfully connect to the mosquitto broker using a javascript client (mqtt.js) with the following session:

mqttClient = mqtt.connect(`wss://myserver:443/mqtt`, options)

Finally i attach my instance of mqtt session in swift:

        let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
        let topic = "my_topic"
        let clientID = "cocoamqtt_\(String(ProcessInfo().processIdentifier))"
        self.mqtt5 = CocoaMQTT5(clientID: clientID, host: GlobalConfiguration.apiUrl, port: UInt16(GlobalConfiguration.apiPort) ?? 8083, socket: websocket)
        
        let connectProperties = MqttConnectProperties()
        connectProperties.topicAliasMaximum = 0
        connectProperties.sessionExpiryInterval = 30 * 1000
        connectProperties.receiveMaximum = 100
        connectProperties.maximumPacketSize = 500
        
        if let mqtt5 = self.mqtt5 {
            mqtt5.connectProperties = connectProperties
            mqtt5.autoReconnect = true
            mqtt5.autoReconnectTimeInterval = 1
            mqtt5.enableSSL = true
            
            mqtt5.logLevel = .debug
            
            let _ = mqtt5.connect()
            
            mqtt5.didConnectAck = { cocoaMQTT5, cocoaMQTTCONNACKReasonCode, mqttDecodeConnAck in
                    mqtt5.subscribe(topic, qos: CocoaMQTTQoS.qos1)
                    mqtt5.didReceiveMessage = { mqtt, message, id, publishData in
                          print(message)
                    }
            }
            
        }else{
            print("An error arose while setting up mqtt5")
        }

manfredipist avatar Jul 15 '22 15:07 manfredipist

The bug is still present in 2.0.5 and manual override of func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) is still needed to avoid app crashing!

manfredipist avatar Aug 28 '22 17:08 manfredipist

Bug still present in 2.1.0

manfredipist avatar Jan 28 '23 16:01 manfredipist

Bug still present in 2.1.3

Parameshvadivel avatar Mar 06 '23 18:03 Parameshvadivel

Still present in 2.1.6. Is there a plan to fix this?

gorazdkunej avatar Sep 23 '23 21:09 gorazdkunej

This worked for me without any manual override

import Foundation
import CocoaMQTT
import CocoaMQTTWebSocket

struct MyMqttConfig {
    let clientID: String
    let username: String
    let password: String
    let host: String
    let port: Int
}

class MyMqttConnector {
    let config: MyMqttConfig
    
    init(_ config: MyMqttConfig) {
        self.config = config
    }
    
    func connect() {
        let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
        websocket.enableSSL = true
        let mqtt = CocoaMQTT(clientID: config.clientID, host: config.host, port: UInt16(config.port), socket: websocket)
        mqtt.username = config.username
        mqtt.password = config.password
        mqtt.enableSSL = true
        mqtt.keepAlive = 30
        mqtt.delegate = self
        mqtt.cleanSession = true
        let connect = mqtt.connect()
        Print.d("connect: \(connect)")
    }
    
}
    
extension MyMqttConnector: CocoaMQTTDelegate {
    
    func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
        Print.d()
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
        Print.d()
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didPublishAck id: UInt16) {
        Print.d()
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
        Print.d()
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
        Print.d()
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopics topics: [String]) {
        Print.d()
    }
    
    func mqttDidPing(_ mqtt: CocoaMQTT) {
        Print.d()
    }
    
    func mqttDidReceivePong(_ mqtt: CocoaMQTT) {
        Print.d()
    }
    
    func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) {
        Print.d()
    }
}

chanonly123 avatar Oct 13 '23 12:10 chanonly123