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