blob: 49414452b137241c7ca729b475c3965b9c170e10 [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"
Jake Farrell9689d892011-12-06 01:07:17 +000025#import "TObjective-C.h"
Andrew McGeachie0c895712009-07-21 21:14:19 +000026#import <sys/socket.h>
27#include <netinet/in.h>
28
29
30
31NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification";
32NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor";
33NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
Mark Slee77575e62007-09-24 19:24:53 +000034
35
36@implementation TSocketServer
37
38- (id) initWithPort: (int) port
39 protocolFactory: (id <TProtocolFactory>) protocolFactory
Andrew McGeachie0c895712009-07-21 21:14:19 +000040 processorFactory: (id <TProcessorFactory>) processorFactory;
Mark Slee77575e62007-09-24 19:24:53 +000041{
42 self = [super init];
43
Jake Farrell9689d892011-12-06 01:07:17 +000044 mInputProtocolFactory = [protocolFactory retain_stub];
45 mOutputProtocolFactory = [protocolFactory retain_stub];
46 mProcessorFactory = [processorFactory retain_stub];
David Reiss0c90f6f2008-02-06 22:18:40 +000047
Andrew McGeachie0c895712009-07-21 21:14:19 +000048 // create a socket.
49 int fd = -1;
50 CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
51 if (socket) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000052 CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
Andrew McGeachie0c895712009-07-21 21:14:19 +000053 fd = CFSocketGetNative(socket);
54 int yes = 1;
55 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
David Reiss0c90f6f2008-02-06 22:18:40 +000056
Andrew McGeachie0c895712009-07-21 21:14:19 +000057 struct sockaddr_in addr;
58 memset(&addr, 0, sizeof(addr));
59 addr.sin_len = sizeof(addr);
60 addr.sin_family = AF_INET;
61 addr.sin_port = htons(port);
62 addr.sin_addr.s_addr = htonl(INADDR_ANY);
63 NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
Jake Farrell9689d892011-12-06 01:07:17 +000064 if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000065 CFSocketInvalidate(socket);
66 CFRelease(socket);
Andrew McGeachie0c895712009-07-21 21:14:19 +000067 NSLog(@"*** Could not bind to address");
68 return nil;
69 }
Mark Slee84406052007-11-20 01:39:25 +000070 } else {
Andrew McGeachie0c895712009-07-21 21:14:19 +000071 NSLog(@"*** No server socket");
72 return nil;
Mark Slee84406052007-11-20 01:39:25 +000073 }
Andrew McGeachie0c895712009-07-21 21:14:19 +000074
75 // wrap it in a file handle so we can get messages from it
76 mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
77 closeOnDealloc: YES];
78
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000079 // throw away our socket
80 CFSocketInvalidate(socket);
81 CFRelease(socket);
82
Andrew McGeachie0c895712009-07-21 21:14:19 +000083 // register for notifications of accepted incoming connections
84 [[NSNotificationCenter defaultCenter] addObserver: self
85 selector: @selector(connectionAccepted:)
86 name: NSFileHandleConnectionAcceptedNotification
87 object: mSocketFileHandle];
88
89 // tell socket to listen
90 [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
91
92 NSLog(@"Listening on TCP port %d", port);
93
Mark Slee77575e62007-09-24 19:24:53 +000094 return self;
95}
96
97
98- (void) dealloc {
Jake Farrell6f3a5262012-07-27 15:48:37 +000099 [[NSNotificationCenter defaultCenter] removeObserver:self];
Jake Farrell9689d892011-12-06 01:07:17 +0000100 [mInputProtocolFactory release_stub];
101 [mOutputProtocolFactory release_stub];
102 [mProcessorFactory release_stub];
103 [mSocketFileHandle release_stub];
104 [super dealloc_stub];
Mark Slee77575e62007-09-24 19:24:53 +0000105}
106
107
Mark Slee84406052007-11-20 01:39:25 +0000108- (void) connectionAccepted: (NSNotification *) aNotification
Mark Slee77575e62007-09-24 19:24:53 +0000109{
110 NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
David Reiss0c90f6f2008-02-06 22:18:40 +0000111
Mark Slee77575e62007-09-24 19:24:53 +0000112 // now that we have a client connected, spin off a thread to handle activity
113 [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
114 toTarget: self
115 withObject: socket];
David Reiss0c90f6f2008-02-06 22:18:40 +0000116
Mark Slee77575e62007-09-24 19:24:53 +0000117 [[aNotification object] acceptConnectionInBackgroundAndNotify];
118}
119
120
121- (void) handleClientConnection: (NSFileHandle *) clientSocket
122{
Jake Farrell9689d892011-12-06 01:07:17 +0000123#if __has_feature(objc_arc)
124 @autoreleasepool {
125 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
126 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
127
128 id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
129 id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
130
131 @try {
132 BOOL result = NO;
133 do {
134 @autoreleasepool {
135 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
136 }
137 } while (result);
138 }
139 @catch (TTransportException * te) {
140 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
141 }
142
143 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
144 object: self
145 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
146 processor,
147 kTSocketServer_ProcessorKey,
148 transport,
149 kTSockerServer_TransportKey,
150 nil]];
151 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
152
153 }
154#else
Mark Slee77575e62007-09-24 19:24:53 +0000155 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000156
Mark Slee77575e62007-09-24 19:24:53 +0000157 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000158 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
159
Andrew McGeachieda50d552010-07-21 19:14:44 +0000160 id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
161 id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
David Reiss0c90f6f2008-02-06 22:18:40 +0000162
Mark Slee84406052007-11-20 01:39:25 +0000163 @try {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000164 BOOL result = NO;
165 do {
166 NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
167 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
168 [myPool release];
169 } while (result);
Mark Slee84406052007-11-20 01:39:25 +0000170 }
171 @catch (TTransportException * te) {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000172 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
Mark Slee84406052007-11-20 01:39:25 +0000173 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000174
Andrew McGeachie0c895712009-07-21 21:14:19 +0000175 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
176 object: self
177 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
178 processor,
179 kTSocketServer_ProcessorKey,
180 transport,
181 kTSockerServer_TransportKey,
182 nil]];
183 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
184
Mark Slee77575e62007-09-24 19:24:53 +0000185 [pool release];
Jake Farrell9689d892011-12-06 01:07:17 +0000186#endif
Mark Slee77575e62007-09-24 19:24:53 +0000187}
188
189
190
191@end
192
193
194