MythTV  master
mythudplistener.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QCoreApplication>
3 #include <QDomDocument>
4 #include <QHostAddress>
5 
6 // MythTV
9 #include "mythmainwindow.h"
10 #include "mythudplistener.h"
11 
12 // Std
13 #include <thread>
14 
15 #define LOC QString("UDPListener: ")
16 
18 {
20 }
21 
23 {
24  DoEnable(false);
25 }
26 
27 void MythUDPListener::DoEnable(bool Enable)
28 {
29  if (Enable)
30  {
31  if (m_socketPool)
32  return;
33 
34  LOG(VB_GENERAL, LOG_INFO, LOC + "Enabling");
35  m_socketPool = new ServerPool(this);
37  QList<QHostAddress> addrs = ServerPool::DefaultListen();
39  auto port = static_cast<uint16_t>(gCoreContext->GetNumSetting("UDPNotifyPort", 0));
40  if (!m_socketPool->bind(addrs, port, false))
41  {
42  delete m_socketPool;
43  m_socketPool = nullptr;
44  }
45  }
46  else
47  {
48  if (!m_socketPool)
49  return;
50 
51  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling");
53  delete m_socketPool;
54  m_socketPool = nullptr;
55  }
56 }
57 
58 void MythUDPListener::Process(const QByteArray& Buffer, const QHostAddress& /*Sender*/,
59  quint16 /*SenderPort*/)
60 {
61  QString errormsg;
62  int line = 0;
63  int column = 0;
64  QDomDocument doc;
65  if (!doc.setContent(Buffer, false, &errormsg, &line, &column))
66  {
67  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error parsing xml: Line: %1 Column: %2 Error: %3")
68  .arg(line).arg(column).arg(errormsg));
69  return;
70  }
71 
72  auto element = doc.documentElement();
73  bool notification = false;
74  if (!element.isNull())
75  {
76  if (element.tagName() != "mythmessage" && element.tagName() != "mythnotification")
77  {
78  LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown UDP packet (not <mythmessage> XML)");
79  return;
80  }
81 
82  if (element.tagName() == "mythnotification")
83  notification = true;
84 
85  if (auto version = element.attribute("version", ""); version.isEmpty())
86  {
87  LOG(VB_GENERAL, LOG_ERR, LOC + "<mythmessage> missing 'version' attribute");
88  return;
89  }
90  }
91 
92  QString msg;
93  std::chrono::seconds timeout = 0s;
94  QString image;
95  QString origin;
96  QString description;
97  QString extra;
98  QString progress_text;
99  float progress = -1.0F;
100  bool fullscreen = false;
101  bool error = false;
102  int visibility = 0;
103  QString type = "normal";
104 
105  auto node = element.firstChild();
106  while (!node.isNull())
107  {
108  auto dom = node.toElement();
109  if (!dom.isNull())
110  {
111  auto tagname = dom.tagName();
112  if (tagname == "text")
113  msg = dom.text();
114  else if (tagname == "timeout")
115  timeout = std::chrono::seconds(dom.text().toUInt());
116  else if (notification && tagname == "image")
117  image = dom.text();
118  else if (notification && tagname == "origin")
119  origin = dom.text();
120  else if (notification && tagname == "description")
121  description = dom.text();
122  else if (notification && tagname == "extra")
123  extra = dom.text();
124  else if (notification && tagname == "progress_text")
125  progress_text = dom.text();
126  else if (notification && tagname == "fullscreen")
127  fullscreen = dom.text().toLower() == "true";
128  else if (notification && tagname == "error")
129  error = dom.text().toLower() == "true";
130  else if (tagname == "visibility")
131  visibility = dom.text().toInt();
132  else if (tagname == "type")
133  type = dom.text();
134  else if (notification && tagname == "progress")
135  {
136  bool ok = false;
137  if (progress = dom.text().toFloat(&ok); !ok)
138  progress = -1.0F;
139  }
140  else
141  {
142  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown element: %1")
143  .arg(tagname));
144  }
145  }
146  node = node.nextSibling();
147  }
148 
149  if (!msg.isEmpty() || !image.isEmpty() || !extra.isEmpty())
150  {
151  LOG(VB_GENERAL, LOG_INFO, QString("Received %1 '%2', timeout %3")
152  .arg(notification ? "notification" : "message",
153  msg, QString::number(timeout.count())));
154  if (timeout > 1000s)
155  timeout = notification ? 5s : 0s;
156  if (notification)
157  {
158  origin = origin.isEmpty() ? tr("UDP Listener") : origin;
161  msg, origin, description, image, extra,
162  progress_text, progress, timeout,
163  fullscreen, static_cast<VNMask>(visibility));
164  }
165  else
166  {
167  QStringList args(QString::number(timeout.count()));
168  qApp->postEvent(GetMythMainWindow(), new MythEvent(MythEvent::MythUserMessage, msg, args));
169  }
170  }
171 }
172 
173 void MythUDP::EnableUDPListener(bool Enable)
174 {
176  {
177  emit Instance().m_listener->EnableUDPListener(Enable);
178  }
179  else
180  {
181  LOG(VB_GENERAL, LOG_ERR, LOC +
182  "EnableUDPListener called after MythUDPListener instance is deleted");
183  }
184 }
185 
187 {
188  static MythUDP s_instance;
189  return s_instance;
190 }
191 
193  : m_listener(new MythUDPListener),
194  m_thread(new MThread("UDP"))
195 {
196  m_listener->moveToThread(m_thread->qthread());
197  m_thread->start();
198  do { std::this_thread::sleep_for(5us); }
199  while (!m_thread->qthread()->isRunning());
200 }
201 
203 {
204  if (m_thread)
205  {
206  m_thread->quit();
207  m_thread->wait();
208  }
209  delete m_thread;
210  delete m_listener;
211 }
212 
214 {
215  if (Instance().m_thread)
216  {
217  Instance().m_thread->quit();
218  Instance().m_thread->wait();
219  delete Instance().m_thread;
220  Instance().m_thread = nullptr;
221  }
222 
223  delete Instance().m_listener;
224  Instance().m_listener = nullptr;
225 }
build_compdb.args
args
Definition: build_compdb.py:11
MythUDP::m_thread
MThread * m_thread
Definition: mythudplistener.h:46
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
MThread::quit
void quit(void)
calls exit(0)
Definition: mthread.cpp:298
error
static void error(const char *str,...)
Definition: vbi.cpp:36
ShowNotification
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
Definition: mythnotificationcenter.cpp:1438
ServerPool::newDatagram
void newDatagram(QByteArray, QHostAddress, quint16)
ServerPool::close
void close(void)
Definition: serverpool.cpp:368
MythUDP
Definition: mythudplistener.h:33
progress
bool progress
Definition: mythcommflag.cpp:69
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:303
ServerPool
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:59
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythNotification::TypeFromString
static Type TypeFromString(const QString &Type)
Definition: mythnotification.cpp:228
MythEvent::MythUserMessage
static Type MythUserMessage
Definition: mythevent.h:80
MythUDPListener::Process
static void Process(const QByteArray &Buffer, const QHostAddress &, quint16)
Definition: mythudplistener.cpp:58
mythlogging.h
MythUDP::Instance
static MythUDP & Instance()
Definition: mythudplistener.cpp:186
LOC
#define LOC
Definition: mythudplistener.cpp:15
VNMask
unsigned int VNMask
Definition: mythnotification.h:27
MThread::qthread
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:236
ServerPool::DefaultListen
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:299
MythUDPListener::EnableUDPListener
void EnableUDPListener(bool Enable=true)
MythUDPListener
Definition: mythudplistener.h:11
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:59
ServerPool::bind
bool bind(QList< QHostAddress > addrs, quint16 port, bool requireall=true)
Definition: serverpool.cpp:489
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
MythUDP::EnableUDPListener
static void EnableUDPListener(bool Enable=true)
Definition: mythudplistener.cpp:173
MythUDP::~MythUDP
~MythUDP()
Definition: mythudplistener.cpp:202
Buffer
Definition: MythExternControl.h:36
MythUDPListener::MythUDPListener
MythUDPListener()
Definition: mythudplistener.cpp:17
mythcorecontext.h
mythudplistener.h
MythUDP::m_listener
MythUDPListener * m_listener
Definition: mythudplistener.h:45
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
MythUDPListener::~MythUDPListener
~MythUDPListener() override
Definition: mythudplistener.cpp:22
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
MythUDPListener::m_socketPool
ServerPool * m_socketPool
Definition: mythudplistener.h:30
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
MythUDP::MythUDP
MythUDP()
Definition: mythudplistener.cpp:192
ServerPool::DefaultBroadcast
static QList< QHostAddress > DefaultBroadcast(void)
Definition: serverpool.cpp:333
mythmainwindow.h
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
MythNotification::Error
static Type Error
Definition: mythnotification.h:35
MythUDPListener::DoEnable
void DoEnable(bool Enable=true)
Definition: mythudplistener.cpp:27
MythUDP::StopUDPListener
static void StopUDPListener()
Definition: mythudplistener.cpp:213