5 // Created by Jens Alfke on 5/13/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
12 #import "BLIPRequest.h"
13 #import "BLIPProperties.h"
14 #import "BLIPConnection.h"
18 #import "CollectionUtils.h"
22 #define HAVE_KEYCHAIN_FRAMEWORK 0
23 #if HAVE_KEYCHAIN_FRAMEWORK
24 #import <Keychain/Keychain.h>
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
41 static SecIdentityRef GetClientIdentity(void) {
42 return NULL; // Make this return a valid identity to test client-side certs
45 static SecIdentityRef GetListenerIdentity(void) {
46 return NULL; // Make this return a valid identity to test client-side certs
51 #pragma mark CLIENT TEST:
54 @interface BLIPConnectionTester : NSObject <BLIPConnectionDelegate>
56 BLIPConnection *_conn;
57 NSMutableDictionary *_pending;
63 @implementation BLIPConnectionTester
69 Log(@"** INIT %@",self);
70 _pending = [[NSMutableDictionary alloc] init];
71 IPAddress *addr = [[IPAddress alloc] initWithHostname: kListenerHost port: kListenerPort];
72 _conn = [[BLIPConnection alloc] initToAddress: addr];
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];
87 _conn.delegate = self;
88 Log(@"** Opening connection...");
96 Log(@"** %@ closing",self);
102 - (void) sendAMessage
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++ )
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)})];
120 if( kUseCompression && (random()%2==1) )
122 if( random()%16 > 12 )
124 BLIPResponse *response = [q send];
127 Assert(response.number==q.number);
128 [_pending setObject: $object(size) forKey: $object(q.number)];
129 response.onComplete = $target(self,responseArrived:);
132 Warn(@"There are %u pending messages; waiting for the listener to catch up...",_pending.count);
134 [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
138 - (void) responseArrived: (BLIPResponse*)response
140 Log(@"********** called responseArrived: %@",response);
143 - (void) connectionDidOpen: (TCPConnection*)connection
145 Log(@"** %@ didOpen",connection);
148 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
150 #if HAVE_KEYCHAIN_FRAMEWORK
151 Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
152 Log(@"** %@ authorizeSSLPeer: %@",self,cert);
154 Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
156 return peerCert != nil;
158 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
160 Log(@"** %@ failedToOpen: %@",connection,error);
161 CFRunLoopStop(CFRunLoopGetCurrent());
163 - (void) connectionDidClose: (TCPConnection*)connection
165 Log(@"** %@ didClose",connection);
167 [NSObject cancelPreviousPerformRequestsWithTarget: self];
168 CFRunLoopStop(CFRunLoopGetCurrent());
170 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
172 Log(@"***** %@ received %@",connection,request);
173 [request respondWithData: request.body contentType: request.contentType];
176 - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
178 Log(@"********** %@ received %@",connection,response);
179 NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
182 Warn(@"Got error response: %@",response.error);
184 NSData *body = response.body;
185 size_t size = body.length;
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);
193 [_pending removeObjectForKey: $object(response.number)];
194 Log(@"Now %u replies pending", _pending.count);
197 - (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection
200 Log(@"***** %@ received a close request; returning %i",connection,response);
208 TestCase(BLIPConnection) {
209 #if HAVE_KEYCHAIN_FRAMEWORK
210 [Keychain setUserInteractionAllowed: YES];
212 BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
215 [[NSRunLoop currentRunLoop] run];
217 Log(@"** Runloop stopped");
224 #pragma mark LISTENER TEST:
227 @interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
229 BLIPListener *_listener;
236 @implementation BLIPTestListener
242 _listener = [[BLIPListener alloc] initWithPort: kListenerPort];
243 _listener.delegate = self;
244 _listener.pickAvailablePort = YES;
245 _listener.bonjourServiceType = @"_bliptest._tcp";
246 if( kListenerRequiresSSL ) {
247 SecIdentityRef listenerIdentity = GetListenerIdentity();
248 Assert(listenerIdentity);
249 _listener.SSLProperties = $mdict({kTCPPropertySSLCertificates, $array((id)listenerIdentity)},
250 {kTCPPropertySSLAllowsAnyRoot,$true},
251 {kTCPPropertySSLClientSideAuthentication, $object(kTCPTryAuthenticate)});
253 Assert( [_listener open] );
254 Log(@"%@ is listening...",self);
261 Log(@"%@ closing",self);
267 - (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection
269 Log(@"** %@ accepted %@",self,connection);
270 connection.delegate = self;
273 - (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error
275 Log(@"** BLIPTestListener failed to open: %@",error);
278 - (void) listenerDidOpen: (TCPListener*)listener {Log(@"** BLIPTestListener did open");}
279 - (void) listenerDidClose: (TCPListener*)listener {Log(@"** BLIPTestListener did close");}
281 - (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address
283 Log(@"** %@ shouldAcceptConnectionFrom: %@",self,address);
288 - (void) connectionDidOpen: (TCPConnection*)connection
290 Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
293 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
295 #if HAVE_KEYCHAIN_FRAMEWORK
296 Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
297 Log(@"** %@ authorizeSSLPeer: %@",connection,cert);
299 Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
301 return peerCert != nil || ! kListenerRequiresClientCert;
303 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
305 Log(@"** %@ failedToOpen: %@",connection,error);
307 - (void) connectionDidClose: (TCPConnection*)connection
309 Log(@"** %@ didClose",connection);
310 [connection release];
312 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
314 Log(@"***** %@ received %@",connection,request);
315 NSData *body = request.body;
316 size_t size = body.length;
318 const UInt8 *bytes = body.bytes;
319 for( size_t i=0; i<size; i++ )
320 AssertEq(bytes[i],i % 256);
322 AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
323 Assert([request valueOfProperty: @"User-Agent"] != nil);
324 AssertEq([[request valueOfProperty: @"Size"] intValue], size);
326 [request respondWithData: body contentType: request.contentType];
328 if( ++ _nReceived == kListenerCloseAfter ) {
329 Log(@"********** Closing BLIPTestListener after %i requests",_nReceived);
334 - (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection;
336 Log(@"***** %@ received a close request",connection);
340 - (void) connection: (BLIPConnection*)connection closeRequestFailedWithError: (NSError*)error
342 Log(@"***** %@'s close request failed: %@",connection,error);
349 TestCase(BLIPListener) {
350 EnableLogTo(BLIP,YES);
351 EnableLogTo(PortMapper,YES);
352 EnableLogTo(Bonjour,YES);
353 #if HAVE_KEYCHAIN_FRAMEWORK
354 [Keychain setUserInteractionAllowed: YES];
356 BLIPTestListener *listener = [[BLIPTestListener alloc] init];
358 [[NSRunLoop currentRunLoop] run];
368 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
370 Redistribution and use in source and binary forms, with or without modification, are permitted
371 provided that the following conditions are met:
373 * Redistributions of source code must retain the above copyright notice, this list of conditions
374 and the following disclaimer.
375 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
376 and the following disclaimer in the documentation and/or other materials provided with the
379 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
380 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
381 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
382 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
383 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
384 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
385 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
386 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.