blob: ccbbba18396cbff86fe17be4b57b2d5c979bd37b [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"
Jens Geyer56e5b9b2015-10-09 22:01:55 +020024#import "TTransportError.h"
25
Andrew McGeachie0c895712009-07-21 21:14:19 +000026#import <sys/socket.h>
27#include <netinet/in.h>
28
29
30
Jens Geyer56e5b9b2015-10-09 22:01:55 +020031NSString *const TSocketServerClientConnectionFinished = @"TSocketServerClientConnectionFinished";
32NSString *const TSocketServerProcessorKey = @"TSocketServerProcessor";
33NSString *const TSockerServerTransportKey = @"TSockerServerTransport";
34
35
36@interface TSocketServer ()
37
38@property(strong, nonatomic) id<TProtocolFactory> inputProtocolFactory;
39@property(strong, nonatomic) id<TProtocolFactory> outputProtocolFactory;
40@property(strong, nonatomic) id<TProcessorFactory> processorFactory;
41@property(strong, nonatomic) NSFileHandle *socketFileHandle;
42@property(strong, nonatomic) dispatch_queue_t processingQueue;
43
44@end
Mark Slee77575e62007-09-24 19:24:53 +000045
46
47@implementation TSocketServer
48
Jens Geyer56e5b9b2015-10-09 22:01:55 +020049-(instancetype) initWithPort:(int)port
50 protocolFactory:(id <TProtocolFactory>)protocolFactory
51 processorFactory:(id <TProcessorFactory>)processorFactory;
Mark Slee77575e62007-09-24 19:24:53 +000052{
53 self = [super init];
54
Jens Geyer56e5b9b2015-10-09 22:01:55 +020055 _inputProtocolFactory = protocolFactory;
56 _outputProtocolFactory = protocolFactory;
57 _processorFactory = processorFactory;
58
59 dispatch_queue_attr_t processingQueueAttr =
60 dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
61
62 _processingQueue = dispatch_queue_create("TSocketServer.processing", processingQueueAttr);
David Reiss0c90f6f2008-02-06 22:18:40 +000063
Andrew McGeachie0c895712009-07-21 21:14:19 +000064 // create a socket.
65 int fd = -1;
66 CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
67 if (socket) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +020068 CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
Andrew McGeachie0c895712009-07-21 21:14:19 +000069 fd = CFSocketGetNative(socket);
70 int yes = 1;
71 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
David Reiss0c90f6f2008-02-06 22:18:40 +000072
Andrew McGeachie0c895712009-07-21 21:14:19 +000073 struct sockaddr_in addr;
74 memset(&addr, 0, sizeof(addr));
75 addr.sin_len = sizeof(addr);
76 addr.sin_family = AF_INET;
77 addr.sin_port = htons(port);
78 addr.sin_addr.s_addr = htonl(INADDR_ANY);
79 NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
Jens Geyer56e5b9b2015-10-09 22:01:55 +020080 if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != kCFSocketSuccess) {
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000081 CFSocketInvalidate(socket);
82 CFRelease(socket);
Jens Geyer56e5b9b2015-10-09 22:01:55 +020083 NSLog(@"TSocketServer: Could not bind to address");
Andrew McGeachie0c895712009-07-21 21:14:19 +000084 return nil;
85 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +020086 }
87 else {
88 NSLog(@"TSocketServer: No server socket");
Andrew McGeachie0c895712009-07-21 21:14:19 +000089 return nil;
Mark Slee84406052007-11-20 01:39:25 +000090 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +020091
Andrew McGeachie0c895712009-07-21 21:14:19 +000092 // wrap it in a file handle so we can get messages from it
Jens Geyer56e5b9b2015-10-09 22:01:55 +020093 _socketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd
94 closeOnDealloc:YES];
95
Andrew McGeachieddfe0c92010-02-10 01:03:01 +000096 // throw away our socket
97 CFSocketInvalidate(socket);
98 CFRelease(socket);
Jens Geyer56e5b9b2015-10-09 22:01:55 +020099
100 // register for notifications of accepted incoming connections
101 [[NSNotificationCenter defaultCenter] addObserver:self
102 selector:@selector(connectionAccepted:)
103 name:NSFileHandleConnectionAcceptedNotification
104 object:_socketFileHandle];
105
Andrew McGeachie0c895712009-07-21 21:14:19 +0000106 // tell socket to listen
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200107 [_socketFileHandle acceptConnectionInBackgroundAndNotify];
108
109 NSLog(@"TSocketServer: Listening on TCP port %d", port);
110
Mark Slee77575e62007-09-24 19:24:53 +0000111 return self;
112}
113
114
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200115-(void) dealloc
116{
Jake Farrell6f3a5262012-07-27 15:48:37 +0000117 [[NSNotificationCenter defaultCenter] removeObserver:self];
Mark Slee77575e62007-09-24 19:24:53 +0000118}
119
120
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200121-(void) connectionAccepted:(NSNotification *)notification
Mark Slee77575e62007-09-24 19:24:53 +0000122{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200123 NSFileHandle *socket = [notification.userInfo objectForKey:NSFileHandleNotificationFileHandleItem];
David Reiss0c90f6f2008-02-06 22:18:40 +0000124
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200125 // Now that we have a client connected, handle request on queue
126 dispatch_async(_processingQueue, ^{
David Reiss0c90f6f2008-02-06 22:18:40 +0000127
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200128 [self handleClientConnection:socket];
129
130 });
131
132 // Continue accepting connections
133 [_socketFileHandle acceptConnectionInBackgroundAndNotify];
Mark Slee77575e62007-09-24 19:24:53 +0000134}
135
136
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200137-(void) handleClientConnection:(NSFileHandle *)clientSocket
Mark Slee77575e62007-09-24 19:24:53 +0000138{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200139 @autoreleasepool {
140
141 TNSFileHandleTransport *transport = [[TNSFileHandleTransport alloc] initWithFileHandle:clientSocket];
142 id<TProcessor> processor = [_processorFactory processorForTransport:transport];
143
144 id <TProtocol> inProtocol = [_inputProtocolFactory newProtocolOnTransport:transport];
145 id <TProtocol> outProtocol = [_outputProtocolFactory newProtocolOnTransport:transport];
146
147 NSError *error;
148 if (![processor processOnInputProtocol:inProtocol outputProtocol:outProtocol error:&error]) {
149 // Handle error
150 NSLog(@"Error processing request: %@", error);
Jake Farrell9689d892011-12-06 01:07:17 +0000151 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000152
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200153 dispatch_async(dispatch_get_main_queue(), ^{
David Reiss0c90f6f2008-02-06 22:18:40 +0000154
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200155 [NSNotificationCenter.defaultCenter postNotificationName:TSocketServerClientConnectionFinished
156 object:self
157 userInfo:@{TSocketServerProcessorKey: processor,
158 TSockerServerTransportKey: transport}];
159 });
160
161 }
Mark Slee77575e62007-09-24 19:24:53 +0000162}
163
Mark Slee77575e62007-09-24 19:24:53 +0000164@end