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