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,
+};