From 0b38f6177eb2c59bfec99e18780d579f9d8438a2 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Thu, 10 Mar 2016 10:38:46 -0500 Subject: Fixes to HTTP system request upload * Re-indent SDLProxy * Add comment explaining uploadData * Make new private methods prefixed * Remove timeout on HTTP system request upload * Actually log the response instead of just saying we will * Remove useless error check --- SmartDeviceLink-iOS/SmartDeviceLink/SDLProxy.m | 205 +++++++++++++------------ 1 file changed, 103 insertions(+), 102 deletions(-) diff --git a/SmartDeviceLink-iOS/SmartDeviceLink/SDLProxy.m b/SmartDeviceLink-iOS/SmartDeviceLink/SDLProxy.m index 9e94eee28..94ba0a751 100644 --- a/SmartDeviceLink-iOS/SmartDeviceLink/SDLProxy.m +++ b/SmartDeviceLink-iOS/SmartDeviceLink/SDLProxy.m @@ -69,35 +69,35 @@ const int POLICIES_CORRELATION_ID = 65535; _debugConsoleGroupName = @"default"; _lsm = [[SDLLockScreenManager alloc] init]; _alreadyDestructed = NO; - + _mutableProxyListeners = [NSMutableSet setWithObject:theDelegate]; _protocol = protocol; _transport = transport; _transport.delegate = protocol; [_protocol.protocolDelegateTable addObject:self]; _protocol.transport = transport; - + [self.transport connect]; - + [SDLDebugTool logInfo:@"SDLProxy initWithTransport"]; [[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications]; } - + return self; } - (void)destructObjects { if (!_alreadyDestructed) { _alreadyDestructed = YES; - + [[NSNotificationCenter defaultCenter] removeObserver:self]; [[EAAccessoryManager sharedAccessoryManager] unregisterForLocalNotifications]; - + [[SDLURLSession defaultSession] cancelAllTasks]; - + [self.protocol dispose]; [self.transport dispose]; - + _transport = nil; _protocol = nil; _mutableProxyListeners = nil; @@ -108,7 +108,7 @@ const int POLICIES_CORRELATION_ID = 65535; if (self.transport != nil) { [self.transport disconnect]; } - + [self destructObjects]; } @@ -142,7 +142,7 @@ const int POLICIES_CORRELATION_ID = 65535; _streamingMediaManager = [[SDLStreamingMediaManager alloc] initWithProtocol:self.protocol]; [self.protocol.protocolDelegateTable addObject:_streamingMediaManager]; } - + return _streamingMediaManager; } @@ -151,9 +151,9 @@ const int POLICIES_CORRELATION_ID = 65535; - (void)onProtocolOpened { _isConnected = YES; [SDLDebugTool logInfo:@"StartSession (request)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + [self.protocol sendStartSessionWithType:SDLServiceType_RPC]; - + if (self.startSessionTimer == nil) { self.startSessionTimer = [[SDLTimer alloc] initWithDuration:startSessionTime repeat:NO]; __weak typeof(self) weakSelf = self; @@ -176,10 +176,10 @@ const int POLICIES_CORRELATION_ID = 65535; - (void)handleProtocolStartSessionACK:(SDLServiceType)serviceType sessionID:(Byte)sessionID version:(Byte)version { // Turn off the timer, the start session response came back [self.startSessionTimer cancel]; - + NSString *logMessage = [NSString stringWithFormat:@"StartSession (response)\nSessionId: %d for serviceType %d", sessionID, serviceType]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + if (serviceType == SDLServiceType_RPC || [SDLGlobals globals].protocolVersion >= 2) { [self invokeMethodOnDelegates:@selector(onProxyOpened) withObject:nil]; } @@ -221,7 +221,7 @@ const int POLICIES_CORRELATION_ID = 65535; SDLRPCMessage *message = [[SDLRPCMessage alloc] initWithDictionary:[dict mutableCopy]]; NSString *functionName = [message getFunctionName]; NSString *messageType = [message messageType]; - + // If it's a response, append response if ([messageType isEqualToString:NAMES_response]) { BOOL notGenericResponseMessage = ![functionName isEqualToString:@"GenericResponse"]; @@ -229,50 +229,50 @@ const int POLICIES_CORRELATION_ID = 65535; functionName = [NSString stringWithFormat:@"%@Response", functionName]; } } - + // From the function name, create the corresponding RPCObject and initialize it NSString *functionClassName = [NSString stringWithFormat:@"SDL%@", functionName]; SDLRPCMessage *newMessage = [[NSClassFromString(functionClassName) alloc] initWithDictionary:dict]; - + // Log the RPC message NSString *logMessage = [NSString stringWithFormat:@"%@", newMessage]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + // Intercept and handle several messages ourselves if ([functionName isEqualToString:NAMES_OnAppInterfaceUnregistered] || [functionName isEqualToString:NAMES_UnregisterAppInterface]) { [self handleRPCUnregistered:dict]; } - + if ([functionName isEqualToString:@"RegisterAppInterfaceResponse"]) { [self handleRegisterAppInterfaceResponse:(SDLRPCResponse *)newMessage]; } - + if ([functionName isEqualToString:@"EncodedSyncPDataResponse"]) { [SDLDebugTool logInfo:@"EncodedSyncPData (response)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; } - + if ([functionName isEqualToString:@"OnEncodedSyncPData"]) { [self handleSyncPData:newMessage]; } - + if ([functionName isEqualToString:@"OnSystemRequest"]) { [self handleSystemRequest:dict]; } - + if ([functionName isEqualToString:@"SystemRequestResponse"]) { [self handleSystemRequestResponse:newMessage]; } - + // Formulate the name of the method to call and invoke the method on the delegate(s) NSString *handlerName = [NSString stringWithFormat:@"on%@:", functionName]; SEL handlerSelector = NSSelectorFromString(handlerName); [self invokeMethodOnDelegates:handlerSelector withObject:newMessage]; - + // When an OnHMIStatus notification comes in, after passing it on (above), generate an "OnLockScreenNotification" if ([functionName isEqualToString:@"OnHMIStatus"]) { [self handleAfterHMIStatus:newMessage]; } - + // When an OnDriverDistraction notification comes in, after passing it on (above), generate an "OnLockScreenNotification" if ([functionName isEqualToString:@"OnDriverDistraction"]) { [self handleAfterDriverDistraction:newMessage]; @@ -301,11 +301,11 @@ const int POLICIES_CORRELATION_ID = 65535; // If URL != nil, perform HTTP Post and don't pass the notification to proxy listeners NSString *logMessage = [NSString stringWithFormat:@"OnEncodedSyncPData (notification)\n%@", message]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + NSString *urlString = (NSString *)[message getParameters:@"URL"]; NSDictionary *encodedSyncPData = (NSDictionary *)[message getParameters:@"data"]; NSNumber *encodedSyncPTimeout = (NSNumber *)[message getParameters:@"Timeout"]; - + if (urlString && encodedSyncPData && encodedSyncPTimeout) { [self sendEncodedSyncPData:encodedSyncPData toURL:urlString withTimeout:encodedSyncPTimeout]; } @@ -313,17 +313,17 @@ const int POLICIES_CORRELATION_ID = 65535; - (void)handleSystemRequest:(NSDictionary *)dict { [SDLDebugTool logInfo:@"OnSystemRequest (notification)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + SDLOnSystemRequest *systemRequest = [[SDLOnSystemRequest alloc] initWithDictionary:[dict mutableCopy]]; SDLRequestType *requestType = systemRequest.requestType; - + // Handle the various OnSystemRequest types if (requestType == [SDLRequestType PROPRIETARY]) { [self handleSystemRequestProprietary:systemRequest]; } else if (requestType == [SDLRequestType LOCK_SCREEN_ICON_URL]) { [self handleSystemRequestLockScreenIconURL:systemRequest]; } else if (requestType == [SDLRequestType HTTP]) { - [self handleSystemRequestHTTP:systemRequest]; + [self sdl_handleSystemRequestHTTP:systemRequest]; } } @@ -338,7 +338,7 @@ const int POLICIES_CORRELATION_ID = 65535; NSString *statusString = (NSString *)[message getParameters:NAMES_hmiLevel]; SDLHMILevel *hmiLevel = [SDLHMILevel valueOf:statusString]; _lsm.hmiLevel = hmiLevel; - + SEL callbackSelector = NSSelectorFromString(@"onOnLockScreenNotification:"); [self invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification]; } @@ -347,7 +347,7 @@ const int POLICIES_CORRELATION_ID = 65535; NSString *stateString = (NSString *)[message getParameters:NAMES_state]; BOOL state = [stateString isEqualToString:@"DD_ON"] ? YES : NO; _lsm.driverDistracted = state; - + SEL callbackSelector = NSSelectorFromString(@"onOnLockScreenNotification:"); [self invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification]; } @@ -359,11 +359,11 @@ const int POLICIES_CORRELATION_ID = 65535; if (JSONDictionary == nil || request.url == nil) { return; } - + NSDictionary *requestData = JSONDictionary[@"HTTPRequest"]; NSString *bodyString = requestData[@"body"]; NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - + // Parse and display the policy data. SDLPolicyDataParser *pdp = [[SDLPolicyDataParser alloc] init]; NSData *policyData = [pdp unwrap:bodyData]; @@ -372,33 +372,33 @@ const int POLICIES_CORRELATION_ID = 65535; NSString *logMessage = [NSString stringWithFormat:@"Policy Data from Module\n%@", pdp]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; } - + // Send the HTTP Request [self uploadForBodyDataDictionary:JSONDictionary URLString:request.url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSString *logMessage = nil; - + if (error) { logMessage = [NSString stringWithFormat:@"OnSystemRequest (HTTP response) = ERROR: %@", error]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return; } - + if (data == nil || data.length == 0) { [SDLDebugTool logInfo:@"OnSystemRequest (HTTP response) failure: no data returned" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return; } - + // Show the HTTP response [SDLDebugTool logInfo:@"OnSystemRequest (HTTP response)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + // Create the SystemRequest RPC to send to module. SDLSystemRequest *request = [[SDLSystemRequest alloc] init]; request.correlationID = [NSNumber numberWithInt:POLICIES_CORRELATION_ID]; request.requestType = [SDLRequestType PROPRIETARY]; request.bulkData = data; - + // Parse and display the policy data. SDLPolicyDataParser *pdp = [[SDLPolicyDataParser alloc] init]; NSData *policyData = [pdp unwrap:data]; @@ -407,7 +407,7 @@ const int POLICIES_CORRELATION_ID = 65535; logMessage = [NSString stringWithFormat:@"Policy Data from Cloud\n%@", pdp]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; } - + // Send and log RPC Request logMessage = [NSString stringWithFormat:@"SystemRequest (request)\n%@\nData length=%lu", [request serializeAsDictionary:2], (unsigned long)data.length]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; @@ -423,52 +423,47 @@ const int POLICIES_CORRELATION_ID = 65535; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return; } - + UIImage *icon = [UIImage imageWithData:data]; [self invokeMethodOnDelegates:@selector(onReceivedLockScreenIcon:) withObject:icon]; }]; } -- (void)handleSystemRequestHTTP:(SDLOnSystemRequest *)request { +- (void)sdl_handleSystemRequestHTTP:(SDLOnSystemRequest *)request { if (request.bulkData.length == 0) { // TODO: not sure how we want to handle http requests that don't have bulk data (maybe as GET?) return; } - NSError *error = nil; - if (error) { - NSLog(@"error creating body from bulk data: %@", error.localizedDescription); - return; - } - - [self uploadData:request.bulkData toURLString:request.url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - NSString *logMessage = nil; - if (error) { - logMessage = [NSString stringWithFormat:@"OnSystemRequest (HTTP response) = ERROR: %@", error]; - [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - return; - } - - if (data.length == 0) { - [SDLDebugTool logInfo:@"OnSystemRequest (HTTP response) failure: no data returned" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - return; - } - - // Show the HTTP response - [SDLDebugTool logInfo:@"OnSystemRequest (HTTP response)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - - // Create the SystemRequest RPC to send to module. - SDLPutFile *putFile = [[SDLPutFile alloc] init]; - putFile.fileType = [SDLFileType JSON]; - putFile.correlationID = @(POLICIES_CORRELATION_ID); - putFile.syncFileName = @"response_data"; - putFile.bulkData = data; - - // Send and log RPC Request - logMessage = [NSString stringWithFormat:@"SystemRequest (request)\n%@\nData length=%lu", [request serializeAsDictionary:2], (unsigned long)data.length]; - [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - [self sendRPC:putFile]; - }]; + [self sdl_uploadData:request.bulkData toURLString:request.url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + NSString *logMessage = nil; + if (error != nil) { + logMessage = [NSString stringWithFormat:@"OnSystemRequest (HTTP response) = ERROR: %@", error.localizedDescription]; + [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; + return; + } + + if (data.length == 0) { + [SDLDebugTool logInfo:@"OnSystemRequest (HTTP response) failure: no data returned" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; + return; + } + + // Show the HTTP response + NSString *responseLogString = [NSString stringWithFormat:@"OnSystemRequest (HTTP) response: %@", response]; + [SDLDebugTool logInfo:responseLogString withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; + + // Create the SystemRequest RPC to send to module. + SDLPutFile *putFile = [[SDLPutFile alloc] init]; + putFile.fileType = [SDLFileType JSON]; + putFile.correlationID = @(POLICIES_CORRELATION_ID); + putFile.syncFileName = @"response_data"; + putFile.bulkData = data; + + // Send and log RPC Request + logMessage = [NSString stringWithFormat:@"SystemRequest (request)\n%@\nData length=%lu", [request serializeAsDictionary:2], (unsigned long)data.length]; + [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; + [self sendRPC:putFile]; + }]; } /** @@ -481,18 +476,18 @@ const int POLICIES_CORRELATION_ID = 65535; - (NSDictionary *)validateAndParseSystemRequest:(SDLOnSystemRequest *)request { NSString *urlString = request.url; SDLFileType *fileType = request.fileType; - + // Validate input if (urlString == nil || [NSURL URLWithString:urlString] == nil) { [SDLDebugTool logInfo:@"OnSystemRequest (notification) failure: url is nil" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return nil; } - + if (fileType != [SDLFileType JSON]) { [SDLDebugTool logInfo:@"OnSystemRequest (notification) failure: file type is not JSON" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return nil; } - + // Get data dictionary from the bulkData NSError *error = nil; NSDictionary *JSONDictionary = [NSJSONSerialization JSONObjectWithData:request.bulkData options:kNilOptions error:&error]; @@ -500,18 +495,24 @@ const int POLICIES_CORRELATION_ID = 65535; [SDLDebugTool logInfo:@"OnSystemRequest failure: notification data is not valid JSON." withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return nil; } - + return JSONDictionary; } -- (void)uploadData:(NSData * _Nonnull)data toURLString:(NSString * _Nonnull)urlString completionHandler:(URLSessionTaskCompletionHandler)completionHandler { +/** + * Start an upload for some data to a web address specified + * + * @param data The data to be passed to the server + * @param urlString The URL the data should be POSTed to + * @param completionHandler A completion handler of what to do when the server responds + */ +- (void)sdl_uploadData:(NSData * _Nonnull)data toURLString:(NSString * _Nonnull)urlString completionHandler:(URLSessionTaskCompletionHandler _Nullable)completionHandler { // NSURLRequest configuration NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.timeoutInterval = 7; [request setValue:@"application/json" forHTTPHeaderField:@"content-type"]; request.HTTPMethod = @"POST"; - + // Logging NSString *logMessage = [NSString stringWithFormat:@"OnSystemRequest (HTTP Request) to URL %@", urlString]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; @@ -521,7 +522,7 @@ const int POLICIES_CORRELATION_ID = 65535; } /** - * Start an upload for a body data dictionary + * Start an upload for a body data dictionary, this is used by the "proprietary" system request needed for backward compatibility * * @param dictionary The system request dictionary that contains the HTTP data to be sent * @param urlString A string containing the URL to send the upload to @@ -531,7 +532,7 @@ const int POLICIES_CORRELATION_ID = 65535; NSParameterAssert(dictionary != nil); NSParameterAssert(urlString != nil); NSParameterAssert(completionHandler != NULL); - + // Extract data from the dictionary NSDictionary *requestData = dictionary[@"HTTPRequest"]; NSDictionary *headers = requestData[@"headers"]; @@ -540,18 +541,18 @@ const int POLICIES_CORRELATION_ID = 65535; NSString *method = headers[@"RequestMethod"]; NSString *bodyString = requestData[@"body"]; NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - + // NSURLRequest configuration NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setValue:contentType forHTTPHeaderField:@"content-type"]; request.timeoutInterval = timeout; request.HTTPMethod = method; - + // Logging NSString *logMessage = [NSString stringWithFormat:@"OnSystemRequest (HTTP Request) to URL %@", urlString]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + // Create the upload task [[SDLURLSession defaultSession] uploadWithURLRequest:request data:bodyData completionHandler:completionHandler]; } @@ -594,7 +595,7 @@ const int POLICIES_CORRELATION_ID = 65535; request.HTTPMethod = @"POST"; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; request.timeoutInterval = 60; - + // Prepare the data in the required format NSString *encodedSyncPDataString = [[NSString stringWithFormat:@"%@", encodedSyncPData] componentsSeparatedByString:@"\""][1]; NSArray *array = [NSArray arrayWithObject:encodedSyncPDataString]; @@ -606,14 +607,14 @@ const int POLICIES_CORRELATION_ID = 65535; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return; } - + // Send the HTTP Request [[SDLURLSession defaultSession] uploadWithURLRequest:request data:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [self syncPDataNetworkRequestCompleteWithData:data response:response error:error]; }]; - + [SDLDebugTool logInfo:@"OnEncodedSyncPData (HTTP request)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; } @@ -621,13 +622,13 @@ const int POLICIES_CORRELATION_ID = 65535; - (void)syncPDataNetworkRequestCompleteWithData:(NSData *)data response:(NSURLResponse *)response error:(NSError *)error { // Sample of response: {"data":["SDLKGLSDKFJLKSjdslkfjslkJLKDSGLKSDJFLKSDJF"]} [SDLDebugTool logInfo:@"OnEncodedSyncPData (HTTP response)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + // Validate response data. if (data == nil || data.length == 0) { [SDLDebugTool logInfo:@"OnEncodedSyncPData (HTTP response) failure: no data returned" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; return; } - + // Convert data to RPCRequest NSError *JSONConversionError = nil; NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&JSONConversionError]; @@ -635,7 +636,7 @@ const int POLICIES_CORRELATION_ID = 65535; SDLEncodedSyncPData *request = [[SDLEncodedSyncPData alloc] init]; request.correlationID = [NSNumber numberWithInt:POLICIES_CORRELATION_ID]; request.data = [responseDictionary objectForKey:@"data"]; - + [self sendRPC:request]; } } @@ -646,7 +647,7 @@ const int POLICIES_CORRELATION_ID = 65535; inputStream.delegate = self; objc_setAssociatedObject(inputStream, @"SDLPutFile", putFileRPCRequest, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(inputStream, @"BaseOffset", [putFileRPCRequest offset], OBJC_ASSOCIATION_RETAIN); - + [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inputStream open]; } @@ -656,29 +657,29 @@ const int POLICIES_CORRELATION_ID = 65535; case NSStreamEventHasBytesAvailable: { // Grab some bytes from the stream and send them in a SDLPutFile RPC Request NSUInteger currentStreamOffset = [[stream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedIntegerValue]; - + NSMutableData *buffer = [NSMutableData dataWithLength:[SDLGlobals globals].maxMTUSize]; NSUInteger nBytesRead = [(NSInputStream *)stream read:(uint8_t *)buffer.mutableBytes maxLength:buffer.length]; if (nBytesRead > 0) { NSData *data = [buffer subdataWithRange:NSMakeRange(0, nBytesRead)]; NSUInteger baseOffset = [(NSNumber *)objc_getAssociatedObject(stream, @"BaseOffset") unsignedIntegerValue]; NSUInteger newOffset = baseOffset + currentStreamOffset; - + SDLPutFile *putFileRPCRequest = (SDLPutFile *)objc_getAssociatedObject(stream, @"SDLPutFile"); [putFileRPCRequest setOffset:[NSNumber numberWithUnsignedInteger:newOffset]]; [putFileRPCRequest setLength:[NSNumber numberWithUnsignedInteger:nBytesRead]]; [putFileRPCRequest setBulkData:data]; - + [self sendRPC:putFileRPCRequest]; } - + break; } case NSStreamEventEndEncountered: { // Cleanup the stream [stream close]; [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - + break; } case NSStreamEventErrorOccurred: { -- cgit v1.2.1