CocoaMQTT
CocoaMQTT copied to clipboard
Connection to AWS WSS fails due to lack of implementation of urlSession(_:didReceive:completionHandler:)
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?
hi . I will review on this🧐.
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")
}
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!
Bug still present in 2.1.0
Bug still present in 2.1.3
Still present in 2.1.6. Is there a plan to fix this?
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()
}
}