Skip to content

Commit

Permalink
Merge pull request #1482 from smartdevicelink/bugfix/issue-1476-Secur…
Browse files Browse the repository at this point in the history
…ityManager-Set-For-SecondaryProtocol

Security manager set for secondary protocol
  • Loading branch information
joeljfischer committed Jan 7, 2020
2 parents 086250f + 256f03a commit 84b6518
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
24 changes: 20 additions & 4 deletions SmartDeviceLink/SDLSecondaryTransportManager.m
Expand Up @@ -18,6 +18,7 @@
#import "SDLLogMacros.h"
#import "SDLProtocol.h"
#import "SDLProtocolHeader.h"
#import "SDLNotificationConstants.h"
#import "SDLSecondaryTransportPrimaryProtocolHandler.h"
#import "SDLStateMachine.h"
#import "SDLTCPTransport.h"
Expand Down Expand Up @@ -94,6 +95,8 @@ @interface SDLSecondaryTransportManager ()
@property (strong, nonatomic, nullable) NSString *ipAddress;
// TCP port number of SDL Core. If the information isn't available then TCPPortUnspecified is stored.
@property (assign, nonatomic) int tcpPort;
// App is ready to set security manager to secondary protocol
@property (assign, nonatomic, getter=isAppReady) BOOL appReady;

@end

Expand All @@ -119,6 +122,8 @@ - (instancetype)initWithStreamingProtocolDelegate:(id<SDLStreamingProtocolDelega
@(SDLServiceTypeVideo):@(SDLTransportClassInvalid)} mutableCopy];
_tcpPort = TCPPortUnspecified;

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeReady) name:SDLDidBecomeReady object:nil];

return self;
}

Expand Down Expand Up @@ -224,8 +229,8 @@ - (void)didEnterStateStarted {
}

