reSIProcate/stack  9694
ConnectionBase.cxx
Go to the documentation of this file.
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