* Fixed path type of MYUtilities folder ref; this fixes issue #2.
* Added MYDNSService.h/m to iPhone project.
* Changed base SDK of iPhone project to 2.2.1 (from 2.0)
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 #import <Security/Security.h>
23 #import <SecurityInterface/SFChooseIdentityPanel.h>
25 @interface TCPEndpoint ()
26 + (NSString*) describeCert: (SecCertificateRef)cert;
27 + (NSString*) describeIdentity: (SecIdentityRef)identity;
31 #define kListenerHost @"localhost"
32 #define kListenerPort 46353
33 #define kSendInterval 0.5
34 #define kNBatchedMessages 20
35 #define kUseCompression YES
36 #define kUrgentEvery 4
37 #define kListenerCloseAfter 50
38 #define kClientAcceptCloseRequest YES
40 #define kListenerUsesSSL YES // Does the listener (server) use an SSL connection?
41 #define kListenerRequiresClientCert YES // Does the listener require clients to have an SSL cert?
42 #define kClientRequiresSSL YES // Does the client require the listener to use SSL?
43 #define kClientUsesSSLCert YES // Does the client use an SSL cert?
46 static SecIdentityRef ChooseIdentity( NSString *prompt ) {
47 NSMutableArray *identities = [NSMutableArray array];
49 SecKeychainCopyDefault(&kc);
50 SecIdentitySearchRef search;
51 SecIdentitySearchCreate(kc, CSSM_KEYUSE_ANY, &search);
52 SecIdentityRef identity;
53 while (SecIdentitySearchCopyNext(search, &identity) == noErr)
54 [identities addObject: (id)identity];
55 Log(@"Found %u identities -- prompting '%@'", identities.count, prompt);
56 if (identities.count > 0) {
57 SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];
58 if ([panel runModalForIdentities: identities message: prompt] == NSOKButton) {
59 Log(@"Using SSL identity: %@", panel.identity);
60 return panel.identity;
66 static SecIdentityRef GetClientIdentity(void) {
67 return ChooseIdentity(@"Choose an identity for the BLIP Client Test:");
70 static SecIdentityRef GetListenerIdentity(void) {
71 return ChooseIdentity(@"Choose an identity for the BLIP Listener Test:");
76 #pragma mark CLIENT TEST:
79 @interface BLIPConnectionTester : NSObject <BLIPConnectionDelegate>
81 BLIPConnection *_conn;
82 NSMutableDictionary *_pending;
88 @implementation BLIPConnectionTester
94 Log(@"** INIT %@",self);
95 _pending = [[NSMutableDictionary alloc] init];
96 IPAddress *addr = [[IPAddress alloc] initWithHostname: kListenerHost port: kListenerPort];
97 _conn = [[BLIPConnection alloc] initToAddress: addr];
102 if( kClientUsesSSLCert ) {
103 [_conn setPeerToPeerIdentity: GetClientIdentity()];
104 } else if( kClientRequiresSSL ) {
105 _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true},
106 {(id)kCFStreamSSLPeerName, [NSNull null]});
108 _conn.delegate = self;
109 Log(@"** Opening connection...");
117 Log(@"** %@ closing",self);
123 - (void) sendAMessage
125 if( _conn.status==kTCP_Open || _conn.status==kTCP_Opening ) {
126 if(_pending.count<100) {
127 Log(@"** Sending another %i messages...", kNBatchedMessages);
128 for( int i=0; i<kNBatchedMessages; i++ ) {
129 size_t size = random() % 32768;
130 NSMutableData *body = [NSMutableData dataWithLength: size];
131 UInt8 *bytes = body.mutableBytes;
132 for( size_t i=0; i<size; i++ )
135 BLIPRequest *q = [_conn requestWithBody: body
136 properties: $dict({@"Content-Type", @"application/octet-stream"},
137 {@"User-Agent", @"BLIPConnectionTester"},
138 {@"Date", [[NSDate date] description]},
139 {@"Size",$sprintf(@"%u",size)})];
141 if( kUseCompression && (random()%2==1) )
143 if( random()%16 > 12 )
145 BLIPResponse *response = [q send];
148 Assert(response.number==q.number);
149 [_pending setObject: $object(size) forKey: $object(q.number)];
150 response.onComplete = $target(self,responseArrived:);
153 Warn(@"There are %u pending messages; waiting for the listener to catch up...",_pending.count);
155 [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
159 - (void) responseArrived: (BLIPResponse*)response
161 Log(@"********** called responseArrived: %@",response);
164 - (void) connectionDidOpen: (TCPConnection*)connection
166 Log(@"** %@ didOpen",connection);
169 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
171 Log(@"** %@ authorizeSSLPeer: %@",self, [TCPEndpoint describeCert:peerCert]);
172 return peerCert != nil;
174 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
176 Warn(@"** %@ failedToOpen: %@",connection,error);
177 CFRunLoopStop(CFRunLoopGetCurrent());
179 - (void) connectionDidClose: (TCPConnection*)connection
181 if (connection.error)
182 Warn(@"** %@ didClose: %@", connection,connection.error);
184 Log(@"** %@ didClose", connection);
186 [NSObject cancelPreviousPerformRequestsWithTarget: self];
187 CFRunLoopStop(CFRunLoopGetCurrent());
189 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
191 Log(@"***** %@ received %@",connection,request);
192 [request respondWithData: request.body contentType: request.contentType];
195 - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
197 Log(@"********** %@ received %@",connection,response);
198 NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
201 Warn(@"Got error response: %@",response.error);
203 NSData *body = response.body;
204 size_t size = body.length;
206 const UInt8 *bytes = body.bytes;
207 for( size_t i=0; i<size; i++ )
208 AssertEq(bytes[i],i % 256);
209 AssertEq(size,sizeObj.unsignedIntValue);
212 [_pending removeObjectForKey: $object(response.number)];
213 Log(@"Now %u replies pending", _pending.count);
216 - (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection
218 BOOL response = kClientAcceptCloseRequest;
219 Log(@"***** %@ received a close request; returning %i",connection,response);
227 TestCase(BLIPConnection) {
228 SecKeychainSetUserInteractionAllowed(true);
229 BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
232 [[NSRunLoop currentRunLoop] run];
234 Log(@"** Runloop stopped");
241 #pragma mark LISTENER TEST:
244 @interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
246 BLIPListener *_listener;
253 @implementation BLIPTestListener
259 _listener = [[BLIPListener alloc] initWithPort: kListenerPort];
260 _listener.delegate = self;
261 _listener.pickAvailablePort = YES;
262 _listener.bonjourServiceType = @"_bliptest._tcp";
263 if( kListenerUsesSSL ) {
264 [_listener setPeerToPeerIdentity: GetListenerIdentity()];
265 if (!kListenerRequiresClientCert)
266 [_listener setSSLProperty: $object(kTCPTryAuthenticate)
267 forKey: kTCPPropertySSLClientSideAuthentication];
269 Assert( [_listener open] );
270 Log(@"%@ is listening...",self);
277 Log(@"%@ closing",self);
283 - (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection
285 Log(@"** %@ accepted %@",self,connection);
286 connection.delegate = self;
289 - (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error
291 Log(@"** BLIPTestListener failed to open: %@",error);
294 - (void) listenerDidOpen: (TCPListener*)listener {Log(@"** BLIPTestListener did open");}
295 - (void) listenerDidClose: (TCPListener*)listener {Log(@"** BLIPTestListener did close");}
297 - (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address
299 Log(@"** %@ shouldAcceptConnectionFrom: %@",self,address);
304 - (void) connectionDidOpen: (TCPConnection*)connection
306 Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
309 - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
311 Log(@"** %@ authorizeSSLPeer: %@",self, [TCPEndpoint describeCert:peerCert]);
312 return peerCert != nil || ! kListenerRequiresClientCert;
314 - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
316 Log(@"** %@ failedToOpen: %@",connection,error);
318 - (void) connectionDidClose: (TCPConnection*)connection
320 if (connection.error)
321 Warn(@"** %@ didClose: %@", connection,connection.error);
323 Log(@"** %@ didClose", connection);
324 [connection release];
326 - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
328 Log(@"***** %@ received %@",connection,request);
329 NSData *body = request.body;
330 size_t size = body.length;
332 const UInt8 *bytes = body.bytes;
333 for( size_t i=0; i<size; i++ )
334 AssertEq(bytes[i],i % 256);
336 AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
337 Assert([request valueOfProperty: @"User-Agent"] != nil);
338 AssertEq((size_t)[[request valueOfProperty: @"Size"] intValue], size);
340 [request respondWithData: body contentType: request.contentType];
342 if( ++ _nReceived == kListenerCloseAfter ) {
343 Log(@"********** Closing BLIPTestListener after %i requests",_nReceived);
348 - (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection;
350 Log(@"***** %@ received a close request",connection);
354 - (void) connection: (BLIPConnection*)connection closeRequestFailedWithError: (NSError*)error
356 Log(@"***** %@'s close request failed: %@",connection,error);
363 TestCase(BLIPListener) {
364 EnableLogTo(BLIP,YES);
365 EnableLogTo(PortMapper,YES);
366 EnableLogTo(Bonjour,YES);
367 SecKeychainSetUserInteractionAllowed(true);
368 BLIPTestListener *listener = [[BLIPTestListener alloc] init];
370 [[NSRunLoop currentRunLoop] run];
380 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
382 Redistribution and use in source and binary forms, with or without modification, are permitted
383 provided that the following conditions are met:
385 * Redistributions of source code must retain the above copyright notice, this list of conditions
386 and the following disclaimer.
387 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
388 and the following disclaimer in the documentation and/or other materials provided with the
391 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
392 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
393 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
394 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
395 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
396 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
397 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
398 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.