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