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  m_socketPool(nullptr)
16 {
17  Enable();
18 }
19 
21 {
22  Disable();
23  disconnect();
24  QObject::deleteLater();
25 }
26 
28 {
29  if (m_socketPool)
30  return;
31 
32  LOG(VB_GENERAL, LOG_INFO, LOC + "Enabling");
33 
34  m_socketPool = new ServerPool(this);
35  connect(m_socketPool, SIGNAL(newDatagram(QByteArray, QHostAddress,
36  quint16)),
37  this, SLOT(Process(const QByteArray, QHostAddress,
38  quint16)));
39 
40  QList<QHostAddress> addrs = ServerPool::DefaultListen();
42 
43  if (!m_socketPool->bind(addrs,
44  gCoreContext->GetNumSetting("UDPNotifyPort", 0), false))
45  {
46  delete m_socketPool;
47  m_socketPool = nullptr;
48  }
49 }
50 
52 {
53  if (!m_socketPool)
54  return;
55 
56  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling");
57 
59  delete m_socketPool;
60  m_socketPool = nullptr;
61 }
62 
63 void MythUDPListener::Process(const QByteArray &buf, const QHostAddress& /*sender*/,
64  quint16 /*senderPort*/)
65 {
66  QString errorMsg;
67  int errorLine = 0;
68  int errorColumn = 0;
69  QDomDocument doc;
70  if (!doc.setContent(buf, false, &errorMsg, &errorLine, &errorColumn))
71  {
72  LOG(VB_GENERAL, LOG_ERR, LOC +
73  QString("Parsing xml:\n\t\t\t at line: %1 column: %2\n\t\t\t%3")
74  .arg(errorLine).arg(errorColumn).arg(errorMsg));
75 
76  return;
77  }
78 
79  QDomElement docElem = doc.documentElement();
80  bool notification = false;
81  if (!docElem.isNull())
82  {
83  if (docElem.tagName() != "mythmessage" &&
84  docElem.tagName() != "mythnotification")
85  {
86  LOG(VB_GENERAL, LOG_ERR, LOC +
87  "Unknown UDP packet (not <mythmessage> XML)");
88  return;
89  }
90 
91  if (docElem.tagName() == "mythnotification")
92  {
93  notification = true;
94  }
95 
96  QString version = docElem.attribute("version", "");
97  if (version.isEmpty())
98  {
99  LOG(VB_GENERAL, LOG_ERR, LOC +
100  "<mythmessage> missing 'version' attribute");
101  return;
102  }
103  }
104 
105  QString msg = QString("");
106  uint timeout = 0;
107  QString image;
108  QString origin;
109  QString description = "";
110  QString extra = "";
111  QString progress_text = "";
112  float progress = -1.0F;
113  bool fullscreen = false;
114  bool error = false;
115  int visibility = 0;
116  QString type = "normal";
117 
118  QDomNode n = docElem.firstChild();
119  while (!n.isNull())
120  {
121  QDomElement e = n.toElement();
122  if (!e.isNull())
123  {
124  if (e.tagName() == "text")
125  msg = e.text();
126  else if (e.tagName() == "timeout")
127  timeout = e.text().toUInt();
128  else if (notification && e.tagName() == "image")
129  image = e.text();
130  else if (notification && e.tagName() == "origin")
131  origin = e.text();
132  else if (notification && e.tagName() == "description")
133  description = e.text();
134  else if (notification && e.tagName() == "extra")
135  extra = e.text();
136  else if (notification && e.tagName() == "progress_text")
137  progress_text = e.text();
138  else if (notification && e.tagName() == "fullscreen")
139  fullscreen = e.text().toLower() == "true";
140  else if (notification && e.tagName() == "error")
141  error = e.text().toLower() == "true";
142  else if (e.tagName() == "visibility")
143  visibility = e.text().toUInt();
144  else if (e.tagName() == "type")
145  type = e.text();
146  else if (notification && e.tagName() == "progress")
147  {
148  bool ok = false;
149  progress = e.text().toFloat(&ok);
150  if (!ok)
151  progress = -1.0F;
152  }
153  else
154  {
155  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown element: %1")
156  .arg(e.tagName()));
157  }
158  }
159  n = n.nextSibling();
160  }
161 
162  if (!msg.isEmpty() || !image.isEmpty() || !extra.isEmpty())
163  {
164  LOG(VB_GENERAL, LOG_INFO, QString("Received %1 '%2', timeout %3")
165  .arg(notification ? "notification" : "message")
166  .arg(msg).arg(timeout));
167  if (timeout > 1000)
168  timeout = notification ? 5 : 0;
169  if (notification)
170  {
171  origin = origin.isNull() ? tr("UDP Listener") : origin;
174  msg, origin, description, image, extra,
175  progress_text, progress, timeout, fullscreen,
176  visibility);
177  }
178  else
179  {
180  QStringList args;
181  args << QString::number(timeout);
182  MythMainWindow *window = GetMythMainWindow();
183  auto* me = new MythEvent(MythEvent::MythUserMessage, msg, args);
184  qApp->postEvent(window, me);
185  }
186  }
187 }
static void Process(const QByteArray &buf, const QHostAddress &sender, quint16 senderPort)
static void error(const char *str,...)
Definition: vbi.c:42
virtual void deleteLater(void)
bool bind(QList< QHostAddress > addrs, quint16 port, bool requireall=true)
Definition: serverpool.cpp:482
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:67
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:325
MythMainWindow * GetMythMainWindow(void)
int GetNumSetting(const QString &key, int defaultval=0)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void close(void)
Definition: serverpool.cpp:359
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:289