Showing
4 changed files
with
37 additions
and
8 deletions
| @@ -462,6 +462,8 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -462,6 +462,8 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
| 462 | + (unsigned long)maxBandwidthPerSecond; | 462 | + (unsigned long)maxBandwidthPerSecond; |
| 463 | + (void)setMaxBandwidthPerSecond:(unsigned long)bytes; | 463 | + (void)setMaxBandwidthPerSecond:(unsigned long)bytes; |
| 464 | 464 | ||
| 465 | ++ (unsigned long)averageBandwidthUsedPerSecond; | ||
| 466 | + | ||
| 465 | #if TARGET_OS_IPHONE | 467 | #if TARGET_OS_IPHONE |
| 466 | // Set to YES to automatically turn on throttling when WWAN is connected, and automatically turn it off when it isn't | 468 | // Set to YES to automatically turn on throttling when WWAN is connected, and automatically turn it off when it isn't |
| 467 | + (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle; | 469 | + (void)setShouldThrottleBandwidthForWWAN:(BOOL)throttle; |
| @@ -49,6 +49,8 @@ static NSError *ASIAuthenticationError; | @@ -49,6 +49,8 @@ static NSError *ASIAuthenticationError; | ||
| 49 | static NSError *ASIUnableToCreateRequestError; | 49 | static NSError *ASIUnableToCreateRequestError; |
| 50 | static NSError *ASITooMuchRedirectionError; | 50 | static NSError *ASITooMuchRedirectionError; |
| 51 | 51 | ||
| 52 | +static NSMutableArray *bandwidthUsageTracker = nil; | ||
| 53 | + | ||
| 52 | // Used for throttling bandwidth | 54 | // Used for throttling bandwidth |
| 53 | // I am assuming you don't have a connection capable of more than 4GB/second? If so, why are you reading this? Aren't you supposed to be backing up the Internet?! | 55 | // I am assuming you don't have a connection capable of more than 4GB/second? If so, why are you reading this? Aren't you supposed to be backing up the Internet?! |
| 54 | static unsigned long bandwidthUsedInLastSecond = 0; | 56 | static unsigned long bandwidthUsedInLastSecond = 0; |
| @@ -78,6 +80,7 @@ BOOL shouldThrottleBandwidth = NO; | @@ -78,6 +80,7 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 78 | + (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes; | 80 | + (void)incrementBandwidthUsedInLastSecond:(unsigned long)bytes; |
| 79 | + (void)performBandwidthThrottling; | 81 | + (void)performBandwidthThrottling; |
| 80 | + (BOOL)shouldThrottleBandwidth; | 82 | + (BOOL)shouldThrottleBandwidth; |
| 83 | ++ (void)recordBandwidthUsage; | ||
| 81 | 84 | ||
| 82 | @property (assign) BOOL complete; | 85 | @property (assign) BOOL complete; |
| 83 | @property (retain) NSDictionary *responseHeaders; | 86 | @property (retain) NSDictionary *responseHeaders; |
| @@ -122,6 +125,7 @@ BOOL shouldThrottleBandwidth = NO; | @@ -122,6 +125,7 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 122 | if (self == [ASIHTTPRequest class]) { | 125 | if (self == [ASIHTTPRequest class]) { |
| 123 | progressLock = [[NSRecursiveLock alloc] init]; | 126 | progressLock = [[NSRecursiveLock alloc] init]; |
| 124 | bandwidthThrottlingLock = [[NSLock alloc] init]; | 127 | bandwidthThrottlingLock = [[NSLock alloc] init]; |
| 128 | + bandwidthUsageTracker = [[NSMutableArray alloc] initWithCapacity:10]; | ||
| 125 | ASIRequestTimedOutError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]] retain]; | 129 | ASIRequestTimedOutError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]] retain]; |
| 126 | ASIAuthenticationError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication needed",NSLocalizedDescriptionKey,nil]] retain]; | 130 | ASIAuthenticationError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIAuthenticationErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication needed",NSLocalizedDescriptionKey,nil]] retain]; |
| 127 | ASIRequestCancelledError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request was cancelled",NSLocalizedDescriptionKey,nil]] retain]; | 131 | ASIRequestCancelledError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIRequestCancelledErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request was cancelled",NSLocalizedDescriptionKey,nil]] retain]; |
| @@ -1647,11 +1651,11 @@ BOOL shouldThrottleBandwidth = NO; | @@ -1647,11 +1651,11 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 1647 | } | 1651 | } |
| 1648 | 1652 | ||
| 1649 | // Reduce the buffer size if we're receiving data too quickly when bandwidth throttling is active | 1653 | // Reduce the buffer size if we're receiving data too quickly when bandwidth throttling is active |
| 1650 | - // This just augments the throttling done in performBandwidthThrottling | 1654 | + // This just augments the throttling done in performBandwidthThrottling to reduce the amount we go over the limit |
| 1651 | - if ([ASIHTTPRequest shouldThrottleBandwidth]) { | 1655 | + [bandwidthThrottlingLock lock]; |
| 1652 | - long long maxSize = [ASIHTTPRequest maxBandwidthPerSecond]; | 1656 | + if (shouldThrottleBandwidth) { |
| 1653 | - if (maxSize > 0) { | 1657 | + if (maxBandwidthPerSecond > 0) { |
| 1654 | - maxSize = maxSize-[ASIHTTPRequest bandwidthUsedInLastSecond]; | 1658 | + long long maxSize = maxBandwidthPerSecond-bandwidthUsedInLastSecond; |
| 1655 | if (maxSize < 0) { | 1659 | if (maxSize < 0) { |
| 1656 | // We aren't supposed to read any more data right now, but we'll read a single byte anyway so the CFNetwork's buffer isn't full | 1660 | // We aren't supposed to read any more data right now, but we'll read a single byte anyway so the CFNetwork's buffer isn't full |
| 1657 | bufferSize = 1; | 1661 | bufferSize = 1; |
| @@ -1661,6 +1665,7 @@ BOOL shouldThrottleBandwidth = NO; | @@ -1661,6 +1665,7 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 1661 | } | 1665 | } |
| 1662 | } | 1666 | } |
| 1663 | } | 1667 | } |
| 1668 | + [bandwidthThrottlingLock unlock]; | ||
| 1664 | 1669 | ||
| 1665 | UInt8 buffer[bufferSize]; | 1670 | UInt8 buffer[bufferSize]; |
| 1666 | CFIndex bytesRead = CFReadStreamRead(readStream, buffer, sizeof(buffer)); | 1671 | CFIndex bytesRead = CFReadStreamRead(readStream, buffer, sizeof(buffer)); |
| @@ -2334,6 +2339,29 @@ BOOL shouldThrottleBandwidth = NO; | @@ -2334,6 +2339,29 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 2334 | [bandwidthThrottlingLock unlock]; | 2339 | [bandwidthThrottlingLock unlock]; |
| 2335 | } | 2340 | } |
| 2336 | 2341 | ||
| 2342 | ++ (void)recordBandwidthUsage | ||
| 2343 | +{ | ||
| 2344 | + NSTimeInterval interval = [bandwidthThrottlingMeasurementDate timeIntervalSinceNow]; | ||
| 2345 | + while (interval-1 > 0) { | ||
| 2346 | + [bandwidthUsageTracker removeObjectAtIndex:0]; | ||
| 2347 | + } | ||
| 2348 | + [bandwidthUsageTracker addObject:[NSNumber numberWithUnsignedLong:bandwidthUsedInLastSecond]]; | ||
| 2349 | + bandwidthThrottlingMeasurementDate = [NSDate dateWithTimeIntervalSinceNow:1]; | ||
| 2350 | + bandwidthUsedInLastSecond = 0; | ||
| 2351 | +} | ||
| 2352 | + | ||
| 2353 | ++ (unsigned long)averageBandwidthUsedPerSecond | ||
| 2354 | +{ | ||
| 2355 | + [bandwidthThrottlingLock lock]; | ||
| 2356 | + int measurements = [bandwidthUsageTracker count]; | ||
| 2357 | + unsigned long long totalBytes = 0; | ||
| 2358 | + for (NSNumber *bytes in bandwidthUsageTracker) { | ||
| 2359 | + totalBytes += [bytes unsignedLongValue]; | ||
| 2360 | + } | ||
| 2361 | + [bandwidthThrottlingLock unlock]; | ||
| 2362 | + return totalBytes/measurements; | ||
| 2363 | +} | ||
| 2364 | + | ||
| 2337 | + (void)performBandwidthThrottling | 2365 | + (void)performBandwidthThrottling |
| 2338 | { | 2366 | { |
| 2339 | // Other requests may have to wait for this lock if we're sleeping, but this is fine, since in that case we already know they shouldn't be sending or receiving data | 2367 | // Other requests may have to wait for this lock if we're sleeping, but this is fine, since in that case we already know they shouldn't be sending or receiving data |
| @@ -2342,7 +2370,7 @@ BOOL shouldThrottleBandwidth = NO; | @@ -2342,7 +2370,7 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 2342 | // Are we performing bandwidth throttling? | 2370 | // Are we performing bandwidth throttling? |
| 2343 | if (maxBandwidthPerSecond > 0) { | 2371 | if (maxBandwidthPerSecond > 0) { |
| 2344 | if (!bandwidthThrottlingMeasurementDate || [bandwidthThrottlingMeasurementDate timeIntervalSinceNow] < 0) { | 2372 | if (!bandwidthThrottlingMeasurementDate || [bandwidthThrottlingMeasurementDate timeIntervalSinceNow] < 0) { |
| 2345 | - bandwidthThrottlingMeasurementDate = [NSDate dateWithTimeIntervalSinceNow:1]; | 2373 | + [self recordBandwidthUsage]; |
| 2346 | } | 2374 | } |
| 2347 | 2375 | ||
| 2348 | // How much data can we still send or receive this second? | 2376 | // How much data can we still send or receive this second? |
| @@ -2353,7 +2381,7 @@ BOOL shouldThrottleBandwidth = NO; | @@ -2353,7 +2381,7 @@ BOOL shouldThrottleBandwidth = NO; | ||
| 2353 | 2381 | ||
| 2354 | // Yes, put this request to sleep until a second is up | 2382 | // Yes, put this request to sleep until a second is up |
| 2355 | [NSThread sleepUntilDate:bandwidthThrottlingMeasurementDate]; | 2383 | [NSThread sleepUntilDate:bandwidthThrottlingMeasurementDate]; |
| 2356 | - bandwidthThrottlingMeasurementDate = [NSDate dateWithTimeIntervalSinceNow:1]; | 2384 | + [self recordBandwidthUsage]; |
| 2357 | } | 2385 | } |
| 2358 | } | 2386 | } |
| 2359 | [bandwidthThrottlingLock unlock]; | 2387 | [bandwidthThrottlingLock unlock]; |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment