Repository: thrift
Updated Branches:
  refs/heads/master 90b630490 -> df3223c85


THRIFT-3859: Add support for Unix Domain Sockets to TSocketServer and 
TSocketTransport.
Client: cocoa

TSocketServer and TSocketTransport have been refactored to support sockets 
created using either a port or a path.
Existing behavior for port-based socket transport is unchanged by this commit.

This closes #1031


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/df3223c8
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/df3223c8
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/df3223c8

Branch: refs/heads/master
Commit: df3223c85db910e55bc1d5237c145ddcde93e664
Parents: 90b6304
Author: Chris Vasselli <cvasse...@box.com>
Authored: Tue Jun 21 16:45:39 2016 -0700
Committer: James E. King, III <jk...@apache.org>
Committed: Sun Apr 2 23:14:29 2017 -0400

----------------------------------------------------------------------
 lib/cocoa/src/server/TSocketServer.h       |   4 +
 lib/cocoa/src/server/TSocketServer.m       | 117 +++++++++++++++++++-----
 lib/cocoa/src/transport/TSocketTransport.h |   2 +
 lib/cocoa/src/transport/TSocketTransport.m |  68 +++++++++++++-
 4 files changed, 165 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/df3223c8/lib/cocoa/src/server/TSocketServer.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/server/TSocketServer.h 
b/lib/cocoa/src/server/TSocketServer.h
index fe657ea..95b0d3c 100644
--- a/lib/cocoa/src/server/TSocketServer.h
+++ b/lib/cocoa/src/server/TSocketServer.h
@@ -41,6 +41,10 @@ extern NSString *const TSockerServerTransportKey;
              protocolFactory:(id <TProtocolFactory>)protocolFactory
             processorFactory:(id <TProcessorFactory>)processorFactory;
 
+- (instancetype) initWithPath: (NSString *) path
+              protocolFactory: (id <TProtocolFactory>) protocolFactory
+             processorFactory: (id <TProcessorFactory>) processorFactory;
+
 @end
 
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/df3223c8/lib/cocoa/src/server/TSocketServer.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/server/TSocketServer.m 
b/lib/cocoa/src/server/TSocketServer.m
index ccbbba1..09b603c 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -25,7 +25,7 @@
 
 #import <sys/socket.h>
 #include <netinet/in.h>
-
+#include <sys/un.h>
 
 
 NSString *const TSocketServerClientConnectionFinished = 
@"TSocketServerClientConnectionFinished";
@@ -40,13 +40,14 @@ NSString *const TSockerServerTransportKey = 
@"TSockerServerTransport";
 @property(strong, nonatomic) id<TProcessorFactory> processorFactory;
 @property(strong, nonatomic) NSFileHandle *socketFileHandle;
 @property(strong, nonatomic) dispatch_queue_t processingQueue;
+@property(strong, nonatomic) NSString *domainSocketPath;
 
 @end
 
 
 @implementation TSocketServer
 
--(instancetype) initWithPort:(int)port
+-(instancetype) initWithSocket:(CFSocketRef)socket
              protocolFactory:(id <TProtocolFactory>)protocolFactory
             processorFactory:(id <TProcessorFactory>)processorFactory;
 {
@@ -62,11 +63,50 @@ NSString *const TSockerServerTransportKey = 
@"TSockerServerTransport";
   _processingQueue = dispatch_queue_create("TSocketServer.processing", 
processingQueueAttr);
 
   // create a socket.
-  int fd = -1;
+  int fd = CFSocketGetNative(socket);
+
+  // wrap it in a file handle so we can get messages from it
+  _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:_socketFileHandle];
+
+  // tell socket to listen
+  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+
+  return self;
+}
+
+- (id) initWithPort: (int) port
+    protocolFactory: (id <TProtocolFactory>) protocolFactory
+   processorFactory: (id <TProcessorFactory>) processorFactory
+{
+  CFSocketRef socket = [[self class] createSocketWithPort:port];
+  if (socket == NULL) {
+    return nil;
+  }
+
+  if (self = [self initWithSocket:socket protocolFactory:protocolFactory 
processorFactory:processorFactory]) {
+    NSLog(@"TSocketServer: Listening on TCP port %d", port);
+  }
+  return self;
+}
+
+
++(CFSocketRef) createSocketWithPort:(int)port
+{
   CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, 
SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
   if (socket) {
     CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & 
~kCFSocketCloseOnInvalidate);
-    fd = CFSocketGetNative(socket);
+    int fd = CFSocketGetNative(socket);
     int yes = 1;
     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 
@@ -81,40 +121,75 @@ NSString *const TSockerServerTransportKey = 
@"TSockerServerTransport";
       CFSocketInvalidate(socket);
       CFRelease(socket);
       NSLog(@"TSocketServer: Could not bind to address");
-      return nil;
+      return NULL;
     }
