Skip to content

Commit afd082d

Browse files
committed
add tls options and quic test case
1 parent 2c1f665 commit afd082d

23 files changed

+706
-373
lines changed

Demo/MQTTDemo.xcodeproj/project.pbxproj

+15
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,22 @@
3535
33CC16C22D0994790063F140 /* MQTTDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MQTTDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3636
/* End PBXFileReference section */
3737

38+
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
39+
33F3395E2D1D59C0006B97F0 /* Exceptions for "MQTTDemo" folder in "MQTTDemo" target */ = {
40+
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
41+
membershipExceptions = (
42+
Info.plist,
43+
);
44+
target = 33CC16A72D0994760063F140 /* MQTTDemo */;
45+
};
46+
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
47+
3848
/* Begin PBXFileSystemSynchronizedRootGroup section */
3949
33CC16AA2D0994760063F140 /* MQTTDemo */ = {
4050
isa = PBXFileSystemSynchronizedRootGroup;
51+
exceptions = (
52+
33F3395E2D1D59C0006B97F0 /* Exceptions for "MQTTDemo" folder in "MQTTDemo" target */,
53+
);
4154
path = MQTTDemo;
4255
sourceTree = "<group>";
4356
};
@@ -424,6 +437,7 @@
424437
DEVELOPMENT_TEAM = 24L372QN9V;
425438
ENABLE_PREVIEWS = YES;
426439
GENERATE_INFOPLIST_FILE = YES;
440+
INFOPLIST_FILE = MQTTDemo/Info.plist;
427441
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
428442
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
429443
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -453,6 +467,7 @@
453467
DEVELOPMENT_TEAM = 24L372QN9V;
454468
ENABLE_PREVIEWS = YES;
455469
GENERATE_INFOPLIST_FILE = YES;
470+
INFOPLIST_FILE = MQTTDemo/Info.plist;
456471
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
457472
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
458473
INFOPLIST_KEY_UILaunchScreen_Generation = YES;

Demo/MQTTDemo/Info.plist

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>NSAppTransportSecurity</key>
6+
<dict>
7+
<key>NSAllowsArbitraryLoads</key>
8+
<true/>
9+
</dict>
10+
</dict>
11+
</plist>

Demo/MQTTDemo/MQTTClient.swift

+17-24
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import MQTTNIO
99
import MQTT
1010
import CocoaMQTT
1111
import Foundation
12-
import Network
1312

1413
let client = MQTTClient()
1514
//let mqtt = {
@@ -23,37 +22,31 @@ let client = MQTTClient()
2322
// m.delegate = client
2423
// return m
2524
//}()
25+
2626
let mqtt = {
27-
let params = NWParameters.tls
28-
let endpoint = NWEndpoint.hostPort(host: "broker.beta.jagat.io", port: 1883)
29-
let m = MQTT.ClientV5("swift-mqtt", endpoint: endpoint, params: .tcp)
27+
var options = TLS.Options()
28+
if let file = Bundle.main.path(forResource: "client", ofType: "p12"){
29+
do {
30+
options.credential = try .create(from: file, passwd: "123456")
31+
} catch {
32+
print(error)
33+
}
34+
}
35+
options.verify = .trustAll
36+
options.serverName = "docs"
37+
options.minVersion = .v1_3
38+
options.maxVersion = .v1_3
39+
options.quicOptions = .init()
40+
options.quicOptions?.isDatagram = true
41+
let m = MQTT.ClientV5("swift-mqtt", endpoint: .quic(host: "docs.lerjin.com",options: options))
3042
m.config.username = "jagat-mqtt-pwd-im"
3143
m.config.password = "jagat-mqtt-pwd-im"
3244
m.usingMonitor()
3345
m.usingRetrier()
3446
MQTT.Logger.level = .debug
3547
return m
3648
}()
37-
extension NWParameters{
38-
var isTCP:Bool{
39-
if let _ = self.defaultProtocolStack.transportProtocol as? NWProtocolTCP.Options{
40-
return true
41-
}
42-
return false
43-
}
44-
var isUDP:Bool{
45-
if let _ = self.defaultProtocolStack.transportProtocol as? NWProtocolUDP.Options{
46-
return true
47-
}
48-
return false
49-
}
50-
var isQUIC:Bool{
51-
if let _ = self.defaultProtocolStack.transportProtocol as? NWProtocolQUIC.Options{
52-
return true
53-
}
54-
return false
55-
}
56-
}
49+
5750
//let mqtt = {
5851
// let params = NWParameters.tls
5952
// let endpoint = NWEndpoint.hostPort(host: "broker.beta.jagat.io", port: 1883)

