// // CocoaMQTTReader.swift // CocoaMQTT // // Created by HJianBo on 2019/5/21. // Copyright © 2019 emqx.io. All rights reserved. // import Foundation /// Read tag for AsyncSocket enum CocoaMQTTReadTag: Int { case header = 0 case length case payload } /// protocol CocoaMQTTReaderDelegate: AnyObject { func didReceive(_ reader: CocoaMQTTReader, connack: FrameConnAck) func didReceive(_ reader: CocoaMQTTReader, publish: FramePublish) func didReceive(_ reader: CocoaMQTTReader, puback: FramePubAck) func didReceive(_ reader: CocoaMQTTReader, pubrec: FramePubRec) func didReceive(_ reader: CocoaMQTTReader, pubrel: FramePubRel) func didReceive(_ reader: CocoaMQTTReader, pubcomp: FramePubComp) func didReceive(_ reader: CocoaMQTTReader, suback: FrameSubAck) func didReceive(_ reader: CocoaMQTTReader, unsuback: FrameUnsubAck) func didReceive(_ reader: CocoaMQTTReader, pingresp: FramePingResp) func didReceive(_ reader: CocoaMQTTReader, disconnect: FrameDisconnect) func didReceive(_ reader: CocoaMQTTReader, auth: FrameAuth) } class CocoaMQTTReader { private var socket: CocoaMQTTSocketProtocol private weak var delegate: CocoaMQTTReaderDelegate? private let timeout: TimeInterval = 30_000 /* -- Reader states -- */ private var header: UInt8 = 0 private var length: UInt = 0 private var data: [UInt8] = [] private var multiply = 1 /* -- Reader states -- */ init(socket: CocoaMQTTSocketProtocol, delegate: CocoaMQTTReaderDelegate?) { self.socket = socket self.delegate = delegate } func start() { readHeader() } func headerReady(_ header: UInt8) { self.header = header readLength() } func lengthReady(_ byte: UInt8) { length += (UInt)((Int)(byte & 127) * multiply) // done if byte & 0x80 == 0 { if length == 0 { frameReady() } else { readPayload() } // more } else { let result = multiply.multipliedReportingOverflow(by: 128) if !result.overflow { multiply = result.partialValue } else { reset() } readLength() } } func payloadReady(_ data: Data) { self.data = [UInt8](repeating: 0, count: data.count) data.copyBytes(to: &(self.data), count: data.count) frameReady() } private func readHeader() { reset() socket.readData(toLength: 1, withTimeout: -1, tag: CocoaMQTTReadTag.header.rawValue) } private func readLength() { socket.readData(toLength: 1, withTimeout: timeout, tag: CocoaMQTTReadTag.length.rawValue) } private func readPayload() { socket.readData(toLength: length, withTimeout: timeout, tag: CocoaMQTTReadTag.payload.rawValue) } private func frameReady() { guard let frameType = FrameType(rawValue: UInt8(header & 0xF0)) else { protocolError("Received unknown frame type, header: \(header), data:\(data)") return } // XXX: stupid implement switch frameType { case .connack: guard let connack = FrameConnAck(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, connack: connack) case .publish: guard let publish = FramePublish(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, publish: publish) case .puback: guard let puback = FramePubAck(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, puback: puback) case .pubrec: guard let pubrec = FramePubRec(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, pubrec: pubrec) case .pubrel: guard let pubrel = FramePubRel(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, pubrel: pubrel) case .pubcomp: guard let pubcomp = FramePubComp(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, pubcomp: pubcomp) case .suback: guard let frame = FrameSubAck(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, suback: frame) case .unsuback: guard let frame = FrameUnsubAck(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, unsuback: frame) case .pingresp: guard let frame = FramePingResp(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, pingresp: frame) case .disconnect: guard isMQTT5ProtocolVersion() else { protocolError("Reader received MQTT5-only frame \(frameType) in non-MQTT5 mode, data: \(data)") return } guard let frame = FrameDisconnect(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, disconnect: frame) case .auth: guard isMQTT5ProtocolVersion() else { protocolError("Reader received MQTT5-only frame \(frameType) in non-MQTT5 mode, data: \(data)") return } guard let frame = FrameAuth(packetFixedHeaderType: header, bytes: data) else { protocolError("Reader parse \(frameType) failed, data: \(data)") return } delegate?.didReceive(self, auth: frame) default: protocolError("Received unsupported frame type \(frameType), data: \(data)") return } readHeader() } private func protocolError(_ reason: String) { printError(reason) socket.disconnect() } private func isMQTT5ProtocolVersion() -> Bool { return CocoaMQTTStorage()?.queryMQTTVersion() == "5.0" } private func reset() { length = 0 multiply = 1 header = 0 data = [] } }