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#include <chrono> // for milliseconds
15#include <thread> // for sleep_for
16
17// Qt headers
18#include <QByteArray>
19#include <QHostAddress>
20#include <QList>
21#include <QString>
22
23// MythTV headers
27
28#include "httpserver.h"
29#include "ssdp.h"
30#include "upnp.h"
31
33 Task("UPnpNotifyTask"),
34 m_nServicePort(nServicePort),
35 m_nMaxAge(XmlConfiguration().GetDuration<std::chrono::seconds>("UPnP/SSDP/MaxAge", 1h))
36{
37}
38
39void UPnpNotifyTask::SendNotifyMsg(QUdpSocket& socket, const QString& sNT, const QString& sUDN)
40{
41 QString uniqueServiceName = sNT;
42 if (sUDN.length() > 0)
43 uniqueServiceName = sUDN + "::" + uniqueServiceName;
44
45 QByteArray data = QString("Server: %1\r\n"
46 "NTS: %3\r\n"
47 "NT: %4\r\n"
48 "USN: %5\r\n"
49 "CACHE-CONTROL: max-age=%6\r\n"
50 "Content-Length: 0\r\n\r\n")
53 sNT,
54 uniqueServiceName,
55 QString::number(m_nMaxAge.count())
56 ).toUtf8();
57
58 LOG(VB_UPNP, LOG_INFO,
59 QString("UPnpNotifyTask::SendNotifyMsg : %1:%2 : %3 : %4")
60 .arg(SSDP_GROUP, QString::number(SSDP_PORT),
61 sNT, uniqueServiceName
62 )
63 );
64
65 QList<QHostAddress> addressList = UPnp::g_IPAddrList;
66 for (const auto & addr : std::as_const(addressList))
67 {
68 if (addr.toString().isEmpty())
69 {
70 LOG(VB_GENERAL, LOG_ERR,
71 "UPnpNotifyTask::SendNotifyMsg - NULL in address list");
72 continue;
73 }
74
75 QHostAddress ip = addr;
76 // Descope the Link Local address. The scope is only valid
77 // on the server sending the announcement, not the clients
78 // that receive it
79 ip.setScopeId(QString());
80
81 QString ipaddress = ip.toString();
82
83 // If this looks like an IPv6 address, then enclose it in []'s
84 if (ipaddress.contains(":"))
85 ipaddress = "[" + ipaddress + "]";
86
87 QByteArray datagram =
88 QString("NOTIFY * HTTP/1.1\r\n"
89 "HOST: %1:%2\r\n"
90 "LOCATION: http://%3:%4/getDeviceDesc\r\n")
91 .arg(SSDP_GROUP, QString::number(SSDP_PORT),
92 ipaddress, QString::number(m_nServicePort)
93 ).toUtf8()
94 + data;
95
96 // Send Packet to Socket (Send same packet twice)
97 socket.writeDatagram(datagram, QHostAddress(QString(SSDP_GROUP)), SSDP_PORT);
98 if (m_eNTS != NTS_byebye)
99 {
100 std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(0, 250)));
101
102 socket.writeDatagram(datagram, QHostAddress(QString(SSDP_GROUP)), SSDP_PORT);
103 }
104 }
105}
106
108{
109 QUdpSocket socket;
110 socket.bind(QHostAddress(QHostAddress::AnyIPv4), 0); // required for setSocketOption()
111 socket.setSocketOption(QAbstractSocket::MulticastTtlOption, 4);
112
113 // Must send rootdevice Notification for first device.
114 SendNotifyMsg(socket, "upnp:rootdevice", UPnp::g_UPnpDeviceDesc.m_rootDevice.GetUDN());
115 // Process rest of notifications
116 ProcessDevice(socket, UPnp::g_UPnpDeviceDesc.m_rootDevice);
117
118 // reshedule task if needed (timeout = m_nMaxAge / 2).
119 m_mutex.lock();
120 if (m_eNTS == NTS_alive)
121 pQueue->AddTask( (m_nMaxAge / 2), (Task *)this );
122
123 m_mutex.unlock();
124}
125
126void UPnpNotifyTask::ProcessDevice(QUdpSocket& socket, const UPnpDevice& device)
127{
128 // Loop for each device and send the 2 required messages
129 // -=>TODO: Need to add support to only notify
130 // Version 1 of a service.
131 SendNotifyMsg(socket, device.GetUDN(), "");
132 SendNotifyMsg(socket, device.m_sDeviceType, device.GetUDN());
133 // Loop for each service in this device and send the 1 required message
134 for (const auto* service : std::as_const(device.m_listServices))
135 {
136 SendNotifyMsg(socket, service->m_sServiceType, device.GetUDN());
137 }
138
139 // Process any Embedded Devices
140 for (const auto* embedded_device : std::as_const(device.m_listDevices))
141 {
142 ProcessDevice(socket, *embedded_device);
143 }
144}
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
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
QString GetNTSString()
std::chrono::seconds m_nMaxAge
UPnpNotifyTask(int nServicePort)
void ProcessDevice(QUdpSocket &socket, const UPnpDevice &device)
void SendNotifyMsg(QUdpSocket &socket, const QString &sNT, const QString &sUDN)
void Execute(TaskQueue *pQueue) override
UPnpNotifyNTS m_eNTS
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:108
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:107
#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
STL namespace.
static constexpr uint16_t SSDP_PORT
Definition: ssdp.h:27
static constexpr const char * SSDP_GROUP
Definition: ssdp.h:26
@ NTS_alive
@ NTS_byebye