Package.resolved

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"originHash" : "b83e927ba388edd290fa6356170fa708392416a85c6b3d9eba7ceb01704a68a6",
2+
"originHash" : "62dbc66bc23219bfd055d5192ccbfc21652a4c13efc7765b09495c02dcd76220",
33
"pins" : [
44
{
55
"identity" : "swift-promise",
66
"kind" : "remoteSourceControl",
77
"location" : "https://github.com/sutext/swift-promise",
88
"state" : {
9-
"revision" : "4f7b7ed1a58b99c3b98e8e4a169c18590b046bb1",
10-
"version" : "1.1.0"
9+
"revision" : "fb42db5548489631f978ea3b16e3d0b1034a01af",
10+
"version" : "1.2.0"
1111
}
1212
}
1313
],

Sources/MQTT/Client.swift

+32-21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Promise
1313

1414
public protocol MQTTDelegate:AnyObject{
1515
func mqtt(_ mqtt: MQTT, didUpdate status:MQTT.Status,prev:MQTT.Status)
16-
func mqtt(_ mqtt: MQTT, didReceive error:Message)
16+
func mqtt(_ mqtt: MQTT, didReceive error:MQTT.Message)
1717
func mqtt(_ mqtt: MQTT, didReceive error:Error)
1818

1919
}
@@ -34,9 +34,9 @@ extension MQTT{
3434
/// - clientID: Client Identifier
3535
/// - endpoint:The network endpoint
3636
/// - params: The connection parameters `default` is `.tls`
37-
public init(_ clientId: String, endpoint:NWEndpoint,params:NWParameters = .tls) {
37+
public init(_ clientId: String, endpoint:Endpoint) {
3838
self.config = Config(.v3_1_1,clientId:clientId)
39-
self.socket = Socket(self.config,endpoint: endpoint, params: params)
39+
self.socket = Socket(self.config,endpoint: endpoint)
4040
}
4141
}
4242
}
@@ -75,10 +75,26 @@ extension MQTT.Client{
7575
}
7676
}
7777
extension MQTT.Client{
78-
/// Close gracefully by sending close frame
78+
/// Close from server
79+
/// - Parameters:
80+
/// - reason: close reason code send to the server
81+
/// - Returns: Future waiting on disconnect message to be sent
82+
///
7983
@discardableResult
80-
public func close(_ code:ReasonCode = .success)->Promise<Void>{
81-
self.close(packet: DisconnectPacket(reason: code))
84+
public func close(_ reason:MQTT.CloseReason = .normalClose)->Promise<Void>{
85+
var packet = DisconnectPacket()
86+
if case .disconnect(let reasonCode, let properties) = reason{
87+
switch config.version {
88+
case .v5_0:
89+
packet = .init(reason: reasonCode,properties: properties)
90+
case .v3_1_1:
91+
packet = .init(reason: reasonCode)
92+
}
93+
}
94+
return self.socket.sendNoWait(packet).map { _ in
95+
self.socket.directClose(reason: reason)
96+
return Promise(())
97+
}
8298
}
8399
/// Connect to MQTT server
84100
///
@@ -102,7 +118,7 @@ extension MQTT.Client{
102118
) -> Promise<Bool> {
103119

104120
let message = will.map {
105-
Message(
121+
MQTT.Message(
106122
qos: .atMostOnce,
107123
dup: false,
108124
topic: $0.topic,
@@ -146,7 +162,7 @@ extension MQTT.Client{
146162
qos: MQTTQoS = .atLeastOnce,
147163
retain: Bool = false
148164
) -> Promise<Void> {
149-
let message = Message(qos: qos, dup: false, topic: topic, retain: retain, payload: payload, properties: [])
165+
let message = MQTT.Message(qos: qos, dup: false, topic: topic, retain: retain, payload: payload, properties: [])
150166
let packetId = self.nextPacketId()
151167
let packet = PublishPacket(id:packetId,message: message)
152168
return self.publish(packet: packet).then { _ in }
@@ -255,7 +271,7 @@ extension MQTT.Client {
255271
switch self.config.version {
256272
case .v3_1_1:
257273
if connack.returnCode != 0 {
258-
let returnCode = MQTTError.ConnectionReturnValue(rawValue: connack.returnCode) ?? .unrecognizedReturnValue
274+
let returnCode = ConnectRetrunCode(rawValue: connack.returnCode) ?? .unrecognizedReturnValue
259275
throw MQTTError.connectionError(returnCode)
260276
}
261277
case .v5_0:
@@ -319,26 +335,26 @@ extension MQTT.Client {
319335
// check publish validity
320336
// check qos against server max qos
321337
guard self.connParams.maxQoS.rawValue >= packet.message.qos.rawValue else {
322-
return .init(MQTTPacketError.qosInvalid)
338+
return .init(PacketError.qosInvalid)
323339
}
324340
// check if retain is available
325341
guard packet.message.retain == false || self.connParams.retainAvailable else {
326-
return .init(MQTTPacketError.retainUnavailable)
342+
return .init(PacketError.retainUnavailable)
327343
}
328344
for p in packet.message.properties {
329345
// check topic alias
330346
if case .topicAlias(let alias) = p {
331347
guard alias <= self.connParams.maxTopicAlias, alias != 0 else {
332-
return .init(MQTTPacketError.topicAliasOutOfRange)
348+
return .init(PacketError.topicAliasOutOfRange)
333349
}
334350
}
335351
if case .subscriptionIdentifier = p {
336-
return .init(MQTTPacketError.publishIncludesSubscription)
352+
return .init(PacketError.publishIncludesSubscription)
337353
}
338354
}
339355
// check topic name
340356
guard !packet.message.topic.contains(where: { $0 == "#" || $0 == "+" }) else {
341-
return .init(MQTTPacketError.invalidTopicName)
357+
return .init(PacketError.invalidTopicName)
342358
}
343359

344360
if packet.message.qos == .atMostOnce {
@@ -390,7 +406,7 @@ extension MQTT.Client {
390406
/// - Returns: Future waiting for subscribe to complete. Will wait for SUBACK message from server
391407
func subscribe(packet: SubscribePacket) -> Promise<SubackPacket> {
392408
guard packet.subscriptions.count > 0 else {
393-
return .init((MQTTPacketError.atLeastOneTopicRequired))
409+
return .init((PacketError.atLeastOneTopicRequired))
394410
}
395411
return self.socket.sendPacket(packet).then { ack in
396412
if let suback = ack as? SubackPacket{
@@ -404,7 +420,7 @@ extension MQTT.Client {
404420
/// - Returns: Future waiting for subscribe to complete. Will wait for SUBACK message from server
405421
func unsubscribe(packet: UnsubscribePacket) -> Promise<SubackPacket> {
406422
guard packet.subscriptions.count > 0 else {
407-
return .init((MQTTPacketError.atLeastOneTopicRequired))
423+
return .init((PacketError.atLeastOneTopicRequired))
408424
}
409425
return self.socket.sendPacket(packet).then { ack in
410426
if let suback = ack as? SubackPacket{
@@ -413,11 +429,6 @@ extension MQTT.Client {
413429
throw MQTTError.unexpectedMessage
414430
}
415431
}
416-
/// Close from server
417-
/// - Returns: Future waiting on disconnect message to be sent
418-
func close(packet: DisconnectPacket) -> Promise<Void> {
419-
return self.socket.sendNoWait(packet)
420-
}
421432

422433
func auth(packet: AuthPacket) -> Promise<Packet> {
423434
return self.socket.sendPacket(packet)

Sources/MQTT/ClientV5.swift

+7-8
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ extension MQTT{
2121
/// - clientID: Client Identifier
2222
/// - endpoint:The network endpoint
2323
/// - params: The connection parameters `default` is `.tls`
24-
public init(_ clientId: String, endpoint:NWEndpoint,params:NWParameters = .tls) {
25-
self.client = Client(clientId, endpoint: endpoint,params: params)
24+
public init(_ clientId: String, endpoint:Endpoint) {
25+
self.client = Client(clientId, endpoint: endpoint)
2626
self.client.config.version = .v5_0
2727
}
2828
}
@@ -83,7 +83,7 @@ extension MQTT.ClientV5{
8383
/// received. QoS1 and above return an `MQTTAckV5` which contains a `reason` and `properties`
8484
@discardableResult
8585
public func publish(to topic:String,payload:Data,qos:MQTTQoS = .atLeastOnce, retain:Bool = false,properties:Properties = []) ->Promise<AckV5?> {
86-
let message = Message(qos: qos, dup: false, topic: topic, retain: retain, payload: payload, properties: properties)
86+
let message = MQTT.Message(qos: qos, dup: false, topic: topic, retain: retain, payload: payload, properties: properties)
8787
let packet = PublishPacket(id: client.nextPacketId(),message: message)
8888
return client.publish(packet: packet)
8989
}
@@ -168,7 +168,7 @@ extension MQTT.ClientV5{
168168
) -> Promise<ConnackV5> {
169169

170170
let publish = will.map {
171-
Message(
171+
MQTT.Message(
172172
qos: .atMostOnce,
173173
dup: false,
174174
topic: $0.topic,
@@ -197,13 +197,12 @@ extension MQTT.ClientV5{
197197
}
198198
/// Close from server
199199
/// - Parameters:
200-
/// - code: close reason code send to the server
201-
/// - properties: properties to attach to disconnect packet
200+
/// - reason: close reason code send to the server
202201
/// - Returns: Future waiting on disconnect message to be sent
203202
///
204203
@discardableResult
205-
public func close(_ code:ReasonCode = .success,properties:Properties = [])->Promise<Void>{
206-
self.client.close(packet: DisconnectPacket(reason: code,properties: properties))
204+
public func close(_ reason:MQTT.CloseReason = .normalClose)->Promise<Void>{
205+
self.client.close(reason)
207206
}
208207
/// Re-authenticate with server
209208
///

Sources/MQTT/MQTTError.swift renamed to Sources/MQTT/Errors.swift

+15-22
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,11 @@
66
//
77

88
import Foundation
9-
9+
import Network
1010

1111

1212
/// MQTTClient errors
13-
public enum MQTTError: Error {
14-
/// Value returned in connection error
15-
public enum ConnectionReturnValue: UInt8, Sendable {
16-
/// connection was accepted
17-
case accepted = 0
18-
/// The Server does not support the version of the MQTT protocol requested by the Client.
19-
case unacceptableProtocolVersion = 1
20-
/// The Client Identifier is a valid string but is not allowed by the Server.
21-
case identifierRejected = 2
22-
/// The MQTT Server is not available.
23-
case serverUnavailable = 3
24-
/// The Server does not accept the User Name or Password specified by the Client
25-
case badUserNameOrPassword = 4
26-
/// The client is not authorized to connect
27-
case notAuthorized = 5
28-
/// Return code was unrecognised
29-
case unrecognizedReturnValue = 0xFF
30-
}
31-
13+
public enum MQTTError:Sendable,Equatable, Swift.Error {
3214
/// You called connect on a client that is already connected to the broker
3315
case alreadyConnected
3416
/// You called connect on a client that is already connected to the broker
@@ -38,7 +20,7 @@ public enum MQTTError: Error {
3820
/// We received an unexpected message while connecting
3921
case failedToConnect
4022
/// We received an unsuccessful connection return value
41-
case connectionError(ConnectionReturnValue)
23+
case connectionError(ConnectRetrunCode)
4224
/// We received an unsuccessful return value from either a connect or publish
4325
case reasonError(ReasonCode)
4426
/// client in not connected
@@ -69,7 +51,7 @@ public enum MQTTError: Error {
6951
}
7052

7153
/// Errors generated by bad packets sent by the client
72-
public enum MQTTPacketError:Swift.Error {
54+
public enum PacketError:Sendable,Equatable,Swift.Error {
7355
case badParameter
7456
/// Packet sent contained invalid entries
7557
/// QoS is not accepted by this connection as it is greater than the accepted value
@@ -85,3 +67,14 @@ public enum MQTTPacketError:Swift.Error {
8567
/// client to server publish packets cannot include a subscription identifier
8668
case publishIncludesSubscription
8769
}
70+
71+
public enum DecodeError:Sendable,Equatable,Swift.Error{
72+
/// Read variable length overflow
73+
case variableLengthOverflow
74+
/// some network error
75+
case networkError(_ error:NWError)
76+
/// got unexpected data length when read
77+
case unexpectedDataLength
78+
/// Failed to recognise the packet control type
79+
case unrecognisedPacketType
80+
}

Sources/MQTT/MQTT.swift

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ extension MQTT.Logger{
4343
case debug = 0, info, warning, error, off
4444
}
4545
}
46+
4647
/// Indicates the level of assurance for delivery of a packet.
4748
public enum MQTTQoS: UInt8, Sendable {
4849
/// fire and forget

0 commit comments

Comments
 (0)