1/****************************************************************************** 2 * $Id: PortChecker.m 13492 2012-09-10 02:37:29Z livings124 $ 3 * 4 * Copyright (c) 2006-2012 Transmission authors and contributors 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 *****************************************************************************/ 24 25#import "PortChecker.h" 26 27#define CHECKER_URL(port) [NSString stringWithFormat: @"http://portcheck.transmissionbt.com/%ld", port] 28#define CHECK_FIRE 3.0 29 30@interface PortChecker (Private) 31 32- (void) startProbe: (NSTimer *) timer; 33 34- (void) callBackWithStatus: (port_status_t) status; 35 36@end 37 38@implementation PortChecker 39 40- (id) initForPort: (NSInteger) portNumber delay: (BOOL) delay withDelegate: (id) delegate 41{ 42 if ((self = [super init])) 43 { 44 fDelegate = delegate; 45 46 fStatus = PORT_STATUS_CHECKING; 47 48 fTimer = [[NSTimer scheduledTimerWithTimeInterval: CHECK_FIRE target: self selector: @selector(startProbe:) userInfo: [NSNumber numberWithInteger: portNumber] repeats: NO] retain]; 49 if (!delay) 50 [fTimer fire]; 51 } 52 53 return self; 54} 55 56- (void) dealloc 57{ 58 [fTimer invalidate]; 59 [fTimer release]; 60 61 [fConnection release]; 62 [fPortProbeData release]; 63 [super dealloc]; 64} 65 66- (port_status_t) status 67{ 68 return fStatus; 69} 70 71- (void) cancelProbe 72{ 73 [fTimer invalidate]; 74 [fTimer release]; 75 fTimer = nil; 76 77 [fConnection cancel]; 78} 79 80- (void) connection: (NSURLConnection *) connection didReceiveResponse: (NSURLResponse *) response 81{ 82 [fPortProbeData setLength: 0]; 83} 84 85- (void) connection: (NSURLConnection *) connection didReceiveData: (NSData *) data 86{ 87 [fPortProbeData appendData: data]; 88} 89 90- (void) connection: (NSURLConnection *) connection didFailWithError: (NSError *) error 91{ 92 NSLog(@"Unable to get port status: connection failed (%@)", [error localizedDescription]); 93 [self callBackWithStatus: PORT_STATUS_ERROR]; 94} 95 96- (void) connectionDidFinishLoading: (NSURLConnection *) connection 97{ 98 NSString * probeString = [[NSString alloc] initWithData: fPortProbeData encoding: NSUTF8StringEncoding]; 99 [fPortProbeData release]; 100 fPortProbeData = nil; 101 102 if (probeString) 103 { 104 if ([probeString isEqualToString: @"1"]) 105 [self callBackWithStatus: PORT_STATUS_OPEN]; 106 else if ([probeString isEqualToString: @"0"]) 107 [self callBackWithStatus: PORT_STATUS_CLOSED]; 108 else 109 { 110 NSLog(@"Unable to get port status: invalid response (%@)", probeString); 111 [self callBackWithStatus: PORT_STATUS_ERROR]; 112 } 113 [probeString release]; 114 } 115 else 116 { 117 NSLog(@"Unable to get port status: invalid data received"); 118 [self callBackWithStatus: PORT_STATUS_ERROR]; 119 } 120} 121 122@end 123 124@implementation PortChecker (Private) 125 126- (void) startProbe: (NSTimer *) timer 127{ 128 [fTimer release]; 129 fTimer = nil; 130 131 NSURLRequest * portProbeRequest = [NSURLRequest requestWithURL: [NSURL URLWithString: CHECKER_URL([[timer userInfo] integerValue])] 132 cachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval: 15.0]; 133 134 if ((fConnection = [[NSURLConnection alloc] initWithRequest: portProbeRequest delegate: self])) 135 fPortProbeData = [[NSMutableData alloc] init]; 136 else 137 { 138 NSLog(@"Unable to get port status: failed to initiate connection"); 139 [self callBackWithStatus: PORT_STATUS_ERROR]; 140 } 141} 142 143- (void) callBackWithStatus: (port_status_t) status 144{ 145 fStatus = status; 146 147 if (fDelegate && [fDelegate respondsToSelector: @selector(portCheckerDidFinishProbing:)]) 148 [fDelegate performSelectorOnMainThread: @selector(portCheckerDidFinishProbing:) withObject: self waitUntilDone: NO]; 149} 150 151@end 152 153