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 "compat.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 ( QList<QHostAddress>::Iterator it = addressList.begin();
92  it != addressList.end();
93  ++it )
94  {
95  if ((*it).toString().isEmpty())
96  {
97  LOG(VB_GENERAL, LOG_ERR,
98  "UPnpNotifyTask::SendNotifyMsg - NULL in address list");
99  continue;
100  }
101 
102  QHostAddress ip = *it;
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  std::this_thread::sleep_for(std::chrono::milliseconds(random() % 250));
130  pSocket->writeBlock( scPacket, scPacket.length(),
131  pSocket->address(), pSocket->port() );
132  }
133 }
134 
136 //
138 
140 {
141  MSocketDevice *pMulticast = new MMulticastSocketDevice(
143 
144  // ----------------------------------------------------------------------
145  // Must send rootdevice Notification for first device.
146  // ----------------------------------------------------------------------
147 
149 
150  SendNotifyMsg( pMulticast, "upnp:rootdevice", device.GetUDN() );
151 
152  // ----------------------------------------------------------------------
153  // Process rest of notifications
154  // ----------------------------------------------------------------------
155 
156  ProcessDevice( pMulticast, &device );
157 
158  // ----------------------------------------------------------------------
159  // Clean up and reshedule task if needed (timeout = m_nMaxAge / 2).
160  // ----------------------------------------------------------------------
161 
162  delete pMulticast;
163 
164  pMulticast = nullptr;
165 
166  m_mutex.lock();
167 
168  if (m_eNTS == NTS_alive)
169  pQueue->AddTask( (m_nMaxAge / 2) * 1000, (Task *)this );
170 
171  m_mutex.unlock();
172 
173 }
174 
176 //
178 
180  MSocketDevice *pSocket, UPnpDevice *pDevice)
181 {
182  // ----------------------------------------------------------------------
183  // Loop for each device and send the 2 required messages
184  //
185  // -=>TODO: Need to add support to only notify
186  // Version 1 of a service.
187  // ----------------------------------------------------------------------
188 
189  SendNotifyMsg( pSocket, pDevice->GetUDN(), "" );
190  SendNotifyMsg( pSocket, pDevice->m_sDeviceType, pDevice->GetUDN() );
191 
192  // ------------------------------------------------------------------
193  // Loop for each service in this device and send the 1 required message
194  // ------------------------------------------------------------------
195 
196  UPnpServiceList::const_iterator sit = pDevice->m_listServices.begin();
197  for (; sit != pDevice->m_listServices.end(); ++sit)
198  SendNotifyMsg( pSocket, (*sit)->m_sServiceType, pDevice->GetUDN() );
199 
200  // ----------------------------------------------------------------------
201  // Process any Embedded Devices
202  // ----------------------------------------------------------------------
203 
204  UPnpDeviceList::iterator dit = pDevice->m_listDevices.begin();
205  for (; dit != pDevice->m_listDevices.end(); ++dit)
206  ProcessDevice( pSocket, *dit);
207 }
virtual int GetValue(const QString &sSetting, int Default)=0
QString GetNTSString()
#define SSDP_GROUP
Definition: ssdp.h:26
UPnpServiceList m_listServices
Definition: upnpdevice.h:119
void Execute(TaskQueue *) override
QString GetUDN(void) const
Definition: upnpdevice.cpp:766
UPnpDevice m_rootDevice
Definition: upnpdevice.h:148
void SendNotifyMsg(MSocketDevice *pSocket, const QString &sNT, const QString &sUDN)
UPnpNotifyTask(int nServicePort)
static Configuration * GetConfiguration()
Definition: upnp.cpp:71
void AddTask(long msec, Task *pTask)
Definition: taskqueue.cpp:173
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:120
QString m_sDeviceType
Definition: upnpdevice.h:99
UPnpNotifyNTS m_eNTS
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void ProcessDevice(MSocketDevice *pSocket, UPnpDevice *pDevice)
static QString GetServerVersion(void)
Definition: httpserver.cpp:292
#define SSDP_PORT
Definition: ssdp.h:27
static long int random(void)
Definition: compat.h:149
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:108
Definition: taskqueue.h:53
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:107