jens@0: // jens@0: // BLIPFrameWriter.m jens@0: // MYNetwork jens@0: // jens@0: // Created by Jens Alfke on 5/18/08. jens@0: // Copyright 2008 Jens Alfke. All rights reserved. jens@0: // jens@0: jens@0: #import "BLIPReader.h" jens@0: #import "BLIPWriter.h" jens@0: #import "BLIP_Internal.h" jens@0: jens@0: jens@0: #define kDefaultFrameSize 4096 jens@0: jens@0: jens@0: @implementation BLIPWriter jens@0: jens@0: jens@0: - (void) dealloc jens@0: { jens@0: [_outBox release]; jens@0: [super dealloc]; jens@0: } jens@0: jens@0: - (void) disconnect jens@0: { jens@0: [_outBox makeObjectsPerformSelector: @selector(_connectionClosed) withObject: nil]; jens@0: setObj(&_outBox,nil); jens@0: [super disconnect]; jens@0: } jens@0: jens@0: @synthesize numQueriesSent=_numQueriesSent; jens@0: jens@0: jens@0: - (BOOL) isBusy jens@0: { jens@0: return _outBox.count>0 || [super isBusy]; jens@0: } jens@0: jens@0: jens@0: - (void) _queueMessage: (BLIPMessage*)msg isNew: (BOOL)isNew jens@0: { jens@0: int n = _outBox.count, index; jens@0: if( msg.urgent && n > 1 ) { jens@0: // High-priority gets queued after the last existing high-priority message, jens@0: // leaving one regular-priority message in between if possible. jens@0: for( index=n-1; index>0; index-- ) { jens@0: BLIPMessage *otherMsg = [_outBox objectAtIndex: index]; jens@0: if( [otherMsg urgent] ) { jens@0: index = MIN(index+2, n); jens@0: break; jens@0: } else if( isNew && otherMsg._bytesWritten==0 ) { jens@0: // But have to keep message starts in order jens@0: index = index+1; jens@0: break; jens@0: } jens@0: } jens@0: if( index==0 ) jens@0: index = 1; jens@0: } else { jens@0: // Regular priority goes at the end of the queue: jens@0: index = n; jens@0: } jens@0: if( ! _outBox ) jens@0: _outBox = [[NSMutableArray alloc] init]; jens@0: [_outBox insertObject: msg atIndex: index]; jens@0: jens@0: if( isNew ) { jens@0: LogTo(BLIP,@"%@ queuing outgoing %@ at index %i",self,msg,index); jens@0: if( n==0 ) jens@0: [self queueIsEmpty]; jens@0: } jens@0: } jens@0: jens@0: jens@0: - (BOOL) sendMessage: (BLIPMessage*)message jens@0: { jens@0: if( _shouldClose ) { jens@0: Warn(@"%@: Attempt to send a message after the connection has started closing",self); jens@0: return NO; jens@0: } jens@0: Assert(!message.sent,@"message has already been sent"); jens@0: [self _queueMessage: message isNew: YES]; jens@0: return YES; jens@0: } jens@0: jens@0: jens@0: - (BOOL) sendRequest: (BLIPRequest*)q response: (BLIPResponse*)response jens@0: { jens@0: if( !_shouldClose ) { jens@0: [q _assignedNumber: ++_numQueriesSent]; jens@0: if( response ) { jens@0: [response _assignedNumber: _numQueriesSent]; jens@0: [(BLIPReader*)self.reader _addPendingResponse: response]; jens@0: } jens@0: } jens@0: return [self sendMessage: q]; jens@0: } jens@0: jens@0: jens@0: - (void) queueIsEmpty jens@0: { jens@0: if( _outBox.count > 0 ) { jens@0: // Pop first message in queue: jens@0: BLIPMessage *msg = [[_outBox objectAtIndex: 0] retain]; jens@0: [_outBox removeObjectAtIndex: 0]; jens@0: jens@0: // As an optimization, allow message to send a big frame unless there's a higher-priority jens@0: // message right behind it: jens@0: size_t frameSize = kDefaultFrameSize; jens@0: if( msg.urgent || _outBox.count==0 || ! [[_outBox objectAtIndex: 0] urgent] ) jens@0: frameSize *= 4; jens@0: jens@0: if( [msg _writeFrameTo: self maxSize: frameSize] ) { jens@0: // add it back so it can send its next frame later: jens@0: [self _queueMessage: msg isNew: NO]; jens@0: } jens@0: [msg release]; jens@0: } else { jens@0: LogTo(BLIPVerbose,@"%@: no more work for writer",self); jens@0: } jens@0: } jens@0: jens@0: jens@0: jens@0: @end jens@0: jens@0: jens@0: /* jens@0: Copyright (c) 2008, Jens Alfke . All rights reserved. jens@0: jens@0: Redistribution and use in source and binary forms, with or without modification, are permitted jens@0: provided that the following conditions are met: jens@0: jens@0: * Redistributions of source code must retain the above copyright notice, this list of conditions jens@0: and the following disclaimer. jens@0: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions jens@0: and the following disclaimer in the documentation and/or other materials provided with the jens@0: distribution. jens@0: jens@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR jens@0: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND jens@0: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- jens@0: BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES jens@0: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jens@0: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN jens@0: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF jens@0: THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jens@0: */