You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2015/10/09 22:05:59 UTC
[2/7] thrift git commit: THRIFT-2905 Cocoa compiler should have
option to produce "modern" Objective-C Client: Cocoa (ObjectiveC & Swift)
Author: Kevin Wooten
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/server/TSocketServer.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index 07bc829..ccbbba1 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -21,37 +21,51 @@
#import "TSocketServer.h"
#import "TNSFileHandleTransport.h"
#import "TProtocol.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
#import <sys/socket.h>
#include <netinet/in.h>
-NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification";
-NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor";
-NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
+NSString *const TSocketServerClientConnectionFinished = @"TSocketServerClientConnectionFinished";
+NSString *const TSocketServerProcessorKey = @"TSocketServerProcessor";
+NSString *const TSockerServerTransportKey = @"TSockerServerTransport";
+
+
+@interface TSocketServer ()
+
+@property(strong, nonatomic) id<TProtocolFactory> inputProtocolFactory;
+@property(strong, nonatomic) id<TProtocolFactory> outputProtocolFactory;
+@property(strong, nonatomic) id<TProcessorFactory> processorFactory;
+@property(strong, nonatomic) NSFileHandle *socketFileHandle;
+@property(strong, nonatomic) dispatch_queue_t processingQueue;
+
+@end
@implementation TSocketServer
-- (id) initWithPort: (int) port
- protocolFactory: (id <TProtocolFactory>) protocolFactory
- processorFactory: (id <TProcessorFactory>) processorFactory
+-(instancetype) initWithPort:(int)port
+ protocolFactory:(id <TProtocolFactory>)protocolFactory
+ processorFactory:(id <TProcessorFactory>)processorFactory;
{
self = [super init];
- mInputProtocolFactory = [protocolFactory retain_stub];
- mOutputProtocolFactory = [protocolFactory retain_stub];
- mProcessorFactory = [processorFactory retain_stub];
+ _inputProtocolFactory = protocolFactory;
+ _outputProtocolFactory = protocolFactory;
+ _processorFactory = processorFactory;
+
+ dispatch_queue_attr_t processingQueueAttr =
+ dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
+
+ _processingQueue = dispatch_queue_create("TSocketServer.processing", processingQueueAttr);
// create a socket.
int fd = -1;
CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
if (socket) {
- CFOptionFlags flagsToClear = kCFSocketCloseOnInvalidate;
- CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~flagsToClear);
-
+ CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
fd = CFSocketGetNative(socket);
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
@@ -63,135 +77,88 @@ NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
- if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
+ if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != kCFSocketSuccess) {
CFSocketInvalidate(socket);
CFRelease(socket);
- NSLog(@"*** Could not bind to address");
+ NSLog(@"TSocketServer: Could not bind to address");
return nil;
}
- } else {
- NSLog(@"*** No server socket");
+ }
+ else {
+ NSLog(@"TSocketServer: No server socket");
return nil;
}
-
+
// wrap it in a file handle so we can get messages from it
- mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
- closeOnDealloc: YES];
-
+ _socketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd
+ closeOnDealloc:YES];
+
// throw away our socket
CFSocketInvalidate(socket);
CFRelease(socket);
-
- // register for notifications of accepted incoming connections
- [[NSNotificationCenter defaultCenter] addObserver: self
- selector: @selector(connectionAccepted:)
- name: NSFileHandleConnectionAcceptedNotification
- object: mSocketFileHandle];
-
+
+ // register for notifications of accepted incoming connections
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(connectionAccepted:)
+ name:NSFileHandleConnectionAcceptedNotification
+ object:_socketFileHandle];
+
// tell socket to listen
- [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
-
- NSLog(@"Listening on TCP port %d", port);
-
+ [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+
+ NSLog(@"TSocketServer: Listening on TCP port %d", port);
+
return self;
}
-- (void) dealloc {
+-(void) dealloc
+{
[[NSNotificationCenter defaultCenter] removeObserver:self];
- [mInputProtocolFactory release_stub];
- [mOutputProtocolFactory release_stub];
- [mProcessorFactory release_stub];
- [mSocketFileHandle release_stub];
- [super dealloc_stub];
}
-- (void) connectionAccepted: (NSNotification *) aNotification
+-(void) connectionAccepted:(NSNotification *)notification
{
- NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
+ NSFileHandle *socket = [notification.userInfo objectForKey:NSFileHandleNotificationFileHandleItem];
+
+ // Now that we have a client connected, handle request on queue
+ dispatch_async(_processingQueue, ^{
- // now that we have a client connected, spin off a thread to handle activity
- [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
- toTarget: self
- withObject: socket];
+ [self handleClientConnection:socket];
- [[aNotification object] acceptConnectionInBackgroundAndNotify];
+ });
+
+ // Continue accepting connections
+ [_socketFileHandle acceptConnectionInBackgroundAndNotify];
}
-- (void) handleClientConnection: (NSFileHandle *) clientSocket
+-(void) handleClientConnection:(NSFileHandle *)clientSocket
{
-#if __has_feature(objc_arc)
- @autoreleasepool {
- TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
- id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-
- id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
- id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
-
- @try {
- BOOL result = NO;
- do {
- @autoreleasepool {
- result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
- }
- } while (result);
- }
- @catch (TTransportException * te) {
- (void)te;
- //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
- }
-
- NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
- object: self
- userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
- processor,
- kTSocketServer_ProcessorKey,
- transport,
- kTSockerServer_TransportKey,
- nil]];
- [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-
- }
-#else
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
- TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
- id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-
- id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
- id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
-
- @try {
- BOOL result = NO;
- do {
- NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
- result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
- [myPool release];
- } while (result);
- }
- @catch (TTransportException * te) {
- //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
- }
+ @autoreleasepool {
- NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
- object: self
- userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
- processor,
- kTSocketServer_ProcessorKey,
- transport,
- kTSockerServer_TransportKey,
- nil]];
- [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-
- [pool release];
-#endif
-}
+ TNSFileHandleTransport *transport = [[TNSFileHandleTransport alloc] initWithFileHandle:clientSocket];
+ id<TProcessor> processor = [_processorFactory processorForTransport:transport];
+ id <TProtocol> inProtocol = [_inputProtocolFactory newProtocolOnTransport:transport];
+ id <TProtocol> outProtocol = [_outputProtocolFactory newProtocolOnTransport:transport];
+ NSError *error;
+ if (![processor processOnInputProtocol:inProtocol outputProtocol:outProtocol error:&error]) {
+ // Handle error
+ NSLog(@"Error processing request: %@", error);
+ }
-@end
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [NSNotificationCenter.defaultCenter postNotificationName:TSocketServerClientConnectionFinished
+ object:self
+ userInfo:@{TSocketServerProcessorKey: processor,
+ TSockerServerTransportKey: transport}];
+ });
+ }
+}
+@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TAsyncTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TAsyncTransport.h b/lib/cocoa/src/transport/TAsyncTransport.h
index f75b701..bab4fbd 100644
--- a/lib/cocoa/src/transport/TAsyncTransport.h
+++ b/lib/cocoa/src/transport/TAsyncTransport.h
@@ -18,12 +18,29 @@
*/
#import "TTransport.h"
-#import "TException.h"
-typedef void(^TAsyncFailureBlock)(TException *);
+NS_ASSUME_NONNULL_BEGIN
+
+
+@protocol TAsyncTransport;
+
+
+@protocol TAsyncTransportFactory <NSObject>
+
+-(id<TAsyncTransport>) newTransport;
+
+@end
+
+
+typedef void (^TAsyncCompletionBlock)();
+typedef void (^TAsyncFailureBlock)(NSError * __nonnull);
+
@protocol TAsyncTransport <TTransport>
-- (void) flush:(dispatch_block_t)flushed failure:(TAsyncFailureBlock)failure;
+-(void) flushWithCompletion:(TAsyncCompletionBlock)completed failure:(TAsyncFailureBlock)failure;
@end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TFramedTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TFramedTransport.h b/lib/cocoa/src/transport/TFramedTransport.h
index fc38877..ea68ac4 100644
--- a/lib/cocoa/src/transport/TFramedTransport.h
+++ b/lib/cocoa/src/transport/TFramedTransport.h
@@ -20,10 +20,14 @@
#import <Foundation/Foundation.h>
#import "TTransport.h"
-@interface TFramedTransport : NSObject <TTransport> {
- id <TTransport> mTransport;
-}
+NS_ASSUME_NONNULL_BEGIN
-- (id) initWithTransport: (id <TTransport>) transport;
+
+@interface TFramedTransport : NSObject <TTransport>
+
+-(id) initWithTransport:(id <TTransport>)transport;
@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TFramedTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TFramedTransport.m b/lib/cocoa/src/transport/TFramedTransport.m
index 2148806..4db65c4 100644
--- a/lib/cocoa/src/transport/TFramedTransport.m
+++ b/lib/cocoa/src/transport/TFramedTransport.m
@@ -18,126 +18,163 @@
*/
#import "TFramedTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
#define HEADER_SIZE 4
#define INIT_FRAME_SIZE 1024
-@implementation TFramedTransport {
- NSMutableData* writeBuffer;
- NSMutableData* readBuffer;
- NSUInteger readOffset;
- uint8_t dummy_header[HEADER_SIZE];
-}
-- (id) initWithTransport:(id <TTransport>)transport
-{
- mTransport = [transport retain_stub];
- readBuffer = nil;
- readOffset = 0;
- writeBuffer = [[NSMutableData alloc] initWithCapacity:INIT_FRAME_SIZE];
- [writeBuffer appendBytes:dummy_header length:HEADER_SIZE];
- return self;
-}
+@interface TFramedTransport ()
+
+@property(strong, nonatomic) id<TTransport> transport;
+@property(strong, nonatomic) NSMutableData *writeBuffer;
+@property(strong, nonatomic) NSMutableData *readBuffer;
+@property(assign, nonatomic) NSUInteger readOffset;
+
+@end
+
+
+@implementation TFramedTransport
-- (void) dealloc
+-(id) initWithTransport:(id <TTransport>)aTransport
{
- [mTransport release_stub];
- [writeBuffer release_stub];
- if (readBuffer != nil)
- [readBuffer release_stub];
- [super dealloc_stub];
+ if ((self = [self init])) {
+ _transport = aTransport;
+ _readBuffer = nil;
+ _readOffset = 0;
+ _writeBuffer = [NSMutableData dataWithLength:HEADER_SIZE];
+ }
+ return self;
}
-- (void)flush
+-(BOOL) flush:(NSError **)error
{
- size_t headerAndDataLength = [writeBuffer length];
- if (headerAndDataLength < HEADER_SIZE) {
- @throw [TTransportException exceptionWithReason:@"Framed transport buffer has no header"];
+ int len = (int)[_writeBuffer length];
+ int data_len = len - HEADER_SIZE;
+ if (data_len < 0) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{}];
}
+ return NO;
+ }
- size_t dataLength = headerAndDataLength - HEADER_SIZE;
- uint8_t i32rd[HEADER_SIZE];
- i32rd[0] = (uint8_t)(0xff & (dataLength >> 24));
- i32rd[1] = (uint8_t)(0xff & (dataLength >> 16));
- i32rd[2] = (uint8_t)(0xff & (dataLength >> 8));
- i32rd[3] = (uint8_t)(0xff & (dataLength));
-
- // should we make a copy of the writeBuffer instead? Better for threaded operations!
- [writeBuffer replaceBytesInRange:NSMakeRange(0, HEADER_SIZE) withBytes:i32rd length:HEADER_SIZE];
- [mTransport write:[writeBuffer mutableBytes] offset:0 length:headerAndDataLength];
- [mTransport flush];
-
- // reuse old memory buffer
- [writeBuffer setLength:0];
- [writeBuffer appendBytes:dummy_header length:HEADER_SIZE];
+ UInt8 i32rd[HEADER_SIZE];
+ i32rd[0] = (UInt8)(0xff & (data_len >> 24));
+ i32rd[1] = (UInt8)(0xff & (data_len >> 16));
+ i32rd[2] = (UInt8)(0xff & (data_len >> 8));
+ i32rd[3] = (UInt8)(0xff & (data_len));
+
+ // should we make a copy of the writeBuffer instead? Better for threaded
+ // operations!
+ [_writeBuffer replaceBytesInRange:NSMakeRange(0, HEADER_SIZE)
+ withBytes:i32rd length:HEADER_SIZE];
+
+ if (![_transport write:_writeBuffer.mutableBytes offset:0 length:len error:error]) {
+ return NO;
+ }
+
+ if (![_transport flush:error]) {
+ return NO;
+ }
+
+ _writeBuffer.length = HEADER_SIZE;
+
+ return YES;
}
-- (void) write: (const uint8_t *) data offset: (size_t) offset length: (size_t) length
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
{
- [writeBuffer appendBytes:data+offset length:length];
+ [_writeBuffer appendBytes:data+offset length:length];
+
+ return YES;
}
-- (size_t) readAll: (uint8_t *) buf offset: (size_t) offset length: (size_t) length
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
{
- if (readBuffer == nil) {
- [self readFrame];
+ UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+ if (got != length) {
+
+ // Report underflow only if readAvail didn't report error already
+ if (error && !*error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:nil];
}
-
- if (readBuffer != nil) {
- size_t bufferLength = [readBuffer length];
- if (bufferLength - readOffset >= length) {
- [readBuffer getBytes:buf range:NSMakeRange(readOffset,length)]; // copy data
- readOffset += length;
- } else {
- // void the previous readBuffer data and request a new frame
- [self readFrame];
- [readBuffer getBytes:buf range:NSMakeRange(0,length)]; // copy data
- readOffset = length;
- }
- }
- return length;
+
+ return NO;
+ }
+
+ return YES;
}
-- (void)readFrame
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)length error:(NSError *__autoreleasing *)error
{
- uint8_t i32rd[HEADER_SIZE];
- [mTransport readAll: i32rd offset: 0 length: HEADER_SIZE];
- int32_t headerValue =
- ((i32rd[0] & 0xff) << 24) |
- ((i32rd[1] & 0xff) << 16) |
- ((i32rd[2] & 0xff) << 8) |
- ((i32rd[3] & 0xff));
- if (headerValue < 0) {
- NSString *reason = [NSString stringWithFormat:
- @"Frame header reports negative frame size: %"PRId32,
- headerValue];
- @throw [TTransportException exceptionWithReason:reason];
+ UInt32 got = 0;
+ while (got < length) {
+
+ NSUInteger avail = _readBuffer.length - _readOffset;
+ if (avail == 0) {
+ if (![self readFrame:error]) {
+ return 0;
+ }
+ avail = _readBuffer.length;
}
- /* Cast should be safe:
- * Have verified headerValue non-negative and of lesser or equal bitwidth to size_t. */
- size_t frameSize = (size_t)headerValue;
- [self ensureReadBufferHasLength:frameSize];
+ NSRange range;
+ range.location = _readOffset;
+ range.length = MIN(length - got, avail);
+
+ [_readBuffer getBytes:outBuffer+outBufferOffset+got range:range];
+ _readOffset += range.length;
+ got += range.length;
+ }
- [mTransport readAll:[readBuffer mutableBytes] offset:0 length:frameSize];
+ return got;
}
-- (void)ensureReadBufferHasLength:(size_t)length
+-(BOOL) readFrame:(NSError **)error
{
- if (readBuffer == nil) {
- readBuffer = [[NSMutableData alloc] initWithLength:length];
- } else {
- size_t currentLength = [readBuffer length];
- BOOL isTooLong = (currentLength >= length);
- if (isTooLong) {
- [readBuffer setLength:length];
- } else {
- size_t lengthToAdd = length - currentLength;
- [readBuffer increaseLengthBy:lengthToAdd];
- }
+ UInt8 i32rd[HEADER_SIZE];
+ if (![_transport readAll:i32rd offset:0 length:HEADER_SIZE error:error]) {
+ return NO;
+ }
+
+ SInt32 size =
+ ((i32rd[0] & 0xff) << 24) |
+ ((i32rd[1] & 0xff) << 16) |
+ ((i32rd[2] & 0xff) << 8) |
+ ((i32rd[3] & 0xff));
+
+ if (_readBuffer == nil) {
+
+ _readBuffer = [NSMutableData dataWithLength:size];
+
+ }
+ else {
+
+ SInt32 len = (SInt32)_readBuffer.length;
+ if (len >= size) {
+
+ _readBuffer.length = size;
+
+ }
+ else {
+
+ // increase length of data buffer
+ [_readBuffer increaseLengthBy:size-len];
+
}
+
+ }
+
+ // copy into internal memory buffer
+ if (![_transport readAll:_readBuffer.mutableBytes offset:0 length:size error:error]) {
+ return NO;
+ }
+
+ return YES;
}
@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPClient.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPClient.h b/lib/cocoa/src/transport/THTTPClient.h
deleted file mode 100644
index 78935fb..0000000
--- a/lib/cocoa/src/transport/THTTPClient.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-#import "TTransport.h"
-
-@interface THTTPClient : NSObject <TTransport> {
- NSURL * mURL;
- NSMutableURLRequest * mRequest;
- NSMutableData * mRequestData;
- NSData * mResponseData;
- size_t mResponseDataOffset;
- NSString * mUserAgent;
- int mTimeout;
-}
-
-- (id) initWithURL: (NSURL *) aURL;
-
-- (id) initWithURL: (NSURL *) aURL
- userAgent: (NSString *) userAgent
- timeout: (int) timeout;
-
-- (void) setURL: (NSURL *) aURL;
-
-@end
-
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPClient.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPClient.m b/lib/cocoa/src/transport/THTTPClient.m
deleted file mode 100644
index 169927c..0000000
--- a/lib/cocoa/src/transport/THTTPClient.m
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "THTTPClient.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
-
-@implementation THTTPClient
-
-
-- (void) setupRequest
-{
- if (mRequest != nil) {
- [mRequest release_stub];
- }
-
- // set up our request object that we'll use for each request
- mRequest = [[NSMutableURLRequest alloc] initWithURL: mURL];
- [mRequest setHTTPMethod: @"POST"];
- [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Content-Type"];
- [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Accept"];
-
- NSString * userAgent = mUserAgent;
- if (!userAgent) {
- userAgent = @"Cocoa/THTTPClient";
- }
- [mRequest setValue: userAgent forHTTPHeaderField: @"User-Agent"];
-
- [mRequest setCachePolicy: NSURLRequestReloadIgnoringCacheData];
- if (mTimeout) {
- [mRequest setTimeoutInterval: mTimeout];
- }
-}
-
-
-- (id) initWithURL: (NSURL *) aURL
-{
- return [self initWithURL: aURL
- userAgent: nil
- timeout: 0];
-}
-
-
-- (id) initWithURL: (NSURL *) aURL
- userAgent: (NSString *) userAgent
- timeout: (int) timeout
-{
- self = [super init];
- if (!self) {
- return nil;
- }
-
- mTimeout = timeout;
- if (userAgent) {
- mUserAgent = [userAgent retain_stub];
- }
- mURL = [aURL retain_stub];
-
- [self setupRequest];
-
- // create our request data buffer
- mRequestData = [[NSMutableData alloc] initWithCapacity: 1024];
-
- return self;
-}
-
-
-- (void) setURL: (NSURL *) aURL
-{
- [aURL retain_stub];
- [mURL release_stub];
- mURL = aURL;
-
- [self setupRequest];
-}
-
-
-- (void) dealloc
-{
- [mURL release_stub];
- [mUserAgent release_stub];
- [mRequest release_stub];
- [mRequestData release_stub];
- [mResponseData release_stub];
- [super dealloc_stub];
-}
-
-
-- (size_t) readAll: (uint8_t *) buf offset: (size_t) offset length: (size_t) length
-{
- NSRange r;
- r.location = mResponseDataOffset;
- r.length = length;
-
- [mResponseData getBytes: buf+offset range: r];
- mResponseDataOffset += length;
-
- return length;
-}
-
-
-- (void) write: (const uint8_t *) data offset: (size_t) offset length: (size_t) length
-{
- [mRequestData appendBytes: data+offset length: length];
-}
-
-
-- (void) flush
-{
- [mRequest setHTTPBody: mRequestData]; // not sure if it copies the data
-
- // make the HTTP request
- NSURLResponse * response;
- NSError * error;
- NSData * responseData =
- [NSURLConnection sendSynchronousRequest: mRequest returningResponse: &response error: &error];
-
- [mRequestData setLength: 0];
-
- if (responseData == nil) {
- @throw [TTransportException exceptionWithName: @"TTransportException"
- reason: @"Could not make HTTP request"
- error: error];
- }
- if (![response isKindOfClass: [NSHTTPURLResponse class]]) {
- @throw [TTransportException exceptionWithName: @"TTransportException"
- reason: [NSString stringWithFormat: @"Unexpected NSURLResponse type: %@",
- NSStringFromClass([response class])]];
- }
-
- NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
- if ([httpResponse statusCode] != 200) {
- @throw [TTransportException exceptionWithName: @"TTransportException"
- reason: [NSString stringWithFormat: @"Bad response from HTTP server: %ld",
- (long)[httpResponse statusCode]]];
- }
-
- // phew!
- [mResponseData release_stub];
- mResponseData = [responseData retain_stub];
- mResponseDataOffset = 0;
-}
-
-
-@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPSessionTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPSessionTransport.h b/lib/cocoa/src/transport/THTTPSessionTransport.h
new file mode 100644
index 0000000..003499b
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPSessionTransport.h
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "TAsyncTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+typedef NSError *__nullable (^THTTPSessionTransportResponseValidateBlock) (NSHTTPURLResponse *response, NSData *responseData);
+
+
+@interface THTTPSessionTransportFactory : NSObject<TAsyncTransportFactory>
+
+@property (strong, nonatomic) THTTPSessionTransportResponseValidateBlock responseValidate;
+
++(void) setupDefaultsForSessionConfiguration:(NSURLSessionConfiguration *)config
+ withProtocolName:(NSString *)protocolName;
+
+-(id) initWithSession:(NSURLSession *)session
+ URL:(NSURL *)aURL;
+
+@end
+
+
+@interface THTTPSessionTransport : NSObject <TAsyncTransport>
+
+@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPSessionTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPSessionTransport.m b/lib/cocoa/src/transport/THTTPSessionTransport.m
new file mode 100644
index 0000000..c10b7fc
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPSessionTransport.m
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "THTTPSessionTransport.h"
+#import "TTransportError.h"
+
+
+@interface THTTPSessionTransportFactory ()
+
+@property (strong, nonatomic) NSURLSession *session;
+@property (strong, nonatomic) NSURL *url;
+
+@end
+
+
+@interface THTTPSessionTransport ()
+
+@property (strong, nonatomic) THTTPSessionTransportFactory *factory;
+@property (strong, nonatomic) NSMutableData *requestData;
+@property (strong, nonatomic) NSData *responseData;
+@property (assign, nonatomic) NSUInteger responseDataOffset;
+
+-(instancetype) initWithFactory:(THTTPSessionTransportFactory *)factory;
+
+@end
+
+
+@implementation THTTPSessionTransportFactory
+
++(void) setupDefaultsForSessionConfiguration:(NSURLSessionConfiguration *)config withProtocolName:(NSString *)protocolName
+{
+ NSString *thriftContentType = @"application/x-thrift";
+ if (protocolName.length) {
+ thriftContentType = [thriftContentType stringByAppendingFormat:@"; p=%@", protocolName];
+ }
+
+ config.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
+ config.HTTPShouldUsePipelining = YES;
+ config.HTTPShouldSetCookies = NO;
+ config.URLCache = nil;
+ config.HTTPAdditionalHeaders = @{@"Content-Type":thriftContentType,
+ @"Accept":thriftContentType,
+ @"User-Agent":@"Thrift/Cocoa (Session)"};
+}
+
+
+-(id) initWithSession:(NSURLSession *)session URL:(NSURL *)url
+{
+ self = [super init];
+ if (self) {
+ _session = session;
+ _url = url;
+ }
+
+ return self;
+}
+
+-(id<TAsyncTransport>) newTransport
+{
+ return [[THTTPSessionTransport alloc] initWithFactory:self];
+}
+
+-(NSURLSessionDataTask *) taskWithRequest:(NSURLRequest *)request
+ completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
+ error:(NSError *__autoreleasing *)error
+{
+ NSURLSessionDataTask *newTask = [_session dataTaskWithRequest:request completionHandler:completionHandler];
+ if (!newTask) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{NSLocalizedDescriptionKey:@"Failed to create session data task"}];
+ }
+ return nil;
+ }
+
+ return newTask;
+}
+
+-(NSError *) validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data
+{
+ if (_responseValidate) {
+ return _responseValidate(response, data);
+ }
+ return nil;
+}
+
+@end
+
+
+
+@implementation THTTPSessionTransport
+
+-(instancetype) initWithFactory:(THTTPSessionTransportFactory *)factory
+{
+ self = [super init];
+ if (self) {
+ _factory = factory;
+ }
+ return self;
+}
+
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+ UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+ if (got != length) {
+
+ // Report underflow only if readAvail didn't report error already
+ if (error && !*error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:nil];
+ }
+
+ return NO;
+ }
+
+ return YES;
+}
+
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+ NSUInteger avail = _responseData.length - _responseDataOffset;
+
+ NSRange range;
+ range.location = _responseDataOffset;
+ range.length = MIN(maxLength, avail);
+
+ [_responseData getBytes:outBuffer+outBufferOffset range:range];
+ _responseDataOffset += range.length;
+
+ return (UInt32)range.length;
+}
+
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+ if (!_requestData) {
+ _requestData = [NSMutableData dataWithCapacity:256];
+ }
+
+ [_requestData appendBytes:data+offset length:length];
+
+ return YES;
+}
+
+-(void) flushWithCompletion:(TAsyncCompletionBlock)completed failure:(TAsyncFailureBlock)failure
+{
+ NSError *error;
+
+ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:_factory.url];
+ request.HTTPMethod = @"POST";
+ request.HTTPBody = _requestData;
+
+ _requestData = nil;
+
+ NSURLSessionDataTask *task = [_factory taskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+
+ // Check response type
+ if (!error && ![response isKindOfClass:NSHTTPURLResponse.class]) {
+
+ error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{TTransportErrorHttpErrorKey: @(THttpTransportErrorInvalidResponse)}];
+
+ }
+
+ // Check status code
+ NSHTTPURLResponse *httpResponse = (id)response;
+ if (!error && httpResponse.statusCode != 200) {
+
+ THttpTransportError code;
+ if (httpResponse.statusCode == 401) {
+ code = THttpTransportErrorAuthentication;
+ }
+ else {
+ code = THttpTransportErrorInvalidStatus;
+ }
+
+ error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{TTransportErrorHttpErrorKey: @(code),
+ @"statusCode":@(httpResponse.statusCode)}];
+ }
+
+ // Allow factory to check
+ if (!error) {
+ error = [_factory validateResponse:httpResponse data:data];
+ }
+
+ _responseDataOffset = 0;
+
+ if (error) {
+
+ _responseData = nil;
+
+ failure(error);
+
+ }
+ else {
+
+ if (data == nil) {
+ data = [NSData data];
+ }
+
+ _responseData = data;
+
+ completed(self);
+ }
+
+ } error:&error];
+
+ if (!task) {
+ failure(error);
+ return;
+ }
+
+ [task resume];
+}
+
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+ dispatch_semaphore_t completed = dispatch_semaphore_create(0);
+
+ __block BOOL result;
+ __block NSError *internalError;
+
+ [self flushWithCompletion:^(id < TAsyncTransport > transport) {
+
+ result = YES;
+
+ dispatch_semaphore_signal(completed);
+
+ } failure:^(NSError *error) {
+
+ internalError = error;
+
+ result = NO;
+
+ dispatch_semaphore_signal(completed);
+
+ }];
+
+ dispatch_semaphore_wait(completed, DISPATCH_TIME_FOREVER);
+
+ if (error) {
+ *error = internalError;
+ }
+
+ return result;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPTransport.h b/lib/cocoa/src/transport/THTTPTransport.h
new file mode 100644
index 0000000..3c35daf
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPTransport.h
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "TTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface THTTPTransport : NSObject <TTransport>
+
+-(id) initWithURL:(NSURL *)aURL;
+
+-(id) initWithURL:(NSURL *)aURL
+ userAgent:(nullable NSString *)userAgent
+ timeout:(int)timeout;
+
+-(void) setURL:(NSURL *)aURL;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/THTTPTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/THTTPTransport.m b/lib/cocoa/src/transport/THTTPTransport.m
new file mode 100644
index 0000000..e4046c6
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPTransport.m
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "THTTPTransport.h"
+#import "TTransportError.h"
+
+
+@interface THTTPTransport ()
+
+@property (strong, nonatomic) NSURL *url;
+@property (strong, nonatomic) NSMutableURLRequest *request;
+@property (strong, nonatomic) NSMutableData *requestData;
+@property (strong, nonatomic) NSData *responseData;
+@property (assign, nonatomic) NSUInteger responseDataOffset;
+@property (strong, nonatomic) NSString *userAgent;
+@property (assign, nonatomic) NSTimeInterval timeout;
+
+@end
+
+
+@implementation THTTPTransport
+
+-(void) setupRequest
+{
+ // set up our request object that we'll use for each request
+ _request = [[NSMutableURLRequest alloc] initWithURL:_url];
+ [_request setHTTPMethod:@"POST"];
+ [_request setValue:@"application/x-thrift" forHTTPHeaderField:@"Content-Type"];
+ [_request setValue:@"application/x-thrift" forHTTPHeaderField:@"Accept"];
+
+ NSString *userAgent = _userAgent;
+ if (!userAgent) {
+ userAgent = @"Thrift/Cocoa";
+ }
+ [_request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
+
+ [_request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+ if (_timeout) {
+ [_request setTimeoutInterval:_timeout];
+ }
+}
+
+
+-(id) initWithURL:(NSURL *)aURL
+{
+ return [self initWithURL:aURL
+ userAgent:nil
+ timeout:0];
+}
+
+
+-(id) initWithURL:(NSURL *)aURL
+ userAgent:(NSString *)aUserAgent
+ timeout:(int)aTimeout
+{
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _timeout = aTimeout;
+ _userAgent = aUserAgent;
+ _url = aURL;
+
+ [self setupRequest];
+
+ // create our request data buffer
+ _requestData = [[NSMutableData alloc] initWithCapacity:1024];
+
+ return self;
+}
+
+-(void) setURL:(NSURL *)aURL
+{
+ _url = aURL;
+
+ [self setupRequest];
+}
+
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+ UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+ if (got != length) {
+
+ // Report underflow only if readAvail didn't report error already
+ if (error && !*error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:nil];
+ }
+
+ return NO;
+ }
+
+ return YES;
+}
+
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+ NSUInteger avail = _responseData.length - _responseDataOffset;
+
+ NSRange range;
+ range.location = _responseDataOffset;
+ range.length = MIN(maxLength, avail);
+
+ [_responseData getBytes:outBuffer+outBufferOffset range:range];
+ _responseDataOffset += range.length;
+
+ return (UInt32)range.length;
+}
+
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+ [_requestData appendBytes:data+offset length:length];
+
+ return YES;
+}
+
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+ [_request setHTTPBody:_requestData];
+
+ _responseDataOffset = 0;
+
+ // make the HTTP request
+ NSURLResponse *response;
+ _responseData = [NSURLConnection sendSynchronousRequest:_request returningResponse:&response error:error];
+ if (!_responseData) {
+ return NO;
+ }
+
+ [_requestData setLength:0];
+
+ if (![response isKindOfClass:NSHTTPURLResponse.class]) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{TTransportErrorHttpErrorKey: @(THttpTransportErrorInvalidResponse)}];
+ }
+ return NO;
+ }
+
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+ if ([httpResponse statusCode] != 200) {
+ if (error) {
+
+ THttpTransportError code;
+ if (httpResponse.statusCode == 401) {
+ code = THttpTransportErrorAuthentication;
+ }
+ else {
+ code = THttpTransportErrorInvalidStatus;
+ }
+
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorUnknown
+ userInfo:@{TTransportErrorHttpErrorKey: @(code),
+ @"statusCode":@(httpResponse.statusCode)}];
+ }
+ return NO;
+ }
+
+ return YES;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TMemoryBuffer.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TMemoryBuffer.h b/lib/cocoa/src/transport/TMemoryBuffer.h
index fa4d371..6249d32 100644
--- a/lib/cocoa/src/transport/TMemoryBuffer.h
+++ b/lib/cocoa/src/transport/TMemoryBuffer.h
@@ -20,10 +20,18 @@
#import <Foundation/Foundation.h>
#import "TTransport.h"
-@interface TMemoryBuffer : NSObject <TTransport> {
- NSMutableData *mBuffer;
- NSUInteger mOffset;
-}
-- (id)initWithData:(NSData *)data;
-- (NSData *)getBuffer;
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TMemoryBuffer : NSObject <TTransport>
+
+-(NSData *) buffer;
+
+-(id) initWithData:(NSData *)data;
+
+-(id) initWithDataNoCopy:(NSMutableData *)data;
+
@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TMemoryBuffer.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TMemoryBuffer.m b/lib/cocoa/src/transport/TMemoryBuffer.m
index 4513ab8..ec19cc8 100644
--- a/lib/cocoa/src/transport/TMemoryBuffer.m
+++ b/lib/cocoa/src/transport/TMemoryBuffer.m
@@ -18,57 +18,104 @@
*/
#import "TMemoryBuffer.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
#define GARBAGE_BUFFER_SIZE 4096 // 4KiB
+
+@interface TMemoryBuffer ()
+
+@property(strong, nonatomic) NSMutableData *buffer;
+@property(assign, nonatomic) UInt32 bufferOffset;
+
+@end
+
+
@implementation TMemoryBuffer
-- (id)init {
- if ((self = [super init])) {
- mBuffer = [[NSMutableData alloc] init];
- mOffset = 0;
- }
- return self;
+
+-(id) init
+{
+ if ((self = [super init])) {
+ _buffer = [NSMutableData new];
+ _bufferOffset = 0;
+ }
+ return self;
}
-- (id)initWithData:(NSData *)data {
- if ((self = [super init])) {
- mBuffer = [data mutableCopy];
- mOffset = 0;
- }
- return self;
+-(id) initWithData:(NSData *)data
+{
+ if (self = [super init]) {
+ _buffer = [data mutableCopy];
+ _bufferOffset = 0;
+ }
+ return self;
}
-- (size_t) readAll: (uint8_t *) buf offset: (size_t) offset length: (size_t) length
+-(id) initWithDataNoCopy:(NSMutableData *)data
{
- if ([mBuffer length] - mOffset < length) {
- @throw [TTransportException exceptionWithReason:@"Not enough bytes remain in buffer"];
- }
- [mBuffer getBytes:buf range:NSMakeRange(mOffset, length)];
- mOffset += length;
- if (mOffset >= GARBAGE_BUFFER_SIZE) {
- [mBuffer replaceBytesInRange:NSMakeRange(0, mOffset) withBytes:NULL length:0];
- mOffset = 0;
- }
- return length;
+ if (self = [super init]) {
+ _buffer = data;
+ _bufferOffset = 0;
+ }
+ return self;
}
-- (void) write: (const uint8_t *) data offset: (size_t) offset length: (size_t) length
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
{
- [mBuffer appendBytes:data+offset length:length];
+ UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+ if (got != length) {
+
+ // Report underflow only if readAvail didn't report error already
+ if (error && !*error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:nil];
+ }
+
+ return NO;
+ }
+
+ return YES;
}
-- (void)flush {
- // noop
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+ UInt32 avail = (UInt32)_buffer.length - _bufferOffset;
+ if (avail == 0) {
+ return 0;
+ }
+
+ NSRange range;
+ range.location = _bufferOffset;
+ range.length = MIN(maxLength, avail);
+
+ [_buffer getBytes:outBuffer + outBufferOffset range:range];
+ _bufferOffset += range.length;
+
+ if (_bufferOffset >= GARBAGE_BUFFER_SIZE) {
+ [_buffer replaceBytesInRange:NSMakeRange(0, _bufferOffset) withBytes:NULL length:0];
+ _bufferOffset = 0;
+ }
+
+ return (UInt32)range.length;
+}
+
+-(BOOL) write:(const UInt8 *)inBuffer offset:(UInt32)inBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+ [_buffer appendBytes:inBuffer + inBufferOffset length:length];
+
+ return YES;
}
-- (NSData *)getBuffer {
- return [[mBuffer copy] autorelease_stub];
+-(NSData *) buffer
+{
+ return _buffer;
}
-- (void)dealloc {
- [mBuffer release_stub];
- [super dealloc_stub];
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+ return YES;
}
+
@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TNSFileHandleTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.h b/lib/cocoa/src/transport/TNSFileHandleTransport.h
index ba2a209..db6edf3 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.h
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.h
@@ -21,15 +21,18 @@
#import <Foundation/Foundation.h>
#import "TTransport.h"
-@interface TNSFileHandleTransport : NSObject <TTransport> {
- NSFileHandle * mInputFileHandle;
- NSFileHandle * mOutputFileHandle;
-}
+NS_ASSUME_NONNULL_BEGIN
-- (id) initWithFileHandle: (NSFileHandle *) fileHandle;
-- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
- outputFileHandle: (NSFileHandle *) outputFileHandle;
+@interface TNSFileHandleTransport : NSObject <TTransport>
+
+-(id) initWithFileHandle:(NSFileHandle *)fileHandle;
+
+-(id) initWithInputFileHandle:(NSFileHandle *)inputFileHandle
+ outputFileHandle:(NSFileHandle *)outputFileHandle;
@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TNSFileHandleTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
index c2b18ca..c907f87 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.m
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -19,75 +19,100 @@
#import "TNSFileHandleTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
+
+@interface TNSFileHandleTransport ()
+
+@property(strong, nonatomic) NSFileHandle *inputFileHandle;
+@property(strong, nonatomic) NSFileHandle *outputFileHandle;
+
+@end
@implementation TNSFileHandleTransport
-- (id) initWithFileHandle: (NSFileHandle *) fileHandle
+-(id) initWithFileHandle:(NSFileHandle *)fileHandle
{
- return [self initWithInputFileHandle: fileHandle
- outputFileHandle: fileHandle];
+ return [self initWithInputFileHandle:fileHandle
+ outputFileHandle:fileHandle];
}
-- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
- outputFileHandle: (NSFileHandle *) outputFileHandle
+-(id) initWithInputFileHandle:(NSFileHandle *)aInputFileHandle
+ outputFileHandle:(NSFileHandle *)aOutputFileHandle
{
self = [super init];
-
- mInputFileHandle = [inputFileHandle retain_stub];
- mOutputFileHandle = [outputFileHandle retain_stub];
-
+ if (self) {
+ _inputFileHandle = aInputFileHandle;
+ _outputFileHandle = aOutputFileHandle;
+ }
return self;
}
-- (void) dealloc {
- [mInputFileHandle release_stub];
- [mOutputFileHandle release_stub];
- [super dealloc_stub];
+-(BOOL) readAll:(UInt8 *)buf offset:(UInt32)off length:(UInt32)len error:(NSError *__autoreleasing *)error
+{
+ UInt32 got = 0;
+ while (got < len) {
+
+ NSData *d = [_inputFileHandle readDataOfLength:len-got];
+ if (d.length == 0) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:nil];
+ }
+ return NO;
+ }
+
+ [d getBytes:buf+got length:d.length];
+ got += d.length;
+ }
+ return YES;
}
-- (size_t) readAll: (uint8_t *) buf offset: (size_t) offset length: (size_t) length
+-(UInt32) readAvail:(UInt8 *)buf offset:(UInt32)off maxLength:(UInt32)len error:(NSError *__autoreleasing *)error
{
- size_t totalBytesRead = 0;
- while (totalBytesRead < length) {
- NSData * data = [mInputFileHandle readDataOfLength: length-totalBytesRead];
- if ([data length] == 0) {
- @throw [TTransportException exceptionWithName: @"TTransportException"
- reason: @"Cannot read. No more data."];
+ UInt32 got = 0;
+ while (got < len) {
+
+ NSData *d = [_inputFileHandle readDataOfLength:len-got];
+ if (d.length == 0) {
+ break;
}
- [data getBytes: buf+totalBytesRead];
- totalBytesRead += [data length];
+
+ [d getBytes:buf+got length:d.length];
+ got += d.length;
}
- return totalBytesRead;
+ return got;
}
-- (void) write: (const uint8_t *) data offset: (size_t) offset length: (size_t) length
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
{
- const void *pos = data + offset;
- NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: (void *)pos
- length: length
- freeWhenDone: NO];
+ void *pos = (void *)data + offset;
@try {
- [mOutputFileHandle writeData: dataObject];
- } @catch (NSException * e) {
- @throw [TTransportException exceptionWithName: @"TTransportException"
- reason: [NSString stringWithFormat: @"%s: Unable to write data: %@", __PRETTY_FUNCTION__, e]];
+ [_outputFileHandle writeData:[NSData dataWithBytesNoCopy:pos length:length freeWhenDone:NO]];
+ }
+ @catch (NSException *e) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorNotOpen
+ userInfo:@{}];
+ }
+ return NO;
}
- [dataObject release_stub];
+ return YES;
}
-- (void) flush
+-(BOOL) flush:(NSError *__autoreleasing *)error
{
-
+ return YES;
}
@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TNSStreamTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.h b/lib/cocoa/src/transport/TNSStreamTransport.h
index 8011fb9..54c4884 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.h
+++ b/lib/cocoa/src/transport/TNSStreamTransport.h
@@ -20,21 +20,24 @@
#import <Foundation/Foundation.h>
#import "TTransport.h"
-@interface TNSStreamTransport : NSObject <TTransport> {
+NS_ASSUME_NONNULL_BEGIN
-}
-@property (nonatomic, strong) NSInputStream * mInput;
-@property (nonatomic, strong) NSOutputStream * mOutput;
+@interface TNSStreamTransport : NSObject <TTransport>
-- (id) initWithInputStream: (NSInputStream *) input
- outputStream: (NSOutputStream *) output;
+@property (strong, nonatomic) NSInputStream *input;
+@property (strong, nonatomic) NSOutputStream *output;
-- (id) initWithInputStream: (NSInputStream *) input;
+-(id) initWithInputStream:(nullable NSInputStream *)input
+ outputStream:(nullable NSOutputStream *)output;
-- (id) initWithOutputStream: (NSOutputStream *) output;
+-(id) initWithInputStream:(NSInputStream *)input;
-@end
+-(id) initWithOutputStream:(NSOutputStream *)output;
+
+-(void) close;
+@end
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TNSStreamTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.m b/lib/cocoa/src/transport/TNSStreamTransport.m
index 7ac1cdc..c425043 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.m
+++ b/lib/cocoa/src/transport/TNSStreamTransport.m
@@ -18,79 +18,136 @@
*/
#import "TNSStreamTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
+
+@interface TNSStreamTransport ()
+@end
@implementation TNSStreamTransport
-- (id) initWithInputStream: (NSInputStream *) input
- outputStream: (NSOutputStream *) output
+-(id) initWithInputStream:(NSInputStream *)input
+ outputStream:(NSOutputStream *)output
{
self = [super init];
- self.mInput = [input retain_stub];
- self.mOutput = [output retain_stub];
+ if (self) {
+ _input = input;
+ _output = output;
+ }
return self;
}
-- (id) initWithInputStream: (NSInputStream *) input
+-(id) initWithInputStream:(NSInputStream *)input
{
- return [self initWithInputStream: input outputStream: nil];
+ return [self initWithInputStream:input outputStream:nil];
}
-- (id) initWithOutputStream: (NSOutputStream *) output
+-(id) initWithOutputStream:(NSOutputStream *)output
{
- return [self initWithInputStream: nil outputStream: output];
+ return [self initWithInputStream:nil outputStream:output];
}
-- (void) dealloc
+-(void) dealloc
{
- [self.mInput release_stub];
- [self.mOutput release_stub];
- [super dealloc_stub];
+ [self close];
}
+-(BOOL) readAll:(UInt8 *)buf offset:(UInt32)off length:(UInt32)len error:(NSError *__autoreleasing *)error
+{
+ UInt32 got = 0;
+ while (got < len) {
+
+ UInt32 read = (UInt32)[_input read:buf+off+got maxLength:len-got];
+ if (read <= 0) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorNotOpen
+ userInfo:@{}];
+ }
+ return NO;
+ }
-- (size_t) readAll: (uint8_t *) buf offset: (size_t) offset length: (size_t) length
+ got += read;
+ }
+
+ return YES;
+}
+
+
+-(UInt32) readAvail:(UInt8 *)buf offset:(UInt32)off maxLength:(UInt32)len error:(NSError *__autoreleasing *)error
{
- size_t totalBytesRead = 0;
- ssize_t bytesRead = 0;
- while (totalBytesRead < length) {
- bytesRead = [self.mInput read: buf+offset+totalBytesRead maxLength: length-totalBytesRead];
-
- BOOL encounteredErrorOrEOF = (bytesRead <= 0);
- if (encounteredErrorOrEOF) {
- @throw [TTransportException exceptionWithReason: @"Cannot read. Remote side has closed."];
- } else {
- /* bytesRead is guaranteed to be positive and within the range representable by size_t. */
- totalBytesRead += (size_t)bytesRead;
+ UInt32 got = 0;
+ while (got < len) {
+
+ UInt32 read = (UInt32)[_input read:buf+off+got maxLength:len-got];
+ if (read <= 0) {
+ break;
}
+
+ got += read;
}
- return totalBytesRead;
+
+ return got;
}
-- (void) write: (const uint8_t *) data offset: (size_t) offset length: (size_t) length
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
{
- size_t totalBytesWritten = 0;
- ssize_t bytesWritten = 0;
- while (totalBytesWritten < length) {
- bytesWritten = [self.mOutput write: data+offset+totalBytesWritten maxLength: length-totalBytesWritten];
- if (bytesWritten < 0) {
- @throw [TTransportException exceptionWithReason: @"Error writing to transport output stream."
- error: [self.mOutput streamError]];
- } else if (bytesWritten == 0) {
- @throw [TTransportException exceptionWithReason: @"End of output stream."];
- } else {
- /* bytesWritten is guaranteed to be positive and within the range representable by size_t. */
- totalBytesWritten += (size_t)bytesWritten;
+ int got = 0;
+ NSInteger total = 0;
+ while (got < length) {
+
+ total = [_output write:data+offset+got maxLength:length-got];
+ if (total == -1) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorNotOpen
+ userInfo:@{}];
+ }
+ return NO;
}
+ else if (total == 0) {
+ if (error) {
+ *error = [NSError errorWithDomain:TTransportErrorDomain
+ code:TTransportErrorEndOfFile
+ userInfo:@{}];
+ }
+ return NO;
+ }
+
+ got += total;
}
+
+ return YES;
}
-- (void) flush
+-(BOOL) flush:(NSError *__autoreleasing *)error
{
- // no flush for you!
+ return YES;
+}
+
+-(void) close
+{
+ NSInputStream *input = self.input;
+ if (input) {
+ // Close and reset inputstream
+ CFReadStreamSetProperty((__bridge CFReadStreamRef)(input), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+ [input setDelegate:nil];
+ [input close];
+ [input removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+ input = nil;
+ }
+
+ NSOutputStream *output = self.output;
+ if (output) {
+ // Close and reset outputstream
+ CFWriteStreamSetProperty((__bridge CFWriteStreamRef)(output), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+ [output setDelegate:nil];
+ [output close];
+ [output removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+ output = nil;
+ }
}
@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketClient.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketClient.h b/lib/cocoa/src/transport/TSSLSocketClient.h
deleted file mode 100644
index 44de124..0000000
--- a/lib/cocoa/src/transport/TSSLSocketClient.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-#import "TNSStreamTransport.h"
-
-@interface TSSLSocketClient : TNSStreamTransport
-#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
-<NSStreamDelegate>
-#endif
-{
- NSInputStream *inputStream;
- NSOutputStream *outputStream;
-@private
- NSString *sslHostname;
- int sd;
-}
-
-- (id) initWithHostname: (NSString *) hostname
- port: (int) port;
-
-- (BOOL) isOpen;
-
-@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketClient.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketClient.m b/lib/cocoa/src/transport/TSSLSocketClient.m
deleted file mode 100644
index d8c55d6..0000000
--- a/lib/cocoa/src/transport/TSSLSocketClient.m
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#import <Foundation/Foundation.h>
-#import <CoreFoundation/CoreFoundation.h>
-#import "TSSLSocketClient.h"
-#import "TSSLSocketException.h"
-#import "TObjective-C.h"
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-#if !TARGET_OS_IPHONE
-#import <CoreServices/CoreServices.h>
-#else
-#import <CFNetwork/CFNetwork.h>
-#endif
-
-@implementation TSSLSocketClient
-
-- (id) initWithHostname: (NSString *) hostname
- port: (int) port
-{
- sslHostname = hostname;
- CFReadStreamRef readStream = NULL;
- CFWriteStreamRef writeStream = NULL;
-
-
- /* create a socket structure */
- struct sockaddr_in pin;
- struct hostent *hp = NULL;
- for(int i = 0; i < 10; i++) {
-
-
-
- if ((hp = gethostbyname([hostname UTF8String])) == NULL) {
- NSLog(@"failed to resolve hostname %@", hostname);
- herror("resolv");
- if(i == 9) {
- @throw [TSSLSocketException exceptionWithReason: @"failed to resolve hostname"];
- }
- [NSThread sleepForTimeInterval:0.2];
- } else {
- break;
- }
- }
-
- memset (&pin, 0, sizeof(pin));
- pin.sin_family = AF_INET;
- memcpy(&pin.sin_addr, hp->h_addr, sizeof(struct in_addr));
- pin.sin_port = htons (port);
-
- /* create the socket */
- if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
- {
- NSLog(@"failed to create socket for host %@:%d", hostname, port);
- @throw [TSSLSocketException exceptionWithReason: @"failed to create socket"];
- }
-
- /* open a connection */
- if (connect (sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
- {
- NSLog(@"failed to create conenct to host %@:%d", hostname, port);
- @throw [TSSLSocketException exceptionWithReason: @"failed to connect"];
- }
- CFStreamCreatePairWithSocket(kCFAllocatorDefault, sd, &readStream, &writeStream);
-
- CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
- CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
-
- if (readStream && writeStream) {
- CFReadStreamSetProperty(readStream,
- kCFStreamPropertySocketSecurityLevel,
- kCFStreamSocketSecurityLevelTLSv1);
-
- NSDictionary *settings =
- [NSDictionary dictionaryWithObjectsAndKeys:
- (id)kCFBooleanTrue, (id)kCFStreamSSLValidatesCertificateChain,
- nil];
-
- CFReadStreamSetProperty((CFReadStreamRef)readStream,
- kCFStreamPropertySSLSettings,
- (CFTypeRef)settings);
- CFWriteStreamSetProperty((CFWriteStreamRef)writeStream,
- kCFStreamPropertySSLSettings,
- (CFTypeRef)settings);
-
- inputStream = (bridge_stub NSInputStream *)readStream;
- [inputStream retain_stub];
- [inputStream setDelegate:self];
- [inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- [inputStream open];
-
- outputStream = (bridge_stub NSOutputStream *)writeStream;
- [outputStream retain_stub];
- [outputStream setDelegate:self];
- [outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- [outputStream open];
-
-
- CFRelease(readStream);
- CFRelease(writeStream);
- }
-
-
-
- self = [super initWithInputStream: inputStream outputStream: outputStream];
-
- return self;
-}
-
-#pragma mark -
-#pragma mark NSStreamDelegate
-- (void)stream:(NSStream *)aStream
- handleEvent:(NSStreamEvent)eventCode {
- switch (eventCode) {
- case NSStreamEventNone:
- break;
- case NSStreamEventHasBytesAvailable:
- break;
- case NSStreamEventOpenCompleted:
- break;
- case NSStreamEventHasSpaceAvailable:
- {
- SecPolicyRef policy = SecPolicyCreateSSL(NO, (__bridge CFStringRef)(sslHostname));
- SecTrustRef trust = NULL;
- CFArrayRef streamCertificatesRef =
- CFBridgingRetain((__bridge id)((__bridge CFArrayRef)([aStream propertyForKey:(NSString *) kCFStreamPropertySSLPeerCertificates])));
- SecTrustCreateWithCertificates(CFBridgingRetain((__bridge id)(streamCertificatesRef)),
- policy,
- &trust);
-
- SecTrustResultType trustResultType = kSecTrustResultInvalid;
- SecTrustEvaluate(trust, &trustResultType);
-
- BOOL proceed = NO;
- switch (trustResultType) {
- case kSecTrustResultProceed:
- proceed = YES;
- break;
- case kSecTrustResultUnspecified:
- NSLog(@"Trusted by OS");
- proceed = YES;
- break;
- case kSecTrustResultRecoverableTrustFailure:
- proceed = recoverFromTrustFailure(trust);
- break;
- case kSecTrustResultDeny:
- NSLog(@"Deny");
- break;
- case kSecTrustResultFatalTrustFailure:
- NSLog(@"FatalTrustFailure");
- break;
- case kSecTrustResultOtherError:
- NSLog(@"OtherError");
- break;
- case kSecTrustResultInvalid:
- NSLog(@"Invalid");
- break;
- default:
- NSLog(@"Default");
- break;
- }
-
- if (trust) {
- CFRelease(trust);
- }
- if (policy) {
- CFRelease(policy);
- }
- if (!proceed) {
- NSLog(@"Cannot trust certificate. TrustResultType: %u", trustResultType);
- [aStream close];
- @throw [TSSLSocketException exceptionWithReason: @"Cannot trust certificate"];
- }
- }
- break;
- case NSStreamEventErrorOccurred:
- {
- NSError *theError = [aStream streamError];
- NSLog(@"Error occurred opening stream: %@", theError);
-// @throw [TSSLSocketException exceptionWithReason: @"Error occurred opening stream" error: theError];
- break;
- }
- case NSStreamEventEndEncountered:
- break;
- }
-}
-
-bool recoverFromTrustFailure(SecTrustRef myTrust)
-{
-
- SecTrustResultType trustResult;
- OSStatus status = SecTrustEvaluate(myTrust, &trustResult);
-
- CFAbsoluteTime trustTime,currentTime,timeIncrement,newTime;
- CFDateRef newDate;
- if (trustResult == kSecTrustResultRecoverableTrustFailure) {
- trustTime = SecTrustGetVerifyTime(myTrust);
- timeIncrement = 31536000;
- currentTime = CFAbsoluteTimeGetCurrent();
- newTime = currentTime - timeIncrement;
- if (trustTime - newTime){
- newDate = CFDateCreate(NULL, newTime);
- SecTrustSetVerifyDate(myTrust, newDate);
- status = SecTrustEvaluate(myTrust, &trustResult);
- }
- }
- if (trustResult != kSecTrustResultProceed) {
- NSLog(@"Certificate trust failure");
- return false;
- }
- return true;
-}
-
-- (void)close
-{
- if(self.mInput) {
- //Close and reset inputstream
- CFReadStreamSetProperty((__bridge CFReadStreamRef)(self.mInput), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
- [self.mInput setDelegate:nil];
- [self.mInput close];
- [self.mInput removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- self.mInput = nil;
- }
-
- if(self.mOutput) {
- //Close and reset outputstream
- CFReadStreamSetProperty((__bridge CFReadStreamRef)(self.mOutput), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
- [self.mOutput setDelegate:nil];
- [self.mOutput close];
- [self.mOutput removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- self.mOutput = nil;
- }
-}
-
-- (BOOL) isOpen
-{
- if(sd > 0)
- return TRUE;
- else
- return FALSE;
-}
-
-@end
-
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketException.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketException.h b/lib/cocoa/src/transport/TSSLSocketException.h
deleted file mode 100644
index c290b05..0000000
--- a/lib/cocoa/src/transport/TSSLSocketException.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TTransportException.h"
-
-@interface TSSLSocketException : TTransportException
-
-+ (id) exceptionWithReason: (NSString *) reason
- error: (NSError *) error;
-
-+ (id) exceptionWithReason: (NSString *) reason;
-
-@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketException.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketException.m b/lib/cocoa/src/transport/TSSLSocketException.m
deleted file mode 100644
index 99eadf5..0000000
--- a/lib/cocoa/src/transport/TSSLSocketException.m
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TSSLSocketException.h"
-
-@implementation TSSLSocketException
-
-+ (id) exceptionWithReason: (NSString *) reason
- error: (NSError *) error
-{
- NSDictionary * userInfo = nil;
- if (error != nil) {
- userInfo = [NSDictionary dictionaryWithObject: error forKey: @"error"];
- }
-
- return [super exceptionWithName: @"TSSLSocketException"
- reason: reason
- userInfo: userInfo];
-}
-
-+ (id) exceptionWithReason: (NSString *) reason
-{
- return [self exceptionWithReason: reason error: nil];
-}
-
-@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketTransport.h b/lib/cocoa/src/transport/TSSLSocketTransport.h
new file mode 100644
index 0000000..b606c4a
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransport.h
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "TNSStreamTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TSSLSocketTransport : TNSStreamTransport <NSStreamDelegate>
+
+-(id) initWithHostname:(NSString *)hostname
+ port:(int)port
+ error:(NSError **)error;
+
+-(BOOL) isOpen;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketTransport.m b/lib/cocoa/src/transport/TSSLSocketTransport.m
new file mode 100644
index 0000000..ab5eb3d
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransport.m
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#import <Foundation/Foundation.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import "TSSLSocketTransport.h"
+#import "TSSLSocketTransportError.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#if !TARGET_OS_IPHONE
+#import <CoreServices/CoreServices.h>
+#else
+#import <CFNetwork/CFNetwork.h>
+#endif
+
+@interface TSSLSocketTransport ()
+
+@property(strong, nonatomic) NSString *sslHostname;
+@property(assign, nonatomic) int sd;
+
+@end
+
+
+@implementation TSSLSocketTransport
+
+-(id) initWithHostname:(NSString *)hostname
+ port:(int)port
+ error:(NSError **)error
+{
+ _sslHostname = hostname;
+ CFReadStreamRef readStream = NULL;
+ CFWriteStreamRef writeStream = NULL;
+
+
+ /* create a socket structure */
+ struct sockaddr_in pin;
+ struct hostent *hp = NULL;
+ for (int i = 0; i < 10; i++) {
+
+
+
+ if ((hp = gethostbyname([hostname UTF8String])) == NULL) {
+ NSLog(@"failed to resolve hostname %@", hostname);
+ herror("resolv");
+ if (i == 9) {
+ if (error) {
+ *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+ code:TSSLSocketTransportErrorHostanameResolution
+ userInfo:nil];
+ }
+ return nil;
+ }
+ [NSThread sleepForTimeInterval:0.2];
+ }
+ else {
+ break;
+ }
+ }
+
+ memset(&pin, 0, sizeof(pin));
+ pin.sin_family = AF_INET;
+ memcpy(&pin.sin_addr, hp->h_addr, sizeof(struct in_addr));
+ pin.sin_port = htons(port);
+
+ /* create the socket */
+ if ((_sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ NSLog(@"failed to create socket for host %@:%d", hostname, port);
+ if (error) {
+ *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+ code:TSSLSocketTransportErrorSocketCreate
+ userInfo:nil];
+ }
+ return nil;
+ }
+
+ /* open a connection */
+ if (connect(_sd, (struct sockaddr *)&pin, sizeof(pin)) == -1) {
+ NSLog(@"failed to create conenct to host %@:%d", hostname, port);
+ if (error) {
+ *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+ code:TSSLSocketTransportErrorConnect
+ userInfo:nil];
+ }
+ return nil;
+ }
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault, _sd, &readStream, &writeStream);
+
+ CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+ CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+
+ NSInputStream *inputStream;
+ NSOutputStream *outputStream;
+
+ if (readStream && writeStream) {
+
+ CFReadStreamSetProperty(readStream,
+ kCFStreamPropertySocketSecurityLevel,
+ kCFStreamSocketSecurityLevelTLSv1);
+
+ NSDictionary *settings = @{(__bridge NSString *)kCFStreamSSLValidatesCertificateChain: @YES};
+
+ CFReadStreamSetProperty((CFReadStreamRef)readStream,
+ kCFStreamPropertySSLSettings,
+ (CFTypeRef)settings);
+
+ CFWriteStreamSetProperty((CFWriteStreamRef)writeStream,
+ kCFStreamPropertySSLSettings,
+ (CFTypeRef)settings);
+
+ inputStream = (__bridge NSInputStream *)readStream;
+ [inputStream setDelegate:self];
+ [inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+ [inputStream open];
+
+ outputStream = (__bridge NSOutputStream *)writeStream;
+ [outputStream setDelegate:self];
+ [outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+ [outputStream open];
+
+ CFRelease(readStream);
+ CFRelease(writeStream);
+ }
+
+ self = [super initWithInputStream:inputStream outputStream:outputStream];
+
+ return self;
+}
+
+-(void) dealloc
+{
+ [self close];
+}
+
+#pragma mark -
+#pragma mark NSStreamDelegate
+
+-(void) stream:(NSStream *)aStream
+ handleEvent:(NSStreamEvent)eventCode
+{
+ switch (eventCode) {
+ case NSStreamEventNone:
+ break;
+
+ case NSStreamEventHasBytesAvailable:
+ break;
+
+ case NSStreamEventOpenCompleted:
+ break;
+
+ case NSStreamEventHasSpaceAvailable: {
+
+ BOOL proceed = NO;
+ SecTrustResultType trustResult = kSecTrustResultInvalid;
+ CFMutableArrayRef newPolicies = NULL;
+
+ do {
+
+ SecTrustRef trust = (__bridge SecTrustRef)[aStream propertyForKey:(NSString *)kCFStreamPropertySSLPeerTrust];
+
+ // Add new policy to current list of policies
+ SecPolicyRef policy = SecPolicyCreateSSL(NO, (__bridge CFStringRef)(_sslHostname));
+ if (!policy) {
+ break;
+ }
+
+ CFArrayRef policies;
+ if (SecTrustCopyPolicies(trust, &policies) != errSecSuccess) {
+ CFRelease(policy);
+ break;
+ }
+
+ newPolicies = CFArrayCreateMutableCopy(NULL, 0, policies);
+ CFArrayAppendValue(newPolicies, policy);
+
+ CFRelease(policies);
+ CFRelease(policy);
+
+ // Update trust policies
+ if (SecTrustSetPolicies(trust, newPolicies) != errSecSuccess) {
+ break;
+ }
+
+ // Evaluate the trust chain
+ if (SecTrustEvaluate(trust, &trustResult) != errSecSuccess) {
+ break;
+ }
+
+ switch (trustResult) {
+ case kSecTrustResultProceed:
+ // NSLog(@"Trusted by USER");
+ proceed = YES;
+ break;
+
+ case kSecTrustResultUnspecified:
+ // NSLog(@"Trusted by OS");
+ proceed = YES;
+ break;
+
+ case kSecTrustResultRecoverableTrustFailure:
+ proceed = recoverFromTrustFailure(trust, trustResult);
+ break;
+
+ case kSecTrustResultDeny:
+ // NSLog(@"Deny");
+ break;
+
+ case kSecTrustResultFatalTrustFailure:
+ // NSLog(@"FatalTrustFailure");
+ break;
+
+ case kSecTrustResultOtherError:
+ // NSLog(@"OtherError");
+ break;
+
+ case kSecTrustResultInvalid:
+ // NSLog(@"Invalid");
+ break;
+
+ default:
+ // NSLog(@"Default");
+ break;
+ }
+
+ }
+ while (NO);
+
+ if (!proceed) {
+ NSLog(@"TSSLSocketTransport: Cannot trust certificate. Result: %u", trustResult);
+ [aStream close];
+ }
+
+ if (newPolicies) {
+ CFRelease(newPolicies);
+ }
+
+ }
+ break;
+
+ case NSStreamEventErrorOccurred: {
+ NSLog(@"TSSLSocketTransport: Error occurred opening stream: %@", [aStream streamError]);
+ break;
+ }
+
+ case NSStreamEventEndEncountered:
+ break;
+ }
+}
+
+BOOL recoverFromTrustFailure(SecTrustRef myTrust, SecTrustResultType lastTrustResult)
+{
+ CFAbsoluteTime trustTime = SecTrustGetVerifyTime(myTrust);
+ CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
+
+ CFAbsoluteTime timeIncrement = 31536000;
+ CFAbsoluteTime newTime = currentTime - timeIncrement;
+
+ if (trustTime - newTime) {
+
+ CFDateRef newDate = CFDateCreate(NULL, newTime);
+ SecTrustSetVerifyDate(myTrust, newDate);
+ CFRelease(newDate);
+
+ if (SecTrustEvaluate(myTrust, &lastTrustResult) != errSecSuccess) {
+ return NO;
+ }
+
+ }
+
+ if (lastTrustResult == kSecTrustResultProceed || lastTrustResult == kSecTrustResultUnspecified) {
+ return YES;
+ }
+
+ NSLog(@"TSSLSocketTransport: Unable to recover certificate trust failure");
+ return YES;
+}
+
+-(BOOL) isOpen
+{
+ if (_sd > 0) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/thrift/blob/56e5b9b0/lib/cocoa/src/transport/TSSLSocketTransportError.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSSLSocketTransportError.h b/lib/cocoa/src/transport/TSSLSocketTransportError.h
new file mode 100644
index 0000000..e17f39e
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransportError.h
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TTransportError.h"
+
+
+extern NSString *TSSLSocketTransportErrorDomain;
+
+
+typedef NS_ENUM (int, TSSLSocketTransportError) {
+ TSSLSocketTransportErrorHostanameResolution = -10000,
+ TSSLSocketTransportErrorSocketCreate = -10001,
+ TSSLSocketTransportErrorConnect = -10002,
+};