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