Skip to content

Commit

Permalink
>Release date: 2015-08-25
Browse files Browse the repository at this point in the history
[NEW] MQTTSessionManager init with Persistence settings
[NEW] MQTTSessionManager with optional SSL security policy
  • Loading branch information
Christoph Krey committed Aug 25, 2015
1 parent 38cc064 commit bee66fc
Show file tree
Hide file tree
Showing 32 changed files with 596 additions and 141 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
MQTT-Client-Framework iOS Release Notes
=======================================

## MQTT-Client-Framework 0.2.6
>Release date: 2015-08-25
[NEW] MQTTSessionManager init with Persistence settings
[NEW] MQTTSessionManager with optional SSL security policy

## MQTT-Client-Framework 0.2.5
>Release date: 2015-08-22
Expand Down
4 changes: 2 additions & 2 deletions MQTTClient.podspec
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = "MQTTClient"
s.version = "0.2.5"
s.version = "0.2.6"
s.summary = "IOS native ObjectiveC MQTT Framework"
s.homepage = "https://github.com/ckrey/MQTT-Client-Framework"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Christoph Krey" => "krey.christoph@gmail.com" }
s.source = { :git => "https://github.com/ckrey/MQTT-Client-Framework.git", :tag => "0.2.5" }
s.source = { :git => "https://github.com/ckrey/MQTT-Client-Framework.git", :tag => "0.2.6" }

s.source_files = "MQTTClient/MQTTClient", "MQTTClient/MQTTClient/**/*.{h,m}"
s.requires_arc = true
Expand Down
12 changes: 6 additions & 6 deletions MQTTClient/MQTTClient/MQTTPersistence.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@

- (NSUInteger)windowSize:(NSString *)clientId;
- (MQTTFlow *)storeMessageForClientId:(NSString *)clientId
topic:(NSString *)topic
data:(NSData *)data
retainFlag:(BOOL)retainFlag
qos:(MQTTQosLevel)qos
msgId:(UInt16)msgId
incomingFlag:(BOOL)incomingFlag;
topic:(NSString *)topic
data:(NSData *)data
retainFlag:(BOOL)retainFlag
qos:(MQTTQosLevel)qos
msgId:(UInt16)msgId
incomingFlag:(BOOL)incomingFlag;

- (void)deleteFlow:(MQTTFlow *)flow;
- (void)deleteAllFlowsForClientId:(NSString *)clientId;
Expand Down
89 changes: 68 additions & 21 deletions MQTTClient/MQTTClient/MQTTSessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ typedef NS_ENUM(int, MQTTSessionManagerState) {
MQTTSessionManagerStateClosed
};



/** gets called when a new message was received
@param data the data received, might be zero length
@param topic the topic the data was published to
Expand Down Expand Up @@ -60,23 +58,73 @@ typedef NS_ENUM(int, MQTTSessionManagerState) {
*/
@property (nonatomic, readonly) NSError *lastErrorCode;

/** initWithPersistence sets the MQTTPersistence properties other than default
* @param persistent YES or NO (default) to establish file or in memory persistence.
* @param maxWindowSize (a positive number, default is 16) to control the number of messages sent before waiting for acknowledgement in Qos 1 or 2. Additional messages are stored and transmitted later.
* @param maxSize (a positive number of bytes, default is 64 MB) to limit the size of the persistence file. Messages published after the limit is reached are dropped.
* @param maxMessages (a positive number, default is 1024) to limit the number of messages stored. Additional messages published are dropped.
* @return the initialized MQTTSessionManager object
*/

- (MQTTSessionManager *)initWithPersistence:(BOOL)persistent
maxWindowSize:(NSUInteger)maxWindowSize
maxMessages:(NSUInteger)maxMessages
maxSize:(NSUInteger)maxSize;



/** Connects to the MQTT broker and stores the parameters for subsequent reconnects
* @param host specifies the hostname or ip address to connect to. Defaults to @"localhost".
* @param port spefies the port to connect to
* @param port specifies the port to connect to
* @param tls specifies whether to use SSL or not
* @param keepalive The Keep Alive is a time interval measured in seconds. The MQTTClient ensures that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client sends a PINGREQ Packet.
* @param clean specifies if the server should discard previous session information.
* @param auth specifies the user and pass parameters should be used for authenthication
* @param user an NSString object containing the user's name (or ID) for authentication. May be nil.
* @param pass an NSString object containing the user's password. If userName is nil, password must be nil as well.
* @param will indicates whether a will shall be sent
* @param willTopic the Will Topic is a string, must not be nil
* @param willMsg the Will Message, might be zero length
* @param willTopic the Will Topic is a string, may be nil
* @param willMsg the Will Message, might be zero length or nil
* @param willQos specifies the QoS level to be used when publishing the Will Message.
* @param willRetainFlag indicates if the server should publish the Will Messages with retainFlag.
* @param clientId The Client Identifier identifies the Client to the Server. If nil, a random clientId is generated.
* @return the initialised MQTTSessionManager object
*/
* @param securityPolicy A custom SSL security policy or nil.
* @param certificates An NSArray of the pinned certificates to use or nil.
*/

