Fixed a memory leak by adding a -dealloc  method to HostAddress. (Thanks to Mark Onyschuk)
     5 //  Created by Jens Alfke on 5/10/08.
 
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
 
    10 #import "BLIP_Internal.h"
 
    11 #import "BLIPWriter.h"
 
    12 #import "BLIPDispatcher.h"
 
    16 #import "CollectionUtils.h"
 
    19 @interface BLIPReader ()
 
    20 - (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body;
 
    24 @implementation BLIPReader
 
    27 #define _blipConn ((BLIPConnection*)_conn)
 
    30 - (id) initWithConnection: (BLIPConnection*)conn stream: (NSStream*)stream
 
    32     self = [super initWithConnection: conn stream: stream];
 
    34         _pendingRequests = [[NSMutableDictionary alloc] init];
 
    35         _pendingResponses = [[NSMutableDictionary alloc] init];
 
    42     [_pendingRequests release];
 
    43     [_pendingResponses release];
 
    50     for( BLIPResponse *response in [_pendingResponses allValues] ) {
 
    51         [response _connectionClosed];
 
    52         [_conn tellDelegate: @selector(connection:receivedResponse:) withObject: response];
 
    54     setObj(&_pendingResponses,nil);
 
    60 #pragma mark READING FRAMES:
 
    63 - (NSString*) _validateHeader
 
    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);
 
    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];
 
    86     [self _receivedFrameWithHeader: &_curHeader body: _curBody];
 
    87     memset(&_curHeader,0,sizeof(_curHeader));
 
    88     setObj(&_curBody,nil);
 
    96     return _curBytesRead > 0 || _pendingRequests.count > 0 || _pendingResponses.count > 0;
 
   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);
 
   114                 // Finished reading the header!
 
   116                 NSString *err = [self _validateHeader];
 
   118                     Warn(@"%@ read bogus frame header: %@",self,err);
 
   119                     return (void)[self _gotError: BLIPMakeError(kBLIPError_BadData, @"%@", err)];
 
   121                 LogTo(BLIPVerbose,@"%@: Read header; next is %u-byte body",self,_curBody.length);
 
   123                 if( _curBody.length == 0 ) {
 
   124                     // Zero-byte body, so no need to wait for another read
 
   131         // Read (more of) the current frame's body:
 
   132         SInt32 bodyRemaining = (SInt32)_curBody.length + headerLeft;
 
   133         if( bodyRemaining > 0 ) {
 
   134             uint8_t *dst = _curBody.mutableBytes;
 
   135             dst += _curBody.length - bodyRemaining;
 
   136             NSInteger bytesRead = [self read: dst maxLength: bodyRemaining];
 
   137             if( bytesRead > 0 ) {
 
   138                 _curBytesRead += bytesRead;
 
   139                 bodyRemaining -= bytesRead;
 
   140                 LogTo(BLIPVerbose,@"%@: Read %u bytes of frame body (%u left)",self,bytesRead,bodyRemaining);
 
   143         if( bodyRemaining==0 ) {
 
   144             // Done reading this frame: give it to the Connection and reset my state
 
   152 #pragma mark PROCESSING FRAMES:
 
   155 - (void) _addPendingResponse: (BLIPResponse*)response
 
   157     [_pendingResponses setObject: response forKey: $object(response.number)];
 
   161 - (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body
 
   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);
 
   167     id key = $object(header->number);
 
   168     BOOL complete = ! (header->flags & kBLIP_MoreComing);
 
   172             BLIPRequest *request = [_pendingRequests objectForKey: key];
 
   174                 // Continuation frame of a request:
 
   176                     [[request retain] autorelease];
 
   177                     [_pendingRequests removeObjectForKey: key];
 
   179             } else if( header->number == _numRequestsReceived+1 ) {
 
   181                 request = [[[BLIPRequest alloc] _initWithConnection: _blipConn
 
   183                                                           flags: header->flags | kBLIP_MoreComing
 
   184                                                          number: header->number
 
   188                     [_pendingRequests setObject: request forKey: key];
 
   189                 _numRequestsReceived++;
 
   191                 return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
 
   192                                                @"Received bad request frame #%u (next is #%u)",
 
   193                                                header->number,_numRequestsReceived+1)];
 
   195             if( ! [request _receivedFrameWithHeader: header body: body] )
 
   196                 return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
 
   197                                                @"Couldn't parse message frame")];
 
   200                 [_blipConn _dispatchRequest: request];
 
   206             BLIPResponse *response = [_pendingResponses objectForKey: key];
 
   209                     [[response retain] autorelease];
 
   210                     [_pendingResponses removeObjectForKey: key];
 
   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];
 
   220                 if( header->number <= ((BLIPWriter*)self.writer).numRequestsSent )
 
   221                     LogTo(BLIP,@"??? %@ got unexpected response frame to my msg #%u",
 
   222                           self,header->number); //benign
 
   224                     return [self _gotError: BLIPMakeError(kBLIPError_BadFrame, 
 
   225                                                           @"Bogus message number %u in response",
 
   232             // To leave room for future expansion, undefined message types are just ignored.
 
   233             Log(@"??? %@ received header with unknown message type %i", self,type);
 
   244  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
 
   246  Redistribution and use in source and binary forms, with or without modification, are permitted
 
   247  provided that the following conditions are met:
 
   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
 
   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.