MythTV  0.28pre
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 
297  for (int nIdx = 0; count && nIdx < (int)NumberOfSockets; nIdx++ )
298  {
299  bool cond1 = m_Sockets[nIdx] != NULL;
300  bool cond2 = cond1 && m_Sockets[nIdx]->socket() >= 0;
301  bool cond3 = cond2 && FD_ISSET(m_Sockets[nIdx]->socket(), &read_set);
302 
303  if (cond3)
304  {
305 #if 0
306  LOG(VB_GENERAL, LOG_DEBUG, QString("FD_ISSET( %1 )").arg(nIdx));
307 #endif
308 
309  ProcessData(m_Sockets[nIdx]);
310  count--;
311  }
312  }
313  }
314 
315  RunEpilog();
316 }
317 
319 //
321 
323 {
324  QByteArray buffer;
325  long nBytes = pSocket->bytesAvailable();
326  int retries = 0;
327  // Note: this function MUST do a read even if someone sends a zero byte UDP message
328  // Otherwise the select() will continue to signal data ready, so to prevent using 100%
329  // CPU, we need to call a recv function to make select() block again
330  bool didDoRead = 0;
331 
332  // UDP message of zero length? OK, "recv" it and move on
333  if (nBytes == 0)
334  {
335  LOG(VB_UPNP, LOG_WARNING, QString("SSDP: Received 0 byte UDP message"));
336  }
337 
338  while ((nBytes = pSocket->bytesAvailable()) > 0 || (nBytes == 0 && !didDoRead))
339  {
340  buffer.resize(nBytes);
341 
342  long nRead = 0;
343  do
344  {
345  long ret = pSocket->readBlock( buffer.data() + nRead, nBytes - nRead );
346  didDoRead = 1;
347  if (ret < 0)
348  {
349  if (errno == EAGAIN || errno == EWOULDBLOCK)
350  {
351  if (retries == 3)
352  {
353  nBytes = nRead;
354  buffer.resize(nBytes);
355  break;
356  }
357  retries++;
358  usleep(10000);
359  continue;
360  }
361  LOG(VB_GENERAL, LOG_ERR, QString("Socket readBlock error %1")
362  .arg(pSocket->error()));
363  buffer.clear();
364  break;
365  }
366  retries = 0;
367 
368  nRead += ret;
369 
370  if (0 == ret && nBytes != 0)
371  {
372  LOG(VB_SOCKET, LOG_WARNING,
373  QString("%1 bytes reported available, "
374  "but only %2 bytes read.")
375  .arg(nBytes).arg(nRead));
376  nBytes = nRead;
377  buffer.resize(nBytes);
378  break;
379  }
380  }
381  while (nRead < nBytes);
382 
383  if (buffer.isEmpty())
384  continue;
385 
386  QHostAddress peerAddress = pSocket->peerAddress();
387  quint16 peerPort = pSocket->peerPort ();
388 
389  // ------------------------------------------------------------------
390  QString str = QString(buffer.constData());
391  QStringList lines = str.split("\r\n", QString::SkipEmptyParts);
392  QString sRequestLine = lines.size() ? 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 ( QStringList::Iterator it = lines.begin();
413  it != lines.end(); ++it )
414  {
415  QString sLine = *it;
416  QString sName = sLine.section( ':', 0, 0 ).trimmed();
417  QString sValue = sLine.section( ':', 1 );
418 
419  sValue.truncate( sValue.length() ); //-2
420 
421  if ((sName.length() != 0) && (sValue.length() !=0))
422  headers.insert( sName.toLower(), sValue.trimmed() );
423  }
424 
425 #if 0
426  pSocket->SetDestAddress( peerAddress, peerPort );
427 #endif
428 
429  // --------------------------------------------------------------
430  // See if this is a valid request
431  // --------------------------------------------------------------
432 
433  switch( eType )
434  {
435  case SSDP_MSearch:
436  {
437  // ----------------------------------------------------------
438  // If we haven't enabled notifications yet, then we don't
439  // want to answer search requests.
440  // ----------------------------------------------------------
441 
442  if (m_pNotifyTask != NULL)
443  ProcessSearchRequest( headers, peerAddress, peerPort );
444 
445  break;
446  }
447 
448  case SSDP_MSearchResp:
449  ProcessSearchResponse( headers);
450  break;
451 
452  case SSDP_Notify:
453  ProcessNotify( headers );
454  break;
455 
456  case SSDP_Unknown:
457  default:
458  LOG(VB_UPNP, LOG_ERR,
459  "SSPD::ProcessData - Unknown request Type.");
460  break;
461  }
462  }
463 }
464 
466 //
468 
470 {
471  QStringList tokens = sLine.split(m_procReqLineExp, QString::SkipEmptyParts);
472 
473  // ----------------------------------------------------------------------
474  // if this is actually a response, then sLine's format will be:
475  // HTTP/m.n <response code> <response text>
476  // otherwise:
477  // <method> <Resource URI> HTTP/m.n
478  // ----------------------------------------------------------------------
479 
480  if ( sLine.startsWith( QString("HTTP/") ))
481  return SSDP_MSearchResp;
482  else
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 
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  QHostAddress peerAddress,
515  quint16 peerPort )
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 = (int)(0 + ((unsigned short)random() % nMX)) * 1000;
547 
548  // ----------------------------------------------------------------------
549  // See what they are looking for...
550  // ----------------------------------------------------------------------
551 
552  if ((sST == "ssdp:all") || (sST == "upnp:rootdevice"))
553  {
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( NULL );
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  {
581  peerAddress,
582  peerPort,
583  sST,
584  sUDN );
585 
586  // Excute task now for fastest response, queue for time-delayed response
587  // -=>TODO: To be trully uPnp compliant, this Execute should be removed.
588  pTask->Execute( NULL );
589 
590  TaskQueue::Instance()->AddTask( nNewMX, pTask );
591 
592  pTask->DecrRef();
593 
594  return true;
595  }
596 
597  return false;
598 }
599 
601 //
603 
605 {
606  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
607  QString sST = GetHeaderValue( headers, "ST" , "" );
608  QString sUSN = GetHeaderValue( headers, "USN" , "" );
609  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
610 
611  LOG(VB_UPNP, LOG_DEBUG,
612  QString( "SSDP::ProcessSearchResponse ...\n"
613  "DescURL=%1\n"
614  "ST =%2\n"
615  "USN =%3\n"
616  "Cache =%4")
617  .arg(sDescURL).arg(sST).arg(sUSN).arg(sCache));
618 
619  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
620 
621  if (nPos < 0)
622  return false;
623 
624  if ((nPos = sCache.indexOf("=", nPos)) < 0)
625  return false;
626 
627  int nSecs = sCache.mid( nPos+1 ).toInt();
628 
629  SSDPCache::Instance()->Add( sST, sUSN, sDescURL, nSecs );
630 
631  return true;
632 }
633 
635 //
637 
638 bool SSDP::ProcessNotify( const QStringMap &headers )
639 {
640  QString sDescURL = GetHeaderValue( headers, "LOCATION" , "" );
641  QString sNTS = GetHeaderValue( headers, "NTS" , "" );
642  QString sNT = GetHeaderValue( headers, "NT" , "" );
643  QString sUSN = GetHeaderValue( headers, "USN" , "" );
644  QString sCache = GetHeaderValue( headers, "CACHE-CONTROL" , "" );
645 
646  LOG(VB_UPNP, LOG_DEBUG,
647  QString( "SSDP::ProcessNotify ...\n"
648  "DescURL=%1\n"
649  "NTS =%2\n"
650  "NT =%3\n"
651  "USN =%4\n"
652  "Cache =%5" )
653  .arg(sDescURL).arg(sNTS).arg(sNT).arg(sUSN).arg(sCache));
654 
655  if (sNTS.contains( "ssdp:alive"))
656  {
657  int nPos = sCache.indexOf("max-age", 0, Qt::CaseInsensitive);
658 
659  if (nPos < 0)
660  return false;
661 
662  if ((nPos = sCache.indexOf("=", nPos)) < 0)
663  return false;
664 
665  int nSecs = sCache.mid( nPos+1 ).toInt();
666 
667  SSDPCache::Instance()->Add( sNT, sUSN, sDescURL, nSecs );
668 
669  return true;
670  }
671 
672 
673  if ( sNTS.contains( "ssdp:byebye" ) )
674  {
675  SSDPCache::Instance()->Remove( sNT, sUSN );
676 
677  return true;
678  }
679 
680  return false;
681 }
682 
685 //
686 // SSDPExtension Implementation
687 //
690 
692 //
694 
695 SSDPExtension::SSDPExtension( int nServicePort , const QString &sSharePath)
696  : HttpServerExtension( "SSDP" , sSharePath),
697  m_nServicePort(nServicePort)
698 {
700  m_sUPnpDescPath = UPnp::GetConfiguration()->GetValue( "UPnP/DescXmlPath",
701  m_sSharePath );
702 }
703 
705 //
707 
709 {
710 }
711 
713 //
715 
716 SSDPMethod SSDPExtension::GetMethod( const QString &sURI )
717 {
718  if (sURI == "getDeviceDesc" ) return( SSDPM_GetDeviceDesc );
719  if (sURI == "getDeviceList" ) return( SSDPM_GetDeviceList );
720 
721  return( SSDPM_Unknown );
722 }
723 
725 //
727 
729 {
730  // -=>TODO: This is very inefficient... should look into making
731  // it a unique path.
732 
733  return QStringList( "/" );
734 }
735 
737 //
739 
741 {
742  if (pRequest)
743  {
744  if ( pRequest->m_sBaseUrl != "/")
745  return( false );
746 
747  switch( GetMethod( pRequest->m_sMethod ))
748  {
749  case SSDPM_GetDeviceDesc: GetDeviceDesc( pRequest ); return( true );
750  case SSDPM_GetDeviceList: GetDeviceList( pRequest ); return( true );
751 
752  default: break;
753  }
754  }
755 
756  return( false );
757 }
758 
760 //
762 
764 {
765  pRequest->m_eResponseType = ResponseTypeXML;
766 
767  QString sUserAgent = pRequest->GetRequestHeader( "User-Agent", "" );
768 
769  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceDesc - " +
770  QString( "Host=%1 Port=%2 UserAgent=%3" )
771  .arg(pRequest->GetHostAddress()) .arg(m_nServicePort)
772  .arg(sUserAgent));
773 
774  QTextStream stream( &(pRequest->m_response) );
775 
778  stream,
779  sUserAgent );
780 }
781 
783 //
785 
786 void SSDPExtension::GetFile( HTTPRequest *pRequest, QString sFileName )
787 {
788  pRequest->m_eResponseType = ResponseTypeHTML;
789 
790  pRequest->m_sFileName = m_sUPnpDescPath + sFileName;
791 
792  if (QFile::exists( pRequest->m_sFileName ))
793  {
794  LOG(VB_UPNP, LOG_DEBUG,
795  QString("SSDPExtension::GetFile( %1 ) - Exists")
796  .arg(pRequest->m_sFileName));
797 
798  pRequest->m_eResponseType = ResponseTypeFile;
799  pRequest->m_nResponseStatus = 200;
800  pRequest->m_mapRespHeaders[ "Cache-Control" ]
801  = "no-cache=\"Ext\", max-age = 7200"; // 2 hours
802  }
803  else
804  {
805  pRequest->m_nResponseStatus = 404;
806  pRequest->m_response.write( pRequest->GetResponsePage() );
807  LOG(VB_UPNP, LOG_ERR,
808  QString("SSDPExtension::GetFile( %1 ) - Not Found")
809  .arg(pRequest->m_sFileName));
810  }
811 
812 }
813 
815 //
817 
819 {
820  LOG(VB_UPNP, LOG_DEBUG, "SSDPExtension::GetDeviceList");
821 
822  QString sXML;
823  QTextStream os(&sXML, QIODevice::WriteOnly);
824 
825  uint nDevCount, nEntryCount;
826  SSDPCache::Instance()->OutputXML(os, &nDevCount, &nEntryCount);
827 
828  NameValues list;
829  list.push_back(
830  NameValue("DeviceCount", (int)nDevCount));
831  list.push_back(
832  NameValue("DevicesAllocated", SSDPCacheEntries::g_nAllocated));
833  list.push_back(
834  NameValue("CacheEntriesFound", (int)nEntryCount));
835  list.push_back(
836  NameValue("CacheEntriesAllocated", DeviceLocation::g_nAllocated));
837  list.push_back(
838  NameValue("DeviceList", sXML));
839 
840  pRequest->FormatActionResponse(list);
841 
842  pRequest->m_eResponseType = ResponseTypeXML;
843  pRequest->m_nResponseStatus = 200;
844 }
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:708
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:695
QString m_sBaseUrl
Definition: httprequest.h:122
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:83
static TaskQueue * Instance()
Definition: taskqueue.cpp:66
void GetDeviceDesc(HTTPRequest *pRequest)
Definition: ssdp.cpp:763
QString m_sSharePath
Definition: httpserver.h:76
static QMutex g_pSSDPCreationLock
Definition: ssdp.cpp:42
SSDPRequestType ProcessRequestLine(const QString &sLine)
Definition: ssdp.cpp:469
bool isValid() const
bool m_bAnnouncementsEnabled
Definition: ssdp.h:75
void GetDeviceList(HTTPRequest *pRequest)
Definition: ssdp.cpp:818
int socket() const
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:124
virtual void Execute(TaskQueue *)
QStringMap m_mapRespHeaders
Definition: httprequest.h:148
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:147
unsigned int uint
Definition: compat.h:136
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
QByteArray GetResponsePage(void)
QMap< QString, QString > QStringMap
Definition: upnputil.h:40
QString GetHeaderValue(const QStringMap &headers, const QString &sKey, const QString &sDefault)
Definition: ssdp.cpp:498
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:513
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:150
ResponseType m_eResponseType
Definition: httprequest.h:144
void ProcessData(MSocketDevice *pSocket)
Definition: ssdp.cpp:322
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:209
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:728
bool ProcessSearchResponse(const QStringMap &sHeaders)
Definition: ssdp.cpp:604
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:786
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:203
QBuffer m_response
Definition: httprequest.h:152
int m_nServicePort
Definition: ssdp.h:72
bool ProcessRequest(HTTPRequest *pRequest)
Definition: ssdp.cpp:740
bool ProcessNotify(const QStringMap &sHeaders)
Definition: ssdp.cpp:638
static long int random(void)
Definition: compat.h:143
SSDPMethod GetMethod(const QString &sURI)
Definition: ssdp.cpp:716
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