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  if ((m_pHttpServer = pHttpServer) == nullptr)
102  {
103  LOG(VB_GENERAL, LOG_ERR,
104  "UPnp::Initialize - Invalid Parameter (pHttpServer == NULL)");
105  return false;
106  }
107 
108  g_IPAddrList = sIPAddrList;
109  bool ipv4 = gCoreContext->GetBoolSetting("IPv4Support",true);
110  bool ipv6 = gCoreContext->GetBoolSetting("IPv6Support",true);
111 
112  for (int it = 0; it < g_IPAddrList.size(); ++it)
113  {
114  // If IPV4 support is disabled and this is an IPV4 address,
115  // remove this address
116  // If IPV6 support is disabled and this is an IPV6 address,
117  // remove this address
118  if ((g_IPAddrList[it].protocol() == QAbstractSocket::IPv4Protocol
119  && ! ipv4)
120  ||(g_IPAddrList[it].protocol() == QAbstractSocket::IPv6Protocol
121  && ! ipv6))
122  g_IPAddrList.removeAt(it--);
123  }
124 
125  m_nServicePort = nServicePort;
126 
127  // ----------------------------------------------------------------------
128  // Register any HttpServerExtensions
129  // ----------------------------------------------------------------------
130 
133 
134  LOG(VB_UPNP, LOG_DEBUG, "UPnp::Initialize - End");
135 
136  return true;
137 }
138 
140 // Delay startup of Discovery Threads until all Extensions are registered.
142 
144 {
145  LOG(VB_UPNP, LOG_DEBUG, "UPnp::Start - Enabling SSDP Notifications");
146  // ----------------------------------------------------------------------
147  // Turn on Device Announcements
148  // (this will also create/startup SSDP if not already done)
149  // ----------------------------------------------------------------------
150 
152 
153  LOG(VB_UPNP, LOG_DEBUG, "UPnp::Start - Returning");
154 }
155 
157 //
159 
161 {
162  LOG(VB_UPNP, LOG_INFO, "UPnp::CleanUp() - disabling SSDP notifications");
163 
165 }
166 
168 //
170 
172 {
173  return UPnpDeviceDesc::Retrieve( sURL );
174 }
175 
177 //
179 
181 {
182  switch( eCode )
183  {
184  case UPnPResult_Success : return "Success";
185  case UPnPResult_InvalidAction : return "Invalid Action";
186  case UPnPResult_InvalidArgs : return "Invalid Args";
187  case UPnPResult_ActionFailed : return "Action Failed";
188  case UPnPResult_ArgumentValueInvalid : return "Argument Value Invalid";
189  case UPnPResult_ArgumentValueOutOfRange : return "Argument Value Out Of Range";
190  case UPnPResult_OptionalActionNotImplemented: return "Optional Action Not Implemented";
191  case UPnPResult_OutOfMemory : return "Out Of Memory";
192  case UPnPResult_HumanInterventionRequired : return "Human Intervention Required";
193  case UPnPResult_StringArgumentTooLong : return "String Argument Too Long";
194  case UPnPResult_ActionNotAuthorized : return "Action Not Authorized";
195  case UPnPResult_SignatureFailure : return "Signature Failure";
196  case UPnPResult_SignatureMissing : return "Signature Missing";
197  case UPnPResult_NotEncrypted : return "Not Encrypted";
198  case UPnPResult_InvalidSequence : return "Invalid Sequence";
199  case UPnPResult_InvalidControlURL : return "Invalid Control URL";
200  case UPnPResult_NoSuchSession : return "No Such Session";
201  case UPnPResult_MS_AccessDenied : return "Access Denied";
202 
203  case UPnPResult_CDS_NoSuchObject : return "No Such Object";
204  case UPnPResult_CDS_InvalidCurrentTagValue : return "Invalid CurrentTagValue";
205  case UPnPResult_CDS_InvalidNewTagValue : return "Invalid NewTagValue";
206  case UPnPResult_CDS_RequiredTag : return "Required Tag";
207  case UPnPResult_CDS_ReadOnlyTag : return "Read Only Tag";
208  case UPnPResult_CDS_ParameterMismatch : return "Parameter Mismatch";
209  case UPnPResult_CDS_InvalidSearchCriteria : return "Invalid Search Criteria";
210  case UPnPResult_CDS_InvalidSortCriteria : return "Invalid Sort Criteria";
211  case UPnPResult_CDS_NoSuchContainer : return "No Such Container";
212  case UPnPResult_CDS_RestrictedObject : return "Restricted Object";
213  case UPnPResult_CDS_BadMetadata : return "Bad Metadata";
214  case UPnPResult_CDS_ResrtictedParentObject : return "Resrticted Parent Object";
215  case UPnPResult_CDS_NoSuchSourceResource : return "No Such Source Resource";
216  case UPnPResult_CDS_ResourceAccessDenied : return "Resource Access Denied";
217  case UPnPResult_CDS_TransferBusy : return "Transfer Busy";
218  case UPnPResult_CDS_NoSuchFileTransfer : return "No Such File Transfer";
219  case UPnPResult_CDS_NoSuchDestRes : return "No Such Destination Resource";
220  case UPnPResult_CDS_DestResAccessDenied : return "Destination Resource Access Denied";
221  case UPnPResult_CDS_CannotProcessRequest : return "Cannot Process The Request";
222 
223  //case UPnPResult_CMGR_IncompatibleProtocol = 701,
224  //case UPnPResult_CMGR_IncompatibleDirections = 702,
225  //case UPnPResult_CMGR_InsufficientNetResources = 703,
226  //case UPnPResult_CMGR_LocalRestrictions = 704,
227  //case UPnPResult_CMGR_AccessDenied = 705,
228  //case UPnPResult_CMGR_InvalidConnectionRef = 706,
229  case UPnPResult_CMGR_NotInNetwork : return "Not In Network";
230  case UPnPResult_MythTV_NoNamespaceGiven: return "No Namespace Given";
231  case UPnPResult_MythTV_XmlParseError : return "XML Parse Error";
232  }
233 
234  return "Unknown";
235 }
236 
238 //
240 
242  UPnPResultCode eCode,
243  const QString &msg )
244 {
245  QString sMsg( msg );
246 
247  if (pRequest != nullptr)
248  {
249  QString sDetails = "";
250 
251  if (pRequest->m_bSOAPRequest)
252  sDetails = "<UPnPResult xmlns=\"urn:schemas-upnp-org:control-1-0\">";
253 
254  if (sMsg.length() == 0)
255  sMsg = GetResultDesc( eCode );
256 
257  sDetails += QString( "<errorCode>%1</errorCode>"
258  "<errorDescription>%2</errorDescription>" )
259  .arg( eCode )
260  .arg( HTTPRequest::Encode( sMsg ) );
261 
262  if (pRequest->m_bSOAPRequest)
263  sDetails += "</UPnPResult>";
264 
265 
266  pRequest->FormatErrorResponse ( true, // -=>TODO: Should make this dynamic
267  "UPnPResult",
268  sDetails );
269  }
270  else
271  LOG(VB_GENERAL, LOG_ERR, "Response not created - pRequest == NULL" );
272 }
273 
275 //
277 
279  const QString &hostName )
280 {
282  pRequest->m_nResponseStatus = 301;
283 
284  QStringList sItems = pRequest->m_sRawRequest.split( ' ' );
285  QString sUrl = "http://" + pRequest->GetLastHeader( "host" ) + sItems[1];
286  QUrl url( sUrl );
287  QString ipAddress = gCoreContext->GetSettingOnHost
288  ("BackendServerAddr",hostName,hostName);
289  url.setHost( ipAddress );
290 
291  pRequest->m_mapRespHeaders[ "Location" ] = url.toString();
292 
293  LOG(VB_UPNP, LOG_INFO, QString("Sending http redirect to: %1")
294  .arg(url.toString()));
295 
296  pRequest->SendResponse();
297 }
298 
299 void UPnp::DisableNotifications(std::chrono::milliseconds /*unused*/)
300 {
302 }
303 
304 void UPnp::EnableNotificatins(std::chrono::milliseconds /*unused*/) const
305 {
307 }
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:622
UPnPResult_CDS_BadMetadata
@ UPnPResult_CDS_BadMetadata
Definition: upnp.h:66
UPnp::Start
virtual void Start()
Definition: upnp.cpp:143
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:160
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:1738
UPnPResult_OutOfMemory
@ UPnPResult_OutOfMemory
Definition: upnp.h:45
UPnp::FormatErrorResponse
static void FormatErrorResponse(HTTPRequest *pRequest, UPnPResultCode eCode, const QString &sMsg="")
Definition: upnp.cpp:241
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:278
mythlogging.h
UPnPResult_NoSuchSession
@ UPnPResult_NoSuchSession
Definition: upnp.h:54
UPnp::GetDeviceDesc
static UPnpDeviceDesc * GetDeviceDesc(QString &sURL)
Definition: upnp.cpp:171
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:75
UPnPResult_CDS_NoSuchSourceResource
@ UPnPResult_CDS_NoSuchSourceResource
Definition: upnp.h:68
UPnp::DisableNotifications
static void DisableNotifications(std::chrono::milliseconds)
Definition: upnp.cpp:299
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:304
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:905
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:925
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:180