Advertisement
Guest User

Untitled

a guest
Oct 6th, 2013
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #import "NMASwitchPinger.h"
  2.  
  3. /**
  4.  *  Private interface.
  5.  */
  6. @interface NMASwitchPinger () {
  7.     /**
  8.      *  The delegate of this class.
  9.      */
  10.     __weak id<NMASwitchPingerDelegate> delegate;
  11.     /**
  12.      *  The timeout after which the pinger stops waiting for a response.
  13.      */
  14.     NSTimeInterval timeout;
  15.     /**
  16.      *  The socket which is used to send the ping.
  17.      */
  18.     GCDAsyncUdpSocket *socket;
  19.     /**
  20.      *  List of pings which are awaiting a response.
  21.      */
  22.     NSMutableDictionary *pendingPings;
  23.     /**
  24.      *  Dispatch queue which serializes access to the pendingPings dictionary.
  25.      */
  26.     dispatch_queue_t pendingPingsAccessQueue;
  27.     /**
  28.      *  The queue on which the delegate methods of the socket are executed.
  29.      */
  30.     dispatch_queue_t socketDelegateQueue;
  31.     /**
  32.      *  Is set to true when the SwitchPinger started receiving responses (after first send)
  33.      */
  34.     bool receiving;
  35. }
  36. @end
  37.  
  38.  
  39. @implementation NMASwitchPinger
  40.  
  41. #pragma mark - Initialization
  42.  
  43. - (id)initWithTimeout:(NSTimeInterval)newTimeout delegate:(id<NMASwitchPingerDelegate>)newDelegate {
  44.     self = [super init];
  45.     if (self) {
  46.         // setting passed values
  47.         timeout = newTimeout;
  48.         delegate = newDelegate;
  49.        
  50.         // init data structures
  51.         pendingPings = [[NSMutableDictionary alloc] init];
  52.         pendingPingsAccessQueue = dispatch_queue_create("de.nexans-ans.pingerPendingAccess", DISPATCH_QUEUE_SERIAL);
  53.        
  54.         // create the socket for udp sending
  55.         socketDelegateQueue = dispatch_queue_create("de.nexans-ans.pingerDelegate", DISPATCH_QUEUE_CONCURRENT);
  56.         socket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:socketDelegateQueue];
  57.     }
  58.     return self;
  59. }
  60.  
  61. - (id)init {
  62.     NSAssert(NO, @"Use the designated initializer");
  63.     return nil;
  64. }
  65.  
  66. #pragma mark - Sending a ping
  67.  
  68. - (void)sendPingToAddress:(NSString *)address {
  69.     // we allow only one ping at a time to the same ip
  70.     __block BOOL alreadyInList = NO;
  71.     dispatch_sync(pendingPingsAccessQueue, ^{
  72.         if (pendingPings[address]) {
  73.             alreadyInList = YES;
  74.         } else {
  75.             pendingPings[address] = [[NSDate alloc] init];
  76.         }
  77.     });
  78.    
  79.     // don't send a second ping to the same address
  80.     if (alreadyInList) {
  81.         NSLog(@"SimplePinger: did not send ping because already a ping pending to this addres: %@", address);
  82.         return;
  83.     }
  84.    
  85.     // create a minimal packet (3 bytes)
  86.     NSMutableData *packet = [[NSMutableData alloc] initWithCapacity:3];
  87.     uint16_t vendor_value = CFSwapInt16HostToBig(266);
  88.     uint8_t request_type = 1;
  89.     [packet appendBytes:&vendor_value length:sizeof(vendor_value)];
  90.     [packet appendBytes:&request_type length:sizeof(request_type)];
  91.    
  92.     // send over the wire
  93.     [socket sendData:packet toHost:address port:50266 withTimeout:timeout tag:0];
  94.    
  95.     // schedule timeout handler
  96.     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
  97.     dispatch_after(popTime, pendingPingsAccessQueue, ^(void){
  98.         [self removeTimedOutPingWithAddress:address];
  99.     });
  100.    
  101.     // start receiving when not already receiving
  102.     if (!receiving) {
  103.         bool recvGood = [socket beginReceiving:nil];
  104.         NSAssert(recvGood, @"SimplePinger: could not start receiving");
  105.         receiving = YES;
  106.     }
  107. }
  108.  
  109.  
  110. #pragma mark - GCDAsyncSocket delegate
  111.  
  112. - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext {
  113.     NSString *ipAddress = [GCDAsyncUdpSocket hostFromAddress:address];
  114.    
  115.     __block BOOL pingStillPending = NO;
  116.     dispatch_sync(pendingPingsAccessQueue, ^{
  117.         NSDate *sendDate = pendingPings[ipAddress];
  118.         if (sendDate) {
  119.             [pendingPings removeObjectForKey:ipAddress];
  120.             pingStillPending = YES;
  121.         }
  122.     });
  123.    
  124.     if (pingStillPending) {
  125.         dispatch_async(dispatch_get_main_queue(), ^{
  126.             [delegate switchPinger:self didReceiveResponse:data fromAddress:ipAddress];
  127.         });
  128.     }
  129. }
  130.  
  131. - (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error {
  132.     NSLog(@"didnt send data");
  133. }
  134.  
  135. - (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag {
  136.     NSLog(@"did send");
  137. }
  138.  
  139. #pragma mark - Private methods
  140.  
  141. /**
  142.  *  Removes a timed out ping. A call of this function gets scheduled when a ping is send.
  143.  *
  144.  *  @param address The address of the ping which should be removed.
  145.  */
  146. - (void)removeTimedOutPingWithAddress:(NSString*)address {
  147.     NSDate *sendDate = pendingPings[address];
  148.    
  149.     if (sendDate) {
  150.         NSLog(@"timeout: %@", address);
  151.         NSAssert(fabs([sendDate timeIntervalSinceNow]) >= timeout, @"SimplePing: removed ping before timout");
  152.         [pendingPings removeObjectForKey:address];
  153.         dispatch_async(dispatch_get_main_queue(), ^{
  154.             [delegate switchPinger:self didReceiveTimeoutFromAddress:address];
  155.         });
  156.     }
  157. }
  158.  
  159. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement