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