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  m_nServicePort(nServicePort)
49 {
50  m_nMaxAge = XmlConfiguration().GetDuration<std::chrono::seconds>("UPnP/SSDP/MaxAge" , 1h);
51 }
52 
54 //
56 
57 void UPnpNotifyTask::SendNotifyMsg( MSocketDevice *pSocket,
58  const QString& sNT,
59  const QString& sUDN )
60 {
61  QString sUSN;
62 
63  if ( sUDN.length() > 0)
64  sUSN = sUDN + "::" + sNT;
65  else
66  sUSN = sNT;
67 
68  QString sData = QString ( "Server: %1\r\n"
69  "NTS: %3\r\n"
70  "NT: %4\r\n"
71  "USN: %5\r\n"
72  "CACHE-CONTROL: max-age=%6\r\n"
73  "Content-Length: 0\r\n\r\n" )
75  GetNTSString(),
76  sNT,
77  sUSN,
78  QString::number(m_nMaxAge.count()));
79 
80  LOG(VB_UPNP, LOG_INFO,
81  QString("UPnpNotifyTask::SendNotifyMsg : %1:%2 : %3 : %4")
82  .arg(pSocket->address().toString(), QString::number(pSocket->port()),
83  sNT, sUSN));
84 
85  QMutexLocker qml(&m_mutex); // for addressList
86 
87  // -------------------------------------------------------------------
88  // Refresh IP Address List in case of changes
89  // -------------------------------------------------------------------
90 
91  QList<QHostAddress> addressList = UPnp::g_IPAddrList;
92 
93  for (const auto & addr : std::as_const(addressList))
94  {
95  if (addr.toString().isEmpty())
96  {
97  LOG(VB_GENERAL, LOG_ERR,
98  "UPnpNotifyTask::SendNotifyMsg - NULL in address list");
99  continue;
100  }
101 
102  QHostAddress ip = addr;
103  // Descope the Link Local address. The scope is only valid
104  // on the server sending the announcement, not the clients
105  // that receive it
106  ip.setScopeId(QString());
107 
108  QString ipaddress = ip.toString();
109 
110  // If this looks like an IPv6 address, then enclose it in []'s
111  if (ipaddress.contains(":"))
112  ipaddress = "[" + ipaddress + "]";
113 
114  QString sHeader = QString("NOTIFY * HTTP/1.1\r\n"
115  "HOST: %1:%2\r\n"
116  "LOCATION: http://%3:%4/getDeviceDesc\r\n")
117  .arg(pSocket->address().toString()) .arg(pSocket->port())
118  .arg(ipaddress) .arg(m_nServicePort);
119 
120  QString sPacket = sHeader + sData;
121  QByteArray scPacket = sPacket.toUtf8();
122 
123  // ---------------------------------------------------------------
124  // Send Packet to Socket (Send same packet twice)
125  // ---------------------------------------------------------------
126 
127  pSocket->writeBlock( scPacket, scPacket.length(),
128  pSocket->address(), pSocket->port() );
129  if (m_eNTS != NTS_byebye)
130  {
131  std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(0, 250)));
132 
133  pSocket->writeBlock( scPacket, scPacket.length(),
134  pSocket->address(), pSocket->port() );
135  }
136  }
137 }
138 
140 //
142 
144 {
145  MSocketDevice *pMulticast = new MMulticastSocketDevice(
147 
148  // ----------------------------------------------------------------------
149  // Must send rootdevice Notification for first device.
150  // ----------------------------------------------------------------------
151 
153 
154  SendNotifyMsg( pMulticast, "upnp:rootdevice", device.GetUDN() );
155 
156  // ----------------------------------------------------------------------
157  // Process rest of notifications
158  // ----------------------------------------------------------------------
159 
160  ProcessDevice( pMulticast, &device );
161 
162  // ----------------------------------------------------------------------
163  // Clean up and reshedule task if needed (timeout = m_nMaxAge / 2).
164  // ----------------------------------------------------------------------
165 
166  delete pMulticast;
167 
168  pMulticast = nullptr;
169 
170  m_mutex.lock();
171 
172  if (m_eNTS == NTS_alive)
173  pQueue->AddTask( (m_nMaxAge / 2), (Task *)this );
174 
175  m_mutex.unlock();
176 
177 }
178 
180 //
182 
184  MSocketDevice *pSocket, UPnpDevice *pDevice)
185 {
186  // ----------------------------------------------------------------------
187  // Loop for each device and send the 2 required messages
188  //
189  // -=>TODO: Need to add support to only notify
190  // Version 1 of a service.
191  // ----------------------------------------------------------------------
192 
193  SendNotifyMsg( pSocket, pDevice->GetUDN(), "" );
194  SendNotifyMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
195 
196  // ------------------------------------------------------------------
197  // Loop for each service in this device and send the 1 required message
198  // ------------------------------------------------------------------
199 
200  for (auto sit = pDevice->m_listServices.cbegin(); sit != pDevice->m_listServices.cend(); ++sit)
201  SendNotifyMsg( pSocket, (*sit)->m_sServiceType, pDevice->GetUDN() );
202 
203  // ----------------------------------------------------------------------
204  // Process any Embedded Devices
205  // ----------------------------------------------------------------------
206 
207  for (const auto & dev : std::as_const(pDevice->m_listDevices))
208  ProcessDevice( pSocket, dev);
209 }
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
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:57
UPnpNotifyTask::UPnpNotifyTask
UPnpNotifyTask(int nServicePort)
Definition: upnptasknotify.cpp:46
UPnpNotifyTask::ProcessDevice
void ProcessDevice(MSocketDevice *pSocket, UPnpDevice *pDevice)
Definition: upnptasknotify.cpp:183
NTS_byebye
@ NTS_byebye
Definition: upnptasknotify.h:42
TaskQueue::AddTask
void AddTask(std::chrono::milliseconds msec, Task *pTask)
Add a task to run in the future.
Definition: taskqueue.cpp:173
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:783
UPnpNotifyTask::Execute
void Execute(TaskQueue *pQueue) override
Definition: upnptasknotify.cpp:143
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
NTS_alive
@ NTS_alive
Definition: upnptasknotify.h:41
SSDP_PORT
static constexpr uint16_t SSDP_PORT
Definition: ssdp.h:30
UPnpNotifyTask::GetNTSString
QString GetNTSString()
Definition: upnptasknotify.h:83