First public release.
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 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
39 static SecIdentityRef GetClientIdentity(void) {
40 return NULL; // Make this return a valid identity to test client-side certs
43 static SecIdentityRef GetListenerIdentity(void) {
44 return NULL; // Make this return a valid identity to test client-side certs
49 #pragma mark CLIENT TEST:
52 @interface BLIPConnectionTester : NSObject <BLIPConnectionDelegate>
54 BLIPConnection *_conn;
55 NSMutableDictionary *_pending;
61 @implementation BLIPConnectionTester
67 Log(@"** INIT %@",self);
68 _pending = [[NSMutableDictionary alloc] init];
69 IPAddress *addr = [[IPAddress alloc] initWithHostname: @"localhost" port: kListenerPort];
70 _conn = [[BLIPConnection alloc] initToAddress: addr];
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];
85 _conn.delegate = self;
86 Log(@"** Opening connection...");
94 Log(@"** %@ closing",self);
100 - (void) sendAMessage
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++ )
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)})];
116 if( kUseCompression && (random()%2==1) )
118 if( random()%16 > 12 )
120 BLIPResponse *response = [q send];
123 Assert(response.number==q.number);
124 [_pending setObject: $object(size) forKey: $object(q.number)];
125 response.onComplete = $target(self,responseArrived:);
127 [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
130 - (void) responseArrived: (BLIPResponse*)response
132 Log(@"********** called responseArrived: %@",response);
135 - (void) connectionDidOpen: (TCPConnection*)connection
137 Log(@"** %@ didOpen",connection);
140 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
142 #if HAVE_KEYCHAIN_FRAMEWORK
143 Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
144 Log(@"** %@ authorizeSSLPeer: %@",self,cert);
146 Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
148 return peerCert != nil;
150 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
152 Log(@"** %@ failedToOpen: %@",connection,error);
153 CFRunLoopStop(CFRunLoopGetCurrent());
155 - (void) connectionDidClose: (TCPConnection*)connection
157 Log(@"** %@ didClose",connection);
159 [NSObject cancelPreviousPerformRequestsWithTarget: self];
160 CFRunLoopStop(CFRunLoopGetCurrent());
162 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
164 Log(@"***** %@ received %@",connection,request);
165 [request respondWithData: request.body contentType: request.contentType];
168 - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
170 Log(@"********** %@ received %@",connection,response);
171 NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
174 Warn(@"Got error response: %@",response.error);
176 NSData *body = response.body;
177 size_t size = body.length;
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);
185 [_pending removeObjectForKey: $object(response.number)];
186 Log(@"Now %u replies pending", _pending.count);
187 Assert(_pending.count<100);
194 TestCase(BLIPConnection) {
195 #if HAVE_KEYCHAIN_FRAMEWORK
196 [Keychain setUserInteractionAllowed: YES];
198 BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
201 [[NSRunLoop currentRunLoop] run];
203 Log(@"** Runloop stopped");
210 #pragma mark LISTENER TEST:
213 @interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
215 BLIPListener *_listener;
221 @implementation BLIPTestListener
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(kTryAuthenticate)});
238 Assert( [_listener open] );
239 Log(@"%@ is listening...",self);
246 Log(@"%@ closing",self);
252 - (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection
254 Log(@"** %@ accepted %@",self,connection);
255 connection.delegate = self;
258 - (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error
260 Log(@"** BLIPTestListener failed to open: %@",error);
263 - (void) listenerDidOpen: (TCPListener*)listener {Log(@"** BLIPTestListener did open");}
264 - (void) listenerDidClose: (TCPListener*)listener {Log(@"** BLIPTestListener did close");}
266 - (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address
268 Log(@"** %@ shouldAcceptConnectionFrom: %@",self,address);
273 - (void) connectionDidOpen: (TCPConnection*)connection
275 Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
277 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
279 #if HAVE_KEYCHAIN_FRAMEWORK
280 Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
281 Log(@"** %@ authorizeSSLPeer: %@",connection,cert);
283 Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
285 return peerCert != nil || ! kListenerRequiresClientCert;
287 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
289 Log(@"** %@ failedToOpen: %@",connection,error);
291 - (void) connectionDidClose: (TCPConnection*)connection
293 Log(@"** %@ didClose",connection);
294 [connection release];
296 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
298 Log(@"***** %@ received %@",connection,request);
299 NSData *body = request.body;
300 size_t size = body.length;
302 const UInt8 *bytes = body.bytes;
303 for( size_t i=0; i<size; i++ )
304 AssertEq(bytes[i],i % 256);
306 AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
307 AssertEqual([request valueOfProperty: @"User-Agent"], @"BLIPConnectionTester");
308 AssertEq([[request valueOfProperty: @"Size"] intValue], size);
310 [request respondWithData: body contentType: request.contentType];
317 TestCase(BLIPListener) {
318 EnableLogTo(BLIP,YES);
319 EnableLogTo(PortMapper,YES);
320 EnableLogTo(Bonjour,YES);
321 #if HAVE_KEYCHAIN_FRAMEWORK
322 [Keychain setUserInteractionAllowed: YES];
324 BLIPTestListener *listener = [[BLIPTestListener alloc] init];
326 [[NSRunLoop currentRunLoop] run];
336 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
338 Redistribution and use in source and binary forms, with or without modification, are permitted
339 provided that the following conditions are met:
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
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.