BLIP/BLIPReader.m
author Jens Alfke <jens@mooseyard.com>
Sun May 10 19:00:50 2009 -0700 (2009-05-10)
changeset 45 8efb48eabd08
parent 18 3be241de1630
permissions -rw-r--r--
Fixed MYAddressLookup to allocate an NSSet, and to send correct KV notifications. (Based on Jim Roepke's patch, but outsourcing the KV grunge to CollectionUtils.)
     1 //
     2 //  BLIPReader.m
     3 //  MYNetwork
     4 //
     5 //  Created by Jens Alfke on 5/10/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "BLIPReader.h"
    10 #import "BLIP_Internal.h"
    11 #import "BLIPWriter.h"
    12 #import "BLIPDispatcher.h"
    13 
    14 #import "Logging.h"
    15 #import "Test.h"
    16 #import "CollectionUtils.h"
    17 
    18 
    19 @interface BLIPReader ()
    20 - (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body;
    21 @end
    22 
    23 
    24 @implementation BLIPReader
    25 
    26 
    27 #define _blipConn ((BLIPConnection*)_conn)
    28 
    29 
    30 - (id) initWithConnection: (BLIPConnection*)conn stream: (NSStream*)stream
    31 {
    32     self = [super initWithConnection: conn stream: stream];
    33     if (self != nil) {
    34         _pendingRequests = [[NSMutableDictionary alloc] init];
    35         _pendingResponses = [[NSMutableDictionary alloc] init];
    36     }
    37     return self;
    38 }
    39 
    40 - (void) dealloc
    41 {
    42     [_pendingRequests release];
    43     [_pendingResponses release];
    44     [_curBody release];
    45     [super dealloc];
    46 }
    47 
    48 - (void) disconnect
    49 {
    50     for( BLIPResponse *response in [_pendingResponses allValues] ) {
    51         [response _connectionClosed];
    52         [_conn tellDelegate: @selector(connection:receivedResponse:) withObject: response];
    53     }
    54     setObj(&_pendingResponses,nil);
    55     [super disconnect];
    56 }
    57 
    58 
    59 #pragma mark -
    60 #pragma mark READING FRAMES:
    61 
    62 
    63 - (NSString*) _validateHeader
    64 {
    65     // Convert header to native byte order:
    66     _curHeader.magic = NSSwapBigIntToHost(_curHeader.magic);
    67     _curHeader.number= NSSwapBigIntToHost(_curHeader.number);
    68     _curHeader.flags = NSSwapBigShortToHost(_curHeader.flags);
    69     _curHeader.size  = NSSwapBigShortToHost(_curHeader.size);
    70     
    71     if( _curHeader.magic != kBLIPFrameHeaderMagicNumber )
    72         return $sprintf(@"Incorrect magic number (%08X not %08X)",
    73                         _curHeader.magic,kBLIPFrameHeaderMagicNumber);
    74     size_t bodyLength = _curHeader.size;
    75     if( bodyLength < sizeof(BLIPFrameHeader) )
    76         return @"Length is impossibly short";
    77     bodyLength -= sizeof(BLIPFrameHeader);
    78     _curBody = [[NSMutableData alloc] initWithLength: bodyLength];
    79     return nil;
    80 }
    81     
    82 
    83 - (void) _endCurFrame
    84 {
    85     [self retain];
    86     [self _receivedFrameWithHeader: &_curHeader body: _curBody];
    87     memset(&_curHeader,0,sizeof(_curHeader));
    88     setObj(&_curBody,nil);
    89     _curBytesRead = 0;
    90     [self release];
    91 }
    92 
    93 
    94 - (BOOL) isBusy
    95 {
    96     return _curBytesRead > 0 || _pendingRequests.count > 0 || _pendingResponses.count > 0;
    97 }
    98 
    99 
   100 - (void) _canRead
   101 {
   102     SInt32 headerLeft = sizeof(BLIPFrameHeader) - _curBytesRead;
   103     if( headerLeft > 0 ) {
   104         // Read (more of) the header:
   105         NSInteger bytesRead = [self read: (uint8_t*)&_curHeader +_curBytesRead
   106                                maxLength: headerLeft];
   107         if( bytesRead > 0 ) {
   108             _curBytesRead += bytesRead;
   109             if( _curBytesRead < sizeof(BLIPFrameHeader) ) {
   110                 // Incomplete header:
   111                 LogTo(BLIPVerbose,@"%@ read %u bytes of header (%u left)",
   112                       self,bytesRead,sizeof(BLIPFrameHeader)-_curBytesRead);
   113             } else {
   114                 // Finished reading the header!
   115                 NSString *err = [self _validateHeader];
   116                 if( err ) {
   117                     Warn(@"%@ read bogus frame header: %@",self,err);
   118                     return (void)[self _gotError: BLIPMakeError(kBLIPError_BadData, @"%@", err)];
   119                 }
   120                 LogTo(BLIPVerbose,@"%@: Read header; next is %u-byte body",self,_curBody.length);
   121                 
   122                 if( _curBody.length == 0 ) {
   123                     // Zero-byte body, so no need to wait for another read
   124                     [self _endCurFrame];
   125                 }
   126             }
   127         }
   128         
   129     } else {
   130         // Read (more of) the current frame's body:
   131         SInt32 bodyRemaining = (SInt32)_curBody.length + headerLeft;
   132         if( bodyRemaining > 0 ) {
   133             uint8_t *dst = _curBody.mutableBytes;
   134             dst += _curBody.length - bodyRemaining;
   135             NSInteger bytesRead = [self read: dst maxLength: bodyRemaining];
   136             if( bytesRead > 0 ) {
   137                 _curBytesRead += bytesRead;
   138                 bodyRemaining -= bytesRead;
   139                 LogTo(BLIPVerbose,@"%@: Read %u bytes of frame body (%u left)",self,bytesRead,bodyRemaining);
   140             }
   141         }
   142         if( bodyRemaining==0 ) {
   143             // Done reading this frame: give it to the Connection and reset my state
   144             [self _endCurFrame];
   145         }
   146     }
   147 }
   148 
   149 
   150 #pragma mark -
   151 #pragma mark PROCESSING FRAMES:
   152 
   153 
   154 - (void) _addPendingResponse: (BLIPResponse*)response
   155 {
   156     [_pendingResponses setObject: response forKey: $object(response.number)];
   157 }
   158 
   159 
   160 - (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body
   161 {
   162     static const char* kTypeStrs[16] = {"MSG","RPY","ERR","3??","4??","5??","6??","7??"};
   163     BLIPMessageType type = header->flags & kBLIP_TypeMask;
   164     LogTo(BLIPVerbose,@"%@ rcvd frame of %s #%u, length %u",self,kTypeStrs[type],header->number,body.length);
   165 
   166     id key = $object(header->number);
   167     BOOL complete = ! (header->flags & kBLIP_MoreComing);
   168     switch(type) {
   169         case kBLIP_MSG: {
   170             // Incoming request:
   171             BLIPRequest *request = [_pendingRequests objectForKey: key];
   172             if( request ) {
   173                 // Continuation frame of a request:
   174                 if( complete ) {
   175                     [[request retain] autorelease];
   176                     [_pendingRequests removeObjectForKey: key];
   177                 }
   178             } else if( header->number == _numRequestsReceived+1 ) {
   179                 // Next new request:
   180                 request = [[[BLIPRequest alloc] _initWithConnection: _blipConn
   181                                                          isMine: NO
   182                                                           flags: header->flags | kBLIP_MoreComing
   183                                                          number: header->number
   184                                                            body: nil]
   185                                 autorelease];
   186                 if( ! complete )
   187                     [_pendingRequests setObject: request forKey: key];
   188                 _numRequestsReceived++;
   189             } else
   190                 return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   191                                                @"Received bad request frame #%u (next is #%u)",
   192                                                header->number,_numRequestsReceived+1)];
   193             
   194             if( ! [request _receivedFrameWithHeader: header body: body] )
   195                 return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   196                                                @"Couldn't parse message frame")];
   197             
   198             if( complete )
   199                 [_blipConn _dispatchRequest: request];
   200             break;
   201         }
   202             
   203         case kBLIP_RPY:
   204         case kBLIP_ERR: {
   205             BLIPResponse *response = [_pendingResponses objectForKey: key];
   206             if( response ) {
   207                 if( complete ) {
   208                     [[response retain] autorelease];
   209                     [_pendingResponses removeObjectForKey: key];
   210                 }
   211                 
   212                 if( ! [response _receivedFrameWithHeader: header body: body] ) {
   213                     return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   214                                                           @"Couldn't parse response frame")];
   215                 } else if( complete ) 
   216                     [_blipConn _dispatchResponse: response];
   217                 
   218             } else {
   219                 if( header->number <= ((BLIPWriter*)self.writer).numRequestsSent )
   220                     LogTo(BLIP,@"??? %@ got unexpected response frame to my msg #%u",
   221                           self,header->number); //benign
   222                 else
   223                     return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   224                                                           @"Bogus message number %u in response",
   225                                                           header->number)];
   226             }
   227             break;
   228         }
   229             
   230         default:
   231             // To leave room for future expansion, undefined message types are just ignored.
   232             Log(@"??? %@ received header with unknown message type %i", self,type);
   233             break;
   234     }
   235     return YES;
   236 }
   237 
   238 
   239 @end
   240 
   241 
   242 /*
   243  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   244  
   245  Redistribution and use in source and binary forms, with or without modification, are permitted
   246  provided that the following conditions are met:
   247  
   248  * Redistributions of source code must retain the above copyright notice, this list of conditions
   249  and the following disclaimer.
   250  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   251  and the following disclaimer in the documentation and/or other materials provided with the
   252  distribution.
   253  
   254  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   255  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   256  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   257  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   258  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   259   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   260  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   261  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   262  */