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