blob: 07bc829b5b92cd49442fe83b23e53812d927d76e [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
Roger Meier6b616012015-03-01 12:32:50 +010040 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) {
Roger Meier6b616012015-03-01 12:32:50 +010052 CFOptionFlags flagsToClear = kCFSocketCloseOnInvalidate;
53 CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~flagsToClear);
54
Andrew McGeachie0c895712009-07-21 21:14:19 +000055 fd = CFSocketGetNative(socket);
56 int yes = 1;
57 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
David Reiss0c90f6f2008-02-06 22:18:40 +000058
Andrew McGeachie0c895712009-07-21 21:14:19 +000059 struct sockaddr_in addr;
60 memset(&addr, 0, sizeof(addr));
61 addr.sin_len = sizeof(addr);
62 addr.sin_family = AF_INET;
63 addr.sin_port = htons(port);
64 addr.sin_addr.s_addr = htonl(INADDR_ANY);
65 NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
Jake Farrell9689d892011-12-06 01:07:17 +000066 if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000067 CFSocketInvalidate(socket);
68 CFRelease(socket);
Andrew McGeachie0c895712009-07-21 21:14:19 +000069 NSLog(@"*** Could not bind to address");
70 return nil;
71 }
Mark Slee84406052007-11-20 01:39:25 +000072 } else {
Andrew McGeachie0c895712009-07-21 21:14:19 +000073 NSLog(@"*** No server socket");
74 return nil;
Mark Slee84406052007-11-20 01:39:25 +000075 }
Andrew McGeachie0c895712009-07-21 21:14:19 +000076
77 // wrap it in a file handle so we can get messages from it
78 mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
79 closeOnDealloc: YES];
80
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000081 // throw away our socket
82 CFSocketInvalidate(socket);
83 CFRelease(socket);
84
Andrew McGeachie0c895712009-07-21 21:14:19 +000085 // register for notifications of accepted incoming connections
86 [[NSNotificationCenter defaultCenter] addObserver: self
87 selector: @selector(connectionAccepted:)
88 name: NSFileHandleConnectionAcceptedNotification
89 object: mSocketFileHandle];
90
91 // tell socket to listen
92 [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
93
94 NSLog(@"Listening on TCP port %d", port);
95
Mark Slee77575e62007-09-24 19:24:53 +000096 return self;
97}
98
99
100- (void) dealloc {
Jake Farrell6f3a5262012-07-27 15:48:37 +0000101 [[NSNotificationCenter defaultCenter] removeObserver:self];
Jake Farrell9689d892011-12-06 01:07:17 +0000102 [mInputProtocolFactory release_stub];
103 [mOutputProtocolFactory release_stub];
104 [mProcessorFactory release_stub];
105 [mSocketFileHandle release_stub];
106 [super dealloc_stub];
Mark Slee77575e62007-09-24 19:24:53 +0000107}
108
109
Mark Slee84406052007-11-20 01:39:25 +0000110- (void) connectionAccepted: (NSNotification *) aNotification
Mark Slee77575e62007-09-24 19:24:53 +0000111{
112 NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
David Reiss0c90f6f2008-02-06 22:18:40 +0000113
Mark Slee77575e62007-09-24 19:24:53 +0000114 // now that we have a client connected, spin off a thread to handle activity
115 [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
116 toTarget: self
117 withObject: socket];
David Reiss0c90f6f2008-02-06 22:18:40 +0000118
Mark Slee77575e62007-09-24 19:24:53 +0000119 [[aNotification object] acceptConnectionInBackgroundAndNotify];
120}
121
122
123- (void) handleClientConnection: (NSFileHandle *) clientSocket
124{
Jake Farrell9689d892011-12-06 01:07:17 +0000125#if __has_feature(objc_arc)
126 @autoreleasepool {
127 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
128 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
129
130 id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
131 id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
132
133 @try {
134 BOOL result = NO;
135 do {
136 @autoreleasepool {
137 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
138 }
139 } while (result);
140 }
141 @catch (TTransportException * te) {
Roger Meier6b616012015-03-01 12:32:50 +0100142 (void)te;
Jake Farrell9689d892011-12-06 01:07:17 +0000143 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
144 }
145
146 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
147 object: self
148 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
149 processor,
150 kTSocketServer_ProcessorKey,
151 transport,
152 kTSockerServer_TransportKey,
153 nil]];
154 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
155
156 }
157#else
Mark Slee77575e62007-09-24 19:24:53 +0000158 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000159
Mark Slee77575e62007-09-24 19:24:53 +0000160 TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
Andrew McGeachie0c895712009-07-21 21:14:19 +0000161 id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
162
Andrew McGeachieda50d552010-07-21 19:14:44 +0000163 id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
164 id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
David Reiss0c90f6f2008-02-06 22:18:40 +0000165
Mark Slee84406052007-11-20 01:39:25 +0000166 @try {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000167 BOOL result = NO;
168 do {
169 NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
170 result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
171 [myPool release];
172 } while (result);
Mark Slee84406052007-11-20 01:39:25 +0000173 }
174 @catch (TTransportException * te) {
Andrew McGeachie0c895712009-07-21 21:14:19 +0000175 //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
Mark Slee84406052007-11-20 01:39:25 +0000176 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000177
Andrew McGeachie0c895712009-07-21 21:14:19 +0000178 NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
179 object: self
180 userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
181 processor,
182 kTSocketServer_ProcessorKey,
183 transport,
184 kTSockerServer_TransportKey,
185 nil]];
186 [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
187
Mark Slee77575e62007-09-24 19:24:53 +0000188 [pool release];
Jake Farrell9689d892011-12-06 01:07:17 +0000189#endif
Mark Slee77575e62007-09-24 19:24:53 +0000190}
191
192
193
194@end
195
196
197