blob: 56a5beafbdfa52afc281322a5150885e588c4d80 [file] [log] [blame]
/*
* 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 "TSocketServer.h"
#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
processorFactory: (id <TProcessorFactory>) processorFactory;
{
self = [super init];
mInputProtocolFactory = [protocolFactory retain];
mOutputProtocolFactory = [protocolFactory retain];
mProcessorFactory = [processorFactory retain];
// 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));
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(@"*** 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];
[mProcessorFactory release];
[mSocketFileHandle release];
[super dealloc];
}
- (void) connectionAccepted: (NSNotification *) aNotification
{
NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
// now that we have a client connected, spin off a thread to handle activity
[NSThread detachNewThreadSelector: @selector(handleClientConnection:)
toTarget: self
withObject: socket];
[[aNotification object] acceptConnectionInBackgroundAndNotify];
}
- (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 {
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);
}
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];
}
@end