rtspbase.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:18k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: rtspbase.cpp,v 1.11.2.1 2004/07/09 02:04:52 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxcom.h"
  50. #include "hxtypes.h"
  51. #include "hxstring.h"
  52. #include "hxslist.h"
  53. #include "hxengin.h"
  54. #include "ihxpckts.h"
  55. #include "chxpckts.h"
  56. #include "safestring.h"
  57. //#include "rtmlpars.h"
  58. #include "mimehead.h"
  59. #include "mimescan.h"
  60. #include "timerep.h"
  61. #include "rtspmsg.h"
  62. #include "rtsppars.h"
  63. #include "rtspmdsc.h"
  64. #include "basepkt.h"
  65. #include "servrsnd.h"
  66. #include "rtspbase.h"
  67. #include "dbcs.h" // for HXIsEqual
  68. #include "hxheap.h"
  69. #ifdef _DEBUG
  70. #undef HX_THIS_FILE
  71. static const char HX_THIS_FILE[] = __FILE__;
  72. #endif
  73. // XXXHP: NEED TO MODIFY THE SAME STRUCTURE AT DLLMAIN.CPP!!!
  74. struct RTSPError
  75. {
  76.     const char* pErrNo;
  77.     const char* pErrMsg;
  78. };
  79. //
  80. // XXXBAB - turn this into a dictionary
  81. //
  82. // XXXHP: NEED TO REGENERATE ON WIN16 EVERYTIME THIS ARRAY
  83. //   IS MODIFIED!!!
  84. #ifdef _WIN16
  85. extern RTSPError* RTSPErrorTable;
  86. #else
  87. static const RTSPError RTSPErrorTable[] =
  88. {
  89.     { "100", "Continue" },
  90.     { "200", "OK" },
  91.     { "201", "Created" },
  92.     { "250", "Low On Storage Space" },
  93.     { "300", "Multiple Choices" },
  94.     { "301", "Moved Permanently" },
  95.     { "302", "Moved Temporarily" },
  96.     { "303", "See Other" },
  97.     { "304", "Not Modified" },
  98.     { "305", "Use Proxy" },
  99.     { "400", "Bad Request" },
  100.     { "401", "Unauthorized" },
  101.     { "402", "Payment Required" },
  102.     { "403", "Forbidden" },
  103.     { "404", "Not Found" },
  104.     { "405", "Method Not Allowed" },
  105.     { "406", "Not Acceptable" },
  106.     { "407", "Proxy Authentication Required" },
  107.     { "408", "Request Time-out" },
  108.     { "409", "Conflict" },
  109.     { "410", "Gone" },
  110.     { "411", "Length Required" },
  111.     { "412", "Precondition Failed" },
  112.     { "413", "Request Entity Too Large" },
  113.     { "414", "Request-URI Too Large" },
  114.     { "415", "Unsupported Media Type" },
  115.     { "451", "Parameter Not Understood" },
  116.     { "452", "Conference Not Found" },
  117.     { "453", "Not Enough Bandwidth" },
  118.     { "454", "Session Not Found" },
  119.     { "455", "Method Not Valid In This State" },
  120.     { "456", "Header Field Not Valid For Resource" },
  121.     { "457", "Invalid Range" },
  122.     { "458", "Parameter Is Read-Only" },
  123.     { "459", "Aggregate Operation Not Allowed" },
  124.     { "460", "Only Aggregate Operation Allowed" },
  125.     { "461", "Unsupported Transport" },
  126.     { "462", "Destination Unreachable" },
  127.     { "500", "Internal Server Error" },
  128.     { "501", "Not Implemented" },
  129.     { "502", "Bad Gateway" },
  130.     { "503", "Service Unavailable" },
  131.     { "504", "Gateway Time-out" },
  132.     { "505", "RTSP Version not supported" },
  133.     { "551", "Option not supported" }
  134. };
  135. #endif
  136. const RTSPRequireOptions RTSPBaseProtocol::RTSPRequireOptionsTable
  137.     [RTSPBaseProtocol::m_NumRTSPRequireOptions] =
  138.     {
  139.         {"com.real.retain-entity-for-setup", "DESCRIBE", 8},
  140.         {"com.real.load-test-password-enabled", "OPTIONS", 7}
  141.     };
  142. const RTSPAcceptEncodingOptions RTSPBaseProtocol::RTSPAcceptEncodingOptionsTable
  143.     [RTSPBaseProtocol::m_NumRTSPAcceptEncodingOptions] =
  144.     {
  145.         {"mei", "DESCRIBE", 8},
  146.         {"mei", "SETUP", 5}
  147.     };
  148. /*
  149.  * RTSPBaseProtocol methods
  150.  */
  151. RTSPBaseProtocol::RTSPBaseProtocol():
  152.     m_pContext(NULL),
  153.     m_pCommonClassFactory(NULL),
  154.     m_pSocket(0),
  155.     m_pFastSocket(0),
  156.     m_uControlBytesSent(0),
  157.     m_pControlBuffer(0)
  158. {
  159. }
  160. RTSPBaseProtocol::~RTSPBaseProtocol()
  161. {
  162.     clearMessages();
  163.     HX_RELEASE(m_pControlBuffer);
  164.     HX_RELEASE(m_pCommonClassFactory);
  165.     HX_RELEASE(m_pContext);
  166. }
  167. HX_RESULT
  168. RTSPBaseProtocol::enqueueMessage(RTSPMessage* pMsg)
  169. {
  170.     m_msgQueue.AddTail(pMsg);
  171.     return HXR_OK;
  172. }
  173. RTSPMessage*
  174. RTSPBaseProtocol::dequeueMessage(UINT32 seqNo)
  175. {
  176.     LISTPOSITION pos = m_msgQueue.GetHeadPosition();
  177.     while(pos)
  178.     {
  179.         RTSPMessage* pMsg = (RTSPMessage*)m_msgQueue.GetAt(pos);
  180.         if(pMsg->seqNo() == seqNo)
  181.         {
  182.             (void)m_msgQueue.RemoveAt(pos);
  183.             return pMsg;
  184.         }
  185.         (void)m_msgQueue.GetNext(pos);
  186.     }
  187.     return 0;
  188. }
  189. void
  190. RTSPBaseProtocol::clearMessages()
  191. {
  192.     LISTPOSITION pos = m_msgQueue.GetHeadPosition();
  193.     while(pos)
  194.     {
  195.         RTSPMessage* pMsg = (RTSPMessage*)m_msgQueue.GetNext(pos);
  196.         delete pMsg;
  197.     }
  198. }
  199. const char*
  200. RTSPBaseProtocol::getErrorText(const char* pErrNo)
  201. {
  202.     int tabSize = sizeof(RTSPErrorTable) / sizeof(RTSPErrorTable[0]);
  203.     for (int i = 0; i < tabSize; ++i)
  204.     {
  205.         if (strcmp(pErrNo, RTSPErrorTable[i].pErrNo) == 0)
  206.         {
  207.             return RTSPErrorTable[i].pErrMsg;
  208.         }
  209.     }
  210.     return "";
  211. }
  212. HX_RESULT
  213. RTSPBaseProtocol::sendRequest(RTSPRequestMessage* pMsg,
  214.     const char* pContent, const char* pMimeType, UINT32 seqNo)
  215. {
  216.     if(pContent)
  217.     {
  218.         char tmpBuf[32];
  219.         pMsg->addHeader("Content-type", pMimeType);
  220.         SafeSprintf(tmpBuf, 32,"%d", strlen(pContent)); 
  221.         pMsg->addHeader("Content-length", tmpBuf);
  222.         pMsg->setContent(pContent);
  223.     }
  224.     return sendRequest(pMsg, seqNo);
  225. }
  226. HX_RESULT
  227. RTSPBaseProtocol::sendRequest(RTSPRequestMessage* pMsg, UINT32 seqNo)
  228. {
  229.     // set sequence number
  230.     char seqBuf[32]; 
  231.     SafeSprintf(seqBuf, 32, "%ld", seqNo); 
  232.     pMsg->addHeader("CSeq", seqBuf, TRUE); // add to head of list
  233.     pMsg->setSeqNo(seqNo);
  234.     enqueueMessage(pMsg);
  235.     CHXString msgStr = pMsg->asString();
  236.     CHXBuffer* pBuffer = new CHXBuffer;
  237.     pBuffer->AddRef();
  238.     pBuffer->Set((BYTE*)(const char*)msgStr, msgStr.GetLength());
  239.     HX_RESULT rc = sendControlMessage(pBuffer);
  240.     handleSendEvent(pMsg);
  241.     pBuffer->Release();
  242.     return HXR_OK;
  243. }
  244. void
  245. RTSPBaseProtocol::handleDebug(IHXBuffer* pMsgBuf, BOOL bInbound)
  246. {
  247.     // Only implemented by subclasses in server modules
  248. }
  249. void
  250. RTSPBaseProtocol::handleTiming(IHXBuffer* pMsgBuf, BOOL bInbound)
  251. {
  252.     // Only implemented by subclasses in server modules
  253. }
  254. void 
  255. RTSPBaseProtocol::handleSendEvent(RTSPRequestMessage* pMsg)
  256. {
  257.     // Only implemented by subclasses in server modules
  258. }
  259. RTSPResponseMessage*
  260. RTSPBaseProtocol::makeResponseMessage(UINT32 seqNo, const char* pErrNo)
  261. {
  262.     RTSPResponseMessage* pMsg = new RTSPResponseMessage;
  263.     // set sequence number
  264.     char seqBuf[32]; 
  265.     SafeSprintf(seqBuf,32,"%ld", seqNo);
  266.     pMsg->addHeader("CSeq", seqBuf, TRUE); // add to head of list
  267.     pMsg->setSeqNo(seqNo);
  268.     pMsg->setErrorCode(pErrNo);
  269.     pMsg->setErrorMsg(getErrorText(pErrNo));
  270.     UTCTimeRep utcNow;
  271.     pMsg->addHeader("Date", utcNow.asRFC1123String());
  272.     return pMsg;
  273. }
  274. HX_RESULT
  275. RTSPBaseProtocol::sendResponse(UINT32 seqNo, const char* pErrNo)
  276. {
  277.     RTSPResponseMessage* pMsg = makeResponseMessage(seqNo, pErrNo);
  278.     HX_RESULT err = sendResponse(pMsg);
  279.     delete pMsg;
  280.     return err;
  281. }
  282. HX_RESULT
  283. RTSPBaseProtocol::sendResponse(
  284.     RTSPResponseMessage* pMsg, const char* pContent, const char* pMimeType)
  285. {
  286.     if (pContent != NULL)
  287.     {
  288.         char tmpBuf[32]; 
  289.         pMsg->addHeader("Content-type", pMimeType);
  290.         SafeSprintf(tmpBuf,32, "%d", strlen(pContent));  // only for strings 
  291.         pMsg->addHeader("Content-length", tmpBuf);
  292.         pMsg->setContent(pContent);
  293.     }
  294.     CHXString msgStr = pMsg->asString();
  295.     CHXBuffer* pBuffer = new CHXBuffer;
  296.     pBuffer->AddRef();
  297.     pBuffer->Set((BYTE*)(const char*)msgStr, msgStr.GetLength());
  298.     sendControlMessage(pBuffer);
  299.     handleSendEvent(pMsg);
  300.     pBuffer->Release();
  301.     return HXR_OK;
  302. }
  303. void 
  304. RTSPBaseProtocol::handleSendEvent(RTSPResponseMessage* pMsg)
  305. {
  306.     // Only implmented by subclasses in server modules
  307. }
  308. void
  309. RTSPBaseProtocol::addRFC822Headers(RTSPMessage* pMsg,
  310.    IHXValues* pRFC822Headers)
  311. {
  312.     HX_RESULT         res;
  313.     MIMEHeader*       pMimeHeader;
  314.     const char*       pName = NULL;
  315.     IHXBuffer*       pValue = NULL;
  316.     IHXKeyValueList* pKeyedHdrs;
  317.     if (!pRFC822Headers)
  318.     {
  319. return;
  320.     }
  321.     // Find out if the IHXValues supports IHXKeyValueList
  322.     // XXX showell - eventually, we should just make all callers
  323.     // give us an IHXKeyValueList, since it's more efficient,
  324.     // and so we don't overwrite duplicate headers.
  325.     res = pRFC822Headers->QueryInterface(IID_IHXKeyValueList, 
  326.  (void**) &pKeyedHdrs);
  327.     if (res == HXR_OK)
  328.     {
  329. IHXKeyValueListIter* pListIter = NULL;
  330. pKeyedHdrs->GetIter(pListIter);
  331. HX_ASSERT(pListIter);
  332. while (pListIter->GetNextPair(pName, pValue) == HXR_OK)
  333. {
  334.     pMimeHeader = new MIMEHeader(pName);
  335.     pMimeHeader->addHeaderValue((char*)pValue->GetBuffer());
  336.     pMsg->addHeader(pMimeHeader);
  337.     HX_RELEASE(pValue);
  338. }
  339. HX_RELEASE(pListIter);
  340.     }
  341.     else
  342.     {
  343. res = pRFC822Headers->GetFirstPropertyCString(pName, pValue);
  344. while (res == HXR_OK)
  345. {
  346.     pMimeHeader = new MIMEHeader(pName);
  347.     pMimeHeader->addHeaderValue((char*)pValue->GetBuffer());
  348.     pMsg->addHeader(pMimeHeader);
  349.     pValue->Release();
  350.     res = pRFC822Headers->GetNextPropertyCString(pName, pValue);
  351. }
  352.     }
  353.     HX_RELEASE(pKeyedHdrs);
  354. }
  355. void
  356. RTSPBaseProtocol::getRFC822Headers(RTSPMessage* pMsg,
  357.     REF(IHXValues*) pRFC822Headers)
  358. {
  359.     MIMEHeader* pHeader = NULL;
  360.     IUnknown* pUnknown = NULL;
  361.     IHXKeyValueList* pList = NULL;
  362.     pRFC822Headers = NULL;
  363.     if (!m_pCommonClassFactory)
  364.     {
  365. goto cleanup;
  366.     }
  367.     if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXKeyValueList,
  368. (void**) &pUnknown))
  369.     {
  370. goto cleanup;
  371.     }
  372.     if (HXR_OK != pUnknown->QueryInterface(IID_IHXKeyValueList, 
  373.    (void**) &pList))
  374.     {
  375. goto cleanup;
  376.     }
  377.     pHeader = pMsg->getFirstHeader();
  378.     while (pHeader)
  379.     {
  380. MIMEHeaderValue* pHeaderValue;
  381. /*
  382.  * XXX...There is way too much memcpy() going on here
  383.  */
  384. pHeaderValue = pHeader->getFirstHeaderValue();
  385. CHXString HeaderString;
  386. while (pHeaderValue)
  387. {
  388.     CHXString TempString;
  389.     pHeaderValue->asString(TempString);
  390.     HeaderString += TempString;
  391.     pHeaderValue = pHeader->getNextHeaderValue();
  392.     if (pHeaderValue)
  393.     {
  394. HeaderString += ", ";
  395.     }
  396. }
  397. IHXBuffer *pBuffer = NULL;
  398. CHXBuffer::FromCharArray((const char*) HeaderString, &pBuffer);
  399. pList->AddKeyValue(pHeader->name(), pBuffer);
  400. HX_RELEASE(pBuffer);
  401. pHeader = pMsg->getNextHeader();
  402.     }
  403.     // XXX showell - Yet another item for rnvalues cleanup phase II.  We should
  404.     // just change this function so its callers don't expect IHXValues, since
  405.     // the IHXKeyValueList interface is better for header data.
  406.     if (HXR_OK != pList->QueryInterface(IID_IHXValues,
  407. (void**) &pRFC822Headers))
  408.     {
  409. pRFC822Headers = NULL;
  410.     }
  411. cleanup:
  412.     HX_RELEASE(pList);
  413.     HX_RELEASE(pUnknown);
  414. }
  415. HX_RESULT
  416. RTSPBaseProtocol::sendControlMessage(IHXBuffer* pBuffer)
  417. {
  418.     HX_RESULT hxr = HXR_OK;
  419.     handleDebug(pBuffer, FALSE);
  420.     handleTiming(pBuffer, FALSE);
  421.     if (!m_pSocket)
  422.     {
  423.         m_pControlBuffer = pBuffer;
  424.         m_pControlBuffer->AddRef();
  425.         hxr = reopenSocket();
  426.     }
  427.     else
  428.     {
  429.         m_uControlBytesSent += pBuffer->GetSize();
  430.         if (m_pFastSocket)
  431.         {
  432.             hxr = m_pFastSocket->BufferedWrite(pBuffer);
  433.             m_pFastSocket->FlushWrite();
  434.         }
  435.         else
  436.         {
  437.             hxr = m_pSocket->Write(pBuffer);
  438.         }
  439.     }
  440.     return hxr;
  441. }
  442. HX_RESULT
  443. RTSPBaseProtocol::handleACK(IHXPacketResend* pPacketResend,
  444.     RTSPResendBuffer* pResendBuffer,
  445.     UINT16 uStreamNumber,
  446.     UINT16* pAckList,
  447.     UINT32 uAckListCount,
  448.     UINT16* pNakList,
  449.     UINT32 uNakListCount,
  450.     BOOL bIgnoreACK)
  451. {
  452.     if (!pResendBuffer)
  453.     {
  454. return HXR_UNEXPECTED;
  455.     }
  456.     /*
  457.      * ACKs and NAKs only have meaning for resend buffers
  458.      *
  459.      * NOTE: keep the ACKing/NAKing in order by starting at the back of
  460.      *       the lists
  461.      */
  462.         
  463.     INT32 i;
  464.     
  465.     if (!bIgnoreACK)
  466.     {
  467. for (i = uAckListCount - 1; i >= 0; i--)
  468. {
  469.     pResendBuffer->Remove(pAckList[i]);
  470. }
  471.     }
  472.     
  473.     if (uNakListCount)
  474.     {
  475. //XXXGH...must be BasePacket
  476. BasePacket** ppPacket = new BasePacket*[uNakListCount + 1];
  477. /*
  478.  * Only allow 10 packets to be resent
  479.  */
  480. UINT16 j = 0;
  481. for (i = uNakListCount - 1; i >= 0 && j < 10; i--)
  482. {
  483.     BasePacket* pPacket;
  484.     pPacket = pResendBuffer->Find(pNakList[i], TRUE);
  485.     if (pPacket)
  486.     {
  487. ppPacket[j++] = pPacket;
  488. pPacket->AddRef();
  489.     }
  490. }
  491. ppPacket[j] = 0;
  492. //XXX..will the BasePacket have the stream number in it?
  493. pPacketResend->OnPacket(uStreamNumber, ppPacket);
  494. BasePacket* pReleasePacket = NULL;
  495. BasePacket** ppReleasePacket = ppPacket;
  496. for (; (pReleasePacket = *ppReleasePacket); ppReleasePacket++)
  497. {
  498.     HX_RELEASE(pReleasePacket);
  499. }     
  500. HX_VECTOR_DELETE(ppPacket);
  501.     }
  502.     return HXR_OK;
  503. }
  504. /*
  505.  *  The grammer in RFC2326, I think, is wrong....But in any case, there is no 
  506.  *  gurantee seq_no and rtptime are present in RTP-Info.
  507.  */
  508. RTPInfoEnum
  509. RTSPBaseProtocol::parseRTPInfoHeader(
  510.     MIMEHeaderValue* pSeqValue, UINT16& streamID, UINT16& seqNum,
  511.     UINT32& ulTimestamp, const char*& pControl)
  512. {
  513.     BOOL bFoundSeqNo = FALSE;
  514.     BOOL bFoundRTPTime = FALSE;
  515.     MIMEParameter* pParam = pSeqValue->getFirstParameter();
  516.     while (pParam != NULL)
  517.     {
  518. if(pParam->m_attribute == "url")
  519. {
  520.     // Note: We don't currently do anything with the first section
  521.     // of the "url" attribute (the actual player-requested URL). If
  522.     // we ever do, please note that all ';' characters were escaped 
  523.     // by the server when this message was created, because ';' has
  524.     // special meaning as a delimiter in this message. Remember to
  525.     // unescape all instances of "%3b" to ";" before using the URL.
  526.     const char* pUrl = (const char*) pParam->m_value;
  527.     const char* pEq  = strrchr(pUrl, '=');
  528.     if (pEq != NULL)
  529.     {
  530. streamID = (UINT16)strtol(pEq + 1, 0, 10);
  531.     }
  532.     // take the control string...
  533.     pControl = pUrl;
  534. }
  535. else if(pParam->m_attribute == "seq")
  536. {
  537.     bFoundSeqNo = TRUE;
  538.     seqNum = (UINT16)strtol((const char*)pParam->m_value,0,10);
  539. }
  540. else if(pParam->m_attribute == "rtptime")
  541. {
  542.     bFoundRTPTime = TRUE;
  543.     ulTimestamp = (UINT32)strtoul((const char*)pParam->m_value, 0, 10);
  544. }
  545. pParam = pSeqValue->getNextParameter();
  546.     }
  547.     if (bFoundSeqNo)
  548.     {
  549. if (bFoundRTPTime)
  550. {
  551.     return RTPINFO_SEQ_RTPTIME;
  552. }
  553. return RTPINFO_SEQ;
  554.     }
  555.     if (bFoundRTPTime)
  556.     {
  557. return RTPINFO_RTPTIME;
  558.     }
  559.     return RTPINFO_EMPTY;
  560. }
  561. BOOL 
  562. RTSPBaseProtocol::isRequired(RTSPMessage* pRTSPMessageToSearch, 
  563.      UINT32 ulOptionToFind)
  564. {
  565.     BOOL bRetainState = FALSE;
  566.     MIMEHeader* pMIMEHeaderRequire;
  567.     pMIMEHeaderRequire = pRTSPMessageToSearch->getHeader("Require");
  568.     // If a require header was found
  569.     if (pMIMEHeaderRequire != NULL)
  570.     {
  571. MIMEHeaderValue* pMIMEHeaderValueRequire =
  572.     pMIMEHeaderRequire->getFirstHeaderValue();
  573. while (pMIMEHeaderValueRequire != NULL)
  574. {
  575.     if (!strcasecmp(RTSPRequireOptionsTable[ulOptionToFind].pcharOption,
  576.                             pMIMEHeaderValueRequire->value()))
  577.     {
  578. bRetainState = TRUE;
  579.     }
  580.     pMIMEHeaderValueRequire = pMIMEHeaderRequire->getNextHeaderValue();
  581. }
  582.     }
  583.     return bRetainState;
  584. }