BLIP/BLIPReader.m
changeset 0 9d67172bb323
child 1 8267d5c429c4
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/BLIP/BLIPReader.m	Fri May 23 17:37:36 2008 -0700
     1.3 @@ -0,0 +1,263 @@
     1.4 +//
     1.5 +//  BLIPReader.m
     1.6 +//  MYNetwork
     1.7 +//
     1.8 +//  Created by Jens Alfke on 5/10/08.
     1.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    1.10 +//
    1.11 +
    1.12 +#import "BLIPReader.h"
    1.13 +#import "BLIP_Internal.h"
    1.14 +#import "BLIPWriter.h"
    1.15 +#import "BLIPDispatcher.h"
    1.16 +
    1.17 +
    1.18 +@interface BLIPReader ()
    1.19 +- (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body;
    1.20 +@end
    1.21 +
    1.22 +
    1.23 +@implementation BLIPReader
    1.24 +
    1.25 +
    1.26 +#define _blipConn ((BLIPConnection*)_conn)
    1.27 +
    1.28 +
    1.29 +- (id) initWithConnection: (BLIPConnection*)conn stream: (NSStream*)stream
    1.30 +{
    1.31 +    self = [super initWithConnection: conn stream: stream];
    1.32 +    if (self != nil) {
    1.33 +        _pendingQueries = [[NSMutableDictionary alloc] init];
    1.34 +        _pendingReplies = [[NSMutableDictionary alloc] init];
    1.35 +    }
    1.36 +    return self;
    1.37 +}
    1.38 +
    1.39 +- (void) dealloc
    1.40 +{
    1.41 +    [_pendingQueries release];
    1.42 +    [_pendingReplies release];
    1.43 +    [_curBody release];
    1.44 +    [super dealloc];
    1.45 +}
    1.46 +
    1.47 +- (void) disconnect
    1.48 +{
    1.49 +    for( BLIPResponse *response in [_pendingReplies allValues] ) {
    1.50 +        [response _connectionClosed];
    1.51 +        [_conn tellDelegate: @selector(connection:receivedResponse:) withObject: response];
    1.52 +    }
    1.53 +    setObj(&_pendingReplies,nil);
    1.54 +    [super disconnect];
    1.55 +}
    1.56 +
    1.57 +
    1.58 +#pragma mark -
    1.59 +#pragma mark READING FRAMES:
    1.60 +
    1.61 +
    1.62 +- (NSString*) _validateHeader
    1.63 +{
    1.64 +    // Convert header to native byte order:
    1.65 +    _curHeader.magic = EndianU32_BtoN(_curHeader.magic);
    1.66 +    _curHeader.number= EndianU32_BtoN(_curHeader.number);
    1.67 +    _curHeader.flags = EndianU16_BtoN(_curHeader.flags);
    1.68 +    _curHeader.size  = EndianU16_BtoN(_curHeader.size);
    1.69 +    
    1.70 +    if( _curHeader.magic != kBLIPFrameHeaderMagicNumber )
    1.71 +        return $sprintf(@"Incorrect magic number (%08X not %08X)",
    1.72 +                        _curHeader.magic,kBLIPFrameHeaderMagicNumber);
    1.73 +    size_t bodyLength = _curHeader.size;
    1.74 +    if( bodyLength < sizeof(BLIPFrameHeader) )
    1.75 +        return @"Length is impossibly short";
    1.76 +    bodyLength -= sizeof(BLIPFrameHeader);
    1.77 +    _curBody = [[NSMutableData alloc] initWithLength: bodyLength];
    1.78 +    return nil;
    1.79 +}
    1.80 +    
    1.81 +
    1.82 +- (void) _endCurFrame
    1.83 +{
    1.84 +    [self retain];
    1.85 +    [self _receivedFrameWithHeader: &_curHeader body: _curBody];
    1.86 +    memset(&_curHeader,0,sizeof(_curHeader));
    1.87 +    setObj(&_curBody,nil);
    1.88 +    _curBytesRead = 0;
    1.89 +    [self release];
    1.90 +}
    1.91 +
    1.92 +
    1.93 +- (BOOL) isBusy
    1.94 +{
    1.95 +    return _curBytesRead > 0;
    1.96 +}
    1.97 +
    1.98 +
    1.99 +- (void) _canRead
   1.100 +{
   1.101 +    SInt32 headerLeft = sizeof(BLIPFrameHeader) - _curBytesRead;
   1.102 +    if( headerLeft > 0 ) {
   1.103 +        // Read (more of) the header:
   1.104 +        NSInteger bytesRead = [(NSInputStream*)_stream read: (uint8_t*)&_curHeader +_curBytesRead
   1.105 +                                                  maxLength: headerLeft];
   1.106 +        if( bytesRead < 0 ) {
   1.107 +            [self _gotError];
   1.108 +        } else {
   1.109 +            _curBytesRead += bytesRead;
   1.110 +            if( _curBytesRead < sizeof(BLIPFrameHeader) ) {
   1.111 +                // Incomplete header:
   1.112 +                LogTo(BLIPVerbose,@"%@ read %u bytes of header (%u left)",
   1.113 +                      self,bytesRead,sizeof(BLIPFrameHeader)-_curBytesRead);
   1.114 +            } else {
   1.115 +                // Finished reading the header!
   1.116 +                headerLeft = 0;
   1.117 +                NSString *err = [self _validateHeader];
   1.118 +                if( err ) {
   1.119 +                    Warn(@"%@ read bogus frame header: %@",self,err);
   1.120 +                    return (void)[self _gotError: BLIPMakeError(kBLIPError_BadData, @"%@", err)];
   1.121 +                }
   1.122 +                LogTo(BLIPVerbose,@"%@: Read header; next is %u-byte body",self,_curBody.length);
   1.123 +                
   1.124 +                if( _curBody.length == 0 ) {
   1.125 +                    // Zero-byte body, so no need to wait for another read
   1.126 +                    [self _endCurFrame];
   1.127 +                }
   1.128 +            }
   1.129 +        }
   1.130 +        
   1.131 +    } else {
   1.132 +        // Read (more of) the current frame's body:
   1.133 +        SInt32 bodyRemaining = (SInt32)_curBody.length + headerLeft;
   1.134 +        if( bodyRemaining > 0 ) {
   1.135 +            uint8_t *dst = _curBody.mutableBytes;
   1.136 +            dst += _curBody.length - bodyRemaining;
   1.137 +            NSInteger bytesRead = [(NSInputStream*)_stream read: dst maxLength: bodyRemaining];
   1.138 +            if( bytesRead < 0 )
   1.139 +                return (void)[self _gotError];
   1.140 +            else if( bytesRead > 0 ) {
   1.141 +                _curBytesRead += bytesRead;
   1.142 +                bodyRemaining -= bytesRead;
   1.143 +                LogTo(BLIPVerbose,@"%@: Read %u bytes of frame body (%u left)",self,bytesRead,bodyRemaining);
   1.144 +            }
   1.145 +        }
   1.146 +        if( bodyRemaining==0 ) {
   1.147 +            // Done reading this frame: give it to the Connection and reset my state
   1.148 +            [self _endCurFrame];
   1.149 +        }
   1.150 +    }
   1.151 +}
   1.152 +
   1.153 +
   1.154 +#pragma mark -
   1.155 +#pragma mark PROCESSING FRAMES:
   1.156 +
   1.157 +
   1.158 +- (void) _addPendingResponse: (BLIPResponse*)response
   1.159 +{
   1.160 +    [_pendingReplies setObject: response forKey: $object(response.number)];
   1.161 +}
   1.162 +
   1.163 +
   1.164 +- (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body
   1.165 +{
   1.166 +    static const char* kTypeStrs[16] = {"MSG","RPY","ERR","3??","4??","5??","6??","7??"};
   1.167 +    BLIPMessageType type = header->flags & kBLIP_TypeMask;
   1.168 +    LogTo(BLIPVerbose,@"%@ rcvd frame of %s #%u, length %u",self,kTypeStrs[type],header->number,body.length);
   1.169 +
   1.170 +    id key = $object(header->number);
   1.171 +    BOOL complete = ! (header->flags & kBLIP_MoreComing);
   1.172 +    switch(type) {
   1.173 +        case kBLIP_MSG: {
   1.174 +            // Incoming request:
   1.175 +            BLIPRequest *request = [_pendingQueries objectForKey: key];
   1.176 +            if( request ) {
   1.177 +                // Continuation frame of a request:
   1.178 +                if( complete ) {
   1.179 +                    [[request retain] autorelease];
   1.180 +                    [_pendingQueries removeObjectForKey: key];
   1.181 +                }
   1.182 +            } else if( header->number == _numQueriesReceived+1 ) {
   1.183 +                // Next new request:
   1.184 +                request = [[[BLIPRequest alloc] _initWithConnection: _blipConn
   1.185 +                                                         isMine: NO
   1.186 +                                                          flags: header->flags | kBLIP_MoreComing
   1.187 +                                                         number: header->number
   1.188 +                                                           body: nil]
   1.189 +                                autorelease];
   1.190 +                if( ! complete )
   1.191 +                    [_pendingQueries setObject: request forKey: key];
   1.192 +                _numQueriesReceived++;
   1.193 +            } else
   1.194 +                return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   1.195 +                                               @"Received bad request frame #%u (next is #%u)",
   1.196 +                                               header->number,_numQueriesReceived+1)];
   1.197 +            
   1.198 +            if( ! [request _receivedFrameWithHeader: header body: body] )
   1.199 +                return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   1.200 +                                               @"Couldn't parse message frame")];
   1.201 +            
   1.202 +            if( complete )
   1.203 +                [_blipConn _dispatchRequest: request];
   1.204 +            break;
   1.205 +        }
   1.206 +            
   1.207 +        case kBLIP_RPY:
   1.208 +        case kBLIP_ERR: {
   1.209 +            BLIPResponse *response = [_pendingReplies objectForKey: key];
   1.210 +            if( response ) {
   1.211 +                if( complete ) {
   1.212 +                    [[response retain] autorelease];
   1.213 +                    [_pendingReplies removeObjectForKey: key];
   1.214 +                }
   1.215 +                
   1.216 +                if( ! [response _receivedFrameWithHeader: header body: body] ) {
   1.217 +                    return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   1.218 +                                                          @"Couldn't parse response frame")];
   1.219 +                } else if( complete ) 
   1.220 +                    [_blipConn _dispatchResponse: response];
   1.221 +                
   1.222 +            } else {
   1.223 +                if( header->number <= ((BLIPWriter*)self.writer).numQueriesSent )
   1.224 +                    LogTo(BLIP,@"??? %@ got unexpected response frame to my msg #%u",
   1.225 +                          self,header->number); //benign
   1.226 +                else
   1.227 +                    return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
   1.228 +                                                          @"Bogus message number %u in response",
   1.229 +                                                          header->number)];
   1.230 +            }
   1.231 +            break;
   1.232 +        }
   1.233 +            
   1.234 +        default:
   1.235 +            // To leave room for future expansion, undefined message types are just ignored.
   1.236 +            Log(@"??? %@ received header with unknown message type %i", self,type);
   1.237 +            break;
   1.238 +    }
   1.239 +    return YES;
   1.240 +}
   1.241 +
   1.242 +
   1.243 +@end
   1.244 +
   1.245 +
   1.246 +/*
   1.247 + Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   1.248 + 
   1.249 + Redistribution and use in source and binary forms, with or without modification, are permitted
   1.250 + provided that the following conditions are met:
   1.251 + 
   1.252 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   1.253 + and the following disclaimer.
   1.254 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   1.255 + and the following disclaimer in the documentation and/or other materials provided with the
   1.256 + distribution.
   1.257 + 
   1.258 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   1.259 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   1.260 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   1.261 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   1.262 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   1.263 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   1.264 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   1.265 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1.266 + */