- (void)didEnterStateConfigured {
if ((self.secondaryTransportType == SDLSecondaryTransportTypeTCP && [self sdl_isTCPReady])
|| self.secondaryTransportType == SDLSecondaryTransportTypeIAP) {
if ((self.secondaryTransportType == SDLSecondaryTransportTypeTCP && [self sdl_isTCPReady] && self.isAppReady)
|| (self.secondaryTransportType == SDLSecondaryTransportTypeIAP && self.isAppReady)) {
[self.stateMachine transitionToState:SDLSecondaryTransportStateConnecting];
}
}
Expand Down Expand Up @@ -277,6 +282,7 @@ - (void)willTransitionFromStateRegisteredToStateStopped {
}

- (void)didEnterStateReconnecting {
self.appReady = NO;
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(RetryConnectionDelay * NSEC_PER_SEC)), _stateMachineQueue, ^{
if ([weakSelf.stateMachine isCurrentState:SDLSecondaryTransportStateReconnecting]) {
Expand Down Expand Up @@ -366,7 +372,7 @@ - (void)sdl_handleTransportEventUpdate {
return;
}

if ([self.stateMachine isCurrentState:SDLSecondaryTransportStateConfigured] && [self sdl_isTCPReady]) {
if ([self.stateMachine isCurrentState:SDLSecondaryTransportStateConfigured] && [self sdl_isTCPReady] && self.isAppReady) {
[self.stateMachine transitionToState:SDLSecondaryTransportStateConnecting];
} else if ([self sdl_isTransportOpened]) {
// Disconnect current transport. If the IP address is available then we will reconnect immediately.
Expand Down Expand Up @@ -507,6 +513,7 @@ - (BOOL)sdl_startTCPSecondaryTransport {
transport.delegate = protocol;
protocol.transport = transport;
[protocol.protocolDelegateTable addObject:self];
protocol.securityManager = self.primaryProtocol.securityManager;

self.secondaryProtocol = protocol;
self.secondaryTransport = transport;
Expand All @@ -529,6 +536,7 @@ - (BOOL)sdl_startIAPSecondaryTransport {
transport.delegate = protocol;
protocol.transport = transport;
[protocol.protocolDelegateTable addObject:self];
protocol.securityManager = self.primaryProtocol.securityManager;

self.secondaryProtocol = protocol;
self.secondaryTransport = transport;
Expand Down Expand Up @@ -648,7 +656,7 @@ - (void)sdl_onAppStateUpdated:(NSNotification *)notification {
}
} else if (notification.name == UIApplicationDidBecomeActiveNotification) {
if (([self.stateMachine isCurrentState:SDLSecondaryTransportStateConfigured])
&& self.secondaryTransportType == SDLSecondaryTransportTypeTCP && [self sdl_isTCPReady]) {
&& self.secondaryTransportType == SDLSecondaryTransportTypeTCP && [self sdl_isTCPReady] && self.isAppReady) {
SDLLogD(@"Resuming TCP transport since the app becomes foreground");
[self.stateMachine transitionToState:SDLSecondaryTransportStateConnecting];
}
Expand Down Expand Up @@ -705,6 +713,14 @@ - (SDLSecondaryTransportType)sdl_getTransportTypeFromProtocol:(SDLProtocol *)pro
}
}

- (void)appDidBecomeReady {
self.appReady = YES;
if (([self.stateMachine.currentState isEqualToString:SDLSecondaryTransportStateConfigured] && self.tcpPort != SDLControlFrameInt32NotFound && self.ipAddress != nil)
|| self.secondaryTransportType == SDLSecondaryTransportTypeIAP) {
[self.stateMachine transitionToState:SDLSecondaryTransportStateConnecting];
}
}

@end

NS_ASSUME_NONNULL_END
72 changes: 61 additions & 11 deletions SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m
Expand Up @@ -14,11 +14,13 @@
#import "SDLControlFramePayloadRPCStartServiceAck.h"
#import "SDLControlFramePayloadTransportEventUpdate.h"
#import "SDLIAPTransport.h"
#import "SDLNotificationConstants.h"
#import "SDLProtocol.h"
#import "SDLSecondaryTransportManager.h"
#import "SDLStateMachine.h"
#import "SDLTCPTransport.h"
#import "SDLV2ProtocolMessage.h"
#import "SDLFakeSecurityManager.h"

/* copied from SDLSecondaryTransportManager.m */
typedef NSNumber SDLServiceTypeBox;
Expand All @@ -45,13 +47,15 @@ @interface SDLSecondaryTransportManager ()

// we need to reach to private properties for the tests
@property (assign, nonatomic) SDLSecondaryTransportType secondaryTransportType;
@property (nullable, strong, nonatomic) SDLProtocol *primaryProtocol;
@property (nullable, strong, nonatomic) id<SDLTransportType> secondaryTransport;
@property (nullable, strong, nonatomic) SDLProtocol *secondaryProtocol;
@property (strong, nonatomic, nonnull) NSArray<SDLTransportClassBox *> *transportsForAudioService;
@property (strong, nonatomic, nonnull) NSArray<SDLTransportClassBox *> *transportsForVideoService;
@property (strong, nonatomic) NSMutableDictionary<SDLServiceTypeBox *, SDLTransportClassBox *> *streamingServiceTransportMap;
@property (strong, nonatomic, nullable) NSString *ipAddress;
@property (assign, nonatomic) int tcpPort;
@property (assign, nonatomic, getter=isAppReady) BOOL appReady;

@end

Expand Down Expand Up @@ -409,6 +413,7 @@ + (void)swapConnectionMethods {

testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
manager.appReady = YES;
});

it(@"should configure its properties and immediately transition to Connecting state", ^{
Expand Down Expand Up @@ -483,36 +488,58 @@ + (void)swapConnectionMethods {
});
});


describe(@"In Configured state", ^{
describe(@"if secondary transport is iAP", ^{
beforeEach(^{
// in this case we assume the primary transport is TCP
testPrimaryProtocol = [[SDLProtocol alloc] init];
testPrimaryTransport = [[SDLTCPTransport alloc] init];
testPrimaryProtocol.transport = testPrimaryTransport;

dispatch_sync(testStateMachineQueue, ^{
[manager startWithPrimaryProtocol:testPrimaryProtocol];
});

manager.secondaryTransportType = SDLTransportSelectionIAP;
});

it(@"should transition to Connecting state", ^{
// setToState cannot be used here, as the method will set the state after calling didEnterStateConfigured
dispatch_sync(testStateMachineQueue, ^{
[manager.stateMachine transitionToState:SDLSecondaryTransportStateConfigured];
});
});

expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConnecting));
OCMVerifyAll(testStreamingProtocolDelegate);
context(@"before the security manager is set by register app interface response", ^{
it(@"should stay in state Configured", ^{
expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConfigured));
expect(manager.secondaryProtocol.securityManager).to(beNil());
expect(manager.isAppReady).to(equal(NO));

OCMVerifyAll(testStreamingProtocolDelegate);
});
});

context(@"after the security manager is set by register app interface response", ^{
beforeEach(^{
testPrimaryProtocol.securityManager = OCMClassMock([SDLFakeSecurityManager class]);
// By the time this notification is recieved the RAIR should have been sent and the security manager should exist if available
[[NSNotificationCenter defaultCenter] postNotificationName:SDLDidBecomeReady object:nil];
});

it(@"should transition to Connecting state", ^{
expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConnecting));
expect(manager.secondaryProtocol.securityManager).to(equal(testPrimaryProtocol.securityManager));
expect(manager.isAppReady).to(equal(YES));

OCMVerifyAll(testStreamingProtocolDelegate);
});
});
});