- (void)connectTo:(NSString *)host
port:(NSInteger)port
tls:(BOOL)tls
keepalive:(NSInteger)keepalive
clean:(BOOL)clean
auth:(BOOL)auth
user:(NSString *)user
pass:(NSString *)pass
will:(BOOL)will
willTopic:(NSString *)willTopic
willMsg:(NSData *)willMsg
willQos:(MQTTQosLevel)willQos
willRetainFlag:(BOOL)willRetainFlag
withClientId:(NSString *)clientId
securityPolicy:(MQTTSSLSecurityPolicy *)securityPolicy
certificates:(NSArray *)certificates;

/** Convenience alternative to full paramter connectTo
* @param host see connectTo description
* @param port see connectTo description
* @param tls see connectTo description
* @param keepalive see connectTo description
* @param clean see connectTo description
* @param auth see connectTo description
* @param user see connectTo description
* @param pass see connectTo description
* @param will see connectTo description
* @param willTopic see connectTo description
* @param willMsg see connectTo description
* @param willQos see connectTo description
* @param willRetainFlag see connectTo description
* @param clientId see connectTo description
*/

- (void)connectTo:(NSString *)host
port:(NSInteger)port
Expand All @@ -93,24 +141,23 @@ typedef NS_ENUM(int, MQTTSessionManagerState) {
willRetainFlag:(BOOL)willRetainFlag
withClientId:(NSString *)clientId;

/** Connects to the MQTT broker and stores the parameters for subsequent reconnects
* @param host specifies the hostname or ip address to connect to. Defaults to @"localhost".
* @param port spefies the port to connect to
* @param tls specifies whether to use SSL or not
* @param keepalive The Keep Alive is a time interval measured in seconds. The MQTTClient ensures that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client sends a PINGREQ Packet.
* @param clean specifies if the server should discard previous session information.
* @param auth specifies the user and pass parameters should be used for authenthication
* @param user an NSString object containing the user's name (or ID) for authentication. May be nil.
* @param pass an NSString object containing the user's password. If userName is nil, password must be nil as well.
/** Convenience alternative to full paramter connectTo
* @param host see connectTo description
* @param port see connectTo description
* @param tls see connectTo description
* @param keepalive see connectTo description
* @param clean see connectTo description
* @param auth see connectTo description
* @param user see connectTo description
* @param pass see connectTo description
* @param willTopic the Will Topic is a string, must not be nil
* @param will the Will Message, might be zero length
* @param willQos specifies the QoS level to be used when publishing the Will Message.
* @param willRetainFlag indicates if the server should publish the Will Messages with retainFlag.
* @param clientId The Client Identifier identifies the Client to the Server. If nil, a random clientId is generated.
* @return the initialised MQTTSessionManager object
* @param willQos see connectTo description
* @param willRetainFlag see connectTo description
* @param clientId see connectTo description
*/

- (void)connectTo:(NSString *)host
- (void)connectTo:(NSString *)host
port:(NSInteger)port
tls:(BOOL)tls
keepalive:(NSInteger)keepalive
Expand Down
71 changes: 68 additions & 3 deletions MQTTClient/MQTTClient/MQTTSessionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ @interface MQTTSessionManager()
@property (nonatomic) NSInteger willQos;
@property (nonatomic) BOOL willRetainFlag;
@property (strong, nonatomic) NSString *clientId;
@property (strong, nonatomic) MQTTSSLSecurityPolicy *securityPolicy;
@property (strong, nonatomic) NSArray *certificates;

@property (strong, nonatomic) NSTimer *disconnectTimer;
@property (strong, nonatomic) NSTimer *activityTimer;
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
@property (strong, nonatomic) void (^completionHandler)(UIBackgroundFetchResult);

@property (nonatomic) BOOL persistent;
@property (nonatomic) NSUInteger maxWindowSize;
@property (nonatomic) NSUInteger maxSize;
@property (nonatomic) NSUInteger maxMessages;

@end

#define RECONNECT_TIMER 1.0
Expand All @@ -49,7 +56,6 @@ - (id)init
{
self = [super init];


self.state = MQTTSessionManagerStateStarting;
self.backgroundTask = UIBackgroundTaskInvalid;
self.completionHandler = nil;
Expand All @@ -73,6 +79,18 @@ - (id)init
return self;
}

- (MQTTSessionManager *)initWithPersistence:(BOOL)persistent
maxWindowSize:(NSUInteger)maxWindowSize
maxMessages:(NSUInteger)maxMessages
maxSize:(NSUInteger)maxSize {
self = [self init];
self.persistent = persistent;
self.maxWindowSize = maxWindowSize;
self.maxSize = maxSize;
self.maxMessages = maxMessages;
return self;
}

- (void)appWillResignActive
{
[self disconnect];
Expand Down Expand Up @@ -137,6 +155,41 @@ - (void)connectTo:(NSString *)host
willQos:(MQTTQosLevel)willQos
willRetainFlag:(BOOL)willRetainFlag
withClientId:(NSString *)clientId
{
[self connectTo:host
port:port
tls:tls
keepalive:keepalive
clean:clean
auth:auth
user:user
pass:pass
will:will
willTopic:willTopic
willMsg:willMsg
willQos:willQos
willRetainFlag:willRetainFlag
withClientId:clientId
securityPolicy:nil
certificates:nil];
}

- (void)connectTo:(NSString *)host
port:(NSInteger)port
tls:(BOOL)tls
keepalive:(NSInteger)keepalive
clean:(BOOL)clean
auth:(BOOL)auth
user:(NSString *)user
pass:(NSString *)pass
will:(BOOL)will
willTopic:(NSString *)willTopic
willMsg:(NSData *)willMsg
willQos:(MQTTQosLevel)willQos
willRetainFlag:(BOOL)willRetainFlag
withClientId:(NSString *)clientId
securityPolicy:(MQTTSSLSecurityPolicy *)securityPolicy
certificates:(NSArray *)certificates
{
if (!self.session ||
![host isEqualToString:self.host] ||
Expand All @@ -151,7 +204,9 @@ - (void)connectTo:(NSString *)host
![willMsg isEqualToData:self.willMsg] ||
willQos != self.willQos ||
willRetainFlag != self.willRetainFlag ||
![clientId isEqualToString:self.clientId]) {
![clientId isEqualToString:self.clientId] ||
securityPolicy != self.securityPolicy ||
certificates != self.certificates) {
self.host = host;
self.port = (int)port;
self.tls = tls;
Expand All @@ -166,6 +221,8 @@ - (void)connectTo:(NSString *)host
self.willQos = willQos;
self.willRetainFlag = willRetainFlag;
self.clientId = clientId;
self.securityPolicy = securityPolicy;
self.certificates = certificates;

self.session = [[MQTTSession alloc] initWithClientId:clientId
userName:auth ? user : nil
Expand All @@ -179,7 +236,15 @@ - (void)connectTo:(NSString *)host
willRetainFlag:willRetainFlag
protocolLevel:4
runLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
forMode:NSDefaultRunLoopMode
securityPolicy:securityPolicy
certificates:certificates];

self.session.persistence.persistent = self.persistent;
self.session.persistence.maxWindowSize = self.maxWindowSize;
self.session.persistence.maxSize = self.maxSize;
self.session.persistence.maxMessages = self.maxMessages;

self.session.delegate = self;
self.reconnectTime = RECONNECT_TIMER;
self.reconnectFlag = FALSE;
Expand Down
84 changes: 84 additions & 0 deletions MQTTClient/MQTTClientTests/MQTTSessionManagerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,88 @@ - (void)timeout:(NSTimer *)timer {
self.step++;
}

- (void)testMQTTSessionManagerPersistent {
for (NSString *broker in BROKERLIST) {
NSLog(@"testing broker %@", broker);
NSDictionary *parameters = BROKERS[broker];

self.step = -1;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:[parameters[@"timeout"] intValue]
target:self
selector:@selector(timeout:)
userInfo:nil
repeats:true];

self.received = 0;
MQTTSessionManager *manager = [[MQTTSessionManager alloc] initWithPersistence:true
maxWindowSize:2
maxMessages:1024
maxSize:64*1024*1024];
manager.delegate = self;
manager.subscriptions = [@{@"#": @(0)} mutableCopy];
[manager connectTo:parameters[@"host"]
port:[parameters[@"port"] intValue]
tls:[parameters[@"tls"] boolValue]
keepalive:60
clean:TRUE
auth:NO
user:nil
pass:nil
will:NO
willTopic:nil
willMsg:nil
willQos:MQTTQosLevelAtMostOnce
willRetainFlag:FALSE
withClientId:@"MQTTSessionManager"];
while (self.step == -1 && manager.state != MQTTSessionManagerStateConnected) {
NSLog(@"waiting for connect %d", manager.state);
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(manager.state, MQTTSessionManagerStateConnected);

while (self.step <= 0) {
NSLog(@"received %d on #", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelExactlyOnce retain:FALSE];
self.sent++;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{@"#": @(0),@"$SYS/#": @(0)} mutableCopy];
while (self.step == 1) {
NSLog(@"received %d on # or $SYS/#", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelExactlyOnce retain:FALSE];
self.sent++;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{@"$SYS/#": @(0)} mutableCopy];
while (self.step <= 2) {
NSLog(@"received %d on $SYS/#", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelExactlyOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{} mutableCopy];
while (self.step <= 3) {
NSLog(@"received %d on nothing", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelExactlyOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]];
}
XCTAssertEqual(self.received, self.sent);

[manager disconnect];
while (self.step <= 4) {
NSLog(@"received %d after disconnect", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelExactlyOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]];
}
XCTAssertEqual(self.received, self.sent);
[timer invalidate];
}
}


@end
Loading

0 comments on commit bee66fc

Please sign in to comment.