BLIP/BLIPTest.m
changeset 0 9d67172bb323
child 1 8267d5c429c4
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/BLIP/BLIPTest.m	Fri May 23 17:37:36 2008 -0700
     1.3 @@ -0,0 +1,350 @@
     1.4 +//
     1.5 +//  BLIPTest.m
     1.6 +//  MYNetwork
     1.7 +//
     1.8 +//  Created by Jens Alfke on 5/13/08.
     1.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    1.10 +//
    1.11 +
    1.12 +#ifndef NDEBUG
    1.13 +
    1.14 +
    1.15 +#import "BLIPRequest.h"
    1.16 +#import "BLIPProperties.h"
    1.17 +#import "BLIPConnection.h"
    1.18 +#import "IPAddress.h"
    1.19 +#import "Target.h"
    1.20 +
    1.21 +#define HAVE_KEYCHAIN_FRAMEWORK 0
    1.22 +#if HAVE_KEYCHAIN_FRAMEWORK
    1.23 +#import <Keychain/Keychain.h>
    1.24 +#endif
    1.25 +
    1.26 +#define kListenerPort               46353
    1.27 +#define kSendInterval               0.5
    1.28 +#define kNBatchedMessages           20
    1.29 +#define kUseCompression             YES
    1.30 +#define kUrgentEvery                4
    1.31 +#define kClientRequiresSSL          NO
    1.32 +#define kClientUsesSSLCert          NO
    1.33 +#define kListenerRequiresSSL        NO
    1.34 +#define kListenerRequiresClientCert NO
    1.35 +
    1.36 +
    1.37 +static SecIdentityRef GetClientIdentity(void) {
    1.38 +    return NULL;    // Make this return a valid identity to test client-side certs
    1.39 +}
    1.40 +
    1.41 +static SecIdentityRef GetListenerIdentity(void) {
    1.42 +    return NULL;    // Make this return a valid identity to test client-side certs
    1.43 +}
    1.44 +
    1.45 +
    1.46 +#pragma mark -
    1.47 +#pragma mark CLIENT TEST:
    1.48 +
    1.49 +
    1.50 +@interface BLIPConnectionTester : NSObject <BLIPConnectionDelegate>
    1.51 +{
    1.52 +    BLIPConnection *_conn;
    1.53 +    NSMutableDictionary *_pending;
    1.54 +}
    1.55 +
    1.56 +@end
    1.57 +
    1.58 +
    1.59 +@implementation BLIPConnectionTester
    1.60 +
    1.61 +- (id) init
    1.62 +{
    1.63 +    self = [super init];
    1.64 +    if (self != nil) {
    1.65 +        Log(@"** INIT %@",self);
    1.66 +        _pending = [[NSMutableDictionary alloc] init];
    1.67 +        IPAddress *addr = [[IPAddress alloc] initWithHostname: @"localhost" port: kListenerPort];
    1.68 +        _conn = [[BLIPConnection alloc] initToAddress: addr];
    1.69 +        if( ! _conn ) {
    1.70 +            [self release];
    1.71 +            return nil;
    1.72 +        }
    1.73 +        if( kClientRequiresSSL ) {
    1.74 +            _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true});
    1.75 +            if( kClientUsesSSLCert ) {
    1.76 +                SecIdentityRef clientIdentity = GetClientIdentity();
    1.77 +                if( clientIdentity ) {
    1.78 +                    [_conn setSSLProperty: $array((id)clientIdentity)
    1.79 +                                   forKey: kTCPPropertySSLCertificates];
    1.80 +                }
    1.81 +            }
    1.82 +        }
    1.83 +        _conn.delegate = self;
    1.84 +        Log(@"** Opening connection...");
    1.85 +        [_conn open];
    1.86 +    }
    1.87 +    return self;
    1.88 +}
    1.89 +
    1.90 +- (void) dealloc
    1.91 +{
    1.92 +    Log(@"** %@ closing",self);
    1.93 +    [_conn close];
    1.94 +    [_conn release];
    1.95 +    [super dealloc];
    1.96 +}
    1.97 +
    1.98 +- (void) sendAMessage
    1.99 +{
   1.100 +    Log(@"** Sending another %i messages...", kNBatchedMessages);
   1.101 +    for( int i=0; i<kNBatchedMessages; i++ ) {
   1.102 +        size_t size = random() % 32768;
   1.103 +        NSMutableData *body = [NSMutableData dataWithLength: size];
   1.104 +        UInt8 *bytes = body.mutableBytes;
   1.105 +        for( size_t i=0; i<size; i++ )
   1.106 +            bytes[i] = i % 256;
   1.107 +        
   1.108 +        BLIPRequest *q = [_conn requestWithBody: body
   1.109 +                                     properties: $dict({@"Content-Type", @"application/octet-stream"},
   1.110 +                                                       {@"User-Agent", @"BLIPConnectionTester"},
   1.111 +                                                       {@"Date", [[NSDate date] description]},
   1.112 +                                                       {@"Size",$sprintf(@"%u",size)})];
   1.113 +        Assert(q);
   1.114 +        if( kUseCompression && (random()%2==1) )
   1.115 +            q.compressed = YES;
   1.116 +        if( random()%16 > 12 )
   1.117 +            q.urgent = YES;
   1.118 +        BLIPResponse *response = [q send];
   1.119 +        Assert(response);
   1.120 +        Assert(q.number>0);
   1.121 +        Assert(response.number==q.number);
   1.122 +        [_pending setObject: $object(size) forKey: $object(q.number)];
   1.123 +        response.onComplete = $target(self,responseArrived:);
   1.124 +    }
   1.125 +    [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
   1.126 +}
   1.127 +
   1.128 +- (void) responseArrived: (BLIPResponse*)response
   1.129 +{
   1.130 +    Log(@"********** called responseArrived: %@",response);
   1.131 +}
   1.132 +
   1.133 +- (void) connectionDidOpen: (TCPConnection*)connection
   1.134 +{
   1.135 +    Log(@"** %@ didOpen",connection);
   1.136 +    [self sendAMessage];
   1.137 +}
   1.138 +- (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   1.139 +{
   1.140 +#if HAVE_KEYCHAIN_FRAMEWORK
   1.141 +    Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
   1.142 +    Log(@"** %@ authorizeSSLPeer: %@",self,cert);
   1.143 +#else
   1.144 +    Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
   1.145 +#endif
   1.146 +    return peerCert != nil;
   1.147 +}
   1.148 +- (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   1.149 +{
   1.150 +    Log(@"** %@ failedToOpen: %@",connection,error);
   1.151 +    CFRunLoopStop(CFRunLoopGetCurrent());
   1.152 +}
   1.153 +- (void) connectionDidClose: (TCPConnection*)connection
   1.154 +{
   1.155 +    Log(@"** %@ didClose",connection);
   1.156 +    setObj(&_conn,nil);
   1.157 +    [NSObject cancelPreviousPerformRequestsWithTarget: self];
   1.158 +    CFRunLoopStop(CFRunLoopGetCurrent());
   1.159 +}
   1.160 +- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
   1.161 +{
   1.162 +    Log(@"***** %@ received %@",connection,request);
   1.163 +    [request respondWithData: request.body];
   1.164 +}
   1.165 +
   1.166 +- (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
   1.167 +{
   1.168 +    Log(@"********** %@ received %@",connection,response);
   1.169 +    NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
   1.170 +
   1.171 +    if( response.error )
   1.172 +        Warn(@"Got error response: %@",response.error);
   1.173 +    else {
   1.174 +        NSData *body = response.body;
   1.175 +        size_t size = body.length;
   1.176 +        Assert(size<32768);
   1.177 +        const UInt8 *bytes = body.bytes;
   1.178 +        for( size_t i=0; i<size; i++ )
   1.179 +            AssertEq(bytes[i],i % 256);
   1.180 +        AssertEq(size,sizeObj.intValue);
   1.181 +    }
   1.182 +    Assert(sizeObj);
   1.183 +    [_pending removeObjectForKey: $object(response.number)];
   1.184 +    Log(@"Now %u replies pending", _pending.count);
   1.185 +    Assert(_pending.count<100);
   1.186 +}
   1.187 +
   1.188 +
   1.189 +@end
   1.190 +
   1.191 +
   1.192 +TestCase(BLIPConnection) {
   1.193 +#if HAVE_KEYCHAIN_FRAMEWORK
   1.194 +    [Keychain setUserInteractionAllowed: YES];
   1.195 +#endif
   1.196 +    BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
   1.197 +    CAssert(tester);
   1.198 +    
   1.199 +    [[NSRunLoop currentRunLoop] run];
   1.200 +    
   1.201 +    Log(@"** Runloop stopped");
   1.202 +    [tester release];
   1.203 +}
   1.204 +
   1.205 +
   1.206 +
   1.207 +
   1.208 +#pragma mark LISTENER TEST:
   1.209 +
   1.210 +
   1.211 +@interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
   1.212 +{
   1.213 +    BLIPListener *_listener;
   1.214 +}
   1.215 +
   1.216 +@end
   1.217 +
   1.218 +
   1.219 +@implementation BLIPTestListener
   1.220 +
   1.221 +- (id) init
   1.222 +{
   1.223 +    self = [super init];
   1.224 +    if (self != nil) {
   1.225 +        _listener = [[BLIPListener alloc] initWithPort: kListenerPort];
   1.226 +        _listener.delegate = self;
   1.227 +        _listener.pickAvailablePort = YES;
   1.228 +        _listener.bonjourServiceType = @"_bliptest._tcp";
   1.229 +        if( kListenerRequiresSSL ) {
   1.230 +            SecIdentityRef listenerIdentity = GetListenerIdentity();
   1.231 +            Assert(listenerIdentity);
   1.232 +            _listener.SSLProperties = $mdict({kTCPPropertySSLCertificates, $array((id)listenerIdentity)},
   1.233 +                                             {kTCPPropertySSLAllowsAnyRoot,$true},
   1.234 +            {kTCPPropertySSLClientSideAuthentication, $object(kTryAuthenticate)});
   1.235 +        }
   1.236 +        Assert( [_listener open] );
   1.237 +        Log(@"%@ is listening...",self);
   1.238 +    }
   1.239 +    return self;
   1.240 +}
   1.241 +
   1.242 +- (void) dealloc
   1.243 +{
   1.244 +    Log(@"%@ closing",self);
   1.245 +    [_listener close];
   1.246 +    [_listener release];
   1.247 +    [super dealloc];
   1.248 +}
   1.249 +
   1.250 +- (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection
   1.251 +{
   1.252 +    Log(@"** %@ accepted %@",self,connection);
   1.253 +    connection.delegate = self;
   1.254 +}
   1.255 +
   1.256 +- (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error
   1.257 +{
   1.258 +    Log(@"** BLIPTestListener failed to open: %@",error);
   1.259 +}
   1.260 +
   1.261 +- (void) listenerDidOpen: (TCPListener*)listener   {Log(@"** BLIPTestListener did open");}
   1.262 +- (void) listenerDidClose: (TCPListener*)listener   {Log(@"** BLIPTestListener did close");}
   1.263 +
   1.264 +- (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address
   1.265 +{
   1.266 +    Log(@"** %@ shouldAcceptConnectionFrom: %@",self,address);
   1.267 +    return YES;
   1.268 +}
   1.269 +
   1.270 +
   1.271 +- (void) connectionDidOpen: (TCPConnection*)connection
   1.272 +{
   1.273 +    Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
   1.274 +}
   1.275 +- (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   1.276 +{
   1.277 +#if HAVE_KEYCHAIN_FRAMEWORK
   1.278 +    Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
   1.279 +    Log(@"** %@ authorizeSSLPeer: %@",connection,cert);
   1.280 +#else
   1.281 +    Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
   1.282 +#endif
   1.283 +    return peerCert != nil || ! kListenerRequiresClientCert;
   1.284 +}
   1.285 +- (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   1.286 +{
   1.287 +    Log(@"** %@ failedToOpen: %@",connection,error);
   1.288 +}
   1.289 +- (void) connectionDidClose: (TCPConnection*)connection
   1.290 +{
   1.291 +    Log(@"** %@ didClose",connection);
   1.292 +    [connection release];
   1.293 +}
   1.294 +- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
   1.295 +{
   1.296 +    Log(@"***** %@ received %@",connection,request);
   1.297 +    NSData *body = request.body;
   1.298 +    size_t size = body.length;
   1.299 +    Assert(size<32768);
   1.300 +    const UInt8 *bytes = body.bytes;
   1.301 +    for( size_t i=0; i<size; i++ )
   1.302 +        AssertEq(bytes[i],i % 256);
   1.303 +    
   1.304 +    AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
   1.305 +    AssertEqual([request valueOfProperty: @"User-Agent"], @"BLIPConnectionTester");
   1.306 +    AssertEq([[request valueOfProperty: @"Size"] intValue], size);
   1.307 +
   1.308 +    [request respondWithData: body];
   1.309 +}
   1.310 +
   1.311 +
   1.312 +@end
   1.313 +
   1.314 +
   1.315 +TestCase(BLIPListener) {
   1.316 +    EnableLogTo(BLIP,YES);
   1.317 +    EnableLogTo(PortMapper,YES);
   1.318 +    EnableLogTo(Bonjour,YES);
   1.319 +#if HAVE_KEYCHAIN_FRAMEWORK
   1.320 +    [Keychain setUserInteractionAllowed: YES];
   1.321 +#endif
   1.322 +    BLIPTestListener *listener = [[BLIPTestListener alloc] init];
   1.323 +    
   1.324 +    [[NSRunLoop currentRunLoop] run];
   1.325 +    
   1.326 +    [listener release];
   1.327 +}
   1.328 +
   1.329 +
   1.330 +#endif
   1.331 +
   1.332 +
   1.333 +/*
   1.334 + Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   1.335 + 
   1.336 + Redistribution and use in source and binary forms, with or without modification, are permitted
   1.337 + provided that the following conditions are met:
   1.338 + 
   1.339 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   1.340 + and the following disclaimer.
   1.341 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   1.342 + and the following disclaimer in the documentation and/or other materials provided with the
   1.343 + distribution.
   1.344 + 
   1.345 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   1.346 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   1.347 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   1.348 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   1.349 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   1.350 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   1.351 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   1.352 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.353 + */