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