summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2021-04-28 10:19:28 -0400
committerGitHub <noreply@github.com>2021-04-28 10:19:28 -0400
commit0b61d8490e57b3cf4cc2ef10e56b49e6e327fa5c (patch)
tree392abda4c5167cc6bbe00e7efab4785f1def7c98
parent85b5fa8b663f7cc8c36f27e63d984a4d02227d0f (diff)
parent6f5565403f723fd8705e3863a7a1812630ab616d (diff)
downloadsdl_ios-hotfix/7.1.1.tar.gz
Merge pull request #1955 from smartdevicelink/bugfix/issue-1954-rpc-encryption-multi-framehotfix/7.1.1
Support TLS max size when encrypted
-rw-r--r--SmartDeviceLink/private/SDLProtocol.m101
-rw-r--r--SmartDeviceLink/private/SDLProtocolMessage.m2
-rw-r--r--SmartDeviceLink/private/SDLProtocolMessageAssembler.m19
-rw-r--r--SmartDeviceLink/private/SDLProtocolMessageDisassembler.h6
-rw-r--r--SmartDeviceLink/private/SDLProtocolMessageDisassembler.m50
-rw-r--r--SmartDeviceLink/private/SDLV2ProtocolHeader.m2
-rw-r--r--SmartDeviceLink/public/SDLProtocolConstants.h2
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m186
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLProtocolMessageDisassemblerSpec.m166
m---------generator/rpc_spec0
10 files changed, 347 insertions, 187 deletions
diff --git a/SmartDeviceLink/private/SDLProtocol.m b/SmartDeviceLink/private/SDLProtocol.m
index a2f8cc021..8f87bbdfb 100644
--- a/SmartDeviceLink/private/SDLProtocol.m
+++ b/SmartDeviceLink/private/SDLProtocol.m
@@ -34,7 +34,8 @@
#import "SDLV2ProtocolHeader.h"
NSString *const SDLProtocolSecurityErrorDomain = @"com.sdl.protocol.security";
-
+static const NSUInteger TLSMaxDataSize = 16834;
+static const NSUInteger TLSMaxRPCPayloadDataToEncryptSize = 16384 /*TLS Max Record Size*/ - 5 /*TLS Record Header Size*/ - 32 /*TLS MES Auth CDE Size*/ - 256 /*TLS Max Record Padding Size*/;
#pragma mark - SDLProtocol Private Interface
@@ -82,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
_transport.delegate = self;
_encryptionLifecycleManager = encryptionManager;
-
+
return self;
}
@@ -185,7 +186,7 @@ NS_ASSUME_NONNULL_BEGIN
// TLS initialization succeeded. Build and send the message.
SDLProtocolMessage *message = [self sdl_createStartServiceMessageWithType:serviceType encrypted:YES payload:nil];
- SDLLogD(@"TLS initialized, sending start service for message: %@", message);
+ SDLLogD(@"TLS initialized, sending start service with encryption for message: %@", message);
[self sdl_sendDataToTransport:message.data onService:serviceType];
}];
}
@@ -309,7 +310,7 @@ NS_ASSUME_NONNULL_BEGIN
*error = jsonError;
return NO;
}
-
+
NSData *messagePayload = nil;
SDLLogV(@"Sending RPC: %@", message);
@@ -346,27 +347,7 @@ NS_ASSUME_NONNULL_BEGIN
return NO;
}
- // If we're trying to encrypt, try to have the security manager encrypt it. Return if it fails.
- NSError *encryptError = nil;
- if (encryption) {
- messagePayload = [self.securityManager encryptData:rpcPayload.data withError:&encryptError];
-
- if (encryptError != nil) {
- SDLLogE(@"Error encrypting request! %@", encryptError);
- }
- } else {
- messagePayload = rpcPayload.data;
- }
-
- // If the encryption failed, pass back the error and return false
- if (!messagePayload) {
- if (encryptError != nil) {
- *error = encryptError;
- } else {
- *error = [NSError sdl_encryption_unknown];
- }
- return NO;
- }
+ messagePayload = rpcPayload.data;
} break;
default: {
NSAssert(NO, @"Attempting to send an RPC based on an unknown version number: %@, message: %@", @([SDLGlobals sharedGlobals].protocolVersion.major), message);
@@ -389,14 +370,57 @@ NS_ASSUME_NONNULL_BEGIN
SDLProtocolMessage *protocolMessage = [SDLProtocolMessage messageWithHeader:header andPayload:messagePayload];
// See if the message is small enough to send in one transmission. If not, break it up into smaller messages and send.
- if (protocolMessage.size < [[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeRPC]) {
- SDLLogV(@"Sending protocol message: %@", protocolMessage);
- [self sdl_sendDataToTransport:protocolMessage.data onService:SDLServiceTypeRPC];
+ NSUInteger rpcMTUSize = [[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeRPC];
+ NSUInteger mtuSize = (encryption ? MIN(TLSMaxRPCPayloadDataToEncryptSize, rpcMTUSize) : rpcMTUSize);
+ NSArray<SDLProtocolMessage *> *protocolMessages = nil;
+ if (protocolMessage.size < mtuSize) {
+ protocolMessages = @[protocolMessage];
} else {
- NSArray<SDLProtocolMessage *> *messages = [SDLProtocolMessageDisassembler disassemble:protocolMessage withLimit:[[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeRPC]];
- for (SDLProtocolMessage *smallerMessage in messages) {
- SDLLogV(@"Sending protocol message: %@", smallerMessage);
- [self sdl_sendDataToTransport:smallerMessage.data onService:SDLServiceTypeRPC];
+ protocolMessages = [SDLProtocolMessageDisassembler disassemble:protocolMessage withMTULimit:mtuSize];
+ }
+
+ // If the message should be encrypted, encrypt the payloads
+ if (encryption) {
+ BOOL success = [self sdl_encryptProtocolMessages:protocolMessages error:error];
+ if (!success) {
+ SDLLogE(@"Error encrypting protocol messages. Messages will not be sent. Error: %@", *error);
+ return NO;
+ }
+ }
+
+ // Send each message
+ for (SDLProtocolMessage *message in protocolMessages) {
+ SDLLogV(@"Sending protocol message: %@", message);
+ [self sdl_sendDataToTransport:message.data onService:SDLServiceTypeRPC];
+ }
+
+ return YES;
+}
+
+/// Receives an array of `SDLProtocolMessage` and attempts to encrypt their payloads in place through the active security manager. If anything fails, it will return NO and pass back the error.
+/// @param protocolMessages The array of protocol messages to encrypt.
+/// @param error A passback error object if attempting to encrypt the protocol message payloads fails.
+/// @returns YES if the encryption was successful, NO if it was not
+- (BOOL)sdl_encryptProtocolMessages:(NSArray<SDLProtocolMessage *> *)protocolMessages error:(NSError *__autoreleasing *)error {
+ for (SDLProtocolMessage *message in protocolMessages) {
+ if (message.header.frameType == SDLFrameTypeFirst) { continue; }
+
+ // If we're trying to encrypt, try to have the security manager encrypt it. Return if it fails.
+ NSError *encryptError = nil;
+ NSData *encryptedMessagePayload = [self.securityManager encryptData:message.payload withError:&encryptError];
+
+ // If the encryption failed, pass back the error and return false
+ if (encryptedMessagePayload.length == 0 || encryptError != nil) {
+ if (encryptError != nil) {
+ *error = encryptError;
+ } else {
+ *error = [NSError sdl_encryption_unknown];
+ }
+
+ return NO;
+ } else {
+ message.payload = encryptedMessagePayload;
+ message.header.bytesInPayload = (UInt32)encryptedMessagePayload.length;
}
}
@@ -418,7 +442,16 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)sendEncryptedRawData:(NSData *)data onService:(SDLServiceType)serviceType {
- [self sdl_sendRawData:data onService:serviceType encryption:YES];
+ // Break up data larger than the max TLS size so the data can be encrypted by the security manager without failing due to the data size being too big
+ NSUInteger offset = 0;
+ do {
+ NSUInteger remainingDataLength = data.length - offset;
+ NSUInteger chunkSize = (remainingDataLength > TLSMaxDataSize) ? TLSMaxDataSize : remainingDataLength;
+ NSData *chunk = [NSData dataWithBytesNoCopy:(BytePtr)data.bytes + offset length:chunkSize freeWhenDone:NO];
+
+ [self sdl_sendRawData:chunk onService:serviceType encryption:YES];
+ offset += chunkSize;
+ } while (offset < data.length);
}
- (void)sdl_sendRawData:(NSData *)data onService:(SDLServiceType)service encryption:(BOOL)encryption {
@@ -444,7 +477,7 @@ NS_ASSUME_NONNULL_BEGIN
SDLLogV(@"Sending protocol message: %@", message);
[self sdl_sendDataToTransport:message.data onService:header.serviceType];
} else {
- NSArray<SDLProtocolMessage *> *messages = [SDLProtocolMessageDisassembler disassemble:message withLimit:[[SDLGlobals sharedGlobals] mtuSizeForServiceType:service]];
+ NSArray<SDLProtocolMessage *> *messages = [SDLProtocolMessageDisassembler disassemble:message withMTULimit:[[SDLGlobals sharedGlobals] mtuSizeForServiceType:service]];
for (SDLProtocolMessage *smallerMessage in messages) {
SDLLogV(@"Sending protocol message: %@", smallerMessage);
[self sdl_sendDataToTransport:smallerMessage.data onService:header.serviceType];
diff --git a/SmartDeviceLink/private/SDLProtocolMessage.m b/SmartDeviceLink/private/SDLProtocolMessage.m
index 6ed86e05d..7e2da7d0c 100644
--- a/SmartDeviceLink/private/SDLProtocolMessage.m
+++ b/SmartDeviceLink/private/SDLProtocolMessage.m
@@ -55,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
[description appendString:self.header.description];
if (self.header.encrypted) {
- [description appendString:@", Payload is encrypted - no description can be provided"];
+ [description appendString:@"Payload is encrypted - no description can be provided"];
return description;
}
diff --git a/SmartDeviceLink/private/SDLProtocolMessageAssembler.m b/SmartDeviceLink/private/SDLProtocolMessageAssembler.m
index e02ead324..e4a07541c 100644
--- a/SmartDeviceLink/private/SDLProtocolMessageAssembler.m
+++ b/SmartDeviceLink/private/SDLProtocolMessageAssembler.m
@@ -32,13 +32,12 @@ NS_ASSUME_NONNULL_BEGIN
}
if (self.parts == nil) {
- self.parts = [NSMutableDictionary new];
+ self.parts = [NSMutableDictionary dictionary];
}
// Determine which frame it is and save it.
- // Note: frames are numbered 1,2,3, ..., 0
- // Always 0 for last frame.
+ // Note: frames are numbered 1,2,3, ..., 0. Always 0 for last frame.
if (message.header.frameType == SDLFrameTypeFirst) {
// If it's the first-frame, extract the meta-data
self.expectedBytes = NSSwapBigIntToHost(((UInt32 *)message.payload.bytes)[0]);
@@ -51,27 +50,23 @@ NS_ASSUME_NONNULL_BEGIN
self.parts[frameNumberObj] = message.payload;
}
-
- //
// If we have all the parts, assemble it and execute the completion handler.
- //
SDLProtocolMessage *assembledMessage = nil;
if (self.parts.count == self.frameCount + 1) { // +1 since we also require the first-frame
-
// Create the header
SDLProtocolHeader *header = message.header.copy;
header.frameType = SDLFrameTypeSingle;
header.frameData = SDLFrameInfoSingleFrame;
-
// Create the payload
- NSMutableData *payload = [[NSMutableData alloc] init];
+ NSMutableData *payload = [NSMutableData data];
for (unsigned int i = 1; i < self.frameCount; i++) {
- NSData *dataToAppend = [self.parts objectForKey:[NSNumber numberWithUnsignedInt:i]];
+ NSData *dataToAppend = self.parts[@(i)];
[payload appendData:dataToAppend];
}
+
// Append the last frame, it has a frame # of 0.
- NSData *dataToAppend = [self.parts objectForKey:[NSNumber numberWithUnsignedInt:0]];
+ NSData *dataToAppend = self.parts[@0];
[payload appendData:dataToAppend];
// Validation
@@ -82,7 +77,6 @@ NS_ASSUME_NONNULL_BEGIN
// Create the message.
assembledMessage = [SDLProtocolMessage messageWithHeader:header andPayload:payload];
-
// Execute completion handler.
if (completionHandler != nil) {
completionHandler(YES, assembledMessage);
@@ -90,7 +84,6 @@ NS_ASSUME_NONNULL_BEGIN
// Done with this data, release it.
self.parts = nil;
-
} else {
// Not done, let caller know
if (completionHandler != nil) {
diff --git a/SmartDeviceLink/private/SDLProtocolMessageDisassembler.h b/SmartDeviceLink/private/SDLProtocolMessageDisassembler.h
index 644b1c1de..8deabf8db 100644
--- a/SmartDeviceLink/private/SDLProtocolMessageDisassembler.h
+++ b/SmartDeviceLink/private/SDLProtocolMessageDisassembler.h
@@ -9,7 +9,11 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLProtocolMessageDisassembler : NSObject
-+ (NSArray<SDLProtocolMessage *> *)disassemble:(SDLProtocolMessage *)protocolMessage withLimit:(NSUInteger)mtu;
+/// Use to break up a large message into a sequence of smaller messages, each of which is less than 'mtu' number of bytes total size.
+///
+/// @param protocolMessage The message to break up
+/// @param mtu The MTU size to use to determine where to break up the message payload
++ (NSArray<SDLProtocolMessage *> *)disassemble:(SDLProtocolMessage *)protocolMessage withMTULimit:(NSUInteger)mtu;
@end
diff --git a/SmartDeviceLink/private/SDLProtocolMessageDisassembler.m b/SmartDeviceLink/private/SDLProtocolMessageDisassembler.m
index 21ab55f63..a8b77c806 100644
--- a/SmartDeviceLink/private/SDLProtocolMessageDisassembler.m
+++ b/SmartDeviceLink/private/SDLProtocolMessageDisassembler.m
@@ -9,25 +9,18 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLProtocolMessageDisassembler
++ (NSArray<SDLProtocolMessage *> *)disassemble:(SDLProtocolMessage *)protocolMessage withMTULimit:(NSUInteger)mtu {
+ if (protocolMessage.size < mtu) {
+ return @[protocolMessage];
+ }
-// Use to break up a large message into a sequence of smaller messages,
-// each of which is less than 'mtu' number of bytes total size.
-+ (NSArray<SDLProtocolMessage *> *)disassemble:(SDLProtocolMessage *)incomingMessage withLimit:(NSUInteger)mtu {
- // Questions:
- // What message IDs does the current system use? Same messageIDs? Same CorrelationIDs?
- // What gets simply copied from incoming header to created headers; and what needs adjustment?
-
- // How big is the message header?
- NSUInteger headerSize = incomingMessage.header.size;
-
- // The size of the message is too big to send in one chunk.
- // So lets break it up.
- // Just how big IS this message?
- NSUInteger incomingPayloadSize = (incomingMessage.data.length - headerSize);
+ // How big is the message header and payload?
+ NSUInteger headerSize = protocolMessage.header.size;
+ NSUInteger payloadSize = (protocolMessage.data.length - headerSize);
// How many messages do we need to create to hold that many bytes?
- // Note: this does NOT count the special first message which acts as a descriptor.
- NSUInteger numberOfMessagesRequired = (NSUInteger)ceil((float)incomingPayloadSize / (float)(mtu - headerSize));
+ // Note: This does NOT count the special first message which acts as a descriptor.
+ NSUInteger numberOfMessagesRequired = (NSUInteger)ceilf((float)payloadSize / (float)(mtu - headerSize));
// And how many data bytes go in each message?
NSUInteger numberOfDataBytesPerMessage = mtu - headerSize;
@@ -35,48 +28,45 @@ NS_ASSUME_NONNULL_BEGIN
// Create the outgoing array to hold the messages we will create.
NSMutableArray<SDLProtocolMessage *> *outgoingMessages = [NSMutableArray arrayWithCapacity:numberOfMessagesRequired + 1];
-
- // Create the first message
- SDLProtocolHeader *firstFrameHeader = [incomingMessage.header copy];
+ // Create the first message, which cannot be encrypted because it needs to be exactly 8 bytes
+ SDLProtocolHeader *firstFrameHeader = [protocolMessage.header copy];
firstFrameHeader.frameType = SDLFrameTypeFirst;
+ firstFrameHeader.encrypted = NO;
UInt32 payloadData[2];
- payloadData[0] = CFSwapInt32HostToBig((UInt32)incomingMessage.payload.length);
+ payloadData[0] = CFSwapInt32HostToBig((UInt32)protocolMessage.payload.length);
payloadData[1] = CFSwapInt32HostToBig((UInt32)numberOfMessagesRequired);
NSMutableData *firstFramePayload = [NSMutableData dataWithBytes:payloadData length:sizeof(payloadData)];
SDLProtocolMessage *firstMessage = [SDLProtocolMessage messageWithHeader:firstFrameHeader andPayload:firstFramePayload];
- outgoingMessages[0] = firstMessage;
-
+ [outgoingMessages addObject:firstMessage];
// Create the middle messages (the ones carrying the actual data).
for (NSUInteger n = 0; n < numberOfMessagesRequired - 1; n++) {
- // Frame # after 255 must cycle back to 1, not 0.
- // A 0 signals last frame.
+ // Frame # after 255 must cycle back to 1, not 0. A 0 signals last frame (SDLFrameInfoConsecutiveLastFrame).
UInt8 frameNumber = (n % 255) + 1;
- SDLProtocolHeader *nextFrameHeader = [incomingMessage.header copy];
+ SDLProtocolHeader *nextFrameHeader = [protocolMessage.header copy];
nextFrameHeader.frameType = SDLFrameTypeConsecutive;
nextFrameHeader.frameData = frameNumber;
NSUInteger offsetOfDataForThisFrame = headerSize + (n * numberOfDataBytesPerMessage);
- NSData *nextFramePayload = [incomingMessage.data subdataWithRange:NSMakeRange(offsetOfDataForThisFrame, numberOfDataBytesPerMessage)];
+ NSData *nextFramePayload = [protocolMessage.data subdataWithRange:NSMakeRange(offsetOfDataForThisFrame, numberOfDataBytesPerMessage)];
SDLProtocolMessage *nextMessage = [SDLProtocolMessage messageWithHeader:nextFrameHeader andPayload:nextFramePayload];
outgoingMessages[n + 1] = nextMessage;
}
-
// Create the last message
- SDLProtocolHeader *lastFrameHeader = [incomingMessage.header copy];
+ SDLProtocolHeader *lastFrameHeader = [protocolMessage.header copy];
lastFrameHeader.frameType = SDLFrameTypeConsecutive;
lastFrameHeader.frameData = SDLFrameInfoConsecutiveLastFrame;
NSUInteger numberOfMessagesCreatedSoFar = numberOfMessagesRequired - 1;
NSUInteger numberOfDataBytesSentSoFar = numberOfMessagesCreatedSoFar * numberOfDataBytesPerMessage;
- NSUInteger numberOfDataBytesInLastMessage = incomingPayloadSize - numberOfDataBytesSentSoFar;
+ NSUInteger numberOfDataBytesInLastMessage = payloadSize - numberOfDataBytesSentSoFar;
NSUInteger offsetOfDataForLastFrame = headerSize + numberOfDataBytesSentSoFar;
- NSData *lastFramePayload = [incomingMessage.data subdataWithRange:NSMakeRange(offsetOfDataForLastFrame, numberOfDataBytesInLastMessage)];
+ NSData *lastFramePayload = [protocolMessage.data subdataWithRange:NSMakeRange(offsetOfDataForLastFrame, numberOfDataBytesInLastMessage)];
SDLProtocolMessage *lastMessage = [SDLProtocolMessage messageWithHeader:lastFrameHeader andPayload:lastFramePayload];
outgoingMessages[numberOfMessagesRequired] = lastMessage;
diff --git a/SmartDeviceLink/private/SDLV2ProtocolHeader.m b/SmartDeviceLink/private/SDLV2ProtocolHeader.m
index d89fdeb1f..00567180c 100644
--- a/SmartDeviceLink/private/SDLV2ProtocolHeader.m
+++ b/SmartDeviceLink/private/SDLV2ProtocolHeader.m
@@ -109,7 +109,7 @@ const int ProtocolV2HeaderByteSize = 12;
}
NSMutableString *description = [[NSMutableString alloc] init];
- [description appendFormat:@"Version:%i, encrypted:%i, frameType:%@(%i), serviceType:%i, frameData:%@(%i), sessionID:%i, dataSize:%i, messageID:%i ",
+ [description appendFormat:@"Version:%i, encrypted:%i, frameType:%@(%i), serviceType:%i, frameData:%@(%i), sessionID:%i, dataSize:%i, messageID:%i, ",
self.version,
self.encrypted,
frameTypeString,
diff --git a/SmartDeviceLink/public/SDLProtocolConstants.h b/SmartDeviceLink/public/SDLProtocolConstants.h
index 6da05c02e..b994ef437 100644
--- a/SmartDeviceLink/public/SDLProtocolConstants.h
+++ b/SmartDeviceLink/public/SDLProtocolConstants.h
@@ -94,5 +94,5 @@ typedef NS_ENUM(UInt8, SDLFrameInfo) {
SDLFrameInfoFirstFrame = 0x00, // If frameType == First (0x02)
/// Frame in a multiple frame payload.
- SDLFrameInfoConsecutiveLastFrame = 0x00 // If frametype == Consecutive (0x03)
+ SDLFrameInfoConsecutiveLastFrame = 0x00 // If frameType == Consecutive (0x03)
};
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
index 137006e6b..0dee191ef 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
@@ -9,18 +9,22 @@
#import <Nimble/Nimble.h>
#import <OCMock/OCMock.h>
-#import "SDLTransportType.h"
#import "SDLControlFramePayloadAudioStartServiceAck.h"
#import "SDLControlFramePayloadRegisterSecondaryTransportNak.h"
#import "SDLControlFramePayloadRPCStartServiceAck.h"
#import "SDLControlFramePayloadVideoStartServiceAck.h"
+#import "SDLDeleteCommand.h"
+#import "SDLEncryptionLifecycleManager.h"
#import "SDLGlobals.h"
#import "SDLProtocolHeader.h"
#import "SDLProtocol.h"
#import "SDLProtocolMessage.h"
+#import "SDLProtocolMessageDisassembler.h"
#import "SDLProtocolReceivedMessageRouter.h"
+#import "SDLRPCFunctionNames.h"
#import "SDLRPCRequest.h"
#import "SDLRPCParameterNames.h"
+#import "SDLTransportType.h"
#import "SDLV1ProtocolMessage.h"
#import "SDLV2ProtocolMessage.h"
#import "SDLV1ProtocolHeader.h"
@@ -35,10 +39,12 @@ NSDictionary* dictionaryV1 = @{SDLRPCParameterNameRequest:
SDLRPCParameterNameCorrelationId:@0x98765,
SDLRPCParameterNameParameters:
@{SDLRPCParameterNameCommandId:@55}}};
-NSDictionary* dictionaryV2 = @{SDLRPCParameterNameCommandId:@55};
+// Send StartService Tests
describe(@"Send StartService Tests", ^{
+ // Insecure
context(@"Insecure", ^{
+ // Should send the correct data
it(@"Should send the correct data", ^{
// Reset max protocol version before test. (This test case expects V1 header. If other test ran
// prior to this one, SDLGlobals would keep the max protocol version and this test case would fail.)
@@ -110,8 +116,11 @@ describe(@"Send StartService Tests", ^{
});
});
+// Send EndSession Tests
describe(@"Send EndSession Tests", ^{
+ // During V1 session
context(@"During V1 session", ^{
+ // Should send the correct data
it(@"Should send the correct data", ^{
__block BOOL verified = NO;
id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
@@ -168,7 +177,9 @@ describe(@"Send EndSession Tests", ^{
});
});
+// Send Register Secondary Transport Tests
describe(@"Send Register Secondary Transport Tests", ^{
+ // Should send the correct data
it(@"Should send the correct data", ^{
__block BOOL verified = NO;
id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
@@ -201,13 +212,20 @@ describe(@"Send Register Secondary Transport Tests", ^{
});
});
-describe(@"SendRPCRequest Tests", ^{
+// SendRPC Tests
+describe(@"SendRPC Tests", ^{
__block id mockRequest;
beforeEach(^{
mockRequest = OCMPartialMock([[SDLRPCRequest alloc] init]);
});
-
+
+ afterEach(^{
+ [SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = [SDLVersion versionWithMajor:1 minor:0 patch:0];
+ });
+
+ // During V1 session
context(@"During V1 session", ^{
+ // Should send the correct data
it(@"Should send the correct data", ^{
[[[[mockRequest stub] andReturn:dictionaryV1] ignoringNonObjectArgs] serializeAsDictionary:1];
@@ -245,42 +263,28 @@ describe(@"SendRPCRequest Tests", ^{
expect(error).to(beNil());
});
});
-
+
+ // During V2 session
context(@"During V2 session", ^{
- it(@"Should send the correct data bulk data when bulk data is available", ^{
- [[[[mockRequest stub] andReturn:dictionaryV2] ignoringNonObjectArgs] serializeAsDictionary:2];
- [[[mockRequest stub] andReturn:@0x98765] correlationID];
- [[[mockRequest stub] andReturn:@"DeleteCommand"] name];
- [[[mockRequest stub] andReturn:[NSData dataWithBytes:"COMMAND" length:strlen("COMMAND")]] bulkData];
-
- __block BOOL verified = NO;
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = [SDLVersion versionWithMajor:2 minor:0 patch:0];
+ });
+
+ // Should send the correct data bulk data when bulk data is available
+ it(@"should correctly send a request smaller than the MTU size", ^{
+ SDLDeleteCommand *deleteRequest = [[SDLDeleteCommand alloc] initWithId:55];
+ deleteRequest.correlationID = @12345;
+ deleteRequest.bulkData = [NSData dataWithBytes:"COMMAND" length:strlen("COMMAND")];
+
+ __block NSUInteger numTimesCalled = 0;
id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
- [[[transportMock stub] andDo:^(NSInvocation* invocation) {
- verified = YES;
-
- //Without the __unsafe_unretained, a double release will occur. More information: https://github.com/erikdoe/ocmock/issues/123
- __unsafe_unretained NSData* data;
- [invocation getArgument:&data atIndex:2];
- NSData* dataSent = [data copy];
-
- NSData* jsonTestData = [NSJSONSerialization dataWithJSONObject:dictionaryV2 options:0 error:0];
- NSUInteger dataLength = jsonTestData.length;
-
- const char testPayloadHeader[12] = {0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0x87, 0x65, (dataLength >> 24) & 0xFF, (dataLength >> 16) & 0xFF, (dataLength >> 8) & 0xFF, dataLength & 0xFF};
-
- NSMutableData* payloadData = [NSMutableData dataWithBytes:testPayloadHeader length:12];
- [payloadData appendData:jsonTestData];
- [payloadData appendBytes:"COMMAND" length:strlen("COMMAND")];
-
- const char testHeader[12] = {0x20 | SDLFrameTypeSingle, SDLServiceTypeBulkData, SDLFrameInfoSingleFrame, 0x01, (payloadData.length >> 24) & 0xFF, (payloadData.length >> 16) & 0xFF,(payloadData.length >> 8) & 0xFF, payloadData.length & 0xFF, 0x00, 0x00, 0x00, 0x01};
-
- NSMutableData* testData = [NSMutableData dataWithBytes:testHeader length:12];
- [testData appendData:payloadData];
-
- expect(dataSent).to(equal([testData copy]));
+ [[[transportMock stub] andDo:^(NSInvocation *invocation) {
+ numTimesCalled++;
}] sendData:[OCMArg any]];
+
SDLProtocol *testProtocol = [[SDLProtocol alloc] initWithTransport:transportMock encryptionManager:nil];
+ // Send a start service ack to ensure that it's set up for sending the RPC
SDLV2ProtocolHeader *testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:2];
testHeader.serviceType = SDLServiceTypeRPC;
testHeader.sessionID = 0x01;
@@ -289,14 +293,109 @@ describe(@"SendRPCRequest Tests", ^{
NSError *error = nil;
BOOL sent = [testProtocol sendRPC:mockRequest error:&error];
- expect(verified).toEventually(beTrue());
+ expect(numTimesCalled).toEventually(equal(1));
expect(sent).to(beTrue());
expect(error).to(beNil());
});
+
+ it(@"should correctly send a request larger than the MTU size", ^{
+ char dummyBytes[1100];
+
+ SDLDeleteCommand *deleteRequest = [[SDLDeleteCommand alloc] initWithId:55];
+ deleteRequest.correlationID = @12345;
+ deleteRequest.bulkData = [NSData dataWithBytes:dummyBytes length:1100];
+
+ __block NSUInteger numTimesCalled = 0;
+ id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
+ [[[transportMock stub] andDo:^(NSInvocation *invocation) {
+ numTimesCalled++;
+ }] sendData:[OCMArg any]];
+
+ SDLProtocol *testProtocol = [[SDLProtocol alloc] initWithTransport:transportMock encryptionManager:nil];
+
+ NSError *error = nil;
+ [SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = [SDLVersion versionWithMajor:2 minor:0 patch:0];
+ BOOL sent = [testProtocol sendRPC:deleteRequest error:&error];
+
+ expect(numTimesCalled).toEventually(equal(3));
+ expect(sent).to(beTrue());
+ expect(error).to(beNil());
+ });
+
+ describe(@"when encrypting the requests", ^{
+ context(@"when the encryption manager is not ready", ^{
+ it(@"should not send the request and return an error", ^{
+ char dummyBytes[20000];
+
+ SDLDeleteCommand *deleteRequest = [[SDLDeleteCommand alloc] initWithId:55];
+ deleteRequest.correlationID = @12345;
+ deleteRequest.bulkData = [NSData dataWithBytes:dummyBytes length:20000];
+ deleteRequest.payloadProtected = YES;
+
+ __block NSUInteger numTimesCalled = 0;
+ id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
+ [[[transportMock stub] andDo:^(NSInvocation *invocation) {
+ numTimesCalled++;
+ }] sendData:[OCMArg any]];
+
+ SDLProtocol *testProtocol = [[SDLProtocol alloc] initWithTransport:transportMock encryptionManager:nil];
+
+ NSError *error = nil;
+ [SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ BOOL sent = [testProtocol sendRPC:deleteRequest error:&error];
+
+ expect(numTimesCalled).toEventually(equal(0));
+ expect(sent).to(beFalse());
+ expect(error).toNot(beNil());
+ });
+ });
+
+ context(@"when the encryption manager is ready", ^{
+ __block NSUInteger numTimesCalled = 0;
+ __block SDLProtocol *testProtocol = nil;
+ NSUInteger dataSize = 20000;
+ beforeEach(^{
+ id transportMock = OCMProtocolMock(@protocol(SDLTransportType));
+ [[[transportMock stub] andDo:^(NSInvocation *invocation) {
+ numTimesCalled++;
+ }] sendData:[OCMArg any]];
+
+ SDLEncryptionLifecycleManager *encryptionMock = OCMClassMock([SDLEncryptionLifecycleManager class]);
+ OCMStub(encryptionMock.isEncryptionReady).andReturn(YES);
+
+ id securityManager = OCMProtocolMock(@protocol(SDLSecurityType));
+ char dummyBytes[dataSize];
+ NSData *returnData = [NSData dataWithBytes:dummyBytes length:dataSize];
+ OCMStub([securityManager encryptData:[OCMArg any] withError:[OCMArg setTo:nil]]).andReturn(returnData);
+
+ testProtocol = [[SDLProtocol alloc] initWithTransport:transportMock encryptionManager:encryptionMock];
+ testProtocol.securityManager = securityManager;
+ });
+
+ it(@"should correctly adjust the MTU size when the packet is encrypted and the service MTU size is larger than the TLS max size", ^{
+ char dummyBytes[dataSize];
+
+ SDLDeleteCommand *deleteRequest = [[SDLDeleteCommand alloc] initWithId:55];
+ deleteRequest.correlationID = @12345;
+ deleteRequest.bulkData = [NSData dataWithBytes:dummyBytes length:dataSize];
+ deleteRequest.payloadProtected = YES;
+
+ NSError *error = nil;
+ [SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ BOOL sent = [testProtocol sendRPC:deleteRequest error:&error];
+
+ expect(numTimesCalled).toEventually(equal(3));
+ expect(sent).to(beTrue());
+ expect(error).to(beNil());
+ });
+ });
+ });
});
});
+// HandleBytesFromTransport Tests
describe(@"HandleBytesFromTransport Tests", ^{
+ // During V1 session
context(@"During V1 session", ^{
// it(@"Should parse the data correctly", ^{
// id routerMock = OCMClassMock(SDLProtocolReceivedMessageRouter.class);
@@ -343,7 +442,8 @@ describe(@"HandleBytesFromTransport Tests", ^{
// expect(@(verified)).toEventually(beTruthy());
// });
});
-
+
+ // During V2 session
context(@"During V2 session", ^{
// it(@"Should parse the data correctly", ^{
// id routerMock = OCMClassMock(SDLProtocolReceivedMessageRouter.class);
@@ -403,6 +503,7 @@ describe(@"HandleBytesFromTransport Tests", ^{
});
});
+// HandleProtocolSessionStarted tests
describe(@"HandleProtocolSessionStarted tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
@@ -427,7 +528,9 @@ describe(@"HandleProtocolSessionStarted tests", ^{
#pragma clang diagnostic pop
});
+ // For protocol versions 5.0.0 and greater
context(@"For protocol versions 5.0.0 and greater", ^{
+ // If the service type is RPC
context(@"If the service type is RPC", ^{
it(@"Should store the auth token, system info, and the protocol version and pass the start service along to the delegate", ^{
SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.2.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:testMake model:testModel trim:testTrim modelYear:testModelYear systemSoftwareVersion:testSystemSoftwareVersion systemHardwareVersion:testSystemHardwareVersion];
@@ -586,7 +689,9 @@ describe(@"HandleProtocolSessionStarted tests", ^{
});
});
+ // For protocol versions below 5.0.0
context(@"For protocol versions below 5.0.0", ^{
+ // If the service type is RPC
context(@"If the service type is RPC", ^{
it(@"Should store the protocol version and pass the start service along to the delegate", ^{
SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"3.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
@@ -691,6 +796,7 @@ describe(@"HandleProtocolSessionStarted tests", ^{
});
});
+// HandleProtocolRegisterSecondaryTransport Tests
describe(@"HandleProtocolRegisterSecondaryTransport Tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
@@ -700,6 +806,7 @@ describe(@"HandleProtocolRegisterSecondaryTransport Tests", ^{
testProtocol = [[SDLProtocol alloc] initWithTransport:transportMock encryptionManager:nil];
});
+ // Should pass information along to delegate when ACKed
it(@"Should pass information along to delegate when ACKed", ^{
id delegateMock = OCMProtocolMock(@protocol(SDLProtocolDelegate));
@@ -720,6 +827,7 @@ describe(@"HandleProtocolRegisterSecondaryTransport Tests", ^{
OCMVerifyAllWithDelay(delegateMock, 0.1);
});
+ // Should pass information along to delegate when NAKed
it(@"Should pass information along to delegate when NAKed", ^{
id delegateMock = OCMProtocolMock(@protocol(SDLProtocolDelegate));
@@ -743,6 +851,7 @@ describe(@"HandleProtocolRegisterSecondaryTransport Tests", ^{
});
});
+// HandleHeartbeatForSession Tests
describe(@"HandleHeartbeatForSession Tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
@@ -764,6 +873,7 @@ describe(@"HandleHeartbeatForSession Tests", ^{
});
});
+// OnProtocolMessageReceived Tests
describe(@"OnProtocolMessageReceived Tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
@@ -790,6 +900,7 @@ describe(@"OnProtocolMessageReceived Tests", ^{
});
});
+// OnProtocolOpened Tests
describe(@"OnProtocolOpened Tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
@@ -811,6 +922,7 @@ describe(@"OnProtocolOpened Tests", ^{
});
});
+// OnProtocolClosed Tests
describe(@"OnProtocolClosed Tests", ^{
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLProtocolMessageDisassemblerSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLProtocolMessageDisassemblerSpec.m
index 9c211ba05..a65652060 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLProtocolMessageDisassemblerSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLProtocolMessageDisassemblerSpec.m
@@ -18,78 +18,106 @@
QuickSpecBegin(SDLProtocolMessageDisassemblerSpec)
-describe(@"Disassemble Tests", ^ {
- it(@"Should assemble the message properly", ^ {
- //Allocate 2000 bytes, and use it as sample data
- const NSUInteger dataLength = 2000;
- char dummyBytes[dataLength];
-
- SDLGlobals *globals = [[SDLGlobals alloc] init];
- globals.maxHeadUnitProtocolVersion = [SDLVersion versionWithString:@"2.0.0"];
-
- const char testPayloadHeader[12] = {0x20, 0x55, 0x64, 0x73, 0x12, 0x34, 0x43, 0x21, (dataLength >> 24) & 0xFF, (dataLength >> 16) & 0xFF, (dataLength >> 8) & 0xFF, dataLength & 0xFF};
-
- NSMutableData* payloadData = [NSMutableData dataWithBytes:testPayloadHeader length:12];
- [payloadData appendBytes:dummyBytes length:dataLength];
-
- SDLV2ProtocolMessage* testMessage = [[SDLV2ProtocolMessage alloc] init];
- SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] init];
-
- testHeader.frameType = SDLFrameTypeSingle;
- testHeader.serviceType = SDLServiceTypeBulkData;
- testHeader.frameData = SDLFrameInfoSingleFrame;
- testHeader.sessionID = 0x84;
- testHeader.bytesInPayload = (UInt32)payloadData.length;
-
- testMessage.header = testHeader;
- testMessage.payload = payloadData;
-
- NSArray<SDLProtocolMessage *> *messageList = [SDLProtocolMessageDisassembler disassemble:testMessage withLimit:[globals mtuSizeForServiceType:testHeader.serviceType]];
-
- //Payload length per message
- UInt32 payloadLength = 1012; // v1/2 MTU(1024) - header length(12)
-
- const char firstPayload[8] = {(payloadData.length >> 24) & 0xFF, (payloadData.length >> 16) & 0xFF, (payloadData.length >> 8) & 0xFF, payloadData.length & 0xFF, 0x00, 0x00, 0x00, ceil(1.0 * payloadData.length / payloadLength)};
-
- SDLProtocolMessage* message = messageList[0];
-
- //First frame
- expect(message.payload).to(equal([NSData dataWithBytes:firstPayload length:8]));
-
- expect(@(message.header.frameType)).to(equal(@(SDLFrameTypeFirst)));
- expect(@(message.header.serviceType)).to(equal(@(SDLServiceTypeBulkData)));
- expect(@(message.header.frameData)).to(equal(@(SDLFrameInfoFirstFrame)));
- expect(@(message.header.sessionID)).to(equal(@0x84));
- expect(@(message.header.bytesInPayload)).to(equal(@8));
-
- NSUInteger offset = 0;
- for (int i = 1; i < messageList.count - 1; i++) {
- message = messageList[i];
-
- //Consecutive frames
- expect(message.payload).to(equal([NSData dataWithData:[payloadData subdataWithRange:NSMakeRange(offset, payloadLength)]]));
-
+describe(@"SDLProtocolMessageDisassembler Tests", ^ {
+ context(@"when the MTU size is larger than the payload size", ^{
+ it(@"should disassemble the message properly", ^{
+ const NSUInteger dataLength = 400;
+ char dummyBytes[dataLength];
+
+ const char testPayloadHeader[12] = {0x20, 0x55, 0x64, 0x73, 0x12, 0x34, 0x43, 0x21, (dataLength >> 24) & 0xFF, (dataLength >> 16) & 0xFF, (dataLength >> 8) & 0xFF, dataLength & 0xFF};
+
+ NSMutableData* payloadData = [NSMutableData dataWithBytes:testPayloadHeader length:12];
+ [payloadData appendBytes:dummyBytes length:dataLength];
+
+ SDLV2ProtocolMessage *testMessage = [[SDLV2ProtocolMessage alloc] init];
+ SDLV2ProtocolHeader *testHeader = [[SDLV2ProtocolHeader alloc] init];
+
+ testHeader.frameType = SDLFrameTypeSingle;
+ testHeader.serviceType = SDLServiceTypeBulkData;
+ testHeader.frameData = SDLFrameInfoSingleFrame;
+ testHeader.sessionID = 0x84;
+ testHeader.bytesInPayload = (UInt32)payloadData.length;
+
+ testMessage.header = testHeader;
+ testMessage.payload = payloadData;
+
+ NSArray<SDLProtocolMessage *> *messageList = [SDLProtocolMessageDisassembler disassemble:testMessage withMTULimit:1024];
+ expect(messageList.count).to(equal(1));
+ expect(messageList[0]).to(equal(testMessage));
+ });
+ });
+
+ context(@"when the MTU size is smaller than the payload size", ^{
+ it(@"Should disassemble the message properly", ^ {
+ //Allocate 4000 bytes and use it as sample data
+ const NSUInteger dataLength = 4000;
+ char dummyBytes[dataLength];
+
+ const char testPayloadHeader[12] = {0x20, 0x55, 0x64, 0x73, 0x12, 0x34, 0x43, 0x21, (dataLength >> 24) & 0xFF, (dataLength >> 16) & 0xFF, (dataLength >> 8) & 0xFF, dataLength & 0xFF};
+
+ NSMutableData* payloadData = [NSMutableData dataWithBytes:testPayloadHeader length:12];
+ [payloadData appendBytes:dummyBytes length:dataLength];
+
+ SDLV2ProtocolMessage* testMessage = [[SDLV2ProtocolMessage alloc] init];
+ SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] init];
+
+ testHeader.frameType = SDLFrameTypeSingle;
+ testHeader.serviceType = SDLServiceTypeBulkData;
+ testHeader.frameData = SDLFrameInfoSingleFrame;
+ testHeader.sessionID = 0x84;
+ testHeader.bytesInPayload = (UInt32)payloadData.length;
+
+ testMessage.header = testHeader;
+ testMessage.payload = payloadData;
+
+ NSArray<SDLProtocolMessage *> *messageList = [SDLProtocolMessageDisassembler disassemble:testMessage withMTULimit:1024];
+ expect(messageList.count).to(equal(5));
+
+ //Payload length per message
+ UInt32 payloadLength = 1012; // v1/2 MTU(1024) - header length(12)
+
+ const char firstPayload[8] = {(payloadData.length >> 24) & 0xFF, (payloadData.length >> 16) & 0xFF, (payloadData.length >> 8) & 0xFF, payloadData.length & 0xFF, 0x00, 0x00, 0x00, ceil(1.0 * payloadData.length / payloadLength)};
+
+ SDLProtocolMessage* message = messageList[0];
+
+ //First frame
+ expect(message.payload).to(equal([NSData dataWithBytes:firstPayload length:8]));
+
+ expect(@(message.header.frameType)).to(equal(@(SDLFrameTypeFirst)));
+ expect(@(message.header.serviceType)).to(equal(@(SDLServiceTypeBulkData)));
+ expect(@(message.header.frameData)).to(equal(@(SDLFrameInfoFirstFrame)));
+ expect(@(message.header.sessionID)).to(equal(@0x84));
+ expect(@(message.header.bytesInPayload)).to(equal(@8));
+
+ NSUInteger offset = 0;
+ for (int i = 1; i < messageList.count - 1; i++) {
+ message = messageList[i];
+
+ //Consecutive frames
+ expect(message.payload).to(equal([NSData dataWithData:[payloadData subdataWithRange:NSMakeRange(offset, payloadLength)]]));
+
+ expect(@(message.header.frameType)).to(equal(@(SDLFrameTypeConsecutive)));
+ expect(@(message.header.serviceType)).to(equal(@(SDLServiceTypeBulkData)));
+ expect(@(message.header.frameData)).to(equal(@(i)));
+ expect(@(message.header.sessionID)).to(equal(@0x84));
+ expect(@(message.header.bytesInPayload)).to(equal(@(payloadLength)));
+
+ offset += payloadLength;
+ }
+
+ message = [messageList lastObject];
+
+ NSUInteger remaining = payloadData.length - offset;
+
+ //Last frame
+ expect(message.payload).to(equal([NSData dataWithData:[payloadData subdataWithRange:NSMakeRange(offset, remaining)]]));
+
expect(@(message.header.frameType)).to(equal(@(SDLFrameTypeConsecutive)));
expect(@(message.header.serviceType)).to(equal(@(SDLServiceTypeBulkData)));
- expect(@(message.header.frameData)).to(equal(@(i)));
+ expect(@(message.header.frameData)).to(equal(@(SDLFrameInfoConsecutiveLastFrame)));
expect(@(message.header.sessionID)).to(equal(@0x84));
- expect(@(message.header.bytesInPayload)).to(equal(@(payloadLength)));
-
- offset += payloadLength;
- }
-
- message = [messageList lastObject];
-
- NSUInteger remaining = payloadData.length - offset;
-
- //Last frame
- expect(message.payload).to(equal([NSData dataWithData:[payloadData subdataWithRange:NSMakeRange(offset, remaining)]]));
-
- expect(@(message.header.frameType)).to(equal(@(SDLFrameTypeConsecutive)));
- expect(@(message.header.serviceType)).to(equal(@(SDLServiceTypeBulkData)));
- expect(@(message.header.frameData)).to(equal(@(SDLFrameInfoConsecutiveLastFrame)));
- expect(@(message.header.sessionID)).to(equal(@0x84));
- expect(@(message.header.bytesInPayload)).to(equal(@(remaining)));
+ expect(@(message.header.bytesInPayload)).to(equal(@(remaining)));
+ });
});
});
diff --git a/generator/rpc_spec b/generator/rpc_spec
-Subproject 72632f946941d63a57ee5e99896e3eae3627f7d
+Subproject 6b98355357b5b1893bbb59cb668d28545023457