THRIFT-280. Server-side Cocoa implementation.
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@796538 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cocoa/src/TProcessor.h b/lib/cocoa/src/TProcessor.h
index e361d96..980be94 100644
--- a/lib/cocoa/src/TProcessor.h
+++ b/lib/cocoa/src/TProcessor.h
@@ -18,6 +18,7 @@
*/
#import <Foundation/Foundation.h>
+#import "TProtocol.h"
@protocol TProcessor <NSObject>
diff --git a/lib/cocoa/src/TProcessorFactory.h b/lib/cocoa/src/TProcessorFactory.h
new file mode 100644
index 0000000..29d12b3
--- /dev/null
+++ b/lib/cocoa/src/TProcessorFactory.h
@@ -0,0 +1,27 @@
+/*
+ * 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 "TProcessor.h"
+
+@protocol TProcessorFactory <NSObject>
+
+- (id<TProcessor>) processorForTransport: (id<TTransport>) transport;
+
+@end
diff --git a/lib/cocoa/src/TSharedProcessorFactory.h b/lib/cocoa/src/TSharedProcessorFactory.h
new file mode 100644
index 0000000..d3e55c4
--- /dev/null
+++ b/lib/cocoa/src/TSharedProcessorFactory.h
@@ -0,0 +1,27 @@
+/*
+ * 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 "TProcessorFactory.h"
+
+@interface TSharedProcessorFactory : NSObject <TProcessorFactory> {
+ id<TProcessor> mSharedProcessor;
+}
+
+@end
diff --git a/lib/cocoa/src/TSharedProcessorFactory.m b/lib/cocoa/src/TSharedProcessorFactory.m
new file mode 100644
index 0000000..b38e73a
--- /dev/null
+++ b/lib/cocoa/src/TSharedProcessorFactory.m
@@ -0,0 +1,51 @@
+/*
+ * 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 "TSharedProcessorFactory.h"
+
+
+@implementation TSharedProcessorFactory
+
+
+- (id) initWithSharedProcessor: (id<TProcessor>) sharedProcessor
+{
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ mSharedProcessor = [sharedProcessor retain];
+ return self;
+}
+
+
+- (void) dealloc
+{
+ [mSharedProcessor release];
+ [super dealloc];
+}
+
+
+- (id<TProcessor>) processorForTransport: (id<TTransport>) transport
+{
+ return [[mSharedProcessor retain] autorelease];
+}
+
+@end
diff --git a/lib/cocoa/src/server/TSocketServer.h b/lib/cocoa/src/server/TSocketServer.h
index e107aaa..0d66404 100644
--- a/lib/cocoa/src/server/TSocketServer.h
+++ b/lib/cocoa/src/server/TSocketServer.h
@@ -19,7 +19,17 @@
#import <Foundation/Foundation.h>
#import "TProtocolFactory.h"
-#import "TProcessor.h"
+#import "TProcessorFactory.h"
+
+#if !TARGET_OS_IPHONE
+#import <CoreServices/CoreServices.h>
+#else
+#import <CFNetwork/CFNetwork.h>
+#endif
+
+extern NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification;
+extern NSString * const kTSocketServer_ProcessorKey;
+extern NSString * const kTSockerServer_TransportKey;
@interface TSocketServer : NSObject {
@@ -27,12 +37,12 @@
NSFileHandle * mSocketFileHandle;
id <TProtocolFactory> mInputProtocolFactory;
id <TProtocolFactory> mOutputProtocolFactory;
- id <TProcessor> mProcessor;
+ id <TProcessorFactory> mProcessorFactory;
}
- (id) initWithPort: (int) port
protocolFactory: (id <TProtocolFactory>) protocolFactory
- processor: (id <TProcessor>) processor;
+ processorFactory: (id <TProcessorFactory>) processorFactory;
@end
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index 5feb9b6..56a5bea 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -22,54 +22,77 @@
#import "TNSFileHandleTransport.h"
#import "TProtocol.h"
#import "TTransportException.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";
@implementation TSocketServer
- (id) initWithPort: (int) port
protocolFactory: (id <TProtocolFactory>) protocolFactory
- processor: (id <TProcessor>) processor;
+ processorFactory: (id <TProcessorFactory>) processorFactory;
{
self = [super init];
mInputProtocolFactory = [protocolFactory retain];
mOutputProtocolFactory = [protocolFactory retain];
- mProcessor = [processor retain];
+ mProcessorFactory = [processorFactory retain];
- // create a socket
- mServerSocket = [[NSSocketPort alloc] initWithTCPPort: port];
- // FIXME - move this separate start method and add method to close
- // and cleanup any open ports
+ // create a socket.
+ int fd = -1;
+ CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
+ if (socket) {
+ fd = CFSocketGetNative(socket);
+ int yes = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
- if (mServerSocket == nil) {
- NSLog(@"Unable to listen on TCP port %d", port);
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
+ if (CFSocketSetAddress(socket, (CFDataRef)address) != kCFSocketSuccess) {
+ NSLog(@"*** Could not bind to address");
+ return nil;
+ }
} else {
- NSLog(@"Listening on TCP port %d", port);
-
- // wrap it in a file handle so we can get messages from it
- mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: [mServerSocket socket]
- closeOnDealloc: YES];
-
- // register for notifications of accepted incoming connections
- [[NSNotificationCenter defaultCenter] addObserver: self
- selector: @selector(connectionAccepted:)
- name: NSFileHandleConnectionAcceptedNotification
- object: mSocketFileHandle];
-
- // tell socket to listen
- [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
+ NSLog(@"*** 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];
+
+ // register for notifications of accepted incoming connections
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(connectionAccepted:)
+ name: NSFileHandleConnectionAcceptedNotification
+ object: mSocketFileHandle];
+
+ // tell socket to listen
+ [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
+
+ NSLog(@"Listening on TCP port %d", port);
+
return self;
}
- (void) dealloc {
+ [[NSNotificationCenter defaultCenter] removeObject: self];
[mInputProtocolFactory release];
[mOutputProtocolFactory release];
- [mProcessor release];
+ [mProcessorFactory release];
[mSocketFileHandle release];
- [mServerSocket release];
[super dealloc];
}
@@ -90,19 +113,35 @@
- (void) handleClientConnection: (NSFileHandle *) clientSocket
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
+
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 {
- while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]);
+ BOOL result = NO;
+ do {
+ NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
+ result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
+ [myPool release];
+ } while (result);
}
@catch (TTransportException * te) {
- NSLog(@"%@", 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];
+
[pool release];
}
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
index 1533934..b218218 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.m
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -72,8 +72,12 @@
length: length
freeWhenDone: NO];
- [mOutputFileHandle writeData: dataObject];
-
+ @try {
+ [mOutputFileHandle writeData: dataObject];
+ } @catch (NSException * e) {
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: [NSString stringWithFormat: @"%s: Unable to write data: %@", __PRETTY_FUNCTION__, e]];
+ }
[dataObject release];
}