1_0_to_1_1_diffs.diff
author morrowa
Tue Jun 23 12:46:40 2009 -0700 (2009-06-23)
changeset 53 e9f209a24d53
permissions -rw-r--r--
Connections opened by listeners now close correctly.
     1 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPConnection.h
     2 --- a/BLIP/BLIPConnection.h	Thu Jun 19 10:22:19 2008 -0700
     3 +++ b/BLIP/BLIPConnection.h	Mon Jun 23 14:02:31 2008 -0700
     4 @@ -20,6 +20,7 @@
     5  @interface BLIPConnection : TCPConnection
     6  {
     7      BLIPDispatcher *_dispatcher;
     8 +    BOOL _blipClosing;
     9  }
    10  
    11  /** The delegate object that will be called when the connection opens, closes or receives messages. */
    12 @@ -73,6 +74,13 @@
    13  /** Called when a BLIPResponse (to one of your requests) is received from the peer.
    14      This is called <i>after</i> the response object's onComplete target, if any, is invoked.*/
    15  - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response;
    16 +
    17 +/** Called when the peer wants to close the connection. Return YES to allow, NO to prevent. */
    18 +- (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection;
    19 +
    20 +/** Called if the peer refuses a close request. 
    21 +    The typical error is kBLIPError_Forbidden. */
    22 +- (void) connection: (BLIPConnection*)connection closeRequestFailedWithError: (NSError*)error;
    23  @end
    24  
    25  
    26 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPConnection.m
    27 --- a/BLIP/BLIPConnection.m	Thu Jun 19 10:22:19 2008 -0700
    28 +++ b/BLIP/BLIPConnection.m	Mon Jun 23 14:02:31 2008 -0700
    29 @@ -8,6 +8,7 @@
    30  
    31  #import "BLIPConnection.h"
    32  #import "BLIP_Internal.h"
    33 +#import "TCP_Internal.h"
    34  #import "BLIPReader.h"
    35  #import "BLIPWriter.h"
    36  #import "BLIPDispatcher.h"
    37 @@ -15,6 +16,7 @@
    38  #import "Logging.h"
    39  #import "Test.h"
    40  #import "ExceptionUtils.h"
    41 +#import "Target.h"
    42  
    43  
    44  NSString* const BLIPErrorDomain = @"BLIP";
    45 @@ -33,10 +35,14 @@
    46  }
    47  
    48  
    49 +@interface BLIPConnection ()
    50 +- (void) _handleCloseRequest: (BLIPRequest*)request;
    51 +@end
    52  
    53  
    54  @implementation BLIPConnection
    55  
    56 +
    57  - (void) dealloc
    58  {
    59      [_dispatcher release];
    60 @@ -48,6 +54,11 @@
    61  - (id<BLIPConnectionDelegate>) delegate                     {return (id)_delegate;}
    62  - (void) setDelegate: (id<BLIPConnectionDelegate>)delegate  {_delegate = delegate;}
    63  
    64 +
    65 +#pragma mark -
    66 +#pragma mark RECEIVING:
    67 +
    68 +
    69  - (BLIPDispatcher*) dispatcher
    70  {
    71      if( ! _dispatcher ) {
    72 @@ -58,11 +69,23 @@
    73  }
    74  
    75  
    76 +- (void) _dispatchMetaRequest: (BLIPRequest*)request
    77 +{
    78 +    NSString* profile = request.profile;
    79 +    if( [profile isEqualToString: kBLIPProfile_Bye] )
    80 +        [self _handleCloseRequest: request];
    81 +    else
    82 +        [request respondWithErrorCode: kBLIPError_NotFound message: @"Unknown meta profile"];
    83 +}
    84 +
    85 +
    86  - (void) _dispatchRequest: (BLIPRequest*)request
    87  {
    88      LogTo(BLIP,@"Received all of %@",request.descriptionWithProperties);
    89      @try{
    90 -        if( ! [self.dispatcher dispatchMessage: request] )
    91 +        if( request._flags & kBLIP_Meta )
    92 +            [self _dispatchMetaRequest: request];
    93 +        else if( ! [self.dispatcher dispatchMessage: request] )
    94              [self tellDelegate: @selector(connection:receivedRequest:) withObject: request];
    95          if( ! request.noReply && ! request.repliedTo ) {
    96              LogTo(BLIP,@"Returning default empty response to %@",request);
    97 @@ -81,6 +104,10 @@
    98  }
    99  
   100  
   101 +#pragma mark -
   102 +#pragma mark SENDING:
   103 +
   104 +
   105  - (BLIPRequest*) request
   106  {
   107      return [[[BLIPRequest alloc] _initWithConnection: self body: nil properties: nil] autorelease];
   108 @@ -103,11 +130,61 @@
   109  }
   110  
   111  
   112 +#pragma mark -
   113 +#pragma mark CLOSING:
   114 +
   115 +
   116 +- (void) _beginClose
   117 +{
   118 +    // Override of TCPConnection method. Instead of closing the socket, send a 'bye' request:
   119 +    if( ! _blipClosing ) {
   120 +        LogTo(BLIPVerbose,@"Sending close request...");
   121 +        BLIPRequest *r = [self request];
   122 +        [r _setFlag: kBLIP_Meta value: YES];
   123 +        r.profile = kBLIPProfile_Bye;
   124 +        BLIPResponse *response = [r send];
   125 +        response.onComplete = $target(self,_receivedCloseResponse:);
   126 +    }
   127 +    // Put the writer in close mode, to prevent client from sending any more requests:
   128 +    [self.writer close];
   129 +}
   130 +
   131 +- (void) _receivedCloseResponse: (BLIPResponse*)response
   132 +{
   133 +    NSError *error = response.error;
   134 +    LogTo(BLIPVerbose,@"Received close response: error=%@",error);
   135 +    if( error ) {
   136 +        [self _unclose];
   137 +        [self tellDelegate: @selector(connection:closeRequestFailedWithError:) withObject: error];
   138 +    } else {
   139 +        // Now finally close the socket:
   140 +        [super _beginClose];
   141 +    }
   142 +}
   143 +
   144 +
   145 +- (void) _handleCloseRequest: (BLIPRequest*)request
   146 +{
   147 +    LogTo(BLIPVerbose,@"Received a close request");
   148 +    if( [_delegate respondsToSelector: @selector(connectionReceivedCloseRequest:)] )
   149 +        if( ! [_delegate connectionReceivedCloseRequest: self] ) {
   150 +            LogTo(BLIPVerbose,@"Responding with denial of close request");
   151 +            [request respondWithErrorCode: kBLIPError_Forbidden message: @"Close request denied"];
   152 +            return;
   153 +        }
   154 +    
   155 +    LogTo(BLIPVerbose,@"Close request accepted");
   156 +    _blipClosing = YES; // this prevents _beginClose from sending a close request back
   157 +    [self close];
   158 +}
   159 +
   160 +
   161  @end
   162  
   163  
   164  
   165  
   166 +#pragma mark -
   167  @implementation BLIPListener
   168  
   169  - (id) initWithPort: (UInt16)port
   170 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPMessage.m
   171 --- a/BLIP/BLIPMessage.m	Thu Jun 19 10:22:19 2008 -0700
   172 +++ b/BLIP/BLIPMessage.m	Mon Jun 23 14:02:31 2008 -0700
   173 @@ -74,6 +74,8 @@
   174          [desc appendString: @", urgent"];
   175      if( _flags & kBLIP_NoReply )
   176          [desc appendString: @", noreply"];
   177 +    if( _flags & kBLIP_Meta )
   178 +        [desc appendString: @", META"];
   179      [desc appendString: @"]"];
   180      return desc;
   181  }
   182 @@ -103,6 +105,8 @@
   183          _flags &= ~flag;
   184  }
   185  
   186 +- (BLIPMessageFlags) _flags                 {return _flags;}
   187 +
   188  - (BOOL) compressed                         {return (_flags & kBLIP_Compressed) != 0;}
   189  - (BOOL) urgent                             {return (_flags & kBLIP_Urgent) != 0;}
   190  - (void) setCompressed: (BOOL)compressed    {[self _setFlag: kBLIP_Compressed value: compressed];}
   191 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPReader.m
   192 --- a/BLIP/BLIPReader.m	Thu Jun 19 10:22:19 2008 -0700
   193 +++ b/BLIP/BLIPReader.m	Mon Jun 23 14:02:31 2008 -0700
   194 @@ -93,7 +93,7 @@
   195  
   196  - (BOOL) isBusy
   197  {
   198 -    return _curBytesRead > 0;
   199 +    return _curBytesRead > 0 || _pendingRequests.count > 0 || _pendingResponses.count > 0;
   200  }
   201  
   202  
   203 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPRequest.m
   204 --- a/BLIP/BLIPRequest.m	Thu Jun 19 10:22:19 2008 -0700
   205 +++ b/BLIP/BLIPRequest.m	Mon Jun 23 14:02:31 2008 -0700
   206 @@ -199,6 +199,8 @@
   207          setObj(&_mutableBody,nil);
   208          
   209          BLIPMutableProperties *errorProps = [self.properties mutableCopy];
   210 +        if( ! errorProps )
   211 +            errorProps = [[BLIPMutableProperties alloc] init];
   212          NSDictionary *userInfo = error.userInfo;
   213          for( NSString *key in userInfo ) {
   214              id value = $castIf(NSString,[userInfo objectForKey: key]);
   215 @@ -227,8 +229,12 @@
   216  {
   217      Assert(_connection,@"%@ has no connection to send over",self);
   218      Assert(!_sent,@"%@ was already sent",self);
   219 +    BLIPWriter *writer = (BLIPWriter*)_connection.writer;
   220 +    Assert(writer,@"%@'s connection has no writer (already closed?)",self);
   221      [self _encode];
   222 -    return (self.sent = [(BLIPWriter*)_connection.writer sendMessage: self]);
   223 +    BOOL sent = self.sent = [writer sendMessage: self];
   224 +    Assert(sent);
   225 +    return sent;
   226  }
   227  
   228  
   229 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPTest.m
   230 --- a/BLIP/BLIPTest.m	Thu Jun 19 10:22:19 2008 -0700
   231 +++ b/BLIP/BLIPTest.m	Mon Jun 23 14:02:31 2008 -0700
   232 @@ -35,6 +35,7 @@
   233  #define kClientUsesSSLCert          NO
   234  #define kListenerRequiresSSL        NO
   235  #define kListenerRequiresClientCert NO
   236 +#define kListenerCloseAfter         50
   237  
   238  
   239  static SecIdentityRef GetClientIdentity(void) {
   240 @@ -100,36 +101,38 @@
   241  
   242  - (void) sendAMessage
   243  {
   244 -    if(_pending.count<100) {
   245 -        Log(@"** Sending another %i messages...", kNBatchedMessages);
   246 -        for( int i=0; i<kNBatchedMessages; i++ ) {
   247 -            size_t size = random() % 32768;
   248 -            NSMutableData *body = [NSMutableData dataWithLength: size];
   249 -            UInt8 *bytes = body.mutableBytes;
   250 -            for( size_t i=0; i<size; i++ )
   251 -                bytes[i] = i % 256;
   252 -            
   253 -            BLIPRequest *q = [_conn requestWithBody: body
   254 -                                         properties: $dict({@"Content-Type", @"application/octet-stream"},
   255 -                                                           {@"User-Agent", @"BLIPConnectionTester"},
   256 -                                                           {@"Date", [[NSDate date] description]},
   257 -                                                           {@"Size",$sprintf(@"%u",size)})];
   258 -            Assert(q);
   259 -            if( kUseCompression && (random()%2==1) )
   260 -                q.compressed = YES;
   261 -            if( random()%16 > 12 )
   262 -                q.urgent = YES;
   263 -            BLIPResponse *response = [q send];
   264 -            Assert(response);
   265 -            Assert(q.number>0);
   266 -            Assert(response.number==q.number);
   267 -            [_pending setObject: $object(size) forKey: $object(q.number)];
   268 -            response.onComplete = $target(self,responseArrived:);
   269 +    if( _conn.status==kTCP_Open || _conn.status==kTCP_Opening ) {
   270 +        if(_pending.count<100) {
   271 +            Log(@"** Sending another %i messages...", kNBatchedMessages);
   272 +            for( int i=0; i<kNBatchedMessages; i++ ) {
   273 +                size_t size = random() % 32768;
   274 +                NSMutableData *body = [NSMutableData dataWithLength: size];
   275 +                UInt8 *bytes = body.mutableBytes;
   276 +                for( size_t i=0; i<size; i++ )
   277 +                    bytes[i] = i % 256;
   278 +                
   279 +                BLIPRequest *q = [_conn requestWithBody: body
   280 +                                             properties: $dict({@"Content-Type", @"application/octet-stream"},
   281 +                                                               {@"User-Agent", @"BLIPConnectionTester"},
   282 +                                                               {@"Date", [[NSDate date] description]},
   283 +                                                               {@"Size",$sprintf(@"%u",size)})];
   284 +                Assert(q);
   285 +                if( kUseCompression && (random()%2==1) )
   286 +                    q.compressed = YES;
   287 +                if( random()%16 > 12 )
   288 +                    q.urgent = YES;
   289 +                BLIPResponse *response = [q send];
   290 +                Assert(response);
   291 +                Assert(q.number>0);
   292 +                Assert(response.number==q.number);
   293 +                [_pending setObject: $object(size) forKey: $object(q.number)];
   294 +                response.onComplete = $target(self,responseArrived:);
   295 +            }
   296 +        } else {
   297 +            Warn(@"There are %u pending messages; waiting for the listener to catch up...",_pending.count);
   298          }
   299 -    } else {
   300 -        Warn(@"There are %u pending messages; waiting for the listener to catch up...",_pending.count);
   301 +        [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
   302      }
   303 -    [self performSelector: @selector(sendAMessage) withObject: nil afterDelay: kSendInterval];
   304  }
   305  
   306  - (void) responseArrived: (BLIPResponse*)response
   307 @@ -191,6 +194,13 @@
   308      Log(@"Now %u replies pending", _pending.count);
   309  }
   310  
   311 +- (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection
   312 +{
   313 +    BOOL response = NO;
   314 +    Log(@"***** %@ received a close request; returning %i",connection,response);
   315 +    return response;
   316 +}
   317 +
   318  
   319  @end
   320  
   321 @@ -217,6 +227,7 @@
   322  @interface BLIPTestListener : NSObject <TCPListenerDelegate, BLIPConnectionDelegate>
   323  {
   324      BLIPListener *_listener;
   325 +    int _nReceived;
   326  }
   327  
   328  @end
   329 @@ -277,6 +288,7 @@
   330  - (void) connectionDidOpen: (TCPConnection*)connection
   331  {
   332      Log(@"** %@ didOpen [SSL=%@]",connection,connection.actualSecurityLevel);
   333 +    _nReceived = 0;
   334  }
   335  - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   336  {
   337 @@ -312,6 +324,22 @@
   338      AssertEq([[request valueOfProperty: @"Size"] intValue], size);
   339  
   340      [request respondWithData: body contentType: request.contentType];
   341 +    
   342 +    if( ++ _nReceived == kListenerCloseAfter ) {
   343 +        Log(@"********** Closing BLIPTestListener after %i requests",_nReceived);
   344 +        [connection close];
   345 +    }
   346 +}
   347 +
   348 +- (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection;
   349 +{
   350 +    Log(@"***** %@ received a close request",connection);
   351 +    return YES;
   352 +}
   353 +
   354 +- (void) connection: (BLIPConnection*)connection closeRequestFailedWithError: (NSError*)error
   355 +{
   356 +    Log(@"***** %@'s close request failed: %@",connection,error);
   357  }
   358  
   359  
   360 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIPWriter.m
   361 --- a/BLIP/BLIPWriter.m	Thu Jun 19 10:22:19 2008 -0700
   362 +++ b/BLIP/BLIPWriter.m	Mon Jun 23 14:02:31 2008 -0700
   363 @@ -79,10 +79,6 @@
   364  
   365  - (BOOL) sendMessage: (BLIPMessage*)message
   366  {
   367 -    if( _shouldClose ) {
   368 -        Warn(@"%@: Attempt to send a message after the connection has started closing",self);
   369 -        return NO;
   370 -    }
   371      Assert(!message.sent,@"message has already been sent");
   372      [self _queueMessage: message isNew: YES];
   373      return YES;
   374 @@ -91,12 +87,14 @@
   375  
   376  - (BOOL) sendRequest: (BLIPRequest*)q response: (BLIPResponse*)response
   377  {
   378 -    if( !_shouldClose ) {
   379 -        [q _assignedNumber: ++_numRequestsSent];
   380 -        if( response ) {
   381 -            [response _assignedNumber: _numRequestsSent];
   382 -            [(BLIPReader*)self.reader _addPendingResponse: response];
   383 -        }
   384 +    if( _shouldClose ) {
   385 +        Warn(@"%@: Attempt to send a request after the connection has started closing: %@",self,q);
   386 +        return NO;
   387 +    }
   388 +    [q _assignedNumber: ++_numRequestsSent];
   389 +    if( response ) {
   390 +        [response _assignedNumber: _numRequestsSent];
   391 +        [(BLIPReader*)self.reader _addPendingResponse: response];
   392      }
   393      return [self sendMessage: q];
   394  }
   395 diff -r 70590cc555aa -r 16454d63d4c2 BLIP/BLIP_Internal.h
   396 --- a/BLIP/BLIP_Internal.h	Thu Jun 19 10:22:19 2008 -0700
   397 +++ b/BLIP/BLIP_Internal.h	Mon Jun 23 14:02:31 2008 -0700
   398 @@ -29,6 +29,7 @@
   399      kBLIP_Urgent    = 0x0020,       // please send sooner/faster
   400      kBLIP_NoReply   = 0x0040,       // no RPY needed
   401      kBLIP_MoreComing= 0x0080,       // More frames coming (Applies only to individual frame)
   402 +    kBLIP_Meta      = 0x0100,       // Special message type, handled internally (hello, bye, ...)
   403  };
   404  typedef UInt16 BLIPMessageFlags;
   405  
   406 @@ -41,7 +42,10 @@
   407      UInt16           size;          // total size of frame, _including_ this header
   408  } BLIPFrameHeader;
   409  
   410 -#define kBLIPFrameHeaderMagicNumber 0x9B34F205
   411 +#define kBLIPFrameHeaderMagicNumber 0x9B34F206
   412 +
   413 +#define kBLIPProfile_Hi  @"Hi"      // Used for Profile header in meta greeting message
   414 +#define kBLIPProfile_Bye @"Bye"     // Used for Profile header in meta close-request message
   415  
   416  
   417  @interface BLIPConnection ()
   418 @@ -52,6 +56,7 @@
   419  
   420  @interface BLIPMessage ()
   421  @property BOOL sent, propertiesAvailable, complete;
   422 +- (BLIPMessageFlags) _flags;
   423  - (void) _setFlag: (BLIPMessageFlags)flag value: (BOOL)value;
   424  - (void) _encode;
   425  @end