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