MythTV  master
upnptasksearch.cpp
Go to the documentation of this file.
1 // Program Name: upnptasksearch.cpp
3 // Created : Oct. 24, 2005
4 //
5 // Purpose : UPnp Task to handle Discovery Responses
6 //
7 // Copyright (c) 2005 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see COPYING for details
10 //
12 
13 #include <chrono> // for milliseconds
14 #include <cstdlib>
15 #include <thread> // for sleep_for
16 
17 #include <QDateTime>
18 #include <QFile>
19 #include <QStringList>
20 #include <utility>
21 
22 #include "upnp.h"
23 #include "upnptasksearch.h"
24 #include "mythversion.h"
25 #include "compat.h"
26 #include "mythmiscutil.h"
27 #include "mythdate.h"
28 
29 static QPair<QHostAddress, int> kLinkLocal6 =
30  QHostAddress::parseSubnet("fe80::/10");
31 
34 //
35 // UPnpSearchTask Implementation
36 //
39 
41 //
43 
44 UPnpSearchTask::UPnpSearchTask( int nServicePort,
45  QHostAddress peerAddress,
46  int nPeerPort,
47  QString sST,
48  QString sUDN ) :
49  Task("UPnpSearchTask")
50 {
51  m_peerAddress = std::move(peerAddress);
52  m_nPeerPort = nPeerPort;
53  m_sST = std::move(sST);
54  m_sUDN = std::move(sUDN);
55  m_nServicePort= nServicePort;
56  m_nMaxAge = UPnp::GetConfiguration()->GetValue( "UPnP/SSDP/MaxAge" , 3600 );
57 
58 }
59 
61 //
63 
64 void UPnpSearchTask::SendMsg( MSocketDevice *pSocket,
65  const QString& sST,
66  const QString& sUDN )
67 {
68  QString sUSN;
69 
70  if (( sUDN.length() > 0) && ( sUDN != sST ))
71  sUSN = sUDN + "::" + sST;
72  else
73  sUSN = sST;
74 
75  QString sDate = MythDate::current().toString( "d MMM yyyy hh:mm:ss" );
76 
77  QString sData = QString ( "CACHE-CONTROL: max-age=%1\r\n"
78  "DATE: %2\r\n"
79  "EXT:\r\n"
80  "Server: %3\r\n"
81  "ST: %4\r\n"
82  "USN: %5\r\n"
83  "Content-Length: 0\r\n\r\n" )
84  .arg( m_nMaxAge )
85  .arg( sDate )
87  .arg( sST )
88  .arg( sUSN );
89 
90 #if 0
91  LOG(VB_UPNP, LOG_DEBUG, QString("UPnpSearchTask::SendMsg : %1 : %2 ")
92  .arg(sST) .arg(sUSN));
93 
94  LOG(VB_UPNP, LOG_DEBUG,
95  QString("UPnpSearchTask::SendMsg m_peerAddress = %1 Port=%2")
96  .arg(m_peerAddress.toString()) .arg(m_nPeerPort));
97 #endif
98 
99  for (const auto & addr : qAsConst(m_addressList))
100  {
101  QString ipaddress;
102 
103  // Avoid announcing the localhost address
104  if (addr == QHostAddress::LocalHost ||
105  addr == QHostAddress::LocalHostIPv6 ||
106  addr == QHostAddress::AnyIPv4 ||
107  addr == QHostAddress::AnyIPv6)
108  continue;
109 
110  QHostAddress ip = addr;
111  // Descope the Link Local address. The scope is only valid
112  // on the server sending the announcement, not the clients
113  // that receive it
114  ip.setScopeId(QString());
115 
116  // If this looks like an IPv6 address, then enclose it in []'s
117  if (ip.protocol() == QAbstractSocket::IPv6Protocol)
118  ipaddress = "[" + ip.toString() + "]";
119  else
120  ipaddress = ip.toString();
121 
122  QString sHeader = QString ( "HTTP/1.1 200 OK\r\n"
123  "LOCATION: http://%1:%2/getDeviceDesc\r\n" )
124  .arg( ipaddress )
125  .arg( m_nServicePort);
126 
127 
128  QString sPacket = sHeader + sData;
129  QByteArray scPacket = sPacket.toUtf8();
130 
131  // ------------------------------------------------------------------
132  // Send Packet to UDP Socket (Send same packet twice)
133  // ------------------------------------------------------------------
134 
135  pSocket->writeBlock( scPacket, scPacket.length(), m_peerAddress,
136  m_nPeerPort );
137  std::this_thread::sleep_for( std::chrono::milliseconds( MythRandom() % 250 ));
138  pSocket->writeBlock( scPacket, scPacket.length(), m_peerAddress,
139  m_nPeerPort );
140  }
141 }
142 
144 //
146 
147 void UPnpSearchTask::Execute( TaskQueue * /*pQueue*/ )
148 {
149  auto *pSocket = new MSocketDevice( MSocketDevice::Datagram );
150 
151  // ----------------------------------------------------------------------
152  // Refresh IP Address List in case of changes
153  // ----------------------------------------------------------------------
154 
156 
157  // ----------------------------------------------------------------------
158  // Check to see if this is a rootdevice or all request.
159  // ----------------------------------------------------------------------
160 
162 
163  if ((m_sST == "upnp:rootdevice") || (m_sST == "ssdp:all" ))
164  {
165  SendMsg( pSocket, "upnp:rootdevice", device.GetUDN() );
166 
167  if (m_sST == "ssdp:all")
168  ProcessDevice( pSocket, &device );
169  }
170  else
171  {
172  // ------------------------------------------------------------------
173  // Send Device/Service specific response.
174  // ------------------------------------------------------------------
175 
176  SendMsg( pSocket, m_sST, m_sUDN );
177  }
178 
179  delete pSocket;
180  pSocket = nullptr;
181 }
182 
184 //
186 
188  MSocketDevice *pSocket, UPnpDevice *pDevice)
189 {
190  // ----------------------------------------------------------------------
191  // Loop for each device and send the 2 required messages
192  //
193  // -=>TODO: We need to add support to only notify
194  // Version 1 of a service.
195  // ----------------------------------------------------------------------
196 
197  SendMsg( pSocket, pDevice->GetUDN(), "" );
198  SendMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
199 
200  // ------------------------------------------------------------------
201  // Loop for each service in this device and send the 1 required message
202  // ------------------------------------------------------------------
203 
204  for (auto sit = pDevice->m_listServices.cbegin();
205  sit != pDevice->m_listServices.cend(); ++sit)
206  SendMsg(pSocket, (*sit)->m_sServiceType, pDevice->GetUDN());
207 
208  // ----------------------------------------------------------------------
209  // Process any Embedded Devices
210  // ----------------------------------------------------------------------
211 
212  for (auto *device : qAsConst(pDevice->m_listDevices))
213  ProcessDevice( pSocket, device);
214 }
215 
kLinkLocal6
static QPair< QHostAddress, int > kLinkLocal6
Definition: upnptasksearch.cpp:29
UPnpSearchTask::m_nServicePort
int m_nServicePort
Definition: upnptasksearch.h:45
HttpServer::GetServerVersion
static QString GetServerVersion(void)
Definition: httpserver.cpp:285
UPnpDevice::m_listServices
UPnpServiceList m_listServices
Definition: upnpdevice.h:123
UPnpSearchTask::m_nMaxAge
int m_nMaxAge
Definition: upnptasksearch.h:46
UPnpSearchTask::SendMsg
void SendMsg(MSocketDevice *pSocket, const QString &sST, const QString &sUDN)
Definition: upnptasksearch.cpp:64
UPnpSearchTask::m_peerAddress
QHostAddress m_peerAddress
Definition: upnptasksearch.h:48
UPnpSearchTask::m_sST
QString m_sST
Definition: upnptasksearch.h:50
upnptasksearch.h
arg
arg(title).arg(filename).arg(doDelete))
UPnpDevice::m_sDeviceType
QString m_sDeviceType
Definition: upnpdevice.h:103
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
UPnpSearchTask::Execute
void Execute(TaskQueue *pQueue) override
Definition: upnptasksearch.cpp:147
TaskQueue
Definition: taskqueue.h:82
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
UPnpSearchTask::UPnpSearchTask
UPnpSearchTask(int nServicePort, QHostAddress peerAddress, int nPeerPort, QString sST, QString sUDN)
Definition: upnptasksearch.cpp:44
mythversion.h
UPnpSearchTask::m_nPeerPort
int m_nPeerPort
Definition: upnptasksearch.h:49
UPnpDeviceDesc::m_rootDevice
UPnpDevice m_rootDevice
Definition: upnpdevice.h:152
mythdate.h
upnp.h
compat.h
Task
Definition: taskqueue.h:54
UPnpDevice::m_listDevices
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:124
UPnpSearchTask::ProcessDevice
void ProcessDevice(MSocketDevice *pSocket, UPnpDevice *pDevice)
Definition: upnptasksearch.cpp:187
UPnpDevice
Definition: upnpdevice.h:100
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:24
mythmiscutil.h
UPnpSearchTask::m_addressList
QList< QHostAddress > m_addressList
Definition: upnptasksearch.h:44
Configuration::GetValue
virtual int GetValue(const QString &sSetting, int Default)=0
UPnp::GetConfiguration
static Configuration * GetConfiguration()
Definition: upnp.cpp:84
UPnpSearchTask::m_sUDN
QString m_sUDN
Definition: upnptasksearch.h:51
UPnpDevice::GetUDN
QString GetUDN(void) const
Definition: upnpdevice.cpp:766
UPnp::g_UPnpDeviceDesc
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:112
UPnp::g_IPAddrList
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:113