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 COPYING for details
10 //
12 
13 // ANSI C headers
14 #include <cstdlib>
15 
16 #include <chrono> // for milliseconds
17 #include <thread> // for sleep_for
18 
19 // Qt headers
20 #include <QStringList>
21 #include <QUuid>
22 #include <QFile>
23 
24 // MythTV headers
25 #include "mmulticastsocketdevice.h"
26 #include "mythlogging.h"
27 #include "mythversion.h"
28 #include "mythmiscutil.h"
29 #include "upnp.h"
30 
33 //
34 // UPnpNotifyTask Implementation
35 //
38 
40 //
42 
43 UPnpNotifyTask::UPnpNotifyTask( int nServicePort ) :
44  Task("UPnpNotifyTask")
45 {
46  m_nServicePort = nServicePort;
47 
48  m_nMaxAge = UPnp::GetConfiguration()->GetValue( "UPnP/SSDP/MaxAge" , 3600 );
49 }
50 
52 //
54 
55 void UPnpNotifyTask::SendNotifyMsg( MSocketDevice *pSocket,
56  const QString& sNT,
57  const QString& sUDN )
58 {
59  QString sUSN;
60 
61  if ( sUDN.length() > 0)
62  sUSN = sUDN + "::" + sNT;
63  else
64  sUSN = sNT;
65 
66  QString sData = QString ( "Server: %1\r\n"
67  "NTS: %3\r\n"
68  "NT: %4\r\n"
69  "USN: %5\r\n"
70  "CACHE-CONTROL: max-age=%6\r\n"
71  "Content-Length: 0\r\n\r\n" )
73  .arg( GetNTSString() )
74  .arg( sNT )
75  .arg( sUSN )
76  .arg( m_nMaxAge );
77 
78  LOG(VB_UPNP, LOG_INFO,
79  QString("UPnpNotifyTask::SendNotifyMsg : %1:%2 : %3 : %4")
80  .arg(pSocket->address().toString()) .arg(pSocket->port())
81  .arg(sNT) .arg(sUSN));
82 
83  QMutexLocker qml(&m_mutex); // for addressList
84 
85  // -------------------------------------------------------------------
86  // Refresh IP Address List in case of changes
87  // -------------------------------------------------------------------
88 
89  QList<QHostAddress> addressList = UPnp::g_IPAddrList;
90 
91  for (const auto & addr : qAsConst(addressList))
92  {
93  if (addr.toString().isEmpty())
94  {
95  LOG(VB_GENERAL, LOG_ERR,
96  "UPnpNotifyTask::SendNotifyMsg - NULL in address list");
97  continue;
98  }
99 
100  QHostAddress ip = addr;
101  // Descope the Link Local address. The scope is only valid
102  // on the server sending the announcement, not the clients
103  // that receive it
104  ip.setScopeId(QString());
105 
106  QString ipaddress = ip.toString();
107 
108  // If this looks like an IPv6 address, then enclose it in []'s
109  if (ipaddress.contains(":"))
110  ipaddress = "[" + ipaddress + "]";
111 
112  QString sHeader = QString("NOTIFY * HTTP/1.1\r\n"
113  "HOST: %1:%2\r\n"
114  "LOCATION: http://%3:%4/getDeviceDesc\r\n")
115  .arg(pSocket->address().toString()) .arg(pSocket->port())
116  .arg(ipaddress) .arg(m_nServicePort);
117 
118  QString sPacket = sHeader + sData;
119  QByteArray scPacket = sPacket.toUtf8();
120 
121  // ---------------------------------------------------------------
122  // Send Packet to Socket (Send same packet twice)
123  // ---------------------------------------------------------------
124 
125  pSocket->writeBlock( scPacket, scPacket.length(),
126  pSocket->address(), pSocket->port() );
127  std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom() % 250));
128  pSocket->writeBlock( scPacket, scPacket.length(),
129  pSocket->address(), pSocket->port() );
130  }
131 }
132 
134 //
136 
138 {
139  MSocketDevice *pMulticast = new MMulticastSocketDevice(
141 
142  // ----------------------------------------------------------------------
143  // Must send rootdevice Notification for first device.
144  // ----------------------------------------------------------------------
145 
147 
148  SendNotifyMsg( pMulticast, "upnp:rootdevice", device.GetUDN() );
149 
150  // ----------------------------------------------------------------------
151  // Process rest of notifications
152  // ----------------------------------------------------------------------
153 
154  ProcessDevice( pMulticast, &device );
155 
156  // ----------------------------------------------------------------------
157  // Clean up and reshedule task if needed (timeout = m_nMaxAge / 2).
158  // ----------------------------------------------------------------------
159 
160  delete pMulticast;
161 
162  pMulticast = nullptr;
163 
164  m_mutex.lock();
165 
166  if (m_eNTS == NTS_alive)
167  pQueue->AddTask( (m_nMaxAge / 2) * 1000, (Task *)this );
168 
169  m_mutex.unlock();
170 
171 }
172 
174 //
176 
178  MSocketDevice *pSocket, UPnpDevice *pDevice)
179 {
180  // ----------------------------------------------------------------------
181  // Loop for each device and send the 2 required messages
182  //
183  // -=>TODO: Need to add support to only notify
184  // Version 1 of a service.
185  // ----------------------------------------------------------------------
186 
187  SendNotifyMsg( pSocket, pDevice->GetUDN(), "" );
188  SendNotifyMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
189 
190  // ------------------------------------------------------------------
191  // Loop for each service in this device and send the 1 required message
192  // ------------------------------------------------------------------
193 
194  for (auto sit = pDevice->m_listServices.cbegin(); sit != pDevice->m_listServices.cend(); ++sit)
195  SendNotifyMsg( pSocket, (*sit)->m_sServiceType, pDevice->GetUDN() );
196 
197  // ----------------------------------------------------------------------
198  // Process any Embedded Devices
199  // ----------------------------------------------------------------------
200 
201  for (const auto & dev : qAsConst(pDevice->m_listDevices))
202  ProcessDevice( pSocket, dev);
203 }
HttpServer::GetServerVersion
static QString GetServerVersion(void)
Definition: httpserver.cpp:288
UPnpDevice::m_listServices
UPnpServiceList m_listServices
Definition: upnpdevice.h:123
SSDP_PORT
#define SSDP_PORT
Definition: ssdp.h:27
MMulticastSocketDevice
Definition: mmulticastsocketdevice.h:48
arg
arg(title).arg(filename).arg(doDelete))
UPnpNotifyTask::m_mutex
QMutex m_mutex
Definition: upnptasknotify.h:56
UPnpDevice::m_sDeviceType
QString m_sDeviceType
Definition: upnpdevice.h:103
NTS_alive
@ NTS_alive
Definition: upnptasknotify.h:40
TaskQueue::AddTask
void AddTask(long msec, Task *pTask)
Definition: taskqueue.cpp:170
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
UPnpNotifyTask::m_nMaxAge
int m_nMaxAge
Definition: upnptasknotify.h:60
TaskQueue
Definition: taskqueue.h:82
UPnpNotifyTask::m_eNTS
UPnpNotifyNTS m_eNTS
Definition: upnptasknotify.h:62
mythversion.h
UPnpDeviceDesc::m_rootDevice
UPnpDevice m_rootDevice
Definition: upnpdevice.h:152
upnp.h
mythlogging.h
Task
Definition: taskqueue.h:54
UPnpDevice::m_listDevices
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:124
UPnpDevice
Definition: upnpdevice.h:100
UPnpNotifyTask::SendNotifyMsg
void SendNotifyMsg(MSocketDevice *pSocket, const QString &sNT, const QString &sUDN)
Definition: upnptasknotify.cpp:55
UPnpNotifyTask::UPnpNotifyTask
UPnpNotifyTask(int nServicePort)
Definition: upnptasknotify.cpp:43
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:24
UPnpNotifyTask::ProcessDevice
void ProcessDevice(MSocketDevice *pSocket, UPnpDevice *pDevice)
Definition: upnptasknotify.cpp:177
mythmiscutil.h
UPnpNotifyTask::m_nServicePort
int m_nServicePort
Definition: upnptasknotify.h:59
Configuration::GetValue
virtual int GetValue(const QString &sSetting, int Default)=0
mmulticastsocketdevice.h
UPnp::GetConfiguration
static Configuration * GetConfiguration()
Definition: upnp.cpp:84
SSDP_GROUP
#define SSDP_GROUP
Definition: ssdp.h:26
UPnpDevice::GetUDN
QString GetUDN(void) const
Definition: upnpdevice.cpp:766
UPnpNotifyTask::Execute
void Execute(TaskQueue *pQueue) override
Definition: upnptasknotify.cpp:137
UPnp::g_UPnpDeviceDesc
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:112
UPnp::g_IPAddrList
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:113
UPnpNotifyTask::GetNTSString
QString GetNTSString()
Definition: upnptasknotify.h:82