MythTV  master
upnptasknotify.cpp
Go to the documentation of this file.
1 // Program Name: upnptasknotify.cpp
3 // Created : Oct. 24, 2005
4 //
5 // Purpose : UPnp Task to send Notification messages
6 //
7 // Copyright (c) 2005 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see LICENSE for details
10 //
12 #include "upnptasknotify.h"
13 
14 // ANSI C headers
15 #include <cstdlib>
16 
17 #include <chrono> // for milliseconds
18 #include <thread> // for sleep_for
19 
20 // Qt headers
21 #include <QStringList>
22 #include <QUuid>
23 #include <QFile>
24 
25 // MythTV headers
28 #include "libmythbase/mythrandom.h"
29 #include "libmythbase/mythversion.h"
30 
31 #include "mmulticastsocketdevice.h"
32 #include "upnp.h"
33 
36 //
37 // UPnpNotifyTask Implementation
38 //
41 
43 //
45 
46 UPnpNotifyTask::UPnpNotifyTask( int nServicePort ) :
47  Task("UPnpNotifyTask")
48 {
49  m_nServicePort = nServicePort;
50 
51  m_nMaxAge = XmlConfiguration().GetDuration<std::chrono::seconds>("UPnP/SSDP/MaxAge" , 1h);
52 }
53 
55 //
57 
58 void UPnpNotifyTask::SendNotifyMsg( MSocketDevice *pSocket,
59  const QString& sNT,
60  const QString& sUDN )
61 {
62  QString sUSN;
63 
64  if ( sUDN.length() > 0)
65  sUSN = sUDN + "::" + sNT;
66  else
67  sUSN = sNT;
68 
69  QString sData = QString ( "Server: %1\r\n"
70  "NTS: %3\r\n"
71  "NT: %4\r\n"
72  "USN: %5\r\n"
73  "CACHE-CONTROL: max-age=%6\r\n"
74  "Content-Length: 0\r\n\r\n" )
76  GetNTSString(),
77  sNT,
78  sUSN,
79  QString::number(m_nMaxAge.count()));
80 
81  LOG(VB_UPNP, LOG_INFO,
82  QString("UPnpNotifyTask::SendNotifyMsg : %1:%2 : %3 : %4")
83  .arg(pSocket->address().toString(), QString::number(pSocket->port()),
84  sNT, sUSN));
85 
86  QMutexLocker qml(&m_mutex); // for addressList
87 
88  // -------------------------------------------------------------------
89  // Refresh IP Address List in case of changes
90  // -------------------------------------------------------------------
91 
92  QList<QHostAddress> addressList = UPnp::g_IPAddrList;
93 
94  for (const auto & addr : qAsConst(addressList))
95  {
96  if (addr.toString().isEmpty())
97  {
98  LOG(VB_GENERAL, LOG_ERR,
99  "UPnpNotifyTask::SendNotifyMsg - NULL in address list");
100  continue;
101  }
102 
103  QHostAddress ip = addr;
104  // Descope the Link Local address. The scope is only valid
105  // on the server sending the announcement, not the clients
106  // that receive it
107  ip.setScopeId(QString());
108 
109  QString ipaddress = ip.toString();
110 
111  // If this looks like an IPv6 address, then enclose it in []'s
112  if (ipaddress.contains(":"))
113  ipaddress = "[" + ipaddress + "]";
114 
115  QString sHeader = QString("NOTIFY * HTTP/1.1\r\n"
116  "HOST: %1:%2\r\n"
117  "LOCATION: http://%3:%4/getDeviceDesc\r\n")
118  .arg(pSocket->address().toString()) .arg(pSocket->port())
119  .arg(ipaddress) .arg(m_nServicePort);
120 
121  QString sPacket = sHeader + sData;
122  QByteArray scPacket = sPacket.toUtf8();
123 
124  // ---------------------------------------------------------------
125  // Send Packet to Socket (Send same packet twice)
126  // ---------------------------------------------------------------
127 
128  pSocket->writeBlock( scPacket, scPacket.length(),
129  pSocket->address(), pSocket->port() );
130  if (m_eNTS != NTS_byebye)
131  {
132  std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(0, 250)));
133 
134  pSocket->writeBlock( scPacket, scPacket.length(),
135  pSocket->address(), pSocket->port() );
136  }
137  }
138 }
139 
141 //
143 
145 {
146  MSocketDevice *pMulticast = new MMulticastSocketDevice(
148 
149  // ----------------------------------------------------------------------
150  // Must send rootdevice Notification for first device.
151  // ----------------------------------------------------------------------
152 
154 
155  SendNotifyMsg( pMulticast, "upnp:rootdevice", device.GetUDN() );
156 
157  // ----------------------------------------------------------------------
158  // Process rest of notifications
159  // ----------------------------------------------------------------------
160 
161  ProcessDevice( pMulticast, &device );
162 
163  // ----------------------------------------------------------------------
164  // Clean up and reshedule task if needed (timeout = m_nMaxAge / 2).
165  // ----------------------------------------------------------------------
166 
167  delete pMulticast;
168 
169  pMulticast = nullptr;
170 
171  m_mutex.lock();
172 
173  if (m_eNTS == NTS_alive)
174  pQueue->AddTask( (m_nMaxAge / 2), (Task *)this );
175 
176  m_mutex.unlock();
177 
178 }
179 
181 //
183 
185  MSocketDevice *pSocket, UPnpDevice *pDevice)
186 {
187  // ----------------------------------------------------------------------
188  // Loop for each device and send the 2 required messages
189  //
190  // -=>TODO: Need to add support to only notify
191  // Version 1 of a service.
192  // ----------------------------------------------------------------------
193 
194  SendNotifyMsg( pSocket, pDevice->GetUDN(), "" );
195  SendNotifyMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
196 
197  // ------------------------------------------------------------------
198  // Loop for each service in this device and send the 1 required message
199  // ------------------------------------------------------------------
200 
201  for (auto sit = pDevice->m_listServices.cbegin(); sit != pDevice->m_listServices.cend(); ++sit)
202  SendNotifyMsg( pSocket, (*sit)->m_sServiceType, pDevice->GetUDN() );
203 
204  // ----------------------------------------------------------------------
205  // Process any Embedded Devices
206  // ----------------------------------------------------------------------
207 
208  for (const auto & dev : qAsConst(pDevice->m_listDevices))
209  ProcessDevice( pSocket, dev);
210 }
HttpServer::GetServerVersion
static QString GetServerVersion(void)
Definition: httpserver.cpp:288
mythrandom.h
UPnpDevice::m_listServices
UPnpServiceList m_listServices
Definition: upnpdevice.h:126
MMulticastSocketDevice
Definition: mmulticastsocketdevice.h:48
UPnpNotifyTask::m_mutex
QMutex m_mutex
Definition: upnptasknotify.h:57
UPnpDevice::m_sDeviceType
QString m_sDeviceType
Definition: upnpdevice.h:106
NTS_alive
@ NTS_alive
Definition: upnptasknotify.h:41
NTS_byebye
@ NTS_byebye
Definition: upnptasknotify.h:42
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
XmlConfiguration::GetDuration
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDuration(const QString &setting, T defaultValue=T::zero())
Definition: configuration.h:114
TaskQueue
Definition: taskqueue.h:82
UPnpNotifyTask::m_eNTS
UPnpNotifyNTS m_eNTS
Definition: upnptasknotify.h:63
XmlConfiguration
Definition: configuration.h:38
UPnpDeviceDesc::m_rootDevice
UPnpDevice m_rootDevice
Definition: upnpdevice.h:155
upnp.h
mythlogging.h
Task
Definition: taskqueue.h:54
UPnpDevice::m_listDevices
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:127
UPnpDevice
Definition: upnpdevice.h:102
UPnpNotifyTask::m_nMaxAge
std::chrono::seconds m_nMaxAge
Definition: upnptasknotify.h:61
UPnpNotifyTask::SendNotifyMsg
void SendNotifyMsg(MSocketDevice *pSocket, const QString &sNT, const QString &sUDN)
Definition: upnptasknotify.cpp:58
UPnpNotifyTask::UPnpNotifyTask
UPnpNotifyTask(int nServicePort)
Definition: upnptasknotify.cpp:46
UPnpNotifyTask::ProcessDevice
void ProcessDevice(MSocketDevice *pSocket, UPnpDevice *pDevice)
Definition: upnptasknotify.cpp:184
TaskQueue::AddTask
void AddTask(std::chrono::milliseconds msec, Task *pTask)
Add a task to run in the future.
Definition: taskqueue.cpp:172
configuration.h
UPnpNotifyTask::m_nServicePort
int m_nServicePort
Definition: upnptasknotify.h:60
upnptasknotify.h
mmulticastsocketdevice.h
SSDP_GROUP
static constexpr const char * SSDP_GROUP
Definition: ssdp.h:29
UPnpDevice::GetUDN
QString GetUDN(void) const
Definition: upnpdevice.cpp:765
UPnpNotifyTask::Execute
void Execute(TaskQueue *pQueue) override
Definition: upnptasknotify.cpp:144
UPnp::g_UPnpDeviceDesc
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:109
UPnp::g_IPAddrList
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:110
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
SSDP_PORT
static constexpr uint16_t SSDP_PORT
Definition: ssdp.h:30
UPnpNotifyTask::GetNTSString
QString GetNTSString()
Definition: upnptasknotify.h:83