|
MythTV
0.26-pre
|
00001 00002 // Program Name: ssdp.cpp 00003 // Created : Oct. 1, 2005 00004 // 00005 // Purpose : SSDP Discovery Service Implmenetation 00006 // 00007 // Copyright (c) 2005 David Blain <dblain@mythtv.org> 00008 // 00009 // Licensed under the GPL v2 or later, see COPYING for details 00010 // 00012 00013 #include <algorithm> 00014 00015 #include "upnp.h" 00016 #include "mythlogging.h" 00017 00018 #include "upnptasksearch.h" 00019 #include "upnptaskcache.h" 00020 00021 #include "mmulticastsocketdevice.h" 00022 #include "mbroadcastsocketdevice.h" 00023 00024 #include <QRegExp> 00025 #include <QStringList> 00026 00027 #include <stdlib.h> 00028 00031 // 00032 // SSDP Class Implementation 00033 // 00036 00037 // We're creating this class immediately so it will always be available. 00038 00039 static QMutex g_pSSDPCreationLock; 00040 SSDP* SSDP::g_pSSDP = NULL; 00041 00043 // 00045 00046 SSDP* SSDP::Instance() 00047 { 00048 QMutexLocker locker(&g_pSSDPCreationLock); 00049 return g_pSSDP ? g_pSSDP : (g_pSSDP = new SSDP()); 00050 } 00051 00053 // 00055 00056 void SSDP::Shutdown() 00057 { 00058 QMutexLocker locker(&g_pSSDPCreationLock); 00059 delete g_pSSDP; 00060 g_pSSDP = NULL; 00061 } 00062 00064 // 00066 00067 SSDP::SSDP() : 00068 MThread ("SSDP" ), 00069 m_procReqLineExp ("[ \r\n][ \r\n]*"), 00070 m_nPort ( SSDP_PORT ), 00071 m_nSearchPort ( SSDP_SEARCHPORT ), 00072 m_nServicePort ( 0 ), 00073 m_pNotifyTask ( NULL ), 00074 m_bAnnouncementsEnabled( false ), 00075 m_bTermRequested ( false ), 00076 m_lock ( QMutex::NonRecursive ) 00077 { 00078 LOG(VB_UPNP, LOG_NOTICE, "Starting up SSDP Thread..." ); 00079 00080 Configuration *pConfig = UPnp::GetConfiguration(); 00081 00082 m_nPort = pConfig->GetValue("UPnP/SSDP/Port" , SSDP_PORT ); 00083 m_nSearchPort = pConfig->GetValue("UPnP/SSDP/SearchPort", SSDP_SEARCHPORT); 00084 00085 m_Sockets[ SocketIdx_Search ] = 00086 new MMulticastSocketDevice(); 00087 m_Sockets[ SocketIdx_Multicast ] = 00088 new MMulticastSocketDevice(SSDP_GROUP, m_nPort); 00089 m_Sockets[ SocketIdx_Broadcast ] = 00090 new MBroadcastSocketDevice("255.255.255.255", m_nPort); 00091 00092 m_Sockets[ SocketIdx_Search ]->setBlocking( false ); 00093 m_Sockets[ SocketIdx_Multicast ]->setBlocking( false ); 00094 m_Sockets[ SocketIdx_Broadcast ]->setBlocking( false ); 00095 00096 // Setup SearchSocket 00097 QHostAddress ip4addr( QHostAddress::Any ); 00098 00099 m_Sockets[ SocketIdx_Search ]->bind( ip4addr , m_nSearchPort ); 00100 m_Sockets[ SocketIdx_Search ]->bind( QHostAddress::Any, m_nSearchPort ); 00101 00102 // ---------------------------------------------------------------------- 00103 // Create the SSDP (Upnp Discovery) Thread. 00104 // ---------------------------------------------------------------------- 00105 00106 start(); 00107 00108 LOG(VB_UPNP, LOG_INFO, "SSDP Thread Starting soon" ); 00109 } 00110 00112 // 00114 00115 SSDP::~SSDP() 00116 { 00117 LOG(VB_UPNP, LOG_NOTICE, "Shutting Down SSDP Thread..." ); 00118 00119 DisableNotifications(); 00120 00121 m_bTermRequested = true; 00122 wait(); 00123 00124 if (m_pNotifyTask != NULL) 00125 m_pNotifyTask->Release(); 00126 00127 for (int nIdx = 0; nIdx < (int)NumberOfSockets; nIdx++ ) 00128 { 00129 if (m_Sockets[ nIdx ] != NULL ) 00130 { 00131 delete m_Sockets[ nIdx ]; 00132 } 00133 } 00134 00135 LOG(VB_UPNP, LOG_INFO, "SSDP Thread Terminated." ); 00136 } 00137 00138 void SSDP::RequestTerminate(void) 00139 { 00140 m_bTermRequested = true; 00141 } 00142 00144 // 00146 00147 void SSDP::EnableNotifications( int nServicePort ) 00148 { 00149 if ( m_pNotifyTask == NULL ) 00150 { 00151 m_nServicePort = nServicePort; 00152 00153 LOG(VB_UPNP, LOG_INFO, 00154 "SSDP::EnableNotifications() - creating new task"); 00155 m_pNotifyTask = new UPnpNotifyTask( m_nServicePort ); 00156 00157 // ------------------------------------------------------------------ 00158 // Let's make sure to hold on to a reference of the NotifyTask. 00159 // ------------------------------------------------------------------ 00160 00161 m_pNotifyTask->AddRef(); 00162 00163 // ------------------------------------------------------------------ 00164 // First Send out Notification that we are leaving the network. 00165 // ------------------------------------------------------------------ 00166 00167 LOG(VB_UPNP, LOG_INFO, 00168 "SSDP::EnableNotifications() - sending NTS_byebye"); 00169 m_pNotifyTask->SetNTS( NTS_byebye ); 00170 m_pNotifyTask->Execute( NULL ); 00171 00172 m_bAnnouncementsEnabled = true; 00173 } 00174 00175 // ------------------------------------------------------------------ 00176 // Add Announcement Task to the Queue 00177 // ------------------------------------------------------------------ 00178 00179 LOG(VB_UPNP, LOG_INFO, "SSDP::EnableNotifications() - sending NTS_alive"); 00180 00181 m_pNotifyTask->SetNTS( NTS_alive ); 00182 00183 TaskQueue::Instance()->AddTask(m_pNotifyTask); 00184 00185 LOG(VB_UPNP, LOG_INFO, 00186 "SSDP::EnableNotifications() - Task added to UPnP queue"); 00187 } 00188 00190 // 00192 00193 void SSDP::DisableNotifications() 00194 { 00195 m_bAnnouncementsEnabled = false; 00196 00197 if (m_pNotifyTask != NULL) 00198 { 00199 // Send Announcement that we are leaving. 00200 00201 m_pNotifyTask->SetNTS( NTS_byebye ); 00202 m_pNotifyTask->Execute( NULL ); 00203 } 00204 } 00205 00207 // 00209 void SSDP::PerformSearch(const QString &sST, uint timeout_secs) 00210 { 00211 timeout_secs = std::max(std::min(timeout_secs, 5U), 1U); 00212 QString rRequest = QString("M-SEARCH * HTTP/1.1\r\n" 00213 "HOST: 239.255.255.250:1900\r\n" 00214 "MAN: \"ssdp:discover\"\r\n" 00215 "MX: %1\r\n" 00216 "ST: %2\r\n" 00217 "\r\n") 00218 .arg(timeout_secs).arg(sST); 00219 00220 LOG(VB_UPNP, LOG_DEBUG, QString("\n\n%1\n").arg(rRequest)); 00221 00222 QByteArray sRequest = rRequest.toUtf8(); 00223 00224 MSocketDevice *pSocket = m_Sockets[ SocketIdx_Search ]; 00225 if ( !pSocket->isValid() ) 00226 { 00227 pSocket->setProtocol(MSocketDevice::IPv4); 00228 pSocket->setSocket(pSocket->createNewSocket(), MSocketDevice::Datagram); 00229 } 00230 00231 QHostAddress address; 00232 address.setAddress( SSDP_GROUP ); 00233 00234 int nSize = sRequest.size(); 00235 00236 if ( pSocket->writeBlock( sRequest.data(), 00237 sRequest.size(), address, SSDP_PORT ) != nSize) 00238 LOG(VB_GENERAL, LOG_INFO, 00239 "SSDP::PerformSearch - did not write entire buffer."); 00240 00241 usleep( random() % 250000 ); 00242 00243 if ( pSocket->writeBlock( sRequest.data(), 00244 sRequest.size(), address, SSDP_PORT ) != nSize) 00245 LOG(VB_GENERAL, LOG_INFO, 00246 "SSDP::PerformSearch - did not write entire buffer."); 00247 } 00248 00250 // 00252 00253 void SSDP::run() 00254 { 00255 RunProlog(); 00256 00257 fd_set read_set; 00258 struct timeval timeout; 00259 00260 LOG(VB_UPNP, LOG_INFO, "SSDP::Run - SSDP Thread Started." ); 00261 00262 // ---------------------------------------------------------------------- 00263 // Listen for new Requests 00264 // ---------------------------------------------------------------------- 00265 00266 while ( ! m_bTermRequested ) 00267 { 00268 int nMaxSocket = 0; 00269 00270 FD_ZERO( &read_set ); 00271 00272 for (uint nIdx = 0; nIdx < NumberOfSockets; nIdx++ ) 00273 { 00274 if (m_Sockets[nIdx] != NULL && m_Sockets[nIdx]->socket() >= 0) 00275 { 00276 FD_SET( m_Sockets[ nIdx ]->socket(), &read_set ); 00277 nMaxSocket = max( m_Sockets[ nIdx ]->socket(), nMaxSocket ); 00278 00279 #if 0 00280 if (m_Sockets[ nIdx ]->bytesAvailable() > 0) 00281 { 00282 LOG(VB_GENERAL, LOG_DEBUG, 00283 QString("Found Extra data before select: %1") 00284 .arg(nIdx)); 00285 ProcessData( m_Sockets[ nIdx ] ); 00286 } 00287 #endif 00288 } 00289 } 00290 00291 timeout.tv_sec = 1; 00292 timeout.tv_usec = 0; 00293 00294 int count; 00295 count = select(nMaxSocket + 1, &read_set, NULL, NULL, &timeout); 00296 for (int nIdx = 0; count && nIdx < (int)NumberOfSockets; nIdx++ ) 00297 { 00298 if (m_Sockets[nIdx] != NULL && m_Sockets[nIdx]->socket() >= 0 && 00299 FD_ISSET(m_Sockets[nIdx]->socket(), &read_set)) 00300 { 00301 #if 0 00302 LOG(VB_GENERAL, LOG_DEBUG, QString("FD_ISSET( %1 )").arg(nIdx)); 00303 #endif 00304 ProcessData(m_Sockets[nIdx]); 00305 count--; 00306 } 00307 } 00308 } 00309 00310 RunEpilog(); 00311 } 00312 00314 // 00316 00317 void SSDP::ProcessData( MSocketDevice *pSocket ) 00318 { 00319 long nBytes = 0; 00320 long nRead = 0; 00321 00322 while ((nBytes = pSocket->bytesAvailable()) > 0) 00323 { 00324 QByteArray buffer; 00325 buffer.resize(nBytes); 00326 00327 nRead = pSocket->readBlock( buffer.data(), nBytes ); 00328 00329 QHostAddress peerAddress = pSocket->peerAddress(); 00330 quint16 peerPort = pSocket->peerPort (); 00331 00332 // ------------------------------------------------------------------ 00333 QString str = QString(buffer.constData()); 00334 QStringList lines = str.split("\r\n", QString::SkipEmptyParts); 00335 QString sRequestLine = lines.size() ? lines[0] : ""; 00336 00337 lines.pop_front(); 00338 00339 // ------------------------------------------------------------------ 00340 // Parse request Type 00341 // ------------------------------------------------------------------ 00342 00343 LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessData - requestLine: %1") 00344 .arg(sRequestLine)); 00345 00346 SSDPRequestType eType = ProcessRequestLine( sRequestLine ); 00347 00348 // ------------------------------------------------------------------ 00349 // Read Headers into map 00350 // ------------------------------------------------------------------ 00351 00352 QStringMap headers; 00353 00354 for ( QStringList::Iterator it = lines.begin(); 00355 it != lines.end(); ++it ) 00356 { 00357 QString sLine = *it; 00358 QString sName = sLine.section( ':', 0, 0 ).trimmed(); 00359 QString sValue = sLine.section( ':', 1 ); 00360 00361 sValue.truncate( sValue.length() ); //-2 00362 00363 if ((sName.length() != 0) && (sValue.length() !=0)) 00364 headers.insert( sName.toLower(), sValue.trimmed() ); 00365 } 00366 00367 #if 0 00368 pSocket->SetDestAddress( peerAddress, peerPort ); 00369 #endif 00370 00371 // -------------------------------------------------------------- 00372 // See if this is a valid request 00373 // -------------------------------------------------------------- 00374 00375 switch( eType ) 00376 { 00377 case SSDP_MSearch: 00378 { 00379 // ---------------------------------------------------------- 00380 // If we haven't enabled notifications yet, then we don't 00381 // want to answer search requests. 00382 // ---------------------------------------------------------- 00383 00384 if (m_pNotifyTask != NULL) 00385 ProcessSearchRequest( headers, peerAddress, peerPort ); 00386 00387 break; 00388 } 00389 00390 case SSDP_MSearchResp: 00391 ProcessSearchResponse( headers); 00392 break; 00393 00394 case SSDP_Notify: 00395 ProcessNotify( headers ); 00396 break; 00397 00398 case SSDP_Unknown: 00399 default: 00400 LOG(VB_UPNP, LOG_ERR, 00401 "SSPD::ProcessData - Unknown request Type."); 00402 break; 00403 } 00404 } 00405 } 00406 00408 // 00410 00411 SSDPRequestType SSDP::ProcessRequestLine( const QString &sLine ) 00412 { 00413 QStringList tokens = sLine.split(m_procReqLineExp, QString::SkipEmptyParts); 00414 00415 // ---------------------------------------------------------------------- 00416 // if this is actually a response, then sLine's format will be: 00417 // HTTP/m.n <response code> <response text> 00418 // otherwise: 00419 // <method> <Resource URI> HTTP/m.n 00420 // ---------------------------------------------------------------------- 00421 00422 if ( sLine.startsWith( QString("HTTP/") )) 00423 return SSDP_MSearchResp; 00424 else 00425 { 00426 if (tokens.count() > 0) 00427 { 00428 if (tokens[0] == "M-SEARCH" ) return SSDP_MSearch; 00429 if (tokens[0] == "NOTIFY" ) return SSDP_Notify; 00430 } 00431 } 00432 00433 return SSDP_Unknown; 00434 } 00435 00437 // 00439 00440 QString SSDP::GetHeaderValue( const QStringMap &headers, 00441 const QString &sKey, const QString &sDefault ) 00442 { 00443 QStringMap::const_iterator it = headers.find( sKey.toLower() ); 00444 00445 if ( it == headers.end()) 00446 return( sDefault ); 00447 00448 return *it; 00449 } 00450 00452 // 00454 00455 bool SSDP::ProcessSearchRequest( const QStringMap &sHeaders, 00456 QHostAddress peerAddress, 00457 quint16 peerPort ) 00458 { 00459 QString sMAN = GetHeaderValue( sHeaders, "MAN", "" ); 00460 QString sST = GetHeaderValue( sHeaders, "ST" , "" ); 00461 QString sMX = GetHeaderValue( sHeaders, "MX" , "" ); 00462 int nMX = 0; 00463 00464 LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessSearchrequest : [%1] MX=%2") 00465 .arg(sST).arg(sMX)); 00466 00467 // ---------------------------------------------------------------------- 00468 // Validate Header Values... 00469 // ---------------------------------------------------------------------- 00470 00471 #if 0 00472 if ( pRequest->m_sMethod != "*" ) return false; 00473 if ( pRequest->m_sProtocol != "HTTP" ) return false; 00474 if ( pRequest->m_nMajor != 1 ) return false; 00475 #endif 00476 if ( sMAN != "\"ssdp:discover\"" ) return false; 00477 if ( sST.length() == 0 ) return false; 00478 if ( sMX.length() == 0 ) return false; 00479 if ((nMX = sMX.toInt()) == 0 ) return false; 00480 if ( nMX < 0 ) return false; 00481 00482 // ---------------------------------------------------------------------- 00483 // Adjust timeout to be a random interval between 0 and MX (max of 120) 00484 // ---------------------------------------------------------------------- 00485 00486 nMX = (nMX > 120) ? 120 : nMX; 00487 00488 int nNewMX = (int)(0 + ((unsigned short)random() % nMX)) * 1000; 00489 00490 // ---------------------------------------------------------------------- 00491 // See what they are looking for... 00492 // ---------------------------------------------------------------------- 00493 00494 if ((sST == "ssdp:all") || (sST == "upnp:rootdevice")) 00495 { 00496 UPnpSearchTask *pTask = new UPnpSearchTask( m_nServicePort, 00497 peerAddress, peerPort, sST, 00498 UPnp::g_UPnpDeviceDesc.m_rootDevice.GetUDN()); 00499 00500 #if 0 00501 // Excute task now for fastest response, queue for time-delayed response 00502 // -=>TODO: To be trully uPnp compliant, this Execute should be removed. 00503 pTask->Execute( NULL ); 00504 #endif 00505 00506 TaskQueue::Instance()->AddTask( nNewMX, pTask ); 00507 00508 return true; 00509 } 00510 00511 // ---------------------------------------------------------------------- 00512 // Look for a specific device/service 00513 // ---------------------------------------------------------------------- 00514 00515 QString sUDN = UPnp::g_UPnpDeviceDesc.FindDeviceUDN( 00516 &(UPnp::g_UPnpDeviceDesc.m_rootDevice), sST ); 00517 00518 if (sUDN.length() > 0) 00519 { 00520 UPnpSearchTask *pTask = new UPnpSearchTask( m_nServicePort, 00521 peerAddress, 00522 peerPort, 00523 sST, 00524 sUDN ); 00525 00526 // Excute task now for fastest response, queue for time-delayed response 00527 // -=>TODO: To be trully uPnp compliant, this Execute should be removed. 00528 pTask->Execute( NULL ); 00529 00530 TaskQueue::Instance()->AddTask( nNewMX, pTask ); 00531 00532 return true; 00533 } 00534 00535 return false; 00536 } 00537 00539 // 00541 00542 bool SSDP::ProcessSearchResponse( const QStringMap &headers ) 00543 { 00544 QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" ); 00545 QString sST = GetHeaderValue( headers, "ST" , "" ); 00546 QString sUSN = GetHeaderValue( headers, "USN" , "" ); 00547 QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" ); 00548 00549 LOG(VB_UPNP, LOG_DEBUG, 00550 QString( "SSDP::ProcessSearchResponse ...\n" 00551 "DescURL=%1\n" 00552 "ST =%2\n" 00553 "USN =%3\n" 00554 "Cache =%4") 00555 .arg(sDescURL).arg(sST).arg(sUSN).arg(sCache)); 00556 00557 int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive); 00558 00559 if (nPos < 0) 00560 return false; 00561 00562 if ((nPos = sCache.indexOf("=", nPos)) < 0) 00563 return false; 00564 00565 int nSecs = sCache.mid( nPos+1 ).toInt(); 00566 00567 SSDPCache::Instance()->Add( sST, sUSN, sDescURL, nSecs ); 00568 00569 return true; 00570 } 00571 00573 // 00575 00576 bool SSDP::ProcessNotify( const QStringMap &headers ) 00577 { 00578 QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" ); 00579 QString sNTS = GetHeaderValue( headers, "NTS" , "" ); 00580 QString sNT = GetHeaderValue( headers, "NT" , "" ); 00581 QString sUSN = GetHeaderValue( headers, "USN" , "" ); 00582 QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" ); 00583 00584 LOG(VB_UPNP, LOG_DEBUG, 00585 QString( "SSDP::ProcessNotify ...\n" 00586 "DescURL=%1\n" 00587 "NTS =%2\n" 00588 "NT =%3\n" 00589 "USN =%4\n" 00590 "Cache =%5" ) 00591 .arg(sDescURL).arg(sNTS).arg(sNT).arg(sUSN).arg(sCache)); 00592 00593 if (sNTS.contains( "ssdp:alive")) 00594 { 00595 int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive); 00596 00597 if (nPos < 0) 00598 return false; 00599 00600 if ((nPos = sCache.indexOf("=", nPos)) < 0) 00601 return false; 00602 00603 int nSecs = sCache.mid( nPos+1 ).toInt(); 00604 00605 SSDPCache::Instance()->Add( sNT, sUSN, sDescURL, nSecs ); 00606 00607 return true; 00608 } 00609 00610 00611 if ( sNTS.contains( "ssdp:byebye" ) ) 00612 { 00613 SSDPCache::Instance()->Remove( sNT, sUSN ); 00614 00615 return true; 00616 } 00617 00618 return false; 00619 } 00620 00623 // 00624 // SSDPExtension Implementation 00625 // 00628 00630 // 00632 00633 SSDPExtension::SSDPExtension( int nServicePort , const QString sSharePath) 00634 : HttpServerExtension( "SSDP" , sSharePath), 00635 m_nServicePort(nServicePort) 00636 { 00637 m_sUPnpDescPath = UPnp::GetConfiguration()->GetValue( "UPnP/DescXmlPath", 00638 m_sSharePath ); 00639 } 00640 00642 // 00644 00645 SSDPExtension::~SSDPExtension( ) 00646 { 00647 } 00648 00650 // 00652 00653 SSDPMethod SSDPExtension::GetMethod( const QString &sURI ) 00654 { 00655 if (sURI == "getDeviceDesc" ) return( SSDPM_GetDeviceDesc ); 00656 if (sURI == "getDeviceList" ) return( SSDPM_GetDeviceList ); 00657 00658 return( SSDPM_Unknown ); 00659 } 00660 00662 // 00664 00665 QStringList SSDPExtension::GetBasePaths() 00666 { 00667 // -=>TODO: This is very inefficient... should look into making 00668 // it a unique path. 00669 00670 return QStringList( "/" ); 00671 } 00672 00674 // 00676 00677 bool SSDPExtension::ProcessRequest( HTTPRequest *pRequest ) 00678 { 00679 if (pRequest) 00680 { 00681 if ( pRequest->m_sBaseUrl != "/") 00682 return( false ); 00683 00684 switch( GetMethod( pRequest->m_sMethod )) 00685 { 00686 case SSDPM_GetDeviceDesc: GetDeviceDesc( pRequest ); return( true ); 00687 case SSDPM_GetDeviceList: GetDeviceList( pRequest ); return( true ); 00688 00689 default: break; 00690 } 00691 } 00692 00693 return( false ); 00694 } 00695 00697 // 00699 00700 void SSDPExtension::GetDeviceDesc( HTTPRequest *pRequest ) 00701 { 00702 pRequest->m_eResponseType = ResponseTypeXML; 00703 00704 QString sUserAgent = pRequest->GetHeaderValue( "User-Agent", "" ); 00705 00706 LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceDesc - " + 00707 QString( "Host=%1 Port=%2 UserAgent=%3" ) 00708 .arg(pRequest->GetHostAddress()) .arg(m_nServicePort) 00709 .arg(sUserAgent)); 00710 00711 QTextStream stream( &(pRequest->m_response) ); 00712 00713 UPnp::g_UPnpDeviceDesc.GetValidXML( pRequest->GetHostAddress(), 00714 m_nServicePort, 00715 stream, 00716 sUserAgent ); 00717 } 00718 00720 // 00722 00723 void SSDPExtension::GetFile( HTTPRequest *pRequest, QString sFileName ) 00724 { 00725 pRequest->m_eResponseType = ResponseTypeHTML; 00726 pRequest->m_nResponseStatus = 404; 00727 00728 pRequest->m_sFileName = m_sUPnpDescPath + sFileName; 00729 00730 if (QFile::exists( pRequest->m_sFileName )) 00731 { 00732 LOG(VB_UPNP, LOG_DEBUG, 00733 QString("SSDPExtension::GetFile( %1 ) - Exists") 00734 .arg(pRequest->m_sFileName)); 00735 00736 pRequest->m_eResponseType = ResponseTypeFile; 00737 pRequest->m_nResponseStatus = 200; 00738 pRequest->m_mapRespHeaders[ "Cache-Control" ] 00739 = "no-cache=\"Ext\", max-age = 5000"; 00740 } 00741 else 00742 { 00743 LOG(VB_UPNP, LOG_ERR, 00744 QString("SSDPExtension::GetFile( %1 ) - Not Found") 00745 .arg(pRequest->m_sFileName)); 00746 } 00747 00748 } 00749 00751 // 00753 00754 void SSDPExtension::GetDeviceList( HTTPRequest *pRequest ) 00755 { 00756 LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceList"); 00757 00758 QString sXML; 00759 QTextStream os(&sXML, QIODevice::WriteOnly); 00760 00761 uint nDevCount, nEntryCount; 00762 SSDPCache::Instance()->OutputXML(os, &nDevCount, &nEntryCount); 00763 00764 NameValues list; 00765 list.push_back( 00766 NameValue("DeviceCount", (int)nDevCount)); 00767 list.push_back( 00768 NameValue("DevicesAllocated", SSDPCacheEntries::g_nAllocated)); 00769 list.push_back( 00770 NameValue("CacheEntriesFound", (int)nEntryCount)); 00771 list.push_back( 00772 NameValue("CacheEntriesAllocated", DeviceLocation::g_nAllocated)); 00773 list.push_back( 00774 NameValue("DeviceList", sXML)); 00775 00776 pRequest->FormatActionResponse(list); 00777 00778 pRequest->m_eResponseType = ResponseTypeXML; 00779 pRequest->m_nResponseStatus = 200; 00780 }
1.7.6.1