MythTV  master
ssdp.cpp
Go to the documentation of this file.
1 // Program Name: ssdp.cpp
3 // Created : Oct. 1, 2005
4 //
5 // Purpose : SSDP Discovery Service Implmenetation
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 "ssdp.h"
13 
14 #include <algorithm>
15 #include <cerrno>
16 #include <chrono> // for milliseconds
17 #include <cstdlib>
18 #include <thread> // for sleep_for
19 
21 #include "libmythbase/mythchrono.h"
23 #include "libmythbase/mythrandom.h"
24 
25 #include "upnp.h"
26 #include "upnptasksearch.h"
27 #include "upnptaskcache.h"
28 
29 #include "mmulticastsocketdevice.h"
30 #include "mbroadcastsocketdevice.h"
31 
32 #include <QStringList>
33 
34 #ifdef Q_OS_ANDROID
35 #include <sys/select.h>
36 #endif
37 
40 //
41 // SSDP Class Implementation
42 //
45 
46 // We're creating this class immediately so it will always be available.
47 
48 static QMutex g_pSSDPCreationLock;
49 SSDP* SSDP::g_pSSDP = nullptr;
50 
52 //
54 
56 {
57  QMutexLocker locker(&g_pSSDPCreationLock);
58  return g_pSSDP ? g_pSSDP : (g_pSSDP = new SSDP());
59 }
60 
62 //
64 
66 {
67  QMutexLocker locker(&g_pSSDPCreationLock);
68  delete g_pSSDP;
69  g_pSSDP = nullptr;
70 }
71 
73 //
75 
77  MThread("SSDP")
78 {
79  LOG(VB_UPNP, LOG_NOTICE, "Starting up SSDP Thread..." );
80 
81  {
82  auto config = XmlConfiguration();
83 
84  m_nPort = config.GetValue("UPnP/SSDP/Port" , SSDP_PORT );
85  m_nSearchPort = config.GetValue("UPnP/SSDP/SearchPort", SSDP_SEARCHPORT);
86  }
87 
93  new MBroadcastSocketDevice("255.255.255.255", m_nPort);
94 
95  m_sockets[ SocketIdx_Search ]->setBlocking( false );
96  m_sockets[ SocketIdx_Multicast ]->setBlocking( false );
97  m_sockets[ SocketIdx_Broadcast ]->setBlocking( false );
98 
99  // Setup SearchSocket
100  QHostAddress ip4addr( QHostAddress::Any );
101 
102  m_sockets[ SocketIdx_Search ]->bind( ip4addr , m_nSearchPort );
103  m_sockets[ SocketIdx_Search ]->bind( QHostAddress::Any, m_nSearchPort );
104 
105  // ----------------------------------------------------------------------
106  // Create the SSDP (Upnp Discovery) Thread.
107  // ----------------------------------------------------------------------
108 
109  start();
110 
111  LOG(VB_UPNP, LOG_INFO, "SSDP Thread Starting soon" );
112 }
113 
115 //
117 
119 {
120  LOG(VB_UPNP, LOG_NOTICE, "Shutting Down SSDP Thread..." );
121 
123 
125  wait();
126 
127  if (m_pNotifyTask != nullptr)
128  {
130  m_pNotifyTask = nullptr;
131  }
132 
133  for (auto & socket : m_sockets)
134  delete socket;
135 
136  LOG(VB_UPNP, LOG_INFO, "SSDP Thread Terminated." );
137 }
138 
140 {
141  m_bTermRequested = true;
142 }
143 
145 //
147 
148 void SSDP::EnableNotifications( int nServicePort )
149 {
150  if ( m_pNotifyTask == nullptr )
151  {
152  m_nServicePort = nServicePort;
153 
154  LOG(VB_UPNP, LOG_INFO,
155  "SSDP::EnableNotifications() - creating new task");
157 
158  // ------------------------------------------------------------------
159  // First Send out Notification that we are leaving the network.
160  // ------------------------------------------------------------------
161 
162  LOG(VB_UPNP, LOG_INFO,
163  "SSDP::EnableNotifications() - sending NTS_byebye");
165  m_pNotifyTask->Execute( nullptr );
166 
168  }
169 
170  // ------------------------------------------------------------------
171  // Add Announcement Task to the Queue
172  // ------------------------------------------------------------------
173 
174  LOG(VB_UPNP, LOG_INFO, "SSDP::EnableNotifications() - sending NTS_alive");
175 
177 
179 
180  LOG(VB_UPNP, LOG_INFO,
181  "SSDP::EnableNotifications() - Task added to UPnP queue");
182 }
183 
185 //
187 
189 {
190  m_bAnnouncementsEnabled = false;
191 
192  if (m_pNotifyTask != nullptr)
193  {
194  // Send Announcement that we are leaving.
195 
197  m_pNotifyTask->Execute( nullptr );
198  }
199 }
200 
202 //
204 void SSDP::PerformSearch(const QString &sST, std::chrono::seconds timeout)
205 {
206  timeout = std::clamp(timeout, 1s, 5s);
207  QString rRequest = QString("M-SEARCH * HTTP/1.1\r\n"
208  "HOST: 239.255.255.250:1900\r\n"
209  "MAN: \"ssdp:discover\"\r\n"
210  "MX: %1\r\n"
211  "ST: %2\r\n"
212  "\r\n")
213  .arg(timeout.count()).arg(sST);
214 
215  LOG(VB_UPNP, LOG_DEBUG, QString("\n\n%1\n").arg(rRequest));
216 
217  QByteArray sRequest = rRequest.toUtf8();
218 
219  MSocketDevice *pSocket = m_sockets[ SocketIdx_Search ];
220  if ( !pSocket->isValid() )
221  {
222  pSocket->setProtocol(MSocketDevice::IPv4);
223  pSocket->setSocket(pSocket->createNewSocket(), MSocketDevice::Datagram);
224  }
225 
226  QHostAddress address;
227  address.setAddress( SSDP_GROUP );
228 
229  int nSize = sRequest.size();
230 
231  if ( pSocket->writeBlock( sRequest.data(),
232  sRequest.size(), address, SSDP_PORT ) != nSize)
233  LOG(VB_GENERAL, LOG_INFO,
234  "SSDP::PerformSearch - did not write entire buffer.");
235 
236  std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(0, 250)));
237 
238  if ( pSocket->writeBlock( sRequest.data(),
239  sRequest.size(), address, SSDP_PORT ) != nSize)
240  LOG(VB_GENERAL, LOG_INFO,
241  "SSDP::PerformSearch - did not write entire buffer.");
242 }
243 
245 //
247 
248 void SSDP::run()
249 {
250  RunProlog();
251 
252  fd_set read_set;
253  struct timeval timeout {};
254 
255  LOG(VB_UPNP, LOG_INFO, "SSDP::Run - SSDP Thread Started." );
256 
257  // ----------------------------------------------------------------------
258  // Listen for new Requests
259  // ----------------------------------------------------------------------
260 
261  while ( ! m_bTermRequested )
262  {
263  int nMaxSocket = 0;
264 
265  FD_ZERO( &read_set ); // NOLINT(readability-isolate-declaration)
266 
267  for (auto & socket : m_sockets)
268  {
269  if (socket != nullptr && socket->socket() >= 0)
270  {
271  FD_SET( socket->socket(), &read_set );
272  nMaxSocket = std::max( socket->socket(), nMaxSocket );
273 
274 #if 0
275  if (socket->bytesAvailable() > 0)
276  {
277  LOG(VB_GENERAL, LOG_DEBUG,
278  QString("Found Extra data before select: %1")
279  .arg(nIdx));
280  ProcessData( socket );
281  }
282 #endif
283  }
284  }
285 
286  timeout.tv_sec = 1;
287  timeout.tv_usec = 0;
288 
289  int count = select(nMaxSocket + 1, &read_set, nullptr, nullptr, &timeout);
290 
291  for (int nIdx = 0; count && nIdx < kNumberOfSockets; nIdx++ )
292  {
293  bool cond1 = m_sockets[nIdx] != nullptr;
294  bool cond2 = cond1 && m_sockets[nIdx]->socket() >= 0;
295  bool cond3 = cond2 && FD_ISSET(m_sockets[nIdx]->socket(), &read_set);
296 
297  if (cond3)
298  {
299 #if 0
300  LOG(VB_GENERAL, LOG_DEBUG, QString("FD_ISSET( %1 )").arg(nIdx));
301 #endif
302 
303  ProcessData(m_sockets[nIdx]);
304  count--;
305  }
306  }
307  }
308 
309  RunEpilog();
310 }
311 
313 //
315 
316 void SSDP::ProcessData( MSocketDevice *pSocket )
317 {
318  QByteArray buffer;
319  long nBytes = pSocket->bytesAvailable();
320  int retries = 0;
321  // Note: this function MUST do a read even if someone sends a zero byte UDP message
322  // Otherwise the select() will continue to signal data ready, so to prevent using 100%
323  // CPU, we need to call a recv function to make select() block again
324  bool didDoRead = false;
325 
326  // UDP message of zero length? OK, "recv" it and move on
327  if (nBytes == 0)
328  {
329  LOG(VB_UPNP, LOG_WARNING, QString("SSDP: Received 0 byte UDP message"));
330  }
331 
332  while (((nBytes = pSocket->bytesAvailable()) > 0 || (nBytes == 0 && !didDoRead)) && !m_bTermRequested)
333  {
334  buffer.resize(nBytes);
335 
336  long nRead = 0;
337  do
338  {
339  long ret = pSocket->readBlock( buffer.data() + nRead, nBytes - nRead );
340  didDoRead = true;
341  if (ret < 0)
342  {
343  if (errno == EAGAIN
344 #if EAGAIN != EWOULDBLOCK
345  || errno == EWOULDBLOCK
346 #endif
347  )
348  {
349  if (retries == 3)
350  {
351  nBytes = nRead;
352  buffer.resize(nBytes);
353  break;
354  }
355  retries++;
356  std::this_thread::sleep_for(10ms);
357  continue;
358  }
359  LOG(VB_GENERAL, LOG_ERR, QString("Socket readBlock error %1")
360  .arg(pSocket->error()));
361  buffer.clear();
362  break;
363  }
364  retries = 0;
365 
366  nRead += ret;
367 
368  if (0 == ret && nBytes != 0)
369  {
370  LOG(VB_SOCKET, LOG_WARNING,
371  QString("%1 bytes reported available, "
372  "but only %2 bytes read.")
373  .arg(nBytes).arg(nRead));
374  nBytes = nRead;
375  buffer.resize(nBytes);
376  break;
377  }
378  }
379  while (nRead < nBytes);
380 
381  if (buffer.isEmpty())
382  continue;
383 
384  QHostAddress peerAddress = pSocket->peerAddress();
385  quint16 peerPort = pSocket->peerPort ();
386 
387  // ------------------------------------------------------------------
388  QString str = QString(buffer.constData());
389 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
390  QStringList lines = str.split("\r\n", QString::SkipEmptyParts);
391 #else
392  QStringList lines = str.split("\r\n", Qt::SkipEmptyParts);
393 #endif
394  QString sRequestLine = !lines.empty() ? lines[0] : "";
395 
396  if (!lines.isEmpty())
397  lines.pop_front();
398 
399  // ------------------------------------------------------------------
400  // Parse request Type
401  // ------------------------------------------------------------------
402 
403  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessData - requestLine: %1")
404  .arg(sRequestLine));
405 
406  SSDPRequestType eType = ProcessRequestLine( sRequestLine );
407 
408  // ------------------------------------------------------------------
409  // Read Headers into map
410  // ------------------------------------------------------------------
411 
412  QStringMap headers;
413 
414  for (const auto& sLine : qAsConst(lines))
415  {
416  QString sName = sLine.section( ':', 0, 0 ).trimmed();
417  QString sValue = sLine.section( ':', 1 );
418 
419  sValue.truncate( sValue.length() ); //-2
420 
421  if ((sName.length() != 0) && (sValue.length() !=0))
422  headers.insert( sName.toLower(), sValue.trimmed() );
423  }
424 
425 #if 0
426  pSocket->SetDestAddress( peerAddress, peerPort );
427 #endif
428 
429  // --------------------------------------------------------------
430  // See if this is a valid request
431  // --------------------------------------------------------------
432 
433  switch( eType )
434  {
435  case SSDP_MSearch:
436  {
437  // ----------------------------------------------------------
438  // If we haven't enabled notifications yet, then we don't
439  // want to answer search requests.
440  // ----------------------------------------------------------
441 
442  if (m_pNotifyTask != nullptr)
443  ProcessSearchRequest( headers, peerAddress, peerPort );
444 
445  break;
446  }
447 
448  case SSDP_MSearchResp:
449  ProcessSearchResponse( headers);
450  break;
451 
452  case SSDP_Notify:
453  ProcessNotify( headers );
454  break;
455 
456  case SSDP_Unknown:
457  default:
458  LOG(VB_UPNP, LOG_ERR,
459  "SSPD::ProcessData - Unknown request Type.");
460  break;
461  }
462  }
463 }
464 
466 //
468 
470 {
471 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
472  QStringList tokens = sLine.split(m_procReqLineExp, QString::SkipEmptyParts);
473 #else
474  QStringList tokens = sLine.split(m_procReqLineExp, Qt::SkipEmptyParts);
475 #endif
476 
477  // ----------------------------------------------------------------------
478  // if this is actually a response, then sLine's format will be:
479  // HTTP/m.n <response code> <response text>
480  // otherwise:
481  // <method> <Resource URI> HTTP/m.n
482  // ----------------------------------------------------------------------
483 
484  if ( sLine.startsWith( QString("HTTP/") ))
485  return SSDP_MSearchResp;
486 
487  if (tokens.count() > 0)
488  {
489  if (tokens[0] == "M-SEARCH" ) return SSDP_MSearch;
490  if (tokens[0] == "NOTIFY" ) return SSDP_Notify;
491  }
492 
493  return SSDP_Unknown;
494 }
495 
497 //
499 
500 QString SSDP::GetHeaderValue( const QStringMap &headers,
501  const QString &sKey, const QString &sDefault )
502 {
503  QStringMap::const_iterator it = headers.find( sKey.toLower() );
504 
505  if ( it == headers.end())
506  return( sDefault );
507 
508  return *it;
509 }
510 
512 //
514 
515 bool SSDP::ProcessSearchRequest( const QStringMap &sHeaders,
516  const QHostAddress& peerAddress,
517  quint16 peerPort ) const
518 {
519  QString sMAN = GetHeaderValue( sHeaders, "MAN", "" );
520  QString sST = GetHeaderValue( sHeaders, "ST" , "" );
521  QString sMX = GetHeaderValue( sHeaders, "MX" , "" );
522  std::chrono::seconds nMX = 0s;
523 
524  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessSearchrequest : [%1] MX=%2")
525  .arg(sST, sMX));
526 
527  // ----------------------------------------------------------------------
528  // Validate Header Values...
529  // ----------------------------------------------------------------------
530 
531 #if 0
532  if ( pRequest->m_sMethod != "*" ) return false;
533  if ( pRequest->m_sProtocol != "HTTP" ) return false;
534  if ( pRequest->m_nMajor != 1 ) return false;
535 #endif
536  if ( sMAN != "\"ssdp:discover\"" ) return false;
537  if ( sST.length() == 0 ) return false;
538  if ( sMX.length() == 0 ) return false;
539  if ((nMX = std::chrono::seconds(sMX.toInt())) == 0s) return false;
540  if ( nMX < 0s ) return false;
541 
542  // ----------------------------------------------------------------------
543  // Adjust timeout to be a random interval between 0 and MX (max of 120)
544  // ----------------------------------------------------------------------
545 
546  nMX = std::clamp(nMX, 0s, 120s);
547 
548  auto nNewMX = std::chrono::milliseconds(MythRandom(0, (duration_cast<std::chrono::milliseconds>(nMX)).count()));
549 
550  // ----------------------------------------------------------------------
551  // See what they are looking for...
552  // ----------------------------------------------------------------------
553 
554  if ((sST == "ssdp:all") || (sST == "upnp:rootdevice"))
555  {
556  auto *pTask = new UPnpSearchTask( m_nServicePort,
557  peerAddress, peerPort, sST,
558  UPnp::g_UPnpDeviceDesc.m_rootDevice.GetUDN());
559 
560 #if 0
561  // Excute task now for fastest response, queue for time-delayed response
562  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
563  pTask->Execute( nullptr );
564 #endif
565 
566  TaskQueue::Instance()->AddTask( nNewMX, pTask );
567 
568  pTask->DecrRef();
569 
570  return true;
571  }
572 
573  // ----------------------------------------------------------------------
574  // Look for a specific device/service
575  // ----------------------------------------------------------------------
576 
577  QString sUDN = UPnp::g_UPnpDeviceDesc.FindDeviceUDN(
578  &(UPnp::g_UPnpDeviceDesc.m_rootDevice), sST );
579 
580  if (sUDN.length() > 0)
581  {
582  auto *pTask = new UPnpSearchTask( m_nServicePort, peerAddress,
583  peerPort, sST, sUDN );
584 
585  // Excute task now for fastest response, queue for time-delayed response
586  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
587  pTask->Execute( nullptr );
588 
589  TaskQueue::Instance()->AddTask( nNewMX, pTask );
590 
591  pTask->DecrRef();
592 
593  return true;
594  }
595 
596  return false;
597 }
598 
600 //
602 
604 {
605  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
606  QString sST = GetHeaderValue( headers, "ST" , "" );
607  QString sUSN = GetHeaderValue( headers, "USN" , "" );
608  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
609 
610  LOG(VB_UPNP, LOG_DEBUG,
611  QString( "SSDP::ProcessSearchResponse ...\n"
612  "DescURL=%1\n"
613  "ST =%2\n"
614  "USN =%3\n"
615  "Cache =%4")
616  .arg(sDescURL, sST, sUSN, sCache));
617 
618  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
619 
620  if (nPos < 0)
621  return false;
622 
623  if ((nPos = sCache.indexOf("=", nPos)) < 0)
624  return false;
625 
626  auto nSecs = std::chrono::seconds(sCache.mid( nPos+1 ).toInt());
627 
628  SSDPCache::Instance()->Add( sST, sUSN, sDescURL, nSecs );
629 
630  return true;
631 }
632 
634 //
636 
637 bool SSDP::ProcessNotify( const QStringMap &headers )
638 {
639  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
640  QString sNTS = GetHeaderValue( headers, "NTS" , "" );
641  QString sNT = GetHeaderValue( headers, "NT" , "" );
642  QString sUSN = GetHeaderValue( headers, "USN" , "" );
643  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
644 
645  LOG(VB_UPNP, LOG_DEBUG,
646  QString( "SSDP::ProcessNotify ...\n"
647  "DescURL=%1\n"
648  "NTS =%2\n"
649  "NT =%3\n"
650  "USN =%4\n"
651  "Cache =%5" )
652  .arg(sDescURL, sNTS, sNT, sUSN, sCache));
653 
654  if (sNTS.contains( "ssdp:alive"))
655  {
656  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
657 
658  if (nPos < 0)
659  return false;
660 
661  if ((nPos = sCache.indexOf("=", nPos)) < 0)
662  return false;
663 
664  auto nSecs = std::chrono::seconds(sCache.mid( nPos+1 ).toInt());
665 
666  SSDPCache::Instance()->Add( sNT, sUSN, sDescURL, nSecs );
667 
668  return true;
669  }
670 
671 
672  if ( sNTS.contains( "ssdp:byebye" ) )
673  {
674  SSDPCache::Instance()->Remove( sNT, sUSN );
675 
676  return true;
677  }
678 
679  return false;
680 }
681 
684 //
685 // SSDPExtension Implementation
686 //
689 
691 //
693 
694 SSDPExtension::SSDPExtension( int nServicePort , const QString &sSharePath)
695  : HttpServerExtension( "SSDP" , sSharePath),
696  m_nServicePort(nServicePort)
697 {
699  m_sUPnpDescPath = XmlConfiguration().GetValue("UPnP/DescXmlPath", m_sSharePath);
700 }
701 
703 //
705 
706 SSDPMethod SSDPExtension::GetMethod( const QString &sURI )
707 {
708  if (sURI == "getDeviceDesc" ) return( SSDPM_GetDeviceDesc );
709  if (sURI == "getDeviceList" ) return( SSDPM_GetDeviceList );
710 
711  return( SSDPM_Unknown );
712 }
713 
715 //
717 
719 {
720  // -=>TODO: This is very inefficient... should look into making
721  // it a unique path.
722 
723  return QStringList( "/" );
724 }
725 
727 //
729 
731 {
732  if (pRequest)
733  {
734  if ( pRequest->m_sBaseUrl != "/")
735  return( false );
736 
737  switch( GetMethod( pRequest->m_sMethod ))
738  {
739  case SSDPM_GetDeviceDesc: GetDeviceDesc( pRequest ); return( true );
740  case SSDPM_GetDeviceList: GetDeviceList( pRequest ); return( true );
741 
742  default: break;
743  }
744  }
745 
746  return( false );
747 }
748 
750 //
752 
754 {
755  pRequest->m_eResponseType = ResponseTypeXML;
756 
757  QString sUserAgent = pRequest->GetRequestHeader( "User-Agent", "" );
758 
759  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceDesc - " +
760  QString( "Host=%1 Port=%2 UserAgent=%3" )
761  .arg(pRequest->GetHostAddress()) .arg(m_nServicePort)
762  .arg(sUserAgent));
763 
764  QTextStream stream( &(pRequest->m_response) );
765 
768  stream,
769  sUserAgent );
770 }
771 
773 //
775 
776 void SSDPExtension::GetFile( HTTPRequest *pRequest, const QString& sFileName )
777 {
778  pRequest->m_eResponseType = ResponseTypeHTML;
779 
780  pRequest->m_sFileName = m_sUPnpDescPath + sFileName;
781 
782  if (QFile::exists( pRequest->m_sFileName ))
783  {
784  LOG(VB_UPNP, LOG_DEBUG,
785  QString("SSDPExtension::GetFile( %1 ) - Exists")
786  .arg(pRequest->m_sFileName));
787 
788  pRequest->m_eResponseType = ResponseTypeFile;
789  pRequest->m_nResponseStatus = 200;
790  pRequest->m_mapRespHeaders[ "Cache-Control" ]
791  = "no-cache=\"Ext\", max-age = 7200"; // 2 hours
792  }
793  else
794  {
795  pRequest->m_nResponseStatus = 404;
796  pRequest->m_response.write( pRequest->GetResponsePage() );
797  LOG(VB_UPNP, LOG_ERR,
798  QString("SSDPExtension::GetFile( %1 ) - Not Found")
799  .arg(pRequest->m_sFileName));
800  }
801 
802 }
803 
805 //
807 
809 {
810  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceList");
811 
812  QString sXML;
813  QTextStream os(&sXML, QIODevice::WriteOnly);
814 
815  uint nDevCount = 0;
816  uint nEntryCount = 0;
817  SSDPCache::Instance()->OutputXML(os, &nDevCount, &nEntryCount);
818 
819  NameValues list;
820  list.push_back(
821  NameValue("DeviceCount", (int)nDevCount));
822  list.push_back(
823  NameValue("DevicesAllocated", SSDPCacheEntries::g_nAllocated));
824  list.push_back(
825  NameValue("CacheEntriesFound", (int)nEntryCount));
826  list.push_back(
827  NameValue("CacheEntriesAllocated", DeviceLocation::g_nAllocated));
828  list.push_back(
829  NameValue("DeviceList", sXML));
830 
831  pRequest->FormatActionResponse(list);
832 
833  pRequest->m_eResponseType = ResponseTypeXML;
834  pRequest->m_nResponseStatus = 200;
835 }
HTTPRequest::GetRequestHeader
QString GetRequestHeader(const QString &sKey, const QString &sDefault)
Definition: httprequest.cpp:1109
NameValue
Definition: upnputil.h:40
HTTPRequest::m_sBaseUrl
QString m_sBaseUrl
Definition: httprequest.h:127
DeviceLocation::g_nAllocated
static int g_nAllocated
Definition: upnpdevice.h:214
HttpServerExtension::m_nSupportedMethods
uint m_nSupportedMethods
Definition: httpserver.h:83
SSDPExtension::m_nServicePort
int m_nServicePort
Definition: ssdp.h:152
HTTPRequest
Definition: httprequest.h:109
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
SSDP::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: ssdp.cpp:248
SSDPExtension::GetBasePaths
QStringList GetBasePaths() override
Definition: ssdp.cpp:718
UPnpDeviceDesc::GetValidXML
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
Definition: upnpdevice.cpp:324
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
SSDP::PerformSearch
void PerformSearch(const QString &sST, std::chrono::seconds timeout=2s)
Definition: ssdp.cpp:204
mythrandom.h
ssdp.h
UPnpSearchTask
Definition: upnptasksearch.h:41
UPnpNotifyTask
Definition: upnptasknotify.h:53
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
HTTPRequest::m_sMethod
QString m_sMethod
Definition: httprequest.h:129
SSDP::g_pSSDP
static SSDP * g_pSSDP
Definition: ssdp.h:67
MMulticastSocketDevice
Definition: mmulticastsocketdevice.h:48
g_pSSDPCreationLock
static QMutex g_pSSDPCreationLock
Definition: ssdp.cpp:48
SSDP::m_pNotifyTask
UPnpNotifyTask * m_pNotifyTask
Definition: ssdp.h:77
upnptasksearch.h
SSDPM_GetDeviceList
@ SSDPM_GetDeviceList
Definition: ssdp.h:37
NTS_alive
@ NTS_alive
Definition: upnptasknotify.h:41
SSDP_MSearch
@ SSDP_MSearch
Definition: ssdp.h:43
NTS_byebye
@ NTS_byebye
Definition: upnptasknotify.h:42
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
UPnpDeviceDesc::FindDeviceUDN
QString FindDeviceUDN(UPnpDevice *pDevice, QString sST)
Definition: upnpdevice.cpp:548
SSDP::ProcessSearchResponse
static bool ProcessSearchResponse(const QStringMap &sHeaders)
Definition: ssdp.cpp:603
SSDP::m_nSearchPort
int m_nSearchPort
Definition: ssdp.h:74
SSDP::m_nPort
int m_nPort
Definition: ssdp.h:73
SSDPCache::Instance
static SSDPCache * Instance()
Definition: ssdpcache.cpp:245
XmlConfiguration
Definition: configuration.h:38
SSDP::Shutdown
static void Shutdown()
Definition: ssdp.cpp:65
SSDPCache::Add
void Add(const QString &sURI, const QString &sUSN, const QString &sLocation, std::chrono::seconds sExpiresInSecs)
Definition: ssdpcache.cpp:332
ResponseTypeFile
@ ResponseTypeFile
Definition: httprequest.h:84
HTTPRequest::m_mapRespHeaders
QStringMap m_mapRespHeaders
Definition: httprequest.h:153
SSDP::m_nServicePort
int m_nServicePort
Definition: ssdp.h:75
SSDP::Instance
static SSDP * Instance()
Definition: ssdp.cpp:55
NameValues
Definition: upnputil.h:77
HTTPRequest::FormatActionResponse
void FormatActionResponse(Serializer *ser)
Definition: httprequest.cpp:700
SocketIdx_Broadcast
@ SocketIdx_Broadcast
Definition: ssdp.h:60
SSDP_MSearchResp
@ SSDP_MSearchResp
Definition: ssdp.h:44
SSDP::ProcessNotify
static bool ProcessNotify(const QStringMap &sHeaders)
Definition: ssdp.cpp:637
upnp.h
HTTPRequest::m_nResponseStatus
long m_nResponseStatus
Definition: httprequest.h:152
SSDP::m_bTermRequested
bool m_bTermRequested
Definition: ssdp.h:80
mythlogging.h
RequestTypeMSearch
@ RequestTypeMSearch
Definition: httprequest.h:57
HTTPRequest::GetResponsePage
QByteArray GetResponsePage(void)
Definition: httprequest.cpp:949
SocketIdx_Multicast
@ SocketIdx_Multicast
Definition: ssdp.h:59
TaskQueue::Instance
static TaskQueue * Instance()
Definition: taskqueue.cpp:59
SSDPExtension::GetMethod
static SSDPMethod GetMethod(const QString &sURI)
Definition: ssdp.cpp:706
QStringMap
QMap< QString, QString > QStringMap
Definition: upnputil.h:32
SSDPExtension::m_sUPnpDescPath
QString m_sUPnpDescPath
Definition: ssdp.h:151
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
SSDP::~SSDP
~SSDP() override
Definition: ssdp.cpp:118
SSDP_Notify
@ SSDP_Notify
Definition: ssdp.h:45
ResponseTypeXML
@ ResponseTypeXML
Definition: httprequest.h:78
uint
unsigned int uint
Definition: compat.h:79
SSDP_SEARCHPORT
static constexpr uint16_t SSDP_SEARCHPORT
Definition: ssdp.h:31
SSDP::ProcessRequestLine
SSDPRequestType ProcessRequestLine(const QString &sLine)
Definition: ssdp.cpp:469
SSDPExtension::ProcessRequest
bool ProcessRequest(HTTPRequest *pRequest) override
Definition: ssdp.cpp:730
SSDPCache::Remove
void Remove(const QString &sURI, const QString &sUSN)
Definition: ssdpcache.cpp:415
SSDP::kNumberOfSockets
constexpr static int kNumberOfSockets
Definition: ssdp.h:70
SSDP::SSDP
SSDP()
Definition: ssdp.cpp:76
SSDP::m_bAnnouncementsEnabled
bool m_bAnnouncementsEnabled
Definition: ssdp.h:78
HTTPRequest::m_sFileName
QString m_sFileName
Definition: httprequest.h:155
SSDP_Unknown
@ SSDP_Unknown
Definition: ssdp.h:42
ResponseTypeHTML
@ ResponseTypeHTML
Definition: httprequest.h:79
SSDP::DisableNotifications
void DisableNotifications()
Definition: ssdp.cpp:188
SSDPM_Unknown
@ SSDPM_Unknown
Definition: ssdp.h:35
SSDPMethod
SSDPMethod
Definition: ssdp.h:33
SSDPCacheEntries::g_nAllocated
static int g_nAllocated
Definition: ssdpcache.h:63
SSDPCache::OutputXML
QTextStream & OutputXML(QTextStream &os, uint *pnDevCount=nullptr, uint *pnEntryCount=nullptr) const
Outputs the XML for this device.
Definition: ssdpcache.cpp:548
RequestTypeNotify
@ RequestTypeNotify
Definition: httprequest.h:60
XmlConfiguration::GetValue
QString GetValue(const QString &setting)
Definition: configuration.cpp:183
upnptaskcache.h
SSDPRequestType
SSDPRequestType
Definition: ssdp.h:40
UPnpNotifyTask::SetNTS
void SetNTS(UPnpNotifyNTS nts)
Definition: upnptasknotify.h:110
SSDPExtension::GetDeviceList
static void GetDeviceList(HTTPRequest *pRequest)
Definition: ssdp.cpp:808
HTTPRequest::m_eResponseType
HttpResponseType m_eResponseType
Definition: httprequest.h:149
TaskQueue::AddTask
void AddTask(std::chrono::milliseconds msec, Task *pTask)
Add a task to run in the future.
Definition: taskqueue.cpp:172
mbroadcastsocketdevice.h
SSDPExtension::GetDeviceDesc
void GetDeviceDesc(HTTPRequest *pRequest) const
Definition: ssdp.cpp:753
configuration.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
SSDP::ProcessSearchRequest
bool ProcessSearchRequest(const QStringMap &sHeaders, const QHostAddress &peerAddress, quint16 peerPort) const
Definition: ssdp.cpp:515
mythchrono.h
SSDP::m_sockets
std::array< MSocketDevice *, kNumberOfSockets > m_sockets
Definition: ssdp.h:71
mmulticastsocketdevice.h
SSDPM_GetDeviceDesc
@ SSDPM_GetDeviceDesc
Definition: ssdp.h:36
SSDP
Definition: ssdp.h:63
SocketIdx_Search
@ SocketIdx_Search
Definition: ssdp.h:58
SSDP::EnableNotifications
void EnableNotifications(int nServicePort)
Definition: ssdp.cpp:148
SSDP_GROUP
static constexpr const char * SSDP_GROUP
Definition: ssdp.h:29
HTTPRequest::GetHostAddress
virtual QString GetHostAddress()=0
UPnpNotifyTask::Execute
void Execute(TaskQueue *pQueue) override
Definition: upnptasknotify.cpp:144
HttpServerExtension
Definition: httpserver.h:71
UPnp::g_UPnpDeviceDesc
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:109
SSDPExtension::SSDPExtension
SSDPExtension(int nServicePort, const QString &sSharePath)
Definition: ssdp.cpp:694
SSDP::ProcessData
void ProcessData(MSocketDevice *pSocket)
Definition: ssdp.cpp:316
SSDP::GetHeaderValue
static QString GetHeaderValue(const QStringMap &headers, const QString &sKey, const QString &sDefault)
Definition: ssdp.cpp:500
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
HTTPRequest::m_response
QBuffer m_response
Definition: httprequest.h:157
SSDPExtension::GetFile
void GetFile(HTTPRequest *pRequest, const QString &sFileName)
Definition: ssdp.cpp:776
MBroadcastSocketDevice
Definition: mbroadcastsocketdevice.h:26
SSDP_PORT
static constexpr uint16_t SSDP_PORT
Definition: ssdp.h:30
SSDP::RequestTerminate
void RequestTerminate(void)
Definition: ssdp.cpp:139
SSDP::m_procReqLineExp
QRegularExpression m_procReqLineExp
Definition: ssdp.h:69
HttpServerExtension::m_sSharePath
QString m_sSharePath
Definition: httpserver.h:78