| David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 1 | /* | 
 | 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 McGeachie | 6db89f2 | 2009-07-21 14:45:12 +0000 | [diff] [blame] | 20 | #import <Foundation/Foundation.h> | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 21 | #import "TSocketServer.h" | 
 | 22 | #import "TNSFileHandleTransport.h" | 
 | 23 | #import "TProtocol.h" | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 24 | #import "TTransportException.h" | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 25 | #import <sys/socket.h> | 
 | 26 | #include <netinet/in.h> | 
 | 27 |  | 
 | 28 |  | 
 | 29 |  | 
 | 30 | NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification"; | 
 | 31 | NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor"; | 
 | 32 | NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport"; | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 33 |  | 
 | 34 |  | 
 | 35 | @implementation TSocketServer | 
 | 36 |  | 
 | 37 | - (id) initWithPort: (int) port | 
 | 38 |     protocolFactory: (id <TProtocolFactory>) protocolFactory | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 39 |    processorFactory: (id <TProcessorFactory>) processorFactory; | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 40 | { | 
 | 41 |   self = [super init]; | 
 | 42 |  | 
 | 43 |   mInputProtocolFactory = [protocolFactory retain]; | 
 | 44 |   mOutputProtocolFactory = [protocolFactory retain]; | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 45 |   mProcessorFactory = [processorFactory retain]; | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 46 |  | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 47 |   // 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 McGeachie | ddfe0c9 | 2010-02-10 01:03:01 +0000 | [diff] [blame] | 51 |     CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate); | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 52 |     fd = CFSocketGetNative(socket); | 
 | 53 |     int yes = 1; | 
 | 54 |     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)); | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 55 |  | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 56 |     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 McGeachie | ddfe0c9 | 2010-02-10 01:03:01 +0000 | [diff] [blame] | 64 |       CFSocketInvalidate(socket); | 
 | 65 |       CFRelease(socket); | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 66 |       NSLog(@"*** Could not bind to address"); | 
 | 67 |       return nil; | 
 | 68 |     } | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 69 |   } else { | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 70 |     NSLog(@"*** No server socket"); | 
 | 71 |     return nil; | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 72 |   } | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 73 |    | 
 | 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 McGeachie | ddfe0c9 | 2010-02-10 01:03:01 +0000 | [diff] [blame] | 78 |   // throw away our socket | 
 | 79 |   CFSocketInvalidate(socket); | 
 | 80 |   CFRelease(socket); | 
 | 81 |    | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 82 |     // 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 Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 93 |   return self; | 
 | 94 | } | 
 | 95 |  | 
 | 96 |  | 
 | 97 | - (void) dealloc { | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 98 |   [[NSNotificationCenter defaultCenter] removeObject: self]; | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 99 |   [mInputProtocolFactory release]; | 
 | 100 |   [mOutputProtocolFactory release]; | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 101 |   [mProcessorFactory release]; | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 102 |   [mSocketFileHandle release]; | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 103 |   [super dealloc]; | 
 | 104 | } | 
 | 105 |  | 
 | 106 |  | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 107 | - (void) connectionAccepted: (NSNotification *) aNotification | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 108 | { | 
 | 109 |   NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem]; | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 110 |  | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 111 |   // 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 Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 115 |  | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 116 |   [[aNotification object] acceptConnectionInBackgroundAndNotify]; | 
 | 117 | } | 
 | 118 |  | 
 | 119 |  | 
 | 120 | - (void) handleClientConnection: (NSFileHandle *) clientSocket | 
 | 121 | { | 
 | 122 |   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 123 |    | 
| Mark Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 124 |   TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket]; | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 125 |   id<TProcessor> processor = [mProcessorFactory processorForTransport: transport]; | 
 | 126 |    | 
| Andrew McGeachie | da50d55 | 2010-07-21 19:14:44 +0000 | [diff] [blame] | 127 |   id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease]; | 
 | 128 |   id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease]; | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 129 |  | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 130 |   @try { | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 131 |     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 Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 137 |   } | 
 | 138 |   @catch (TTransportException * te) { | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 139 |     //NSLog(@"Caught transport exception, abandoning client connection: %@", te); | 
| Mark Slee | 8440605 | 2007-11-20 01:39:25 +0000 | [diff] [blame] | 140 |   } | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 141 |  | 
| Andrew McGeachie | 0c89571 | 2009-07-21 21:14:19 +0000 | [diff] [blame] | 142 |   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 Slee | 77575e6 | 2007-09-24 19:24:53 +0000 | [diff] [blame] | 152 |   [pool release]; | 
 | 153 | } | 
 | 154 |  | 
 | 155 |  | 
 | 156 |  | 
 | 157 | @end | 
 | 158 |  | 
 | 159 |  | 
 | 160 |  |