BLIP/BLIPWriter.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
jens@0
     1
//
jens@0
     2
//  BLIPFrameWriter.m
jens@0
     3
//  MYNetwork
jens@0
     4
//
jens@0
     5
//  Created by Jens Alfke on 5/18/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 "BLIPWriter.h"
jens@0
    11
#import "BLIP_Internal.h"
jens@0
    12
jens@0
    13
jens@0
    14
#define kDefaultFrameSize 4096
jens@0
    15
jens@0
    16
jens@0
    17
@implementation BLIPWriter
jens@0
    18
jens@0
    19
jens@0
    20
- (void) dealloc
jens@0
    21
{
jens@0
    22
    [_outBox release];
jens@0
    23
    [super dealloc];
jens@0
    24
}
jens@0
    25
jens@0
    26
- (void) disconnect
jens@0
    27
{
jens@0
    28
    [_outBox makeObjectsPerformSelector: @selector(_connectionClosed) withObject: nil];
jens@0
    29
    setObj(&_outBox,nil);
jens@0
    30
    [super disconnect];
jens@0
    31
}
jens@0
    32
jens@0
    33
@synthesize numQueriesSent=_numQueriesSent;
jens@0
    34
jens@0
    35
jens@0
    36
- (BOOL) isBusy
jens@0
    37
{
jens@0
    38
    return _outBox.count>0 || [super isBusy];
jens@0
    39
}
jens@0
    40
jens@0
    41
jens@0
    42
- (void) _queueMessage: (BLIPMessage*)msg isNew: (BOOL)isNew
jens@0
    43
{
jens@0
    44
    int n = _outBox.count, index;
jens@0
    45
    if( msg.urgent && n > 1 ) {
jens@0
    46
        // High-priority gets queued after the last existing high-priority message,
jens@0
    47
        // leaving one regular-priority message in between if possible.
jens@0
    48
        for( index=n-1; index>0; index-- ) {
jens@0
    49
            BLIPMessage *otherMsg = [_outBox objectAtIndex: index];
jens@0
    50
            if( [otherMsg urgent] ) {
jens@0
    51
                index = MIN(index+2, n);
jens@0
    52
                break;
jens@0
    53
            } else if( isNew && otherMsg._bytesWritten==0 ) {
jens@0
    54
                // But have to keep message starts in order
jens@0
    55
                index = index+1;
jens@0
    56
                break;
jens@0
    57
            }
jens@0
    58
        }
jens@0
    59
        if( index==0 )
jens@0
    60
            index = 1;
jens@0
    61
    } else {
jens@0
    62
        // Regular priority goes at the end of the queue:
jens@0
    63
        index = n;
jens@0
    64
    }
jens@0
    65
    if( ! _outBox )
jens@0
    66
        _outBox = [[NSMutableArray alloc] init];
jens@0
    67
    [_outBox insertObject: msg atIndex: index];
jens@0
    68
    
jens@0
    69
    if( isNew ) {
jens@0
    70
        LogTo(BLIP,@"%@ queuing outgoing %@ at index %i",self,msg,index);
jens@0
    71
        if( n==0 )
jens@0
    72
            [self queueIsEmpty];
jens@0
    73
    }
jens@0
    74
}
jens@0
    75
jens@0
    76
jens@0
    77
- (BOOL) sendMessage: (BLIPMessage*)message
jens@0
    78
{
jens@0
    79
    if( _shouldClose ) {
jens@0
    80
        Warn(@"%@: Attempt to send a message after the connection has started closing",self);
jens@0
    81
        return NO;
jens@0
    82
    }
jens@0
    83
    Assert(!message.sent,@"message has already been sent");
jens@0
    84
    [self _queueMessage: message isNew: YES];
jens@0
    85
    return YES;
jens@0
    86
}
jens@0
    87
jens@0
    88
jens@0
    89
- (BOOL) sendRequest: (BLIPRequest*)q response: (BLIPResponse*)response
jens@0
    90
{
jens@0
    91
    if( !_shouldClose ) {
jens@0
    92
        [q _assignedNumber: ++_numQueriesSent];
jens@0
    93
        if( response ) {
jens@0
    94
            [response _assignedNumber: _numQueriesSent];
jens@0
    95
            [(BLIPReader*)self.reader _addPendingResponse: response];
jens@0
    96
        }
jens@0
    97
    }
jens@0
    98
    return [self sendMessage: q];
jens@0
    99
}
jens@0
   100
jens@0
   101
jens@0
   102
- (void) queueIsEmpty
jens@0
   103
{
jens@0
   104
    if( _outBox.count > 0 ) {
jens@0
   105
        // Pop first message in queue:
jens@0
   106
        BLIPMessage *msg = [[_outBox objectAtIndex: 0] retain];
jens@0
   107
        [_outBox removeObjectAtIndex: 0];
jens@0
   108
        
jens@0
   109
        // As an optimization, allow message to send a big frame unless there's a higher-priority
jens@0
   110
        // message right behind it:
jens@0
   111
        size_t frameSize = kDefaultFrameSize;
jens@0
   112
        if( msg.urgent || _outBox.count==0 || ! [[_outBox objectAtIndex: 0] urgent] )
jens@0
   113
            frameSize *= 4;
jens@0
   114
        
jens@0
   115
        if( [msg _writeFrameTo: self maxSize: frameSize] ) {
jens@0
   116
            // add it back so it can send its next frame later:
jens@0
   117
            [self _queueMessage: msg isNew: NO];
jens@0
   118
        }
jens@0
   119
        [msg release];
jens@0
   120
    } else {
jens@0
   121
        LogTo(BLIPVerbose,@"%@: no more work for writer",self);
jens@0
   122
    }
jens@0
   123
}
jens@0
   124
jens@0
   125
jens@0
   126
jens@0
   127
@end
jens@0
   128
jens@0
   129
jens@0
   130
/*
jens@0
   131
 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@0
   132
 
jens@0
   133
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@0
   134
 provided that the following conditions are met:
jens@0
   135
 
jens@0
   136
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@0
   137
 and the following disclaimer.
jens@0
   138
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@0
   139
 and the following disclaimer in the documentation and/or other materials provided with the
jens@0
   140
 distribution.
jens@0
   141
 
jens@0
   142
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@0
   143
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@0
   144
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@0
   145
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@0
   146
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@0
   147
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@0
   148
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@0
   149
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@0
   150
 */