|
reSIProcate/stack
9694
|
00001 #if defined(HAVE_CONFIG_H) 00002 #include "config.h" 00003 #endif 00004 00005 #include "rutil/Logger.hxx" 00006 #include "resip/stack/ConnectionBase.hxx" 00007 #include "resip/stack/SipMessage.hxx" 00008 #include "rutil/WinLeakCheck.hxx" 00009 00010 #ifdef USE_SSL 00011 #include "resip/stack/ssl/Security.hxx" 00012 #include "resip/stack/ssl/TlsConnection.hxx" 00013 #endif 00014 00015 #ifdef USE_SIGCOMP 00016 #include <osc/Stack.h> 00017 #include <osc/TcpStream.h> 00018 #include <osc/SigcompMessage.h> 00019 #include <osc/StateChanges.h> 00020 #endif 00021 00022 using namespace resip; 00023 00024 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT 00025 00026 char 00027 ConnectionBase::connectionStates[ConnectionBase::MAX][32] = { "NewMessage", "ReadingHeaders", "PartialBody" }; 00028 00029 00030 ConnectionBase::ConnectionBase(Transport* transport, const Tuple& who, Compression &compression) 00031 : mSendPos(0), 00032 mTransport(transport), 00033 mWho(who), 00034 mFailureReason(TransportFailure::None), 00035 mFailureSubCode(0), 00036 mCompression(compression), 00037 // NO: #ifdef USE_SIGCOMP // class def doesn't decl members conditionally 00038 mSigcompStack(0), 00039 mSigcompFramer(0), 00040 // NO: #endif 00041 mSendingTransmissionFormat(Unknown), 00042 mReceivingTransmissionFormat(Unknown), 00043 mMessage(0), 00044 mBuffer(0), 00045 mBufferPos(0), 00046 mBufferSize(0), 00047 mLastUsed(Timer::getTimeMs()), 00048 mConnState(NewMessage) 00049 { 00050 DebugLog (<< "ConnectionBase::ConnectionBase, who: " << mWho << " " << this); 00051 #ifdef USE_SIGCOMP 00052 if (mCompression.isEnabled()) 00053 { 00054 DebugLog (<< "Compression enabled for connection: " << this); 00055 mSigcompStack = new osc::Stack(mCompression.getStateHandler()); 00056 mCompression.addCompressorsToStack(mSigcompStack); 00057 } 00058 else 00059 { 00060 DebugLog (<< "Compression disabled for connection: " << this); 00061 } 00062 #else 00063 DebugLog (<< "No compression library available: " << this); 00064 #endif 00065 00066 // deprecated; stop doing this eventually 00067 mWho.transport=mTransport; 00068 mWho.transportKey=mTransport ? mTransport->getKey() : 0; 00069 } 00070 00071 ConnectionBase::~ConnectionBase() 00072 { 00073 if(mTransport) 00074 { 00075 mTransport->flowTerminated(mWho); 00076 } 00077 00078 while (!mOutstandingSends.empty()) 00079 { 00080 SendData* sendData = mOutstandingSends.front(); 00081 mTransport->fail(sendData->transactionId, 00082 mFailureReason ? mFailureReason : TransportFailure::ConnectionUnknown, 00083 mFailureSubCode); 00084 delete sendData; 00085 mOutstandingSends.pop_front(); 00086 } 00087 delete [] mBuffer; 00088 delete mMessage; 00089 #ifdef USE_SIGCOMP 00090 delete mSigcompStack; 00091 #endif 00092 00093 DebugLog (<< "ConnectionBase::~ConnectionBase " << this); 00094 } 00095 00096 void 00097 ConnectionBase::setFailureReason(TransportFailure::FailureReason failReason, int subCode) 00098 { 00099 if ( failReason > mFailureReason ) 00100 { 00101 mFailureReason = failReason; 00102 mFailureSubCode = subCode; 00103 } 00104 } 00105 00106 FlowKey 00107 ConnectionBase::getFlowKey() const 00108 { 00109 return mWho.mFlowKey; 00110 } 00111 00112 bool 00113 ConnectionBase::preparseNewBytes(int bytesRead) 00114 { 00115 DebugLog(<< "In State: " << connectionStates[mConnState]); 00116 00117 start: // If there is an overhang come back here, effectively recursing 00118 00119 switch(mConnState) 00120 { 00121 case NewMessage: 00122 { 00123 if (strncmp(mBuffer + mBufferPos, Symbols::CRLFCRLF, 4) == 0) 00124 { 00125 DebugLog(<< "Got incoming double-CRLF keepalive (aka ping)."); 00126 mBufferPos += 4; 00127 bytesRead -= 4; 00128 onDoubleCRLF(); 00129 if (bytesRead) 00130 { 00131 goto start; 00132 } 00133 else 00134 { 00135 delete [] mBuffer; 00136 mBuffer = 0; 00137 return true; 00138 } 00139 } 00140 else if (strncmp(mBuffer + mBufferPos, Symbols::CRLF, 2) == 0) 00141 { 00142 //DebugLog(<< "Got incoming CRLF keepalive response (aka pong)."); 00143 mBufferPos += 2; 00144 bytesRead -= 2; 00145 onSingleCRLF(); 00146 if (bytesRead) 00147 { 00148 goto start; 00149 } 00150 else 00151 { 00152 delete [] mBuffer; 00153 mBuffer = 0; 00154 return true; 00155 } 00156 } 00157 00158 assert(mTransport); 00159 mMessage = new SipMessage(mTransport); 00160 00161 DebugLog(<< "ConnectionBase::process setting source " << mWho); 00162 mMessage->setSource(mWho); 00163 mMessage->setTlsDomain(mTransport->tlsDomain()); 00164 00165 #ifdef USE_SSL 00166 // Set TlsPeerName if message is from TlsConnection 00167 TlsConnection *tlsConnection = dynamic_cast<TlsConnection *>(this); 00168 if(tlsConnection) 00169 { 00170 std::list<Data> peerNameList; 00171 tlsConnection->getPeerNames(peerNameList); 00172 mMessage->setTlsPeerNames(peerNameList); 00173 } 00174 #endif 00175 mMsgHeaderScanner.prepareForMessage(mMessage); 00176 // Fall through to the next case. 00177 } 00178 case ReadingHeaders: 00179 { 00180 unsigned int chunkLength = (unsigned int)mBufferPos + bytesRead; 00181 char *unprocessedCharPtr; 00182 MsgHeaderScanner::ScanChunkResult scanChunkResult = 00183 mMsgHeaderScanner.scanChunk(mBuffer, 00184 chunkLength, 00185 &unprocessedCharPtr); 00186 if (scanChunkResult == MsgHeaderScanner::scrError) 00187 { 00188 //.jacob. Not a terribly informative warning. 00189 WarningLog(<< "Discarding preparse!"); 00190 delete [] mBuffer; 00191 mBuffer = 0; 00192 delete mMessage; 00193 mMessage = 0; 00194 mConnState=NewMessage; 00195 return false; 00196 } 00197 00198 if (mMsgHeaderScanner.getHeaderCount() > 256) 00199 { 00200 WarningLog(<< "Discarding preparse; too many headers"); 00201 delete [] mBuffer; 00202 mBuffer = 0; 00203 delete mMessage; 00204 mMessage = 0; 00205 mConnState=NewMessage; 00206 return false; 00207 } 00208 00209 unsigned int numUnprocessedChars = 00210 (unsigned int)((mBuffer + chunkLength) - unprocessedCharPtr); 00211 00212 if(numUnprocessedChars > 2048 && 00213 scanChunkResult == MsgHeaderScanner::scrNextChunk) 00214 { 00215 WarningLog(<< "Discarding preparse; header-field-value (or " 00216 "header name) too long"); 00217 delete [] mBuffer; 00218 mBuffer = 0; 00219 delete mMessage; 00220 mMessage = 0; 00221 mConnState=NewMessage; 00222 return false; 00223 } 00224 00225 if(numUnprocessedChars==chunkLength) 00226 { 00227 // .bwc. MsgHeaderScanner wasn't able to parse anything useful; 00228 // don't bother mMessage yet, but make more room in mBuffer. 00229 size_t size = numUnprocessedChars*3/2; 00230 if (size < ConnectionBase::ChunkSize) 00231 { 00232 size = ConnectionBase::ChunkSize; 00233 } 00234 char* newBuffer = 0; 00235 try 00236 { 00237 newBuffer=MsgHeaderScanner::allocateBuffer((int)size); 00238 } 00239 catch(std::bad_alloc&) 00240 { 00241 ErrLog(<<"Failed to alloc a buffer during preparse!"); 00242 return false; 00243 } 00244 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars); 00245 delete [] mBuffer; 00246 mBuffer = newBuffer; 00247 mBufferPos = numUnprocessedChars; 00248 mBufferSize = size; 00249 mConnState = ReadingHeaders; 00250 return true; 00251 } 00252 00253 mMessage->addBuffer(mBuffer); 00254 mBuffer=0; 00255 00256 if (scanChunkResult == MsgHeaderScanner::scrNextChunk) 00257 { 00258 // Message header is incomplete... 00259 if (numUnprocessedChars == 0) 00260 { 00261 // ...but the chunk is completely processed. 00262 //.jacob. I've discarded the "assigned" concept. 00263 //DebugLog(<< "Data assigned, not fragmented, not complete"); 00264 try 00265 { 00266 mBuffer = MsgHeaderScanner::allocateBuffer(ChunkSize); 00267 } 00268 catch(std::bad_alloc&) 00269 { 00270 ErrLog(<<"Failed to alloc a buffer during preparse!"); 00271 return false; 00272 } 00273 mBufferPos = 0; 00274 mBufferSize = ChunkSize; 00275 } 00276 else 00277 { 00278 // ...but some of the chunk must be shifted into the next one. 00279 size_t size = numUnprocessedChars*3/2; 00280 if (size < ConnectionBase::ChunkSize) 00281 { 00282 size = ConnectionBase::ChunkSize; 00283 } 00284 char* newBuffer = 0; 00285 try 00286 { 00287 newBuffer = MsgHeaderScanner::allocateBuffer((int)size); 00288 } 00289 catch(std::bad_alloc&) 00290 { 00291 ErrLog(<<"Failed to alloc a buffer during preparse!"); 00292 return false; 00293 } 00294 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars); 00295 mBuffer = newBuffer; 00296 mBufferPos = numUnprocessedChars; 00297 mBufferSize = size; 00298 } 00299 mConnState = ReadingHeaders; 00300 } 00301 else 00302 { 00303 size_t contentLength = 0; 00304 00305 try 00306 { 00307 // The message header is complete. 00308 contentLength=mMessage->const_header(h_ContentLength).value(); 00309 } 00310 catch(resip::BaseException& e) // Could be SipMessage::Exception or ParseException 00311 { 00312 WarningLog(<<"Malformed Content-Length in connection-based transport" 00313 ". Not much we can do to fix this. " << e); 00314 // .bwc. Bad Content-Length. We are hosed. 00315 delete mMessage; 00316 mMessage = 0; 00317 mBuffer = 0; 00318 // .bwc. mMessage just took ownership of mBuffer, so we don't 00319 // delete it here. We do zero it though, for completeness. 00320 //.jacob. Shouldn't the state also be set here? 00321 return false; 00322 } 00323 00324 if(contentLength > 10485760 || contentLength < 0) 00325 { 00326 // !bwc! No more than 10M, thanks. We should make this 00327 // configurable. 00328 WarningLog(<<"Absurdly large Content-Length in connection-based " 00329 "transport."); 00330 delete mMessage; 00331 mMessage = 0; 00332 mBuffer = 0; 00333 // .bwc. mMessage just took ownership of mBuffer, so we don't 00334 // delete it here. We do zero it though, for completeness. 00335 //.jacob. Shouldn't the state also be set here? 00336 return false; 00337 } 00338 00339 if (numUnprocessedChars < contentLength) 00340 { 00341 // The message body is incomplete. 00342 DebugLog(<< "partial body received"); 00343 size_t newSize=resipMin(resipMax((size_t)numUnprocessedChars*3/2, 00344 (size_t)ConnectionBase::ChunkSize), 00345 contentLength); 00346 char* newBuffer = MsgHeaderScanner::allocateBuffer((int)newSize); 00347 memcpy(newBuffer, unprocessedCharPtr, numUnprocessedChars); 00348 mBufferPos = numUnprocessedChars; 00349 mBufferSize = newSize; 00350 mBuffer = newBuffer; 00351 00352 mConnState = PartialBody; 00353 } 00354 else 00355 { 00356 // Do this stuff BEFORE we kick the message out the door. 00357 // Remember, deleting or passing mMessage on invalidates our 00358 // buffer! 00359 int overHang = numUnprocessedChars - (int)contentLength; 00360 00361 mConnState = NewMessage; 00362 mBuffer = 0; 00363 if (overHang > 0) 00364 { 00365 // The next message has been partially read. 00366 size_t size = overHang*3/2; 00367 if (size < ConnectionBase::ChunkSize) 00368 { 00369 size = ConnectionBase::ChunkSize; 00370 } 00371 char* newBuffer = MsgHeaderScanner::allocateBuffer((int)size); 00372 memcpy(newBuffer, 00373 unprocessedCharPtr + contentLength, 00374 overHang); 00375 mBuffer = newBuffer; 00376 mBufferPos = 0; 00377 mBufferSize = size; 00378 00379 DebugLog (<< "Extra bytes after message: " << overHang); 00380 DebugLog (<< Data(mBuffer, overHang)); 00381 00382 bytesRead = overHang; 00383 } 00384 00385 // The message body is complete. 00386 mMessage->setBody(unprocessedCharPtr, (UInt32)contentLength); 00387 CongestionManager::RejectionBehavior b=mTransport->getRejectionBehaviorForIncoming(); 00388 if (b==CongestionManager::REJECTING_NON_ESSENTIAL 00389 || (b==CongestionManager::REJECTING_NEW_WORK 00390 && mMessage->isRequest())) 00391 { 00392 UInt32 expectedWait(mTransport->getExpectedWaitForIncoming()); 00393 // .bwc. If this fifo is REJECTING_NEW_WORK, we will drop 00394 // requests but not responses ( ?bwc? is this right for ACK?). 00395 // If we are REJECTING_NON_ESSENTIAL, 00396 // we reject all incoming work, since losing something from the 00397 // wire will not cause instability or leaks (see 00398 // CongestionManager.hxx) 00399 00400 // .bwc. This handles all appropriate checking for whether 00401 // this is a response or an ACK. 00402 std::auto_ptr<SendData> tryLater(transport()->make503(*mMessage, expectedWait/1000)); 00403 if(tryLater.get()) 00404 { 00405 transport()->send(tryLater); 00406 } 00407 delete mMessage; // dropping message due to congestion 00408 mMessage = 0; 00409 } 00410 else if (!transport()->basicCheck(*mMessage)) 00411 { 00412 delete mMessage; 00413 mMessage = 0; 00414 } 00415 else 00416 { 00417 Transport::stampReceived(mMessage); 00418 DebugLog(<< "##Connection: " << *this << " received: " << *mMessage); 00419 assert( mTransport ); 00420 mTransport->pushRxMsgUp(mMessage); 00421 mMessage = 0; 00422 } 00423 00424 if (overHang > 0) 00425 { 00426 goto start; 00427 } 00428 } 00429 } 00430 break; 00431 } 00432 case PartialBody: 00433 { 00434 size_t contentLength = 0; 00435 00436 try 00437 { 00438 contentLength = mMessage->const_header(h_ContentLength).value(); 00439 } 00440 catch(resip::BaseException& e) // Could be SipMessage::Exception or ParseException 00441 { 00442 WarningLog(<<"Malformed Content-Length in connection-based transport" 00443 ". Not much we can do to fix this. " << e); 00444 // .bwc. Bad Content-Length. We are hosed. 00445 delete [] mBuffer; 00446 mBuffer = 0; 00447 delete mMessage; 00448 mMessage = 0; 00449 //.jacob. Shouldn't the state also be set here? 00450 return false; 00451 } 00452 00453 mBufferPos += bytesRead; 00454 if (mBufferPos == contentLength) 00455 { 00456 mMessage->addBuffer(mBuffer); 00457 mMessage->setBody(mBuffer, (UInt32)contentLength); 00458 mBuffer=0; 00459 // .bwc. basicCheck takes up substantial CPU. Don't bother doing it 00460 // if we're overloaded. 00461 CongestionManager::RejectionBehavior b=mTransport->getRejectionBehaviorForIncoming(); 00462 if (b==CongestionManager::REJECTING_NON_ESSENTIAL 00463 || (b==CongestionManager::REJECTING_NEW_WORK 00464 && mMessage->isRequest())) 00465 { 00466 UInt32 expectedWait(mTransport->getExpectedWaitForIncoming()); 00467 // .bwc. If this fifo is REJECTING_NEW_WORK, we will drop 00468 // requests but not responses ( ?bwc? is this right for ACK?). 00469 // If we are REJECTING_NON_ESSENTIAL, 00470 // we reject all incoming work, since losing something from the 00471 // wire will not cause instability or leaks (see 00472 // CongestionManager.hxx) 00473 00474 // .bwc. This handles all appropriate checking for whether 00475 // this is a response or an ACK. 00476 std::auto_ptr<SendData> tryLater = transport()->make503(*mMessage, expectedWait/1000); 00477 if(tryLater.get()) 00478 { 00479 transport()->send(tryLater); 00480 } 00481 delete mMessage; // dropping message due to congestion 00482 mMessage = 0; 00483 } 00484 else if (!transport()->basicCheck(*mMessage)) 00485 { 00486 delete mMessage; 00487 mMessage = 0; 00488 } 00489 else 00490 { 00491 DebugLog(<< "##ConnectionBase: " << *this << " received: " << *mMessage); 00492 00493 Transport::stampReceived(mMessage); 00494 assert( mTransport ); 00495 mTransport->pushRxMsgUp(mMessage); 00496 mMessage = 0; 00497 } 00498 mConnState = NewMessage; 00499 } 00500 else if (mBufferPos == mBufferSize) 00501 { 00502 // .bwc. We've filled our buffer; go ahead and make more room. 00503 size_t newSize = resipMin(mBufferSize*3/2, contentLength); 00504 char* newBuffer = 0; 00505 try 00506 { 00507 newBuffer=new char[newSize]; 00508 } 00509 catch(std::bad_alloc&) 00510 { 00511 ErrLog(<<"Failed to alloc a buffer while receiving body!"); 00512 return false; 00513 } 00514 memcpy(newBuffer, mBuffer, mBufferSize); 00515 mBufferSize=newSize; 00516 delete [] mBuffer; 00517 mBuffer = newBuffer; 00518 } 00519 break; 00520 } 00521 default: 00522 assert(0); 00523 } 00524 return true; 00525 } 00526 00527 #ifdef USE_SIGCOMP 00528 void 00529 ConnectionBase::decompressNewBytes(int bytesRead) 00530 { 00531 mConnState = SigComp; 00532 00533 if (!mSigcompFramer) 00534 { 00535 mSigcompFramer = new osc::TcpStream(); 00536 } 00537 00538 mSigcompFramer->addData(mBuffer, bytesRead); 00539 size_t bytesUncompressed; 00540 osc::StateChanges *sc = 0; 00541 char *uncompressed = new char[65536]; 00542 while ((bytesUncompressed = mSigcompStack->uncompressMessage( 00543 *mSigcompFramer, uncompressed, 65536, sc)) > 0) 00544 { 00545 DebugLog (<< "Uncompressed Connection-oriented message"); 00546 mMessage = new SipMessage(mWho.transport); 00547 00548 mMessage->setSource(mWho); 00549 mMessage->setTlsDomain(mWho.transport->tlsDomain()); 00550 00551 char *sipBuffer = new char[bytesUncompressed]; 00552 memmove(sipBuffer, uncompressed, bytesUncompressed); 00553 mMessage->addBuffer(sipBuffer); 00554 mMsgHeaderScanner.prepareForMessage(mMessage); 00555 char *unprocessedCharPtr; 00556 if (mMsgHeaderScanner.scanChunk(sipBuffer, 00557 bytesUncompressed, 00558 &unprocessedCharPtr) != 00559 MsgHeaderScanner::scrEnd) 00560 { 00561 StackLog(<<"Scanner rejecting compressed message as unparsable"); 00562 StackLog(<< Data(sipBuffer, bytesUncompressed)); 00563 delete mMessage; 00564 mMessage=0; 00565 } 00566 00567 unsigned int used = unprocessedCharPtr - sipBuffer; 00568 if (mMessage && (used < bytesUncompressed)) 00569 { 00570 mMessage->setBody(sipBuffer+used, bytesUncompressed-used); 00571 } 00572 00573 if (mMessage && !transport()->basicCheck(*mMessage)) 00574 { 00575 delete mMessage; 00576 mMessage = 0; 00577 } 00578 00579 if (mMessage) 00580 { 00581 Transport::stampReceived(mMessage); 00582 // If the message made it this far, we should let it store 00583 // SigComp state: extract the compartment ID. 00584 const Via &via = mMessage->const_header(h_Vias).front(); 00585 if (mMessage->isRequest()) 00586 { 00587 // For requests, the compartment ID is read out of the 00588 // top via header field; if not present, we use the 00589 // TCP connection for identification purposes. 00590 if (via.exists(p_sigcompId)) 00591 { 00592 Data compId = via.param(p_sigcompId); 00593 if(!compId.empty()) 00594 { 00595 mSigcompStack->provideCompartmentId(sc, compId.data(), compId.size()); 00596 } 00597 } 00598 else 00599 { 00600 mSigcompStack->provideCompartmentId(sc, this, sizeof(this)); 00601 } 00602 } 00603 else 00604 { 00605 // For responses, the compartment ID is supposed to be 00606 // the same as the compartment ID of the request. We 00607 // *could* dig down into the transaction layer to try to 00608 // figure this out, but that's a royal pain, and a rather 00609 // severe layer violation. In practice, we're going to ferret 00610 // the ID out of the the Via header field, which is where we 00611 // squirreled it away when we sent this request in the first place. 00612 Data compId = via.param(p_branch).getSigcompCompartment(); 00613 if(!compId.empty()) 00614 { 00615 mSigcompStack->provideCompartmentId(sc, compId.data(), compId.size()); 00616 } 00617 } 00618 assert( mTransport ); 00619 mTransport->pushRxMsgUp(mMessage); 00620 mMessage = 0; 00621 sc = 0; 00622 } 00623 else 00624 { 00625 delete sc; 00626 sc = 0; 00627 } 00628 } 00629 delete uncompressed; 00630 00631 // If there was a decompression failure, let the other side know. 00632 osc::SigcompMessage *nack = mSigcompStack->getNack(); 00633 if (nack) 00634 { 00635 if (mSendingTransmissionFormat == Compressed) 00636 { 00637 // !bwc! We are not telling anyone that we're interested in having our 00638 // FD put in the writable set... 00639 mOutstandingSends.push_back(new SendData( 00640 who(), 00641 Data(nack->getStreamMessage(), nack->getStreamLength()), 00642 Data::Empty, 00643 Data::Empty, 00644 true)); 00645 } 00646 else 00647 { 00648 delete nack; 00649 } 00650 } 00651 } 00652 #endif 00653 00654 std::pair<char*, size_t> 00655 ConnectionBase::getWriteBuffer() 00656 { 00657 if (mConnState == NewMessage) 00658 { 00659 if (!mBuffer) 00660 { 00661 DebugLog (<< "Creating buffer for " << *this); 00662 00663 mBuffer = MsgHeaderScanner::allocateBuffer(ConnectionBase::ChunkSize); 00664 mBufferSize = ConnectionBase::ChunkSize; 00665 } 00666 mBufferPos = 0; 00667 } 00668 return getCurrentWriteBuffer(); 00669 } 00670 00671 std::pair<char*, size_t> 00672 ConnectionBase::getCurrentWriteBuffer() 00673 { 00674 return std::make_pair(mBuffer + mBufferPos, mBufferSize - mBufferPos); 00675 } 00676 00677 char* 00678 ConnectionBase::getWriteBufferForExtraBytes(int extraBytes) 00679 { 00680 if (extraBytes > 0) 00681 { 00682 char* buffer = MsgHeaderScanner::allocateBuffer((int)mBufferSize + extraBytes); 00683 memcpy(buffer, mBuffer, mBufferSize); 00684 delete [] mBuffer; 00685 mBuffer = buffer; 00686 buffer += mBufferSize; 00687 mBufferSize += extraBytes; 00688 return buffer; 00689 } 00690 else 00691 { 00692 assert(0); 00693 return mBuffer; 00694 } 00695 } 00696 00697 void 00698 ConnectionBase::setBuffer(char* bytes, int count) 00699 { 00700 mBuffer = bytes; 00701 mBufferPos = 0; 00702 mBufferSize = count; 00703 } 00704 00705 Transport* 00706 ConnectionBase::transport() const 00707 { 00708 assert(this); 00709 return mTransport; 00710 } 00711 00712 EncodeStream& 00713 resip::operator<<(EncodeStream& strm, 00714 const resip::ConnectionBase& c) 00715 00716 { 00717 strm << "CONN_BASE: " << &c << " " << c.mWho; 00718 return strm; 00719 } 00720 00721 /* ==================================================================== 00722 * The Vovida Software License, Version 1.0 00723 * 00724 * Copyright (c) 2000 00725 * 00726 * Redistribution and use in source and binary forms, with or without 00727 * modification, are permitted provided that the following conditions 00728 * are met: 00729 * 00730 * 1. Redistributions of source code must retain the above copyright 00731 * notice, this list of conditions and the following disclaimer. 00732 * 00733 * 2. Redistributions in binary form must reproduce the above copyright 00734 * notice, this list of conditions and the following disclaimer in 00735 * the documentation and/or other materials provided with the 00736 * distribution. 00737 * 00738 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00739 * and "Vovida Open Communication Application Library (VOCAL)" must 00740 * not be used to endorse or promote products derived from this 00741 * software without prior written permission. For written 00742 * permission, please contact vocal@vovida.org. 00743 * 00744 * 4. Products derived from this software may not be called "VOCAL", nor 00745 * may "VOCAL" appear in their name, without prior written 00746 * permission of Vovida Networks, Inc. 00747 * 00748 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00749 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00750 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00751 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00752 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00753 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00754 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00755 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00756 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00757 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00758 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00759 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00760 * DAMAGE. 00761 * 00762 * ==================================================================== 00763 * 00764 * This software consists of voluntary contributions made by Vovida 00765 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00766 * Inc. For more information on Vovida Networks, Inc., please see 00767 * <http://www.vovida.org/>. 00768 * 00769 * vi: set shiftwidth=3 expandtab: 00770 */ 00771
1.7.5.1