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