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