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  QStringList lines = str.split("\r\n", Qt::SkipEmptyParts);
390  QString sRequestLine = !lines.empty() ? lines[0] : "";
391 
392  if (!lines.isEmpty())
393  lines.pop_front();
394 
395  // ------------------------------------------------------------------
396  // Parse request Type
397  // ------------------------------------------------------------------
398 
399  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessData - requestLine: %1")
400  .arg(sRequestLine));
401 
402  SSDPRequestType eType = ProcessRequestLine( sRequestLine );
403 
404  // ------------------------------------------------------------------
405  // Read Headers into map
406  // ------------------------------------------------------------------
407 
409 
410  for (const auto& sLine : std::as_const(lines))
411  {
412  QString sName = sLine.section( ':', 0, 0 ).trimmed();
413  QString sValue = sLine.section( ':', 1 );
414 
415  sValue.truncate( sValue.length() ); //-2
416 
417  if ((sName.length() != 0) && (sValue.length() !=0))
418  headers.insert( sName.toLower(), sValue.trimmed() );
419  }
420 
421 #if 0
422  pSocket->SetDestAddress( peerAddress, peerPort );
423 #endif
424 
425  // --------------------------------------------------------------
426  // See if this is a valid request
427  // --------------------------------------------------------------
428 
429  switch( eType )
430  {
431  case SSDP_MSearch:
432  {
433  // ----------------------------------------------------------
434  // If we haven't enabled notifications yet, then we don't
435  // want to answer search requests.
436  // ----------------------------------------------------------
437 
438  if (m_pNotifyTask != nullptr)
439  ProcessSearchRequest( headers, peerAddress, peerPort );
440 
441  break;
442  }
443 
444  case SSDP_MSearchResp:
446  break;
447 
448  case SSDP_Notify:
450  break;
451 
452  case SSDP_Unknown:
453  default:
454  LOG(VB_UPNP, LOG_ERR,
455  "SSPD::ProcessData - Unknown request Type.");
456  break;
457  }
458  }
459 }
460 
462 //
464 
466 {
467  QStringList tokens = sLine.split(m_procReqLineExp, Qt::SkipEmptyParts);
468 
469  // ----------------------------------------------------------------------
470  // if this is actually a response, then sLine's format will be:
471  // HTTP/m.n <response code> <response text>
472  // otherwise:
473  // <method> <Resource URI> HTTP/m.n
474  // ----------------------------------------------------------------------
475 
476  if ( sLine.startsWith( QString("HTTP/") ))
477  return SSDP_MSearchResp;
478 
479  if (tokens.count() > 0)
480  {
481  if (tokens[0] == "M-SEARCH" ) return SSDP_MSearch;
482  if (tokens[0] == "NOTIFY" ) return SSDP_Notify;
483  }
484 
485  return SSDP_Unknown;
486 }
487 
489 //
491 
493  const QString &sKey, const QString &sDefault )
494 {
495  QStringMap::const_iterator it = headers.find( sKey.toLower() );
496 
497  if ( it == headers.end())
498  return( sDefault );
499 
500  return *it;
501 }
502 
504 //
506 
507 bool SSDP::ProcessSearchRequest( const QStringMap &sHeaders,
508  const QHostAddress& peerAddress,
509  quint16 peerPort ) const
510 {
511  QString sMAN = GetHeaderValue( sHeaders, "MAN", "" );
512  QString sST = GetHeaderValue( sHeaders, "ST" , "" );
513  QString sMX = GetHeaderValue( sHeaders, "MX" , "" );
514  std::chrono::seconds nMX = 0s;
515 
516  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessSearchrequest : [%1] MX=%2")
517  .arg(sST, sMX));
518 
519  // ----------------------------------------------------------------------
520  // Validate Header Values...
521  // ----------------------------------------------------------------------
522 
523 #if 0
524  if ( pRequest->m_sMethod != "*" ) return false;
525  if ( pRequest->m_sProtocol != "HTTP" ) return false;
526  if ( pRequest->m_nMajor != 1 ) return false;
527 #endif
528  if ( sMAN != "\"ssdp:discover\"" ) return false;
529  if ( sST.length() == 0 ) return false;
530  if ( sMX.length() == 0 ) return false;
531  nMX = std::chrono::seconds(sMX.toInt());
532  if ( nMX <= 0s ) return false;
533 
534  // ----------------------------------------------------------------------
535  // Adjust timeout to be a random interval between 0 and MX (max of 120)
536  // ----------------------------------------------------------------------
537 
538  nMX = std::clamp(nMX, 0s, 120s);
539 
540  auto nNewMX = std::chrono::milliseconds(MythRandom(0, (duration_cast<std::chrono::milliseconds>(nMX)).count()));
541 
542  // ----------------------------------------------------------------------
543  // See what they are looking for...
544  // ----------------------------------------------------------------------
545 
546  if ((sST == "ssdp:all") || (sST == "upnp:rootdevice"))
547  {
548  auto *pTask = new UPnpSearchTask( m_nServicePort,
549  peerAddress, peerPort, sST,
550  UPnp::g_UPnpDeviceDesc.m_rootDevice.GetUDN());
551 
552 #if 0
553  // Excute task now for fastest response, queue for time-delayed response
554  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
555  pTask->Execute( nullptr );
556 #endif
557 
558  TaskQueue::Instance()->AddTask( nNewMX, pTask );
559 
560  pTask->DecrRef();
561 
562  return true;
563  }
564 
565  // ----------------------------------------------------------------------
566  // Look for a specific device/service
567  // ----------------------------------------------------------------------
568 
569  QString sUDN = UPnp::g_UPnpDeviceDesc.FindDeviceUDN(
570  &(UPnp::g_UPnpDeviceDesc.m_rootDevice), sST );
571 
572  if (sUDN.length() > 0)
573  {
574  auto *pTask = new UPnpSearchTask( m_nServicePort, peerAddress,
575  peerPort, sST, sUDN );
576 
577  // Excute task now for fastest response, queue for time-delayed response
578  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
579  pTask->Execute( nullptr );
580 
581  TaskQueue::Instance()->AddTask( nNewMX, pTask );
582 
583  pTask->DecrRef();
584 
585  return true;
586  }
587 
588  return false;
589 }
590 
592 //
594 
596 {
597  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
598  QString sST = GetHeaderValue( headers, "ST" , "" );
599  QString sUSN = GetHeaderValue( headers, "USN" , "" );
600  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
601 
602  LOG(VB_UPNP, LOG_DEBUG,
603  QString( "SSDP::ProcessSearchResponse ...\n"
604  "DescURL=%1\n"
605  "ST =%2\n"
606  "USN =%3\n"
607  "Cache =%4")
608  .arg(sDescURL, sST, sUSN, sCache));
609 
610  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
611 
612  if (nPos < 0)
613  return false;
614 
615  nPos = sCache.indexOf("=", nPos);
616  if (nPos < 0)
617  return false;
618 
619  auto nSecs = std::chrono::seconds(sCache.mid( nPos+1 ).toInt());
620 
621  SSDPCache::Instance()->Add( sST, sUSN, sDescURL, nSecs );
622 
623  return true;
624 }
625 
627 //
629 
631 {
632  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
633  QString sNTS = GetHeaderValue( headers, "NTS" , "" );
634  QString sNT = GetHeaderValue( headers, "NT" , "" );
635  QString sUSN = GetHeaderValue( headers, "USN" , "" );
636  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
637 
638  LOG(VB_UPNP, LOG_DEBUG,
639  QString( "SSDP::ProcessNotify ...\n"
640  "DescURL=%1\n"
641  "NTS =%2\n"
642  "NT =%3\n"
643  "USN =%4\n"
644  "Cache =%5" )
645  .arg(sDescURL, sNTS, sNT, sUSN, sCache));
646 
647  if (sNTS.contains( "ssdp:alive"))
648  {
649  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
650 
651  if (nPos < 0)
652  return false;
653 
654  nPos = sCache.indexOf("=", nPos);
655  if (nPos < 0)
656  return false;
657 
658  auto nSecs = std::chrono::seconds(sCache.mid( nPos+1 ).toInt());
659 
660  SSDPCache::Instance()->Add( sNT, sUSN, sDescURL, nSecs );
661 
662  return true;
663  }
664 
665 
666  if ( sNTS.contains( "ssdp:byebye" ) )
667  {
668  SSDPCache::Instance()->Remove( sNT, sUSN );
669 
670  return true;
671  }
672 
673  return false;
674 }
675 
678 //
679 // SSDPExtension Implementation
680 //
683 
685 //
687 
688 SSDPExtension::SSDPExtension( int nServicePort , const QString &sSharePath)
689  : HttpServerExtension( "SSDP" , sSharePath),
690  m_nServicePort(nServicePort)
691 {
693  m_sUPnpDescPath = XmlConfiguration().GetValue("UPnP/DescXmlPath", m_sSharePath);
694 }
695 
697 //
699 
700 SSDPMethod SSDPExtension::GetMethod( const QString &sURI )
701 {
702  if (sURI == "getDeviceDesc" ) return( SSDPM_GetDeviceDesc );
703  if (sURI == "getDeviceList" ) return( SSDPM_GetDeviceList );
704 
705  return( SSDPM_Unknown );
706 }
707 
709 //
711 
713 {
714  // -=>TODO: This is very inefficient... should look into making
715  // it a unique path.
716 
717  return QStringList( "/" );
718 }
719 
721 //
723 
725 {
726  if (pRequest)
727  {
728  if ( pRequest->m_sBaseUrl != "/")
729  return( false );
730 
731  switch( GetMethod( pRequest->m_sMethod ))
732  {
733  case SSDPM_GetDeviceDesc: GetDeviceDesc( pRequest ); return( true );
734  case SSDPM_GetDeviceList: GetDeviceList( pRequest ); return( true );
735 
736  default: break;
737  }
738  }
739 
740  return( false );
741 }
742 
744 //
746 
748 {
749  pRequest->m_eResponseType = ResponseTypeXML;
750 
751  QString sUserAgent = pRequest->GetRequestHeader( "User-Agent", "" );
752 
753  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceDesc - " +
754  QString( "Host=%1 Port=%2 UserAgent=%3" )
755  .arg(pRequest->GetHostAddress()) .arg(m_nServicePort)
756  .arg(sUserAgent));
757 
758  QTextStream stream( &(pRequest->m_response) );
759 
762  stream,
763  sUserAgent );
764 }
765 
767 //
769 
770 void SSDPExtension::GetFile( HTTPRequest *pRequest, const QString& sFileName )
771 {
772  pRequest->m_eResponseType = ResponseTypeHTML;
773 
774  pRequest->m_sFileName = m_sUPnpDescPath + sFileName;
775 
776  if (QFile::exists( pRequest->m_sFileName ))
777  {
778  LOG(VB_UPNP, LOG_DEBUG,
779  QString("SSDPExtension::GetFile( %1 ) - Exists")
780  .arg(pRequest->m_sFileName));
781 
782  pRequest->m_eResponseType = ResponseTypeFile;
783  pRequest->m_nResponseStatus = 200;
784  pRequest->m_mapRespHeaders[ "Cache-Control" ]
785  = "no-cache=\"Ext\", max-age = 7200"; // 2 hours
786  }
787  else
788  {
789  pRequest->m_nResponseStatus = 404;
790  pRequest->m_response.write( pRequest->GetResponsePage() );
791  LOG(VB_UPNP, LOG_ERR,
792  QString("SSDPExtension::GetFile( %1 ) - Not Found")
793  .arg(pRequest->m_sFileName));
794  }
795 
796 }
797 
799 //
801 
803 {
804  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceList");
805 
806  QString sXML;
807  QTextStream os(&sXML, QIODevice::WriteOnly);
808 
809  uint nDevCount = 0;
810  uint nEntryCount = 0;
811  SSDPCache::Instance()->OutputXML(os, &nDevCount, &nEntryCount);
812 
813  NameValues list;
814  list.push_back(
815  NameValue("DeviceCount", (int)nDevCount));
816  list.push_back(
817  NameValue("DevicesAllocated", SSDPCacheEntries::g_nAllocated));
818  list.push_back(
819  NameValue("CacheEntriesFound", (int)nEntryCount));
820  list.push_back(
821  NameValue("CacheEntriesAllocated", DeviceLocation::g_nAllocated));
822  list.push_back(
823  NameValue("DeviceList", sXML));
824 
825  pRequest->FormatActionResponse(list);
826 
827  pRequest->m_eResponseType = ResponseTypeXML;
828  pRequest->m_nResponseStatus = 200;
829 }
HTTPRequest::GetRequestHeader
QString GetRequestHeader(const QString &sKey, const QString &sDefault)
Definition: httprequest.cpp:1110
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:102
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:712
UPnpDeviceDesc::GetValidXML
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
Definition: upnpdevice.cpp:318
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
SSDPM_GetDeviceDesc
@ SSDPM_GetDeviceDesc
Definition: ssdp.h:36
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
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
upnptasksearch.h
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:542
SSDP::ProcessSearchResponse
static bool ProcessSearchResponse(const QStringMap &sHeaders)
Definition: ssdp.cpp:595
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:237
ResponseTypeFile
@ ResponseTypeFile
Definition: httprequest.h:84
XmlConfiguration
Definition: configuration.h:38
SSDP::Shutdown
static void Shutdown()
Definition: ssdp.cpp:65
SSDPM_Unknown
@ SSDPM_Unknown
Definition: ssdp.h:35
SSDPCache::Add
void Add(const QString &sURI, const QString &sUSN, const QString &sLocation, std::chrono::seconds sExpiresInSecs)
Definition: ssdpcache.cpp:324
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
SSDP::ProcessNotify
static bool ProcessNotify(const QStringMap &sHeaders)
Definition: ssdp.cpp:630
upnp.h
HTTPRequest::m_nResponseStatus
long m_nResponseStatus
Definition: httprequest.h:152
SSDP::m_bTermRequested
bool m_bTermRequested
Definition: ssdp.h:80
mythlogging.h
SocketIdx_Search
@ SocketIdx_Search
Definition: ssdp.h:58
HTTPRequest::GetResponsePage
QByteArray GetResponsePage(void)
Definition: httprequest.cpp:953
SSDP_Unknown
@ SSDP_Unknown
Definition: ssdp.h:42
TaskQueue::Instance
static TaskQueue * Instance()
Definition: taskqueue.cpp:60
SSDPExtension::GetMethod
static SSDPMethod GetMethod(const QString &sURI)
Definition: ssdp.cpp:700
QStringMap
QMap< QString, QString > QStringMap
Definition: upnputil.h:32
RequestTypeMSearch
@ RequestTypeMSearch
Definition: httprequest.h:57
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
SocketIdx_Broadcast
@ SocketIdx_Broadcast
Definition: ssdp.h:60
SSDPM_GetDeviceList
@ SSDPM_GetDeviceList
Definition: ssdp.h:37
RequestTypeNotify
@ RequestTypeNotify
Definition: httprequest.h:60
SSDP_Notify
@ SSDP_Notify
Definition: ssdp.h:45
uint
unsigned int uint
Definition: compat.h:81
SSDP_SEARCHPORT
static constexpr uint16_t SSDP_SEARCHPORT
Definition: ssdp.h:31
SSDP::ProcessRequestLine
SSDPRequestType ProcessRequestLine(const QString &sLine)
Definition: ssdp.cpp:465
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
SSDPExtension::ProcessRequest
bool ProcessRequest(HTTPRequest *pRequest) override
Definition: ssdp.cpp:724
SSDPCache::Remove
void Remove(const QString &sURI, const QString &sUSN)
Definition: ssdpcache.cpp:409
ResponseTypeHTML
@ ResponseTypeHTML
Definition: httprequest.h:79
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
SSDPMethod
SSDPMethod
Definition: ssdp.h:33
HTTPRequest::m_sFileName
QString m_sFileName
Definition: httprequest.h:155
SSDP::DisableNotifications
void DisableNotifications()
Definition: ssdp.cpp:188
SSDPCacheEntries::g_nAllocated
static int g_nAllocated
Definition: ssdpcache.h:63
SocketIdx_Multicast
@ SocketIdx_Multicast
Definition: ssdp.h:59
SSDPCache::OutputXML
QTextStream & OutputXML(QTextStream &os, uint *pnDevCount=nullptr, uint *pnEntryCount=nullptr) const
Outputs the XML for this device.
Definition: ssdpcache.cpp:542
XmlConfiguration::GetValue
QString GetValue(const QString &setting)
Definition: configuration.cpp:185
NTS_byebye
@ NTS_byebye
Definition: upnptasknotify.h:42
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:802
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:173
mbroadcastsocketdevice.h
SSDPExtension::GetDeviceDesc
void GetDeviceDesc(HTTPRequest *pRequest) const
Definition: ssdp.cpp:747
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:507
mythchrono.h
SSDP::m_sockets
std::array< MSocketDevice *, kNumberOfSockets > m_sockets
Definition: ssdp.h:71
mmulticastsocketdevice.h
SSDP
Definition: ssdp.h:63
SSDP_MSearchResp
@ SSDP_MSearchResp
Definition: ssdp.h:44
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:143
HttpServerExtension
Definition: httpserver.h:71
culrcscrapers.music163.lyricsScraper.headers
dictionary headers
Definition: lyricsScraper.py:19
UPnp::g_UPnpDeviceDesc
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:109
SSDPExtension::SSDPExtension
SSDPExtension(int nServicePort, const QString &sSharePath)
Definition: ssdp.cpp:688
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:492
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
HTTPRequest::m_response
QBuffer m_response
Definition: httprequest.h:157
SSDP_MSearch
@ SSDP_MSearch
Definition: ssdp.h:43
SSDPExtension::GetFile
void GetFile(HTTPRequest *pRequest, const QString &sFileName)
Definition: ssdp.cpp:770
ResponseTypeXML
@ ResponseTypeXML
Definition: httprequest.h:78
MBroadcastSocketDevice
Definition: mbroadcastsocketdevice.h:26
NTS_alive
@ NTS_alive
Definition: upnptasknotify.h:41
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