+
+    return socket;
   }
   else {
     NSLog(@"TSocketServer: No server socket");
+    return NULL;
+  }
+}
+
+- (id) initWithPath: (NSString *) path
+    protocolFactory: (id <TProtocolFactory>) protocolFactory
+   processorFactory: (id <TProcessorFactory>) processorFactory
+{
+  _domainSocketPath = path;
+  CFSocketRef socket = [[self class] createSocketWithPath:path];
+  if (socket == NULL) {
     return nil;
   }
 
-  // wrap it in a file handle so we can get messages from it
-  _socketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd
-                                                    closeOnDealloc:YES];
+  if (self = [self initWithSocket:socket protocolFactory:protocolFactory 
processorFactory:processorFactory]) {
+    NSLog(@"TSocketServer: Listening on path %@", path);
+  }
+  return self;
+}
 
-  // throw away our socket
-  CFSocketInvalidate(socket);
-  CFRelease(socket);
++ (CFSocketRef) createSocketWithPath: (NSString *) path
+{
+  CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_LOCAL, 
SOCK_STREAM, IPPROTO_IP, 0, NULL, NULL);
+  if (socket) {
+    CFSocketSetSocketFlags(socket,  CFSocketGetSocketFlags(socket) & 
~kCFSocketCloseOnInvalidate);
+    int fd = CFSocketGetNative(socket);
+    int yes = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 
-  // register for notifications of accepted incoming connections
-  [[NSNotificationCenter defaultCenter] addObserver:self
-                                           
selector:@selector(connectionAccepted:)
-                                               
name:NSFileHandleConnectionAcceptedNotification
-                                             object:_socketFileHandle];
+    size_t nullTerminatedPathLength = path.length + 1;
+    struct sockaddr_un addr;
+    if (nullTerminatedPathLength> sizeof(addr.sun_path)) {
+      NSLog(@"TSocketServer: Unable to create socket at path %@. Path is too 
long.", path);
+      return NULL;
+    }
 
-  // tell socket to listen
-  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+    addr.sun_family = AF_LOCAL;
+    memcpy(addr.sun_path, path.UTF8String, nullTerminatedPathLength);
+    addr.sun_len = SUN_LEN(&addr);
 
-  NSLog(@"TSocketServer: Listening on TCP port %d", port);
+    NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
+    if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != 
kCFSocketSuccess) {
+      CFSocketInvalidate(socket);
+      CFRelease(socket);
+      NSLog(@"TSocketServer: Could not bind to address");
+      return NULL;
+    }
 
-  return self;
+    return socket;
+  } else {
+    NSLog(@"TSocketServer: No server socket");
+    return NULL;
+  }
 }
 
-
 -(void) dealloc
 {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+  if (_domainSocketPath != nil) {
+    unlink(_domainSocketPath.UTF8String);
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/df3223c8/lib/cocoa/src/transport/TSocketTransport.h
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSocketTransport.h 
b/lib/cocoa/src/transport/TSocketTransport.h
index 4ea03cc..a7b91a2 100644
--- a/lib/cocoa/src/transport/TSocketTransport.h
+++ b/lib/cocoa/src/transport/TSocketTransport.h
@@ -28,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
 -(id) initWithHostname:(NSString *)hostname
                   port:(int)port;
 
+-(id) initWithPath:(NSString *)path;
+
 @end
 
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/df3223c8/lib/cocoa/src/transport/TSocketTransport.m
----------------------------------------------------------------------
diff --git a/lib/cocoa/src/transport/TSocketTransport.m 
b/lib/cocoa/src/transport/TSocketTransport.m
index 272baf6..9c58abb 100644
--- a/lib/cocoa/src/transport/TSocketTransport.m
+++ b/lib/cocoa/src/transport/TSocketTransport.m
@@ -24,21 +24,21 @@
 #import <CFNetwork/CFNetwork.h>
 #endif
 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
 @interface TSocketTransport () <NSStreamDelegate>
 @end
 
 
 @implementation TSocketTransport
 
--(id) initWithHostname:(NSString *)hostname
-                  port:(int)port
+- (id) initWithReadStream: (CFReadStreamRef) readStream writeStream: 
(CFWriteStreamRef) writeStream
 {
   NSInputStream *inputStream = nil;
   NSOutputStream *outputStream = nil;
 
-  CFReadStreamRef readStream = NULL;
-  CFWriteStreamRef writeStream = NULL;
-  CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge 
CFStringRef)hostname, port, &readStream, &writeStream);
   if (readStream && writeStream) {
 
     CFReadStreamSetProperty(readStream, 
kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
@@ -70,4 +70,62 @@
   return [super initWithInputStream:inputStream outputStream:outputStream];
 }
 
+- (id) initWithHostname: (NSString *) hostname
+                   port: (int) port
+{
+  CFReadStreamRef readStream = NULL;
+  CFWriteStreamRef writeStream = NULL;
+  CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge 
CFStringRef)hostname, port, &readStream, &writeStream);
+  return [self initWithReadStream:readStream writeStream:writeStream];
+}
+
+- (id) initWithPath: (NSString *) path
+{
+  CFSocketNativeHandle sockfd = socket(AF_LOCAL, SOCK_STREAM, IPPROTO_IP);
+  int yes = 1;
+  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
+  {
+    NSLog(@"TSocketTransport: Unable to set REUSEADDR property of socket.");
+    return nil;
+  }
+
+  NSData *serverAddress = [[self class] createAddressWithPath:path];
+
+  CFReadStreamRef readStream = NULL;
+  CFWriteStreamRef writeStream = NULL;
+  CFStreamCreatePairWithSocket(kCFAllocatorDefault, sockfd, &readStream, 
&writeStream);
+  if (!readStream || !writeStream)
+  {
+    NSLog(@"TSocketTransport: Unable to create read/write stream pair for 
socket.");
+    return nil;
+  }
+
+  if (connect(sockfd, (struct sockaddr *)serverAddress.bytes, (socklen_t) 
serverAddress.length) < 0)
+  {
+    NSLog(@"TSocketTransport: Connect error: %s\n", strerror(errno));
+    return nil;
+  }
+
+  return [self initWithReadStream:readStream writeStream:writeStream];
+}
+
++ (NSData *) createAddressWithPath: (NSString *)path
+{
+  struct sockaddr_un servaddr;
+
+  size_t nullTerminatedPathLength = path.length + 1;
+  if (nullTerminatedPathLength> sizeof(servaddr.sun_path)) {
+    NSLog(@"TSocketTransport: Unable to create socket at path %@. Path is too 
long.", path);
+    return nil;
+  }
+
+  bzero(&servaddr,sizeof(servaddr));
+  servaddr.sun_family = AF_LOCAL;
+  memcpy(servaddr.sun_path, path.UTF8String, nullTerminatedPathLength);
+  servaddr.sun_len = SUN_LEN(&servaddr);
+
+  return [NSData dataWithBytes:&servaddr length:sizeof(servaddr)];
+}
+
+
 @end

Reply via email to