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