blob: 5f7fa3ccc3122d11423394a841ef9cbef4e9417b [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) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000051 CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
Andrew McGeachie0c895712009-07-21 21:14:19 +000052 fd = CFSocketGetNative(socket);
53 int yes = 1;
54 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
David Reiss0c90f6f2008-02-06 22:18:40 +000055
Andrew McGeachie0c895712009-07-21 21:14:19 +000056 struct sockaddr_in addr;
57 memset(&addr, 0, sizeof(addr));
58 addr.sin_len = sizeof(addr);
59 addr.sin_family = AF_INET;
60 addr.sin_port = htons(port);
61 addr.sin_addr.s_addr = htonl(INADDR_ANY);
62 NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
63 if (CFSocketSetAddress(socket, (CFDataRef)address) != kCFSocketSuccess) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000064 CFSocketInvalidate(socket);
65 CFRelease(socket);
Andrew McGeachie0c895712009-07-21 21:14:19 +000066 NSLog(@"*** Could not bind to address");
67 return nil;
68 }
Mark Slee84406052007-11-20 01:39:25 +000069 } else {
Andrew McGeachie0c895712009-07-21 21:14:19 +000070 NSLog(@"*** No server socket");
71 return nil;
Mark Slee84406052007-11-20 01:39:25 +000072 }
Andrew McGeachie0c895712009-07-21 21:14:19 +000073
74 // wrap it in a file handle so we can get messages from it
75 mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
76 closeOnDealloc: YES];
77
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000078 // throw away our socket
79 CFSocketInvalidate(socket);
80 CFRelease(socket);
81
Andrew McGeachie0c895712009-07-21 21:14:19 +000082 // register for notifications of accepted incoming connections
83 [[NSNotificationCenter defaultCenter] addObserver: self
84 selector: @selector(connectionAccepted:)
85 name: NSFileHandleConnectionAcceptedNotification
86 object: mSocketFileHandle];
87
88 // tell socket to listen
89 [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
90
91 NSLog(@"Listening on TCP port %d", port);
92
Mark Slee77575e62007-09-24 19:24:53 +000093 return self;
94}
95
96
97- (void) dealloc {
Andrew McGeachie0c895712009-07-21 21:14:19 +000098 [[NSNotificationCenter defaultCenter] removeObject: self];
Mark Slee77575e62007-09-24 19:24:53 +000099 [mInputProtocolFactory release];
100 [mOutputProtocolFactory release];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000101 [mProcessorFactory release];
Mark Slee77575e62007-09-24 19:24:53 +0000102 [mSocketFileHandle release];
Mark Slee77575e62007-09-24 19:24:53 +0000103 [super dealloc];
104}
105
106
Mark Slee84406052007-11-20 01:39:25 +0000107- (void) connectionAccepted: (NSNotification *) aNotification
Mark Slee77575e62007-09-24 19:24:53 +0000108{
109 NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
David Reiss0c90f6f2008-02-06 22:18:40 +0000110
Mark Slee77575e62007-09-24 19:24:53 +0000111 // now that we have a client connected, spin off a thread to handle activity
112 [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
113 toTarget: self
114 withObject: socket];
David Reiss0c90f6f2008-02-06 22:18:40 +0000115
Mark Slee77575e62007-09-24 19:24:53 +0000116 [[aNotification object] acceptConnectionInBackgroundAndNotify];
117}
118
119
120- (void) handleClientConnection: (NSFileHandle *) clientSocket
121{
122 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000123
Mark Slee77575e62007-09-24 19:24:53 +0000124 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000125 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
126
Andrew McGeachieda50d552010-07-21 19:14:44 +0000127 id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
128 id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
David Reiss0c90f6f2008-02-06 22:18:40 +0000129
Mark Slee84406052007-11-20 01:39:25 +0000130 @try {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000131 BOOL result = NO;
132 do {
133 NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
134 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
135 [myPool release];
136 } while (result);
Mark Slee84406052007-11-20 01:39:25 +0000137 }
138 @catch (TTransportException * te) {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000139 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
Mark Slee84406052007-11-20 01:39:25 +0000140 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000141
Andrew McGeachie0c895712009-07-21 21:14:19 +0000142 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
143 object: self
144 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
145 processor,
146 kTSocketServer_ProcessorKey,
147 transport,
148 kTSockerServer_TransportKey,
149 nil]];
150 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
151
Mark Slee77575e62007-09-24 19:24:53 +0000152 [pool release];
153}
154
155
156
157@end
158
159
160