MythTV  0.26-pre
upnptasksearch.cpp
Go to the documentation of this file.
00001 
00002 // Program Name: upnptasksearch.cpp
00003 // Created     : Oct. 24, 2005
00004 //
00005 // Purpose     : UPnp Task to handle Discovery Responses
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 <compat.h>
00014 #include <stdlib.h>
00015 
00016 #include <QStringList>
00017 #include <QFile>
00018 #include <QDateTime>
00019 
00020 #include "upnp.h"
00021 #include "upnptasksearch.h"
00022 #include "mythversion.h"
00023 #include "compat.h"
00024 
00027 //
00028 // UPnpSearchTask Implementation
00029 //
00032 
00034 //
00036 
00037 UPnpSearchTask::UPnpSearchTask( int          nServicePort, 
00038                                 QHostAddress peerAddress,
00039                                 int          nPeerPort,  
00040                                 QString      sST, 
00041                                 QString      sUDN )
00042 {
00043     m_PeerAddress = peerAddress;
00044     m_nPeerPort   = nPeerPort;
00045     m_sST         = sST;
00046     m_sUDN        = sUDN;
00047     m_nServicePort= nServicePort;
00048     m_nMaxAge     = UPnp::GetConfiguration()->GetValue( "UPnP/SSDP/MaxAge" , 3600 );
00049 
00050 } 
00051 
00053 //
00055 
00056 UPnpSearchTask::~UPnpSearchTask()  
00057 { 
00058 }
00059 
00061 //
00063 
00064 void UPnpSearchTask::SendMsg( MSocketDevice  *pSocket,
00065                               QString         sST,
00066                               QString         sUDN )
00067 {
00068     QString sUSN;
00069 
00070     if (( sUDN.length() > 0) && ( sUDN != sST ))
00071         sUSN = sUDN + "::" + sST;
00072     else
00073         sUSN = sST;
00074 
00075     QString sDate = QDateTime::currentDateTime().toString( "d MMM yyyy hh:mm:ss" );  
00076 
00077     QString sData = QString ( "CACHE-CONTROL: max-age=%1\r\n"
00078                               "DATE: %2\r\n"
00079                               "EXT:\r\n"
00080                               "Server: %3, UPnP/1.0, MythTV %4\r\n"
00081                               "ST: %5\r\n"
00082                               "USN: %6\r\n"
00083                               "Content-Length: 0\r\n\r\n" )
00084                               .arg( m_nMaxAge    )
00085                               .arg( sDate )
00086                               .arg( HttpServer::GetPlatform() )
00087                               .arg( MYTH_BINARY_VERSION )
00088                               .arg( sST )
00089                               .arg( sUSN );
00090 
00091 #if 0
00092     LOG(VB_UPNP, LOG_DEBUG, QString("UPnpSearchTask::SendMsg : %1 : %2 ")
00093                         .arg(sST) .arg(sUSN));
00094 
00095     LOG(VB_UPNP, LOG_DEBUG,
00096         QString("UPnpSearchTask::SendMsg    m_PeerAddress = %1 Port=%2")
00097                         .arg(m_PeerAddress.toString()) .arg(m_nPeerPort));
00098 #endif
00099 
00100     for ( QStringList::Iterator it  = m_addressList.begin(); 
00101                                 it != m_addressList.end(); 
00102                               ++it ) 
00103     {
00104         QString ipaddress = *it;
00105 
00106         // If this looks like an IPv6 address, then enclose it in []'s
00107         if (ipaddress.contains(":"))
00108             ipaddress = "[" + ipaddress + "]";
00109 
00110         QString sHeader = QString ( "HTTP/1.1 200 OK\r\n"
00111                                     "LOCATION: http://%1:%2/getDeviceDesc\r\n" )
00112                             .arg( ipaddress )
00113                             .arg( m_nServicePort);
00114 
00115 
00116         QString  sPacket  = sHeader + sData;
00117         QByteArray scPacket = sPacket.toUtf8();
00118 
00119         // ------------------------------------------------------------------
00120         // Send Packet to UDP Socket (Send same packet twice)
00121         // ------------------------------------------------------------------
00122 
00123         pSocket->writeBlock( scPacket, scPacket.length(), m_PeerAddress,
00124                              m_nPeerPort );
00125         usleep( random() % 250000 );
00126         pSocket->writeBlock( scPacket, scPacket.length(), m_PeerAddress,
00127                              m_nPeerPort );
00128     }
00129 }
00130 
00132 //
00134 
00135 void UPnpSearchTask::Execute( TaskQueue * /*pQueue*/ )
00136 {
00137     MSocketDevice *pSocket = new MSocketDevice( MSocketDevice::Datagram );
00138 
00139     // ----------------------------------------------------------------------
00140     // Refresh IP Address List in case of changes
00141     // ----------------------------------------------------------------------
00142 
00143     m_addressList = UPnp::g_IPAddrList;
00144 
00145     // ----------------------------------------------------------------------
00146     // Check to see if this is a rootdevice or all request.
00147     // ----------------------------------------------------------------------
00148 
00149     UPnpDevice &device = UPnp::g_UPnpDeviceDesc.m_rootDevice;
00150 
00151     if ((m_sST == "upnp:rootdevice") || (m_sST == "ssdp:all" ))
00152     {
00153         SendMsg( pSocket, "upnp:rootdevice", device.GetUDN() );
00154 
00155         if (m_sST == "ssdp:all")
00156             ProcessDevice( pSocket, &device );
00157     }
00158     else
00159     {
00160         // ------------------------------------------------------------------
00161         // Send Device/Service specific response.
00162         // ------------------------------------------------------------------
00163 
00164         SendMsg( pSocket, m_sST, m_sUDN );
00165     }
00166 
00167     delete pSocket;
00168     pSocket = NULL;
00169 }
00170 
00172 //
00174 
00175 void UPnpSearchTask::ProcessDevice(
00176     MSocketDevice *pSocket, UPnpDevice *pDevice)
00177 {
00178     // ----------------------------------------------------------------------
00179     // Loop for each device and send the 2 required messages
00180     //
00181     // -=>TODO: We need to add support to only notify 
00182     //          Version 1 of a service.
00183     // ----------------------------------------------------------------------
00184 
00185     SendMsg( pSocket, pDevice->GetUDN(), "" );
00186     SendMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
00187         
00188     // ------------------------------------------------------------------
00189     // Loop for each service in this device and send the 1 required message
00190     // ------------------------------------------------------------------
00191 
00192     UPnpServiceList::const_iterator sit = pDevice->m_listServices.begin();
00193     for (; sit != pDevice->m_listServices.end(); ++sit)
00194         SendMsg(pSocket, (*sit)->m_sServiceType, pDevice->GetUDN());
00195 
00196     // ----------------------------------------------------------------------
00197     // Process any Embedded Devices
00198     // ----------------------------------------------------------------------
00199 
00200     UPnpDeviceList::const_iterator dit = pDevice->m_listDevices.begin();
00201     for (; dit != pDevice->m_listDevices.end(); ++dit)
00202         ProcessDevice( pSocket, *dit);
00203 }
00204 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends