BLIP/BLIPTest.m
author Jens Alfke <jens@mooseyard.com>
Sun Jun 01 14:04:22 2008 -0700 (2008-06-01)
changeset 10 a2aeb9b04ecc
parent 2 9fdd8dba529c
child 11 29e8b03c05d4
permissions -rw-r--r--
Copied the necessary Google Toolbox source files into the MYUtilities project, so people don't have to download a separate library.
     1 //
     2 //  BLIPTest.m
     3 //  MYNetwork
     4 //
     5 //  Created by Jens Alfke on 5/13/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #ifndef NDEBUG
    10 
    11 
    12 #import "BLIPRequest.h"
    13 #import "BLIPProperties.h"
    14 #import "BLIPConnection.h"
    15 
    16 #import "IPAddress.h"
    17 #import "Target.h"
    18 #import "CollectionUtils.h"
    19 #import "Logging.h"
    20 #import "Test.h"
    21 
    22 #define HAVE_KEYCHAIN_FRAMEWORK 0
    23 #if HAVE_KEYCHAIN_FRAMEWORK
    24 #import <Keychain/Keychain.h>
    25 #endif
    26 
    27 
    28 #define kListenerPort               46353
    29 #define kSendInterval               0.5
    30 #define kNBatchedMessages           20
    31 #define kUseCompression             YES
    32 #define kUrgentEvery                4
    33 #define kClientRequiresSSL          NO
    34 #define kClientUsesSSLCert          NO
    35 #define kListenerRequiresSSL        NO
    36 #define kListenerRequiresClientCert NO
    37 
    38 
    39 static SecIdentityRef GetClientIdentity(void) {
    40     return NULL;    // Make this return a valid identity to test client-side certs
    41 }
    42 
    43 static SecIdentityRef GetListenerIdentity(void) {
    44     return NULL;    // Make this return a valid identity to test client-side certs
    45 }
    46 
    47 
    48 #pragma mark -
    49 #pragma mark CLIENT TEST:
    50 
    51 
    52 @interface BLIPConnectionTester : NSObject <BLIPConnectionDelegate>
    53 {
    54     BLIPConnection *_conn;
    55     NSMutableDictionary *_pending;
    56 }
    57 
    58 @end
    59 
    60 
    61 @implementation BLIPConnectionTester
    62 
    63 - (id) init
    64 {
    65     self = [super init];
    66     if (self != nil) {
    67         Log(@"** INIT %@",self);
    68         _pending = [[NSMutableDictionary alloc] init];
    69         IPAddress *addr = [[IPAddress alloc] initWithHostname: @"localhost" port: kListenerPort];
    70         _conn = [[BLIPConnection alloc] initToAddress: addr];
    71         if( ! _conn ) {
    72             [self release];
    73             return nil;
    74         }
    75         if( kClientRequiresSSL ) {
    76             _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true});
    77             if( kClientUsesSSLCert ) {
    78                 SecIdentityRef clientIdentity = GetClientIdentity();
    79                 if( clientIdentity ) {
    80                     [_conn setSSLProperty: $array((id)clientIdentity)
    81                                    forKey: kTCPPropertySSLCertificates];
    82                 }
    83             }
    84         }
    85         _conn.delegate = self;
    86         Log(@"** Opening connection...");
    87         [_conn open];
    88     }
    89     return self;
    90 }
    91 
    92 - (void) dealloc
    93 {
    94     Log(@"** %@ closing",self);
    95     [_conn close];
    96     [_conn release];
    97     [super dealloc];
    98 }
    99 
   100 - (void) sendAMessage
   101 {
   102     Log(@"** Sending another %i messages...", kNBatchedMessages);
   103     for( int i=0; i<kNBatchedMessages; i++ ) {
   104         size_t size = random() % 32768;
   105         NSMutableData *body = [NSMutableData dataWithLength: size];
   106         UInt8 *bytes = body.mutableBytes;
   107         for( size_t i=0; i<size; i++ )
   108             bytes[i] = i % 256;
   109         
   110         BLIPRequest *q = [_conn requestWithBody: body
   111                                      properties: $dict({@"Content-Type", @"application/octet-stream"},
   112                                                        {@"User-Agent", @"BLIPConnectionTester"},
   113                                                        {@"Date", [[NSDate date] description]},
   114                                                        {@"Size",$sprintf(@"%u",size)})];
   115         Assert(q);
   116         if( kUseCompression && (random()%2==1) )
   117             q.compressed = YES;
   118         if( random()%16 > 12 )
   119             q.urgent = YES;
   120         BLIPResponse *response = [q send];
   121         Assert(response);
   122         Assert(q.number>0);
   123         Assert(response.number==q.number);
   124         [_pending setObject: $object(size) forKey: $object(q.number)];
   125         response.onComplete = $target(self,responseArrived:);
   126     }
   127     [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
   128 }
   129 
   130 - (void) responseArrived: (BLIPResponse*)response
   131 {
   132     Log(@"********** called responseArrived: %@",response);
   133 }
   134 
   135 - (void) connectionDidOpen: (TCPConnection*)connection
   136 {
   137     Log(@"** %@ didOpen",connection);
   138     [self sendAMessage];
   139 }
   140 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   141 {
   142 #if HAVE_KEYCHAIN_FRAMEWORK
   143     Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
   144     Log(@"** %@ authorizeSSLPeer: %@",self,cert);
   145 #else
   146     Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
   147 #endif
   148     return peerCert != nil;
   149 }
   150 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   151 {
   152     Log(@"** %@ failedToOpen: %@",connection,error);
   153     CFRunLoopStop(CFRunLoopGetCurrent());
   154 }
   155 - (void) connectionDidClose: (TCPConnection*)connection
   156 {
   157     Log(@"** %@ didClose",connection);
   158     setObj(&_conn,nil);
   159     [NSObject cancelPreviousPerformRequestsWithTarget: self];
   160     CFRunLoopStop(CFRunLoopGetCurrent());
   161 }
   162 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
   163 {
   164     Log(@"***** %@ received %@",connection,request);
   165     [request respondWithData: request.body contentType: request.contentType];
   166 }
   167 
   168 - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
   169 {
   170     Log(@"********** %@ received %@",connection,response);
   171     NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
   172 
   173     if( response.error )
   174         Warn(@"Got error response: %@",response.error);
   175     else {
   176         NSData *body = response.body;
   177         size_t size = body.length;
   178         Assert(size<32768);
   179         const UInt8 *bytes = body.bytes;
   180         for( size_t i=0; i<size; i++ )
   181             AssertEq(bytes[i],i % 256);
   182         AssertEq(size,sizeObj.intValue);
   183     }
   184     Assert(sizeObj);
   185     [_pending removeObjectForKey: $object(response.number)];
   186     Log(@"Now %u replies pending", _pending.count);
   187     Assert(_pending.count<100);
   188 }
   189 
   190 
   191 @end
   192 
   193 
   194 TestCase(BLIPConnection) {
   195 #if HAVE_KEYCHAIN_FRAMEWORK
   196     [Keychain setUserInteractionAllowed: YES];
   197 #endif
   198     BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
   199     CAssert(tester);
   200     
   201     [[NSRunLoop currentRunLoop] run];
   202     
   203     Log(@"** Runloop stopped");
   204     [tester release];
   205 }
   206 
   207 
   208 
   209 
   210 #pragma mark LISTENER TEST:
   211 
   212 
   213 @interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
   214 {
   215     BLIPListener *_listener;
   216 }
   217 
   218 @end
   219 
   220 
   221 @implementation BLIPTestListener
   222 
   223 - (id) init
   224 {
   225     self = [super init];
   226     if (self != nil) {
   227         _listener = [[BLIPListener alloc] initWithPort: kListenerPort];
   228         _listener.delegate = self;
   229         _listener.pickAvailablePort = YES;
   230         _listener.bonjourServiceType = @"_bliptest._tcp";
   231         if( kListenerRequiresSSL ) {
   232             SecIdentityRef listenerIdentity = GetListenerIdentity();
   233             Assert(listenerIdentity);
   234             _listener.SSLProperties = $mdict({kTCPPropertySSLCertificates, $array((id)listenerIdentity)},
   235                                              {kTCPPropertySSLAllowsAnyRoot,$true},
   236                             {kTCPPropertySSLClientSideAuthentication, $object(kTCPTryAuthenticate)});
   237         }
   238         Assert( [_listener open] );
   239         Log(@"%@ is listening...",self);
   240     }
   241     return self;
   242 }
   243 
   244 - (void) dealloc
   245 {
   246     Log(@"%@ closing",self);
   247     [_listener close];
   248     [_listener release];
   249     [super dealloc];
   250 }
   251 
   252 - (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection
   253 {
   254     Log(@"** %@ accepted %@",self,connection);
   255     connection.delegate = self;
   256 }
   257 
   258 - (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error
   259 {
   260     Log(@"** BLIPTestListener failed to open: %@",error);
   261 }
   262 
   263 - (void) listenerDidOpen: (TCPListener*)listener   {Log(@"** BLIPTestListener did open");}
   264 - (void) listenerDidClose: (TCPListener*)listener   {Log(@"** BLIPTestListener did close");}
   265 
   266 - (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address
   267 {
   268     Log(@"** %@ shouldAcceptConnectionFrom: %@",self,address);
   269     return YES;
   270 }
   271 
   272 
   273 - (void) connectionDidOpen: (TCPConnection*)connection
   274 {
   275     Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
   276 }
   277 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   278 {
   279 #if HAVE_KEYCHAIN_FRAMEWORK
   280     Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
   281     Log(@"** %@ authorizeSSLPeer: %@",connection,cert);
   282 #else
   283     Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
   284 #endif
   285     return peerCert != nil || ! kListenerRequiresClientCert;
   286 }
   287 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   288 {
   289     Log(@"** %@ failedToOpen: %@",connection,error);
   290 }
   291 - (void) connectionDidClose: (TCPConnection*)connection
   292 {
   293     Log(@"** %@ didClose",connection);
   294     [connection release];
   295 }
   296 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
   297 {
   298     Log(@"***** %@ received %@",connection,request);
   299     NSData *body = request.body;
   300     size_t size = body.length;
   301     Assert(size<32768);
   302     const UInt8 *bytes = body.bytes;
   303     for( size_t i=0; i<size; i++ )
   304         AssertEq(bytes[i],i % 256);
   305     
   306     AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
   307     AssertEqual([request valueOfProperty: @"User-Agent"], @"BLIPConnectionTester");
   308     AssertEq([[request valueOfProperty: @"Size"] intValue], size);
   309 
   310     [request respondWithData: body contentType: request.contentType];
   311 }
   312 
   313 
   314 @end
   315 
   316 
   317 TestCase(BLIPListener) {
   318     EnableLogTo(BLIP,YES);
   319     EnableLogTo(PortMapper,YES);
   320     EnableLogTo(Bonjour,YES);
   321 #if HAVE_KEYCHAIN_FRAMEWORK
   322     [Keychain setUserInteractionAllowed: YES];
   323 #endif
   324     BLIPTestListener *listener = [[BLIPTestListener alloc] init];
   325     
   326     [[NSRunLoop currentRunLoop] run];
   327     
   328     [listener release];
   329 }
   330 
   331 
   332 #endif
   333 
   334 
   335 /*
   336  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   337  
   338  Redistribution and use in source and binary forms, with or without modification, are permitted
   339  provided that the following conditions are met:
   340  
   341  * Redistributions of source code must retain the above copyright notice, this list of conditions
   342  and the following disclaimer.
   343  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   344  and the following disclaimer in the documentation and/or other materials provided with the
   345  distribution.
   346  
   347  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   348  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   349  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   350  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   351  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   352   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   353  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   354  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   355  */