MythTV  0.28pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
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 
15 #include "upnp.h"
16 #include "mythlogging.h"
17 
18 #include "upnptasksearch.h"
19 #include "upnptaskcache.h"
20 
21 #include "mmulticastsocketdevice.h"
22 #include "mbroadcastsocketdevice.h"
23 
24 #include <QRegExp>
25 #include <QStringList>
26 
27 #include <stdlib.h>
28 #include <errno.h>
29 
30 using namespace std;
31 
34 //
35 // SSDP Class Implementation
36 //
39 
40 // We're creating this class immediately so it will always be available.
41 
42 static QMutex g_pSSDPCreationLock;
43 SSDP* SSDP::g_pSSDP = NULL;
44 
46 //
48 
50 {
51  QMutexLocker locker(&g_pSSDPCreationLock);
52  return g_pSSDP ? g_pSSDP : (g_pSSDP = new SSDP());
53 }
54 
56 //
58 
60 {
61  QMutexLocker locker(&g_pSSDPCreationLock);
62  delete g_pSSDP;
63  g_pSSDP = NULL;
64 }
65 
67 //
69 
71  MThread ("SSDP" ),
72  m_procReqLineExp ("[ \r\n][ \r\n]*"),
73  m_nPort ( SSDP_PORT ),
74  m_nSearchPort ( SSDP_SEARCHPORT ),
75  m_nServicePort ( 0 ),
76  m_pNotifyTask ( NULL ),
77  m_bAnnouncementsEnabled( false ),
78  m_bTermRequested ( false ),
79  m_lock ( QMutex::NonRecursive )
80 {
81  LOG(VB_UPNP, LOG_NOTICE, "Starting up SSDP Thread..." );
82 
84 
85  m_nPort = pConfig->GetValue("UPnP/SSDP/Port" , SSDP_PORT );
86  m_nSearchPort = pConfig->GetValue("UPnP/SSDP/SearchPort", SSDP_SEARCHPORT);
87 
88  m_Sockets[ SocketIdx_Search ] =
90  m_Sockets[ SocketIdx_Multicast ] =
91  new MMulticastSocketDevice(SSDP_GROUP, m_nPort);
92  m_Sockets[ SocketIdx_Broadcast ] =
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 
124  m_bTermRequested = true;
125  wait();
126 
127  if (m_pNotifyTask != NULL)
128  {
130  m_pNotifyTask = NULL;
131  }
132 
133  for (int nIdx = 0; nIdx < (int)NumberOfSockets; nIdx++ )
134  {
135  if (m_Sockets[ nIdx ] != NULL )
136  {
137  delete m_Sockets[ nIdx ];
138  }
139  }
140 
141  LOG(VB_UPNP, LOG_INFO, "SSDP Thread Terminated." );
142 }
143 
145 {
146  m_bTermRequested = true;
147 }
148 
150 //
152 
153 void SSDP::EnableNotifications( int nServicePort )
154 {
155  if ( m_pNotifyTask == NULL )
156  {
157  m_nServicePort = nServicePort;
158 
159  LOG(VB_UPNP, LOG_INFO,
160  "SSDP::EnableNotifications() - creating new task");
162 
163  // ------------------------------------------------------------------
164  // First Send out Notification that we are leaving the network.
165  // ------------------------------------------------------------------
166 
167  LOG(VB_UPNP, LOG_INFO,
168  "SSDP::EnableNotifications() - sending NTS_byebye");
170  m_pNotifyTask->Execute( NULL );
171 
173  }
174 
175  // ------------------------------------------------------------------
176  // Add Announcement Task to the Queue
177  // ------------------------------------------------------------------
178 
179  LOG(VB_UPNP, LOG_INFO, "SSDP::EnableNotifications() - sending NTS_alive");
180 
182 
184 
185  LOG(VB_UPNP, LOG_INFO,
186  "SSDP::EnableNotifications() - Task added to UPnP queue");
187 }
188 
190 //
192 
194 {
195  m_bAnnouncementsEnabled = false;
196 
197  if (m_pNotifyTask != NULL)
198  {
199  // Send Announcement that we are leaving.
200 
202  m_pNotifyTask->Execute( NULL );
203  }
204 }
205 
207 //
209 void SSDP::PerformSearch(const QString &sST, uint timeout_secs)
210 {
211  timeout_secs = std::max(std::min(timeout_secs, 5U), 1U);
212  QString rRequest = QString("M-SEARCH * HTTP/1.1\r\n"
213  "HOST: 239.255.255.250:1900\r\n"
214  "MAN: \"ssdp:discover\"\r\n"
215  "MX: %1\r\n"
216  "ST: %2\r\n"
217  "\r\n")
218  .arg(timeout_secs).arg(sST);
219 
220  LOG(VB_UPNP, LOG_DEBUG, QString("\n\n%1\n").arg(rRequest));
221 
222  QByteArray sRequest = rRequest.toUtf8();
223 
224  MSocketDevice *pSocket = m_Sockets[ SocketIdx_Search ];
225  if ( !pSocket->isValid() )
226  {
228  pSocket->setSocket(pSocket->createNewSocket(), MSocketDevice::Datagram);
229  }
230 
231  QHostAddress address;
232  address.setAddress( SSDP_GROUP );
233 
234  int nSize = sRequest.size();
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  usleep( random() % 250000 );
242 
243  if ( pSocket->writeBlock( sRequest.data(),
244  sRequest.size(), address, SSDP_PORT ) != nSize)
245  LOG(VB_GENERAL, LOG_INFO,
246  "SSDP::PerformSearch - did not write entire buffer.");
247 }
248 
250 //
252 
253 void SSDP::run()
254 {
255  RunProlog();
256 
257  fd_set read_set;
258  struct timeval timeout;
259 
260  LOG(VB_UPNP, LOG_INFO, "SSDP::Run - SSDP Thread Started." );
261 
262  // ----------------------------------------------------------------------
263  // Listen for new Requests
264  // ----------------------------------------------------------------------
265 
266  while ( ! m_bTermRequested )
267  {
268  int nMaxSocket = 0;
269 
270  FD_ZERO( &read_set );
271 
272  for (uint nIdx = 0; nIdx < NumberOfSockets; nIdx++ )
273  {
274  if (m_Sockets[nIdx] != NULL && m_Sockets[nIdx]->socket() >= 0)
275  {
276  FD_SET( m_Sockets[ nIdx ]->socket(), &read_set );
277  nMaxSocket = max( m_Sockets[ nIdx ]->socket(), nMaxSocket );
278 
279 #if 0
280  if (m_Sockets[ nIdx ]->bytesAvailable() > 0)
281  {
282  LOG(VB_GENERAL, LOG_DEBUG,
283  QString("Found Extra data before select: %1")
284  .arg(nIdx));
285  ProcessData( m_Sockets[ nIdx ] );
286  }
287 #endif
288  }
289  }
290 
291  timeout.tv_sec = 1;
292  timeout.tv_usec = 0;
293 
294  int count;
295  count = select(nMaxSocket + 1, &read_set, NULL, NULL, &timeout);
296  for (int nIdx = 0; count && nIdx < (int)NumberOfSockets; nIdx++ )
297  {
298  if (m_Sockets[nIdx] != NULL && m_Sockets[nIdx]->socket() >= 0 &&
299  FD_ISSET(m_Sockets[nIdx]->socket(), &read_set))
300  {
301 #if 0
302  LOG(VB_GENERAL, LOG_DEBUG, QString("FD_ISSET( %1 )").arg(nIdx));
303 #endif
304  ProcessData(m_Sockets[nIdx]);
305  count--;
306  }
307  }
308  }
309 
310  RunEpilog();
311 }
312 
314 //
316 
318 {
319  QByteArray buffer;
320  long nBytes = 0;
321  int retries = 0;
322 
323  while ((nBytes = pSocket->bytesAvailable()) > 0)
324  {
325  buffer.resize(nBytes);
326 
327  long nRead = 0;
328  do
329  {
330  long ret = pSocket->readBlock( buffer.data() + nRead, nBytes - nRead );
331  if (ret < 0)
332  {
333  if (errno == EAGAIN || errno == EWOULDBLOCK)
334  {
335  if (retries == 3)
336  {
337  nBytes = nRead;
338  buffer.resize(nBytes);
339  break;
340  }
341  retries++;
342  usleep(10000);
343  continue;
344  }
345  LOG(VB_GENERAL, LOG_ERR, QString("Socket readBlock error %1")
346  .arg(pSocket->error()));
347  buffer.clear();
348  break;
349  }
350  retries = 0;
351 
352  nRead += ret;
353 
354  if (0 == ret)
355  {
356  LOG(VB_SOCKET, LOG_WARNING,
357  QString("%1 bytes reported available, "
358  "but only %2 bytes read.")
359  .arg(nBytes).arg(nRead));
360  nBytes = nRead;
361  buffer.resize(nBytes);
362  break;
363  }
364  }
365  while (nRead < nBytes);
366 
367  if (buffer.isEmpty())
368  continue;
369 
370  QHostAddress peerAddress = pSocket->peerAddress();
371  quint16 peerPort = pSocket->peerPort ();
372 
373  // ------------------------------------------------------------------
374  QString str = QString(buffer.constData());
375  QStringList lines = str.split("\r\n", QString::SkipEmptyParts);
376  QString sRequestLine = lines.size() ? lines[0] : "";
377 
378  if (!lines.isEmpty())
379  lines.pop_front();
380 
381  // ------------------------------------------------------------------
382  // Parse request Type
383  // ------------------------------------------------------------------
384 
385  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessData - requestLine: %1")
386  .arg(sRequestLine));
387 
388  SSDPRequestType eType = ProcessRequestLine( sRequestLine );
389 
390  // ------------------------------------------------------------------
391  // Read Headers into map
392  // ------------------------------------------------------------------
393 
394  QStringMap headers;
395 
396  for ( QStringList::Iterator it = lines.begin();
397  it != lines.end(); ++it )
398  {
399  QString sLine = *it;
400  QString sName = sLine.section( ':', 0, 0 ).trimmed();
401  QString sValue = sLine.section( ':', 1 );
402 
403  sValue.truncate( sValue.length() ); //-2
404 
405  if ((sName.length() != 0) && (sValue.length() !=0))
406  headers.insert( sName.toLower(), sValue.trimmed() );
407  }
408 
409 #if 0
410  pSocket->SetDestAddress( peerAddress, peerPort );
411 #endif
412 
413  // --------------------------------------------------------------
414  // See if this is a valid request
415  // --------------------------------------------------------------
416 
417  switch( eType )
418  {
419  case SSDP_MSearch:
420  {
421  // ----------------------------------------------------------
422  // If we haven't enabled notifications yet, then we don't
423  // want to answer search requests.
424  // ----------------------------------------------------------
425 
426  if (m_pNotifyTask != NULL)
427  ProcessSearchRequest( headers, peerAddress, peerPort );
428 
429  break;
430  }
431 
432  case SSDP_MSearchResp:
433  ProcessSearchResponse( headers);
434  break;
435 
436  case SSDP_Notify:
437  ProcessNotify( headers );
438  break;
439 
440  case SSDP_Unknown:
441  default:
442  LOG(VB_UPNP, LOG_ERR,
443  "SSPD::ProcessData - Unknown request Type.");
444  break;
445  }
446  }
447 }
448 
450 //
452 
454 {
455  QStringList tokens = sLine.split(m_procReqLineExp, QString::SkipEmptyParts);
456 
457  // ----------------------------------------------------------------------
458  // if this is actually a response, then sLine's format will be:
459  // HTTP/m.n <response code> <response text>
460  // otherwise:
461  // <method> <Resource URI> HTTP/m.n
462  // ----------------------------------------------------------------------
463 
464  if ( sLine.startsWith( QString("HTTP/") ))
465  return SSDP_MSearchResp;
466  else
467  {
468  if (tokens.count() > 0)
469  {
470  if (tokens[0] == "M-SEARCH" ) return SSDP_MSearch;
471  if (tokens[0] == "NOTIFY" ) return SSDP_Notify;
472  }
473  }
474 
475  return SSDP_Unknown;
476 }
477 
479 //
481 
482 QString SSDP::GetHeaderValue( const QStringMap &headers,
483  const QString &sKey, const QString &sDefault )
484 {
485  QStringMap::const_iterator it = headers.find( sKey.toLower() );
486 
487  if ( it == headers.end())
488  return( sDefault );
489 
490  return *it;
491 }
492 
494 //
496 
497 bool SSDP::ProcessSearchRequest( const QStringMap &sHeaders,
498  QHostAddress peerAddress,
499  quint16 peerPort )
500 {
501  QString sMAN = GetHeaderValue( sHeaders, "MAN", "" );
502  QString sST = GetHeaderValue( sHeaders, "ST" , "" );
503  QString sMX = GetHeaderValue( sHeaders, "MX" , "" );
504  int nMX = 0;
505 
506  LOG(VB_UPNP, LOG_DEBUG, QString("SSDP::ProcessSearchrequest : [%1] MX=%2")
507  .arg(sST).arg(sMX));
508 
509  // ----------------------------------------------------------------------
510  // Validate Header Values...
511  // ----------------------------------------------------------------------
512 
513 #if 0
514  if ( pRequest->m_sMethod != "*" ) return false;
515  if ( pRequest->m_sProtocol != "HTTP" ) return false;
516  if ( pRequest->m_nMajor != 1 ) return false;
517 #endif
518  if ( sMAN != "\"ssdp:discover\"" ) return false;
519  if ( sST.length() == 0 ) return false;
520  if ( sMX.length() == 0 ) return false;
521  if ((nMX = sMX.toInt()) == 0 ) return false;
522  if ( nMX < 0 ) return false;
523 
524  // ----------------------------------------------------------------------
525  // Adjust timeout to be a random interval between 0 and MX (max of 120)
526  // ----------------------------------------------------------------------
527 
528  nMX = (nMX > 120) ? 120 : nMX;
529 
530  int nNewMX = (int)(0 + ((unsigned short)random() % nMX)) * 1000;
531 
532  // ----------------------------------------------------------------------
533  // See what they are looking for...
534  // ----------------------------------------------------------------------
535 
536  if ((sST == "ssdp:all") || (sST == "upnp:rootdevice"))
537  {
539  peerAddress, peerPort, sST,
540  UPnp::g_UPnpDeviceDesc.m_rootDevice.GetUDN());
541 
542 #if 0
543  // Excute task now for fastest response, queue for time-delayed response
544  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
545  pTask->Execute( NULL );
546 #endif
547 
548  TaskQueue::Instance()->AddTask( nNewMX, pTask );
549 
550  pTask->DecrRef();
551 
552  return true;
553  }
554 
555  // ----------------------------------------------------------------------
556  // Look for a specific device/service
557  // ----------------------------------------------------------------------
558 
559  QString sUDN = UPnp::g_UPnpDeviceDesc.FindDeviceUDN(
560  &(UPnp::g_UPnpDeviceDesc.m_rootDevice), sST );
561 
562  if (sUDN.length() > 0)
563  {
565  peerAddress,
566  peerPort,
567  sST,
568  sUDN );
569 
570  // Excute task now for fastest response, queue for time-delayed response
571  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
572  pTask->Execute( NULL );
573 
574  TaskQueue::Instance()->AddTask( nNewMX, pTask );
575 
576  pTask->DecrRef();
577 
578  return true;
579  }
580 
581  return false;
582 }
583 
585 //
587 
589 {
590  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
591  QString sST = GetHeaderValue( headers, "ST" , "" );
592  QString sUSN = GetHeaderValue( headers, "USN" , "" );
593  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
594 
595  LOG(VB_UPNP, LOG_DEBUG,
596  QString( "SSDP::ProcessSearchResponse ...\n"
597  "DescURL=%1\n"
598  "ST =%2\n"
599  "USN =%3\n"
600  "Cache =%4")
601  .arg(sDescURL).arg(sST).arg(sUSN).arg(sCache));
602 
603  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
604 
605  if (nPos < 0)
606  return false;
607 
608  if ((nPos = sCache.indexOf("=", nPos)) < 0)
609  return false;
610 
611  int nSecs = sCache.mid( nPos+1 ).toInt();
612 
613  SSDPCache::Instance()->Add( sST, sUSN, sDescURL, nSecs );
614 
615  return true;
616 }
617 
619 //
621 
622 bool SSDP::ProcessNotify( const QStringMap &headers )
623 {
624  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
625  QString sNTS = GetHeaderValue( headers, "NTS" , "" );
626  QString sNT = GetHeaderValue( headers, "NT" , "" );
627  QString sUSN = GetHeaderValue( headers, "USN" , "" );
628  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
629 
630  LOG(VB_UPNP, LOG_DEBUG,
631  QString( "SSDP::ProcessNotify ...\n"
632  "DescURL=%1\n"
633  "NTS =%2\n"
634  "NT =%3\n"
635  "USN =%4\n"
636  "Cache =%5" )
637  .arg(sDescURL).arg(sNTS).arg(sNT).arg(sUSN).arg(sCache));
638 
639  if (sNTS.contains( "ssdp:alive"))
640  {
641  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
642 
643  if (nPos < 0)
644  return false;
645 
646  if ((nPos = sCache.indexOf("=", nPos)) < 0)
647  return false;
648 
649  int nSecs = sCache.mid( nPos+1 ).toInt();
650 
651  SSDPCache::Instance()->Add( sNT, sUSN, sDescURL, nSecs );
652 
653  return true;
654  }
655 
656 
657  if ( sNTS.contains( "ssdp:byebye" ) )
658  {
659  SSDPCache::Instance()->Remove( sNT, sUSN );
660 
661  return true;
662  }
663 
664  return false;
665 }
666 
669 //
670 // SSDPExtension Implementation
671 //
674 
676 //
678 
679 SSDPExtension::SSDPExtension( int nServicePort , const QString &sSharePath)
680  : HttpServerExtension( "SSDP" , sSharePath),
681  m_nServicePort(nServicePort)
682 {
684  m_sUPnpDescPath = UPnp::GetConfiguration()->GetValue( "UPnP/DescXmlPath",
685  m_sSharePath );
686 }
687 
689 //
691 
693 {
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, QString sFileName )
771 {
772  pRequest->m_eResponseType = ResponseTypeHTML;
773  pRequest->m_nResponseStatus = 404;
774 
775  pRequest->m_sFileName = m_sUPnpDescPath + sFileName;
776 
777  if (QFile::exists( pRequest->m_sFileName ))
778  {
779  LOG(VB_UPNP, LOG_DEBUG,
780  QString("SSDPExtension::GetFile( %1 ) - Exists")
781  .arg(pRequest->m_sFileName));
782 
783  pRequest->m_eResponseType = ResponseTypeFile;
784  pRequest->m_nResponseStatus = 200;
785  pRequest->m_mapRespHeaders[ "Cache-Control" ]
786  = "no-cache=\"Ext\", max-age = 5000";
787  }
788  else
789  {
790  LOG(VB_UPNP, LOG_ERR,
791  QString("SSDPExtension::GetFile( %1 ) - Not Found")
792  .arg(pRequest->m_sFileName));
793  }
794 
795 }
796 
798 //
800 
802 {
803  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceList");
804 
805  QString sXML;
806  QTextStream os(&sXML, QIODevice::WriteOnly);
807 
808  uint nDevCount, nEntryCount;
809  SSDPCache::Instance()->OutputXML(os, &nDevCount, &nEntryCount);
810 
811  NameValues list;
812  list.push_back(
813  NameValue("DeviceCount", (int)nDevCount));
814  list.push_back(
815  NameValue("DevicesAllocated", SSDPCacheEntries::g_nAllocated));
816  list.push_back(
817  NameValue("CacheEntriesFound", (int)nEntryCount));
818  list.push_back(
819  NameValue("CacheEntriesAllocated", DeviceLocation::g_nAllocated));
820  list.push_back(
821  NameValue("DeviceList", sXML));
822 
823  pRequest->FormatActionResponse(list);
824 
825  pRequest->m_eResponseType = ResponseTypeXML;
826  pRequest->m_nResponseStatus = 200;
827 }
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:216
GLuint buffer
SSDPRequestType
Definition: ssdp.h:38
virtual ~SSDPExtension()
Definition: ssdp.cpp:692
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:291
static SSDPCache * Instance()
Definition: ssdpcache.cpp:239
virtual void Execute(TaskQueue *)
virtual int GetValue(const QString &sSetting, int Default)=0
void Remove(const QString &sURI, const QString &sUSN)
Definition: ssdpcache.cpp:382
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
SSDPMethod
Definition: ssdp.h:30
virtual QString GetHostAddress()=0
SSDPExtension(int nServicePort, const QString &sSharePath)
Definition: ssdp.cpp:679
QString m_sBaseUrl
Definition: httprequest.h:121
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:83
static TaskQueue * Instance()
Definition: taskqueue.cpp:66
void GetDeviceDesc(HTTPRequest *pRequest)
Definition: ssdp.cpp:747
QString m_sSharePath
Definition: httpserver.h:76
static QMutex g_pSSDPCreationLock
Definition: ssdp.cpp:42
SSDPRequestType ProcessRequestLine(const QString &sLine)
Definition: ssdp.cpp:453
bool isValid() const
bool m_bAnnouncementsEnabled
Definition: ssdp.h:75
void GetDeviceList(HTTPRequest *pRequest)
Definition: ssdp.cpp:801
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:308
QString m_sMethod
Definition: httprequest.h:123
virtual void Execute(TaskQueue *)
QStringMap m_mapRespHeaders
Definition: httprequest.h:147
QString GetRequestHeader(const QString &sKey, QString sDefault)
static int g_nAllocated
Definition: ssdpcache.h:62
void EnableNotifications(int nServicePort)
Definition: ssdp.cpp:153
long m_nResponseStatus
Definition: httprequest.h:146
unsigned int uint
Definition: compat.h:139
virtual void setBlocking(bool)
Definition: ssdp.h:61
virtual void setSocket(int socket, Type type)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void setProtocol(Protocol protocol)
void DisableNotifications()
Definition: ssdp.cpp:193
QTextStream & OutputXML(QTextStream &os, uint *pnDevCount=NULL, uint *pnEntryCount=NULL) const
Outputs the XML for this device.
Definition: ssdpcache.cpp:520
qint64 readBlock(char *data, quint64 maxlen)
MSocketDevice * m_Sockets[3]
Definition: ssdp.h:68
QMap< QString, QString > QStringMap
Definition: upnputil.h:40
QString GetHeaderValue(const QStringMap &headers, const QString &sKey, const QString &sDefault)
Definition: ssdp.cpp:482
Error error() const
void PerformSearch(const QString &sST, uint timeout_secs=2)
Definition: ssdp.cpp:209
bool ProcessSearchRequest(const QStringMap &sHeaders, QHostAddress peerAddress, quint16 peerPort)
Definition: ssdp.cpp:497
virtual void run()
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead...
Definition: ssdp.cpp:253
int m_nServicePort
Definition: ssdp.h:149
QRegExp m_procReqLineExp
Definition: ssdp.h:67
The MSocketDevice class provides a platform-independent low-level socket API.
Definition: msocketdevice.h:54
int errno
virtual qint64 writeBlock(const char *data, quint64 len, const QHostAddress &host, quint16 port)
QString FindDeviceUDN(UPnpDevice *pDevice, QString sST)
Definition: upnpdevice.cpp:578
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
qint64 bytesAvailable() const
void RequestTerminate(void)
Definition: ssdp.cpp:144
void FormatActionResponse(Serializer *ser)
UPnpNotifyTask * m_pNotifyTask
Definition: ssdp.h:74
QString m_sFileName
Definition: httprequest.h:149
ResponseType m_eResponseType
Definition: httprequest.h:143
void ProcessData(MSocketDevice *pSocket)
Definition: ssdp.cpp:317
static Configuration * GetConfiguration()
Definition: upnp.cpp:71
void AddTask(long msec, Task *pTask)
Definition: taskqueue.cpp:181
void SetNTS(UPnpNotifyNTS nts)
virtual bool bind(const QHostAddress &, quint16)
static int g_nAllocated
Definition: upnpdevice.h:206
virtual quint16 peerPort() const
voidpf stream
Definition: ioapi.h:136
static SSDP * g_pSSDP
Definition: ssdp.h:65
static SSDP * Instance()
Definition: ssdp.cpp:49
QString m_sUPnpDescPath
Definition: ssdp.h:148
virtual QStringList GetBasePaths()
Definition: ssdp.cpp:712
bool ProcessSearchResponse(const QStringMap &sHeaders)
Definition: ssdp.cpp:588
virtual QHostAddress peerAddress() const
bool m_bTermRequested
Definition: ssdp.h:77
int m_nPort
Definition: ssdp.h:70
void GetFile(HTTPRequest *pRequest, QString sFileName)
Definition: ssdp.cpp:770
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:203
QBuffer m_response
Definition: httprequest.h:151
int m_nServicePort
Definition: ssdp.h:72
bool ProcessRequest(HTTPRequest *pRequest)
Definition: ssdp.cpp:724
bool ProcessNotify(const QStringMap &sHeaders)
Definition: ssdp.cpp:622
static long int random(void)
Definition: compat.h:146
SSDPMethod GetMethod(const QString &sURI)
Definition: ssdp.cpp:700
static void usleep(unsigned long time)
Definition: mthread.cpp:345
void Add(const QString &sURI, const QString &sUSN, const QString &sLocation, long sExpiresInSecs)
Definition: ssdpcache.cpp:327
int m_nSearchPort
Definition: ssdp.h:71
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
Definition: upnpdevice.cpp:337
SSDP()
Definition: ssdp.cpp:70
static void Shutdown()
Definition: ssdp.cpp:59
~SSDP()
Definition: ssdp.cpp:118
static UPnpDeviceDesc g_UPnpDeviceDesc
Definition: upnp.h:106