describe(@"if secondary transport is TCP", ^{
beforeEach(^{
testPrimaryProtocol = [[SDLProtocol alloc] init];
testPrimaryTransport = [[SDLIAPTransport alloc] init];
testPrimaryProtocol.transport = testPrimaryTransport;

dispatch_sync(testStateMachineQueue, ^{
[manager startWithPrimaryProtocol:testPrimaryProtocol];
});
Expand All @@ -529,6 +556,7 @@ + (void)swapConnectionMethods {
describe(@"and Transport Event Update is not received", ^{
it(@"should stay in Configured state", ^{
expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConfigured));

OCMVerifyAll(testStreamingProtocolDelegate);
});
});
Expand All @@ -550,14 +578,33 @@ + (void)swapConnectionMethods {

testTransportEventUpdatePayload = [[SDLControlFramePayloadTransportEventUpdate alloc] initWithTcpIpAddress:testTcpIpAddress tcpPort:testTcpPort];
testTransportEventUpdateMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testTransportEventUpdateHeader andPayload:testTransportEventUpdatePayload.data];
});

it(@"should transition to Connecting state", ^{
[testPrimaryProtocol handleBytesFromTransport:testTransportEventUpdateMessage.data];
[NSThread sleepForTimeInterval:0.1];

expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConnecting));
OCMVerifyAll(testStreamingProtocolDelegate);
});

context(@"before the security manager is set by register app interface response", ^{
it(@"should stay in Configured state", ^{
expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConfigured));
expect(manager.secondaryProtocol.securityManager).to(beNil());
OCMVerifyAll(testStreamingProtocolDelegate);
});
});

context(@"after the security manager is set by register app interface response", ^{
beforeEach(^{
testPrimaryProtocol.securityManager = OCMClassMock([SDLFakeSecurityManager class]);
// By the time this notification is recieved the RAIR should have been sent and the security manager should exist if available
[[NSNotificationCenter defaultCenter] postNotificationName:SDLDidBecomeReady object:nil];
});

it(@"should transition to Connecting", ^{
expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateConnecting));
expect(manager.secondaryProtocol.securityManager).to(equal(testPrimaryProtocol.securityManager));

OCMVerifyAll(testStreamingProtocolDelegate);
});
});
});
});
Expand Down Expand Up @@ -585,7 +632,6 @@ + (void)swapConnectionMethods {
});
});


describe(@"In Connecting state", ^{
__block SDLProtocol *secondaryProtocol = nil;
__block id testSecondaryProtocolMock = nil;
Expand Down Expand Up @@ -685,6 +731,7 @@ + (void)swapConnectionMethods {
[NSThread sleepForTimeInterval:0.1];

expect(manager.stateMachine.currentState).to(equal(SDLSecondaryTransportStateReconnecting));
expect(manager.isAppReady).to(equal(NO));
OCMVerifyAll(testStreamingProtocolDelegate);
});
});
Expand Down Expand Up @@ -729,6 +776,7 @@ + (void)swapConnectionMethods {
beforeEach(^{
testTcpIpAddress = @"172.16.12.34";
testTcpPort = 12345;
manager.appReady = YES;

testTransportEventUpdatePayload = [[SDLControlFramePayloadTransportEventUpdate alloc] initWithTcpIpAddress:testTcpIpAddress tcpPort:testTcpPort];
testTransportEventUpdateMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testTransportEventUpdateHeader andPayload:testTransportEventUpdatePayload.data];
Expand Down Expand Up @@ -816,6 +864,7 @@ + (void)swapConnectionMethods {
manager.secondaryTransportType = SDLTransportSelectionTCP;
manager.ipAddress = @"192.168.1.1";
manager.tcpPort = 12345;
manager.appReady = YES;

testTransportEventUpdateHeader = [SDLProtocolHeader headerForVersion:5];
testTransportEventUpdateHeader.frameType = SDLFrameTypeControl;
Expand Down Expand Up @@ -974,6 +1023,7 @@ + (void)swapConnectionMethods {
manager.secondaryTransportType = SDLTransportSelectionTCP;
manager.ipAddress = @"192.168.1.1";
manager.tcpPort = 12345;
manager.appReady = YES;

testTransportEventUpdateHeader = [SDLProtocolHeader headerForVersion:5];
testTransportEventUpdateHeader.frameType = SDLFrameTypeControl;
Expand Down

0 comments on commit 84b6518

Please sign in to comment.