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