MythTV  master
mythudplistener.cpp
Go to the documentation of this file.
1 #include <QCoreApplication>
2 #include <QUdpSocket>
3 #include <QDomDocument>
4 #include <QList>
5 #include <QHostAddress>
6 
7 #include "mythcorecontext.h"
8 #include "mythlogging.h"
9 #include "mythmainwindow.h"
10 #include "mythudplistener.h"
11 
12 #define LOC QString("UDPListener: ")
13 
15 {
16  Enable();
17 }
18 
20 {
21  Disable();
22  disconnect();
23  QObject::deleteLater();
24 }
25 
27 {
28  if (m_socketPool)
29  return;
30 
31  LOG(VB_GENERAL, LOG_INFO, LOC + "Enabling");
32 
33  m_socketPool = new ServerPool(this);
34  connect(m_socketPool, SIGNAL(newDatagram(QByteArray, QHostAddress,
35  quint16)),
36  this, SLOT(Process(const QByteArray, QHostAddress,
37  quint16)));
38 
39  QList<QHostAddress> addrs = ServerPool::DefaultListen();
41 
42  if (!m_socketPool->bind(addrs,
43  gCoreContext->GetNumSetting("UDPNotifyPort", 0), false))
44  {
45  delete m_socketPool;
46  m_socketPool = nullptr;
47  }
48 }
49 
51 {
52  if (!m_socketPool)
53  return;
54 
55  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling");
56 
58  delete m_socketPool;
59  m_socketPool = nullptr;
60 }
61 
62 void MythUDPListener::Process(const QByteArray &buf, const QHostAddress& /*sender*/,
63  quint16 /*senderPort*/)
64 {
65  QString errorMsg;
66  int errorLine = 0;
67  int errorColumn = 0;
68  QDomDocument doc;
69  if (!doc.setContent(buf, false, &errorMsg, &errorLine, &errorColumn))
70  {
71  LOG(VB_GENERAL, LOG_ERR, LOC +
72  QString("Parsing xml:\n\t\t\t at line: %1 column: %2\n\t\t\t%3")
73  .arg(errorLine).arg(errorColumn).arg(errorMsg));
74 
75  return;
76  }
77 
78  QDomElement docElem = doc.documentElement();
79  bool notification = false;
80  if (!docElem.isNull())
81  {
82  if (docElem.tagName() != "mythmessage" &&
83  docElem.tagName() != "mythnotification")
84  {
85  LOG(VB_GENERAL, LOG_ERR, LOC +
86  "Unknown UDP packet (not <mythmessage> XML)");
87  return;
88  }
89 
90  if (docElem.tagName() == "mythnotification")
91  {
92  notification = true;
93  }
94 
95  QString version = docElem.attribute("version", "");
96  if (version.isEmpty())
97  {
98  LOG(VB_GENERAL, LOG_ERR, LOC +
99  "<mythmessage> missing 'version' attribute");
100  return;
101  }
102  }
103 
104  QString msg = QString("");
105  uint timeout = 0;
106  QString image;
107  QString origin;
108  QString description = "";
109  QString extra = "";
110  QString progress_text = "";
111  float progress = -1.0F;
112  bool fullscreen = false;
113  bool error = false;
114  int visibility = 0;
115  QString type = "normal";
116 
117  QDomNode n = docElem.firstChild();
118  while (!n.isNull())
119  {
120  QDomElement e = n.toElement();
121  if (!e.isNull())
122  {
123  if (e.tagName() == "text")
124  msg = e.text();
125  else if (e.tagName() == "timeout")
126  timeout = e.text().toUInt();
127  else if (notification && e.tagName() == "image")
128  image = e.text();
129  else if (notification && e.tagName() == "origin")
130  origin = e.text();
131  else if (notification && e.tagName() == "description")
132  description = e.text();
133  else if (notification && e.tagName() == "extra")
134  extra = e.text();
135  else if (notification && e.tagName() == "progress_text")
136  progress_text = e.text();
137  else if (notification && e.tagName() == "fullscreen")
138  fullscreen = e.text().toLower() == "true";
139  else if (notification && e.tagName() == "error")
140  error = e.text().toLower() == "true";
141  else if (e.tagName() == "visibility")
142  visibility = e.text().toUInt();
143  else if (e.tagName() == "type")
144  type = e.text();
145  else if (notification && e.tagName() == "progress")
146  {
147  bool ok = false;
148  progress = e.text().toFloat(&ok);
149  if (!ok)
150  progress = -1.0F;
151  }
152  else
153  {
154  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown element: %1")
155  .arg(e.tagName()));
156  }
157  }
158  n = n.nextSibling();
159  }
160 
161  if (!msg.isEmpty() || !image.isEmpty() || !extra.isEmpty())
162  {
163  LOG(VB_GENERAL, LOG_INFO, QString("Received %1 '%2', timeout %3")
164  .arg(notification ? "notification" : "message")
165  .arg(msg).arg(timeout));
166  if (timeout > 1000)
167  timeout = notification ? 5 : 0;
168  if (notification)
169  {
170  origin = origin.isNull() ? tr("UDP Listener") : origin;
173  msg, origin, description, image, extra,
174  progress_text, progress, timeout, fullscreen,
175  visibility);
176  }
177  else
178  {
179  QStringList args;
180  args << QString::number(timeout);
181  MythMainWindow *window = GetMythMainWindow();
182  auto* me = new MythEvent(MythEvent::MythUserMessage, msg, args);
183  qApp->postEvent(window, me);
184  }
185  }
186 }
static void Process(const QByteArray &buf, const QHostAddress &sender, quint16 senderPort)
static void error(const char *str,...)
Definition: vbi.cpp:42
virtual void deleteLater(void)
bool bind(QList< QHostAddress > addrs, quint16 port, bool requireall=true)
Definition: serverpool.cpp:492
QDomDocument doc("MYTHARCHIVEITEM")
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOC
This class is used as a container for messages.
Definition: mythevent.h:16
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
static Type TypeFromString(const QString &type)
return Type object from type name
ServerPool * m_socketPool
static Type MythUserMessage
Definition: mythevent.h:74
unsigned int uint
Definition: compat.h:140
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:59
static QList< QHostAddress > DefaultBroadcast(void)
Definition: serverpool.cpp:333
MythMainWindow * GetMythMainWindow(void)
int GetNumSetting(const QString &key, int defaultval=0)
void close(void)
Definition: serverpool.cpp:369
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:297
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23