MythTV  0.26-pre
ssdp.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends