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