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 
22 // Global/Class Static variables
24 
26 QList<QHostAddress> UPnp::g_IPAddrList;
27 
30 //
31 // UPnp Class implementaion
32 //
35 
37 {
38  LOG(VB_UPNP, LOG_DEBUG, "UPnp - Constructor");
39  // N.B. Ask for 5 second delay to send Bye Bye twice
40  // TODO Check whether we actually send Bye Bye twice:)
41  m_power = MythPower::AcquireRelease(this, true, 5s);
42  if (m_power)
43  {
44  // NB We only listen for WillXXX signals which should give us time to send notifications
49  }
50 }
51 
53 //
55 
57 {
58  LOG(VB_UPNP, LOG_DEBUG, "UPnp - Destructor");
59  CleanUp();
60  if (m_power)
61  MythPower::AcquireRelease(this, false);
62 }
63 
65 //
67 
68 
70 //
72 
73 bool UPnp::Initialize( int nServicePort, HttpServer *pHttpServer )
74 {
75  QList<QHostAddress> sList = ServerPool::DefaultListen();
76  if (sList.contains(QHostAddress(QHostAddress::AnyIPv4)))
77  {
78  sList.removeAll(QHostAddress(QHostAddress::AnyIPv4));
79  sList.removeAll(QHostAddress(QHostAddress::AnyIPv6));
80  sList.append(QNetworkInterface::allAddresses());
81  }
82  return Initialize( sList, nServicePort, pHttpServer );
83 }
84 
86 //
88 
89 bool UPnp::Initialize( QList<QHostAddress> &sIPAddrList, int nServicePort, HttpServer *pHttpServer )
90 {
91  LOG(VB_UPNP, LOG_DEBUG, "UPnp::Initialize - Begin");
92 
93  if (m_pHttpServer)
94  {
95  LOG(VB_GENERAL, LOG_ERR,
96  "UPnp::Initialize - Already initialized, programmer error.");
97  return false;
98  }
99 
100  m_pHttpServer = pHttpServer;
101  if (m_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  {
272  LOG(VB_GENERAL, LOG_ERR, "Response not created - pRequest == NULL" );
273  }
274 }
275 
277 //
279 
281  const QString &hostName )
282 {
284  pRequest->m_nResponseStatus = 301;
285 
286  QStringList sItems = pRequest->m_sRawRequest.split( ' ' );
287  QString sUrl = "http://" + pRequest->GetLastHeader( "host" ) + sItems[1];
288  QUrl url( sUrl );
289  QString ipAddress = gCoreContext->GetSettingOnHost
290  ("BackendServerAddr",hostName,hostName);
291  url.setHost( ipAddress );
292 
293  pRequest->m_mapRespHeaders[ "Location" ] = url.toString();
294 
295  LOG(VB_UPNP, LOG_INFO, QString("Sending http redirect to: %1")
296  .arg(url.toString()));
297 
298  pRequest->SendResponse();
299 }
300 
301 void UPnp::DisableNotifications(std::chrono::milliseconds /*unused*/)
302 {
304 }
305 
306 void UPnp::EnableNotificatins(std::chrono::milliseconds /*unused*/) const
307 {
309 }
HTTPRequest
Definition: httprequest.h:109
ResponseTypeOther
@ ResponseTypeOther
Definition: httprequest.h:85
UPnpDeviceDesc::Retrieve
static UPnpDeviceDesc * Retrieve(QString &sURL)
Definition: upnpdevice.cpp:633
UPnPResult_ActionFailed
@ UPnPResult_ActionFailed
Definition: upnp.h:41
UPnPResult_CDS_BadMetadata
@ UPnPResult_CDS_BadMetadata
Definition: upnp.h:66
UPnp::Start
virtual void Start()
Definition: upnp.cpp:143
UPnPResult_CDS_InvalidSortCriteria
@ UPnPResult_CDS_InvalidSortCriteria
Definition: upnp.h:63
SSDPExtension
Definition: ssdp.h:149
HttpServer::RegisterExtension
void RegisterExtension(HttpServerExtension *pExtension)
Definition: httpserver.cpp:321
UPnPResult_CDS_InvalidCurrentTagValue
@ UPnPResult_CDS_InvalidCurrentTagValue
Definition: upnp.h:57
UPnpDeviceDesc
Definition: upnpdevice.h:151
UPnp::CleanUp
static void CleanUp()
Definition: upnp.cpp:160
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
UPnPResult_OutOfMemory
@ UPnPResult_OutOfMemory
Definition: upnp.h:45
MythPower::WillSuspend
void WillSuspend(std::chrono::milliseconds MilliSeconds=0ms)
UPnp::m_nServicePort
int m_nServicePort
Definition: upnp.h:105
UPnPResult_CMGR_NotInNetwork
@ UPnPResult_CMGR_NotInNetwork
Definition: upnp.h:82
UPnPResult_CDS_ParameterMismatch
@ UPnPResult_CDS_ParameterMismatch
Definition: upnp.h:61
HTTPRequest::Encode
static QString Encode(const QString &sIn)
Definition: httprequest.cpp:1746
UPnPResult_InvalidArgs
@ UPnPResult_InvalidArgs
Definition: upnp.h:40
UPnPResult_InvalidControlURL
@ UPnPResult_InvalidControlURL
Definition: upnp.h:53
UPnPResult_SignatureFailure
@ UPnPResult_SignatureFailure
Definition: upnp.h:49
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:73
MythPower::WillRestart
void WillRestart(std::chrono::milliseconds MilliSeconds=0ms)
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:102
UPnPResult_CDS_TransferBusy
@ UPnPResult_CDS_TransferBusy
Definition: upnp.h:70
UPnPResult_OptionalActionNotImplemented
@ UPnPResult_OptionalActionNotImplemented
Definition: upnp.h:44
upnp.h
UPnPResult_CDS_InvalidNewTagValue
@ UPnPResult_CDS_InvalidNewTagValue
Definition: upnp.h:58
HTTPRequest::m_nResponseStatus
long m_nResponseStatus
Definition: httprequest.h:152
UPnp::FormatRedirectResponse
static void FormatRedirectResponse(HTTPRequest *pRequest, const QString &hostName)
Definition: upnp.cpp:280
mythlogging.h
UPnPResult_StringArgumentTooLong
@ UPnPResult_StringArgumentTooLong
Definition: upnp.h:47
UPnp::GetDeviceDesc
static UPnpDeviceDesc * GetDeviceDesc(QString &sURL)
Definition: upnp.cpp:171
MythPower::AcquireRelease
static MythPower * AcquireRelease(void *Reference, bool Acquire, std::chrono::seconds MinimumDelay=0s)
Definition: mythpower.cpp:72
UPnp::DisableNotifications
static void DisableNotifications(std::chrono::milliseconds)
Definition: upnp.cpp:301
UPnPResult_CDS_NoSuchFileTransfer
@ UPnPResult_CDS_NoSuchFileTransfer
Definition: upnp.h:71
ServerPool::DefaultListen
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:305
UPnPResult_InvalidAction
@ UPnPResult_InvalidAction
Definition: upnp.h:39
UPnPResult_CDS_ResrtictedParentObject
@ UPnPResult_CDS_ResrtictedParentObject
Definition: upnp.h:67
UPnPResult_CDS_DestResAccessDenied
@ UPnPResult_CDS_DestResAccessDenied
Definition: upnp.h:73
HTTPRequest::m_sRawRequest
QString m_sRawRequest
Definition: httprequest.h:123
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
UPnp::EnableNotificatins
void EnableNotificatins(std::chrono::milliseconds) const
Definition: upnp.cpp:306
UPnPResult_ActionNotAuthorized
@ UPnPResult_ActionNotAuthorized
Definition: upnp.h:48
UPnPResult_CDS_ResourceAccessDenied
@ UPnPResult_CDS_ResourceAccessDenied
Definition: upnp.h:69
UPnPResult_CDS_NoSuchDestRes
@ UPnPResult_CDS_NoSuchDestRes
Definition: upnp.h:72
SSDP::DisableNotifications
void DisableNotifications()
Definition: ssdp.cpp:235
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:912
HTTPRequest::m_bSOAPRequest
bool m_bSOAPRequest
Definition: httprequest.h:144
UPnPResult_Success
@ UPnPResult_Success
Definition: upnp.h:37
HttpServer::GetSharePath
QString GetSharePath(void) const
Definition: httpserver.h:128
UPnPResult_NoSuchSession
@ UPnPResult_NoSuchSession
Definition: upnp.h:54
UPnPResult_CDS_ReadOnlyTag
@ UPnPResult_CDS_ReadOnlyTag
Definition: upnp.h:60
UPnPResult_CDS_CannotProcessRequest
@ UPnPResult_CDS_CannotProcessRequest
Definition: upnp.h:74
UPnPResult_InvalidSequence
@ UPnPResult_InvalidSequence
Definition: upnp.h:52
UPnPResult_ArgumentValueInvalid
@ UPnPResult_ArgumentValueInvalid
Definition: upnp.h:42
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:932
HTTPRequest::m_eResponseType
HttpResponseType m_eResponseType
Definition: httprequest.h:149
UPnPResult_MS_AccessDenied
@ UPnPResult_MS_AccessDenied
Definition: upnp.h:84
serverpool.h
UPnPResult_CDS_NoSuchObject
@ UPnPResult_CDS_NoSuchObject
Definition: upnp.h:56
UPnPResult_CDS_InvalidSearchCriteria
@ UPnPResult_CDS_InvalidSearchCriteria
Definition: upnp.h:62
MythPower::WillShutDown
void WillShutDown(std::chrono::milliseconds MilliSeconds=0ms)
UPnPResult_CDS_RestrictedObject
@ UPnPResult_CDS_RestrictedObject
Definition: upnp.h:65
UPnp::UPnp
UPnp()
Definition: upnp.cpp:36
HttpServer
Definition: httpserver.h:112
UPnp::~UPnp
~UPnp() override
Definition: upnp.cpp:56
UPnPResult_NotEncrypted
@ UPnPResult_NotEncrypted
Definition: upnp.h:51
UPnPResult_SignatureMissing
@ UPnPResult_SignatureMissing
Definition: upnp.h:50
UPnPResult_ArgumentValueOutOfRange
@ UPnPResult_ArgumentValueOutOfRange
Definition: upnp.h:43
UPnPResult_HumanInterventionRequired
@ UPnPResult_HumanInterventionRequired
Definition: upnp.h:46
UPnPResult_CDS_RequiredTag
@ UPnPResult_CDS_RequiredTag
Definition: upnp.h:59
UPnp::m_pHttpServer
HttpServer * m_pHttpServer
Definition: upnp.h:104
SSDP::EnableNotifications
void EnableNotifications(int nServicePort)
Definition: ssdp.cpp:195
UPnPResultCode
UPnPResultCode
Definition: upnp.h:35
HTTPRequest::SendResponse
qint64 SendResponse(void)
Definition: httprequest.cpp:301
UPnPResult_CDS_NoSuchSourceResource
@ UPnPResult_CDS_NoSuchSourceResource
Definition: upnp.h:68
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_MythTV_NoNamespaceGiven
@ UPnPResult_MythTV_NoNamespaceGiven
Definition: upnp.h:86
UPnPResult_MythTV_XmlParseError
@ UPnPResult_MythTV_XmlParseError
Definition: upnp.h:87
UPnp::GetResultDesc
static QString GetResultDesc(UPnPResultCode eCode)
Definition: upnp.cpp:180
UPnPResult_CDS_NoSuchContainer
@ UPnPResult_CDS_NoSuchContainer
Definition: upnp.h:64