MythTV master
upnp.cpp
Go to the documentation of this file.
1
2// Program Name: upnp.cpp
3// Created : Oct. 24, 2005
4//
5// Purpose : UPnp Main Class
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 "upnp.h"
13
14#include <QNetworkInterface>
15
19
20#include "ssdp.h"
21#include "ssdpextension.h"
22
24// Global/Class Static variables
26
28QList<QHostAddress> UPnp::g_IPAddrList;
29
32//
33// UPnp Class implementaion
34//
37
39{
40 LOG(VB_UPNP, LOG_DEBUG, "UPnp - Constructor");
41 // N.B. Ask for 5 second delay to send Bye Bye twice
42 // TODO Check whether we actually send Bye Bye twice:)
43 m_power = MythPower::AcquireRelease(this, true, 5s);
44 if (m_power)
45 {
46 // NB We only listen for WillXXX signals which should give us time to send notifications
51 }
52}
53
55//
57
59{
60 LOG(VB_UPNP, LOG_DEBUG, "UPnp - Destructor");
61 CleanUp();
62 if (m_power)
63 MythPower::AcquireRelease(this, false);
64}
65
67//
69
70
72//
74
75bool UPnp::Initialize( int nServicePort, HttpServer *pHttpServer )
76{
77 QList<QHostAddress> sList = ServerPool::DefaultListen();
78 if (sList.contains(QHostAddress(QHostAddress::AnyIPv4)))
79 {
80 sList.removeAll(QHostAddress(QHostAddress::AnyIPv4));
81 sList.removeAll(QHostAddress(QHostAddress::AnyIPv6));
82 sList.append(QNetworkInterface::allAddresses());
83 }
84 return Initialize( sList, nServicePort, pHttpServer );
85}
86
88//
90
91bool UPnp::Initialize( QList<QHostAddress> &sIPAddrList, int nServicePort, HttpServer *pHttpServer )
92{
93 LOG(VB_UPNP, LOG_DEBUG, "UPnp::Initialize - Begin");
94
95 if (m_pHttpServer)
96 {
97 LOG(VB_GENERAL, LOG_ERR,
98 "UPnp::Initialize - Already initialized, programmer error.");
99 return false;
100 }
101
102 m_pHttpServer = pHttpServer;
103 if (m_pHttpServer == nullptr)
104 {
105 LOG(VB_GENERAL, LOG_ERR,
106 "UPnp::Initialize - Invalid Parameter (pHttpServer == NULL)");
107 return false;
108 }
109
110 g_IPAddrList = sIPAddrList;
111 bool ipv4 = gCoreContext->GetBoolSetting("IPv4Support",true);
112 bool ipv6 = gCoreContext->GetBoolSetting("IPv6Support",true);
113
114 for (int it = 0; it < g_IPAddrList.size(); ++it)
115 {
116 // If IPV4 support is disabled and this is an IPV4 address,
117 // remove this address
118 // If IPV6 support is disabled and this is an IPV6 address,
119 // remove this address
120 if ((g_IPAddrList[it].protocol() == QAbstractSocket::IPv4Protocol
121 && ! ipv4)
122 ||(g_IPAddrList[it].protocol() == QAbstractSocket::IPv6Protocol
123 && ! ipv6))
124 g_IPAddrList.removeAt(it--);
125 }
126
127 m_nServicePort = nServicePort;
128
129 // ----------------------------------------------------------------------
130 // Register any HttpServerExtensions
131 // ----------------------------------------------------------------------
132
135
136 LOG(VB_UPNP, LOG_DEBUG, "UPnp::Initialize - End");
137
138 return true;
139}
140
142// Delay startup of Discovery Threads until all Extensions are registered.
144
146{
147 LOG(VB_UPNP, LOG_DEBUG, "UPnp::Start - Enabling SSDP Notifications");
148 // ----------------------------------------------------------------------
149 // Turn on Device Announcements
150 // (this will also create/startup SSDP if not already done)
151 // ----------------------------------------------------------------------
152
154
155 LOG(VB_UPNP, LOG_DEBUG, "UPnp::Start - Returning");
156}
157
159//
161
163{
164 LOG(VB_UPNP, LOG_INFO, "UPnp::CleanUp() - disabling SSDP notifications");
165
167}
168
170//
172
174{
175 return UPnpDeviceDesc::Retrieve( sURL );
176}
177
179//
181
183{
184 switch( eCode )
185 {
186 case UPnPResult_Success : return "Success";
187 case UPnPResult_InvalidAction : return "Invalid Action";
188 case UPnPResult_InvalidArgs : return "Invalid Args";
189 case UPnPResult_ActionFailed : return "Action Failed";
190 case UPnPResult_ArgumentValueInvalid : return "Argument Value Invalid";
191 case UPnPResult_ArgumentValueOutOfRange : return "Argument Value Out Of Range";
192 case UPnPResult_OptionalActionNotImplemented: return "Optional Action Not Implemented";
193 case UPnPResult_OutOfMemory : return "Out Of Memory";
194 case UPnPResult_HumanInterventionRequired : return "Human Intervention Required";
195 case UPnPResult_StringArgumentTooLong : return "String Argument Too Long";
196 case UPnPResult_ActionNotAuthorized : return "Action Not Authorized";
197 case UPnPResult_SignatureFailure : return "Signature Failure";
198 case UPnPResult_SignatureMissing : return "Signature Missing";
199 case UPnPResult_NotEncrypted : return "Not Encrypted";
200 case UPnPResult_InvalidSequence : return "Invalid Sequence";
201 case UPnPResult_InvalidControlURL : return "Invalid Control URL";
202 case UPnPResult_NoSuchSession : return "No Such Session";
203 case UPnPResult_MS_AccessDenied : return "Access Denied";
204
205 case UPnPResult_CDS_NoSuchObject : return "No Such Object";
206 case UPnPResult_CDS_InvalidCurrentTagValue : return "Invalid CurrentTagValue";
207 case UPnPResult_CDS_InvalidNewTagValue : return "Invalid NewTagValue";
208 case UPnPResult_CDS_RequiredTag : return "Required Tag";
209 case UPnPResult_CDS_ReadOnlyTag : return "Read Only Tag";
210 case UPnPResult_CDS_ParameterMismatch : return "Parameter Mismatch";
211 case UPnPResult_CDS_InvalidSearchCriteria : return "Invalid Search Criteria";
212 case UPnPResult_CDS_InvalidSortCriteria : return "Invalid Sort Criteria";
213 case UPnPResult_CDS_NoSuchContainer : return "No Such Container";
214 case UPnPResult_CDS_RestrictedObject : return "Restricted Object";
215 case UPnPResult_CDS_BadMetadata : return "Bad Metadata";
216 case UPnPResult_CDS_ResrtictedParentObject : return "Resrticted Parent Object";
217 case UPnPResult_CDS_NoSuchSourceResource : return "No Such Source Resource";
218 case UPnPResult_CDS_ResourceAccessDenied : return "Resource Access Denied";
219 case UPnPResult_CDS_TransferBusy : return "Transfer Busy";
220 case UPnPResult_CDS_NoSuchFileTransfer : return "No Such File Transfer";
221 case UPnPResult_CDS_NoSuchDestRes : return "No Such Destination Resource";
222 case UPnPResult_CDS_DestResAccessDenied : return "Destination Resource Access Denied";
223 case UPnPResult_CDS_CannotProcessRequest : return "Cannot Process The Request";
224
225 //case UPnPResult_CMGR_IncompatibleProtocol = 701,
226 //case UPnPResult_CMGR_IncompatibleDirections = 702,
227 //case UPnPResult_CMGR_InsufficientNetResources = 703,
228 //case UPnPResult_CMGR_LocalRestrictions = 704,
229 //case UPnPResult_CMGR_AccessDenied = 705,
230 //case UPnPResult_CMGR_InvalidConnectionRef = 706,
231 case UPnPResult_CMGR_NotInNetwork : return "Not In Network";
232 case UPnPResult_MythTV_NoNamespaceGiven: return "No Namespace Given";
233 case UPnPResult_MythTV_XmlParseError : return "XML Parse Error";
234 }
235
236 return "Unknown";
237}
238
240//
242
244 UPnPResultCode eCode,
245 const QString &msg )
246{
247 QString sMsg( msg );
248
249 if (pRequest != nullptr)
250 {
251 QString sDetails = "";
252
253 if (pRequest->m_bSOAPRequest)
254 sDetails = "<UPnPResult xmlns=\"urn:schemas-upnp-org:control-1-0\">";
255
256 if (sMsg.length() == 0)
257 sMsg = GetResultDesc( eCode );
258
259 sDetails += QString( "<errorCode>%1</errorCode>"
260 "<errorDescription>%2</errorDescription>" )
261 .arg( eCode )
262 .arg( HTTPRequest::Encode( sMsg ) );
263
264 if (pRequest->m_bSOAPRequest)
265 sDetails += "</UPnPResult>";
266
267
268 pRequest->FormatErrorResponse ( true, // -=>TODO: Should make this dynamic
269 "UPnPResult",
270 sDetails );
271 }
272 else
273 {
274 LOG(VB_GENERAL, LOG_ERR, "Response not created - pRequest == NULL" );
275 }
276}
277
279//
281
283 const QString &hostName )
284{
286 pRequest->m_nResponseStatus = 301;
287
288 QStringList sItems = pRequest->m_sRawRequest.split( ' ' );
289 QString sUrl = "http://" + pRequest->GetLastHeader( "host" ) + sItems[1];
290 QUrl url( sUrl );
291 QString ipAddress = gCoreContext->GetSettingOnHost
292 ("BackendServerAddr",hostName,hostName);
293 url.setHost( ipAddress );
294
295 pRequest->m_mapRespHeaders[ "Location" ] = url.toString();
296
297 LOG(VB_UPNP, LOG_INFO, QString("Sending http redirect to: %1")
298 .arg(url.toString()));
299
300 pRequest->SendResponse();
301}
302
303void UPnp::DisableNotifications(std::chrono::milliseconds /*unused*/)
304{
306}
307
308void UPnp::EnableNotificatins(std::chrono::milliseconds /*unused*/) const
309{
311}
HttpResponseType m_eResponseType
Definition: httprequest.h:150
long m_nResponseStatus
Definition: httprequest.h:153
qint64 SendResponse(void)
void FormatErrorResponse(bool bServerError, const QString &sFaultString, const QString &sDetails)
bool m_bSOAPRequest
Definition: httprequest.h:145
QString GetLastHeader(const QString &sType) const
QStringMap m_mapRespHeaders
Definition: httprequest.h:154
QString m_sRawRequest
Definition: httprequest.h:124
static QString Encode(const QString &sIn)
QString GetSharePath(void) const
Definition: httpserver.h:124
void RegisterExtension(HttpServerExtension *pExtension)
Definition: httpserver.cpp:309
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
bool GetBoolSetting(const QString &key, bool defaultval=false)
void WokeUp(std::chrono::seconds SecondsAsleep)
void WillSuspend(std::chrono::milliseconds MilliSeconds=0ms)
static MythPower * AcquireRelease(void *Reference, bool Acquire, std::chrono::seconds MinimumDelay=0s)
Definition: mythpower.cpp:74
void WillShutDown(std::chrono::milliseconds MilliSeconds=0ms)
void WillRestart(std::chrono::milliseconds MilliSeconds=0ms)
void EnableNotifications(int nServicePort)
Definition: ssdp.cpp:105
void DisableNotifications()
Definition: ssdp.cpp:143
static SSDP * Instance()
Definition: ssdp.cpp:57
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:305
static UPnpDeviceDesc * Retrieve(QString &sURL)
Definition: upnpdevice.cpp:631
~UPnp() override
Definition: upnp.cpp:58
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:108
MythPower * m_power
Definition: upnp.h:143
static void CleanUp()
Definition: upnp.cpp:162
static void FormatRedirectResponse(HTTPRequest *pRequest, const QString &hostName)
Definition: upnp.cpp:282
static QString GetResultDesc(UPnPResultCode eCode)
Definition: upnp.cpp:182
static UPnpDeviceDesc * GetDeviceDesc(QString &sURL)
Definition: upnp.cpp:173
HttpServer * m_pHttpServer
Definition: upnp.h:102
virtual void Start()
Definition: upnp.cpp:145
int m_nServicePort
Definition: upnp.h:103
static void DisableNotifications(std::chrono::milliseconds)
Definition: upnp.cpp:303
bool Initialize(int nServicePort, HttpServer *pHttpServer)
Definition: upnp.cpp:75
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:107
UPnp()
Definition: upnp.cpp:38
void EnableNotificatins(std::chrono::milliseconds) const
Definition: upnp.cpp:308
static void FormatErrorResponse(HTTPRequest *pRequest, UPnPResultCode eCode, const QString &sMsg="")
Definition: upnp.cpp:243
@ ResponseTypeOther
Definition: httprequest.h:86
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
UPnPResultCode
Definition: upnp.h:34
@ UPnPResult_MS_AccessDenied
Definition: upnp.h:82
@ UPnPResult_CDS_NoSuchDestRes
Definition: upnp.h:70
@ UPnPResult_InvalidControlURL
Definition: upnp.h:51
@ UPnPResult_ArgumentValueOutOfRange
Definition: upnp.h:41
@ UPnPResult_CDS_InvalidSortCriteria
Definition: upnp.h:61
@ UPnPResult_CDS_NoSuchSourceResource
Definition: upnp.h:66
@ UPnPResult_CDS_ParameterMismatch
Definition: upnp.h:59
@ UPnPResult_OutOfMemory
Definition: upnp.h:43
@ UPnPResult_CDS_TransferBusy
Definition: upnp.h:68
@ UPnPResult_CDS_InvalidNewTagValue
Definition: upnp.h:56
@ UPnPResult_CDS_InvalidSearchCriteria
Definition: upnp.h:60
@ UPnPResult_NotEncrypted
Definition: upnp.h:49
@ UPnPResult_CDS_DestResAccessDenied
Definition: upnp.h:71
@ UPnPResult_HumanInterventionRequired
Definition: upnp.h:44
@ UPnPResult_Success
Definition: upnp.h:35
@ UPnPResult_OptionalActionNotImplemented
Definition: upnp.h:42
@ UPnPResult_CDS_CannotProcessRequest
Definition: upnp.h:72
@ UPnPResult_ArgumentValueInvalid
Definition: upnp.h:40
@ UPnPResult_MythTV_XmlParseError
Definition: upnp.h:85
@ UPnPResult_InvalidAction
Definition: upnp.h:37
@ UPnPResult_CDS_NoSuchContainer
Definition: upnp.h:62
@ UPnPResult_StringArgumentTooLong
Definition: upnp.h:45
@ UPnPResult_ActionFailed
Definition: upnp.h:39
@ UPnPResult_CDS_NoSuchObject
Definition: upnp.h:54
@ UPnPResult_CDS_RestrictedObject
Definition: upnp.h:63
@ UPnPResult_CDS_BadMetadata
Definition: upnp.h:64
@ UPnPResult_CDS_InvalidCurrentTagValue
Definition: upnp.h:55
@ UPnPResult_CDS_ResrtictedParentObject
Definition: upnp.h:65
@ UPnPResult_ActionNotAuthorized
Definition: upnp.h:46
@ UPnPResult_NoSuchSession
Definition: upnp.h:52
@ UPnPResult_CDS_ResourceAccessDenied
Definition: upnp.h:67
@ UPnPResult_CDS_RequiredTag
Definition: upnp.h:57
@ UPnPResult_CMGR_NotInNetwork
Definition: upnp.h:80
@ UPnPResult_CDS_NoSuchFileTransfer
Definition: upnp.h:69
@ UPnPResult_InvalidSequence
Definition: upnp.h:50
@ UPnPResult_CDS_ReadOnlyTag
Definition: upnp.h:58
@ UPnPResult_SignatureMissing
Definition: upnp.h:48
@ UPnPResult_MythTV_NoNamespaceGiven
Definition: upnp.h:84
@ UPnPResult_SignatureFailure
Definition: upnp.h:47
@ UPnPResult_InvalidArgs
Definition: upnp.h:38