blob: 56a5beafbdfa52afc281322a5150885e588c4d80 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Andrew McGeachie6db89f22009-07-21 14:45:12 +000020#import <Foundation/Foundation.h>
Mark Slee77575e62007-09-24 19:24:53 +000021#import "TSocketServer.h"
22#import "TNSFileHandleTransport.h"
23#import "TProtocol.h"
Mark Slee84406052007-11-20 01:39:25 +000024#import "TTransportException.h"
Andrew McGeachie0c895712009-07-21 21:14:19 +000025#import <sys/socket.h>
26#include <netinet/in.h>
27
28
29
30NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification";
31NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor";
32NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
Mark Slee77575e62007-09-24 19:24:53 +000033
34
35@implementation TSocketServer
36
37- (id) initWithPort: (int) port
38 protocolFactory: (id <TProtocolFactory>) protocolFactory
Andrew McGeachie0c895712009-07-21 21:14:19 +000039 processorFactory: (id <TProcessorFactory>) processorFactory;
Mark Slee77575e62007-09-24 19:24:53 +000040{
41 self = [super init];
42
43 mInputProtocolFactory = [protocolFactory retain];
44 mOutputProtocolFactory = [protocolFactory retain];
Andrew McGeachie0c895712009-07-21 21:14:19 +000045 mProcessorFactory = [processorFactory retain];
David Reiss0c90f6f2008-02-06 22:18:40 +000046
Andrew McGeachie0c895712009-07-21 21:14:19 +000047 // create a socket.
48 int fd = -1;
49 CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
50 if (socket) {
51 fd = CFSocketGetNative(socket);
52 int yes = 1;
53 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
David Reiss0c90f6f2008-02-06 22:18:40 +000054
Andrew McGeachie0c895712009-07-21 21:14:19 +000055 struct sockaddr_in addr;
56 memset(&addr, 0, sizeof(addr));
57 addr.sin_len = sizeof(addr);
58 addr.sin_family = AF_INET;
59 addr.sin_port = htons(port);
60 addr.sin_addr.s_addr = htonl(INADDR_ANY);
61 NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
62 if (CFSocketSetAddress(socket, (CFDataRef)address) != kCFSocketSuccess) {
63 NSLog(@"*** Could not bind to address");
64 return nil;
65 }
Mark Slee84406052007-11-20 01:39:25 +000066 } else {
Andrew McGeachie0c895712009-07-21 21:14:19 +000067 NSLog(@"*** No server socket");
68 return nil;
Mark Slee84406052007-11-20 01:39:25 +000069 }
Andrew McGeachie0c895712009-07-21 21:14:19 +000070
71 // wrap it in a file handle so we can get messages from it
72 mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
73 closeOnDealloc: YES];
74
75 // register for notifications of accepted incoming connections
76 [[NSNotificationCenter defaultCenter] addObserver: self
77 selector: @selector(connectionAccepted:)
78 name: NSFileHandleConnectionAcceptedNotification
79 object: mSocketFileHandle];
80
81 // tell socket to listen
82 [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
83
84 NSLog(@"Listening on TCP port %d", port);
85
Mark Slee77575e62007-09-24 19:24:53 +000086 return self;
87}
88
89
90- (void) dealloc {
Andrew McGeachie0c895712009-07-21 21:14:19 +000091 [[NSNotificationCenter defaultCenter] removeObject: self];
Mark Slee77575e62007-09-24 19:24:53 +000092 [mInputProtocolFactory release];
93 [mOutputProtocolFactory release];
Andrew McGeachie0c895712009-07-21 21:14:19 +000094 [mProcessorFactory release];
Mark Slee77575e62007-09-24 19:24:53 +000095 [mSocketFileHandle release];
Mark Slee77575e62007-09-24 19:24:53 +000096 [super dealloc];
97}
98
99
Mark Slee84406052007-11-20 01:39:25 +0000100- (void) connectionAccepted: (NSNotification *) aNotification
Mark Slee77575e62007-09-24 19:24:53 +0000101{
102 NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
David Reiss0c90f6f2008-02-06 22:18:40 +0000103
Mark Slee77575e62007-09-24 19:24:53 +0000104 // now that we have a client connected, spin off a thread to handle activity
105 [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
106 toTarget: self
107 withObject: socket];
David Reiss0c90f6f2008-02-06 22:18:40 +0000108
Mark Slee77575e62007-09-24 19:24:53 +0000109 [[aNotification object] acceptConnectionInBackgroundAndNotify];
110}
111
112
113- (void) handleClientConnection: (NSFileHandle *) clientSocket
114{
115 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000116
Mark Slee77575e62007-09-24 19:24:53 +0000117 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000118 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
119
Mark Slee77575e62007-09-24 19:24:53 +0000120 id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
121 id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
David Reiss0c90f6f2008-02-06 22:18:40 +0000122
Mark Slee84406052007-11-20 01:39:25 +0000123 @try {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000124 BOOL result = NO;
125 do {
126 NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
127 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
128 [myPool release];
129 } while (result);
Mark Slee84406052007-11-20 01:39:25 +0000130 }
131 @catch (TTransportException * te) {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000132 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
Mark Slee84406052007-11-20 01:39:25 +0000133 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000134
Andrew McGeachie0c895712009-07-21 21:14:19 +0000135 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
136 object: self
137 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
138 processor,
139 kTSocketServer_ProcessorKey,
140 transport,
141 kTSockerServer_TransportKey,
142 nil]];
143 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
144
Mark Slee77575e62007-09-24 19:24:53 +0000145 [pool release];
146}
147
148
149
150@end
151
152
153