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