CPPMyth
Library to interoperate with MythTV server
Loading...
Searching...
No Matches
mythprotoevent.cpp
1/*
2 * Copyright (C) 2014 Jean-Luc Barriere
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22#include "mythprotoevent.h"
23#include "../private/debug.h"
24#include "../private/socket.h"
25#include "../private/os/threads/latch.h"
26#include "../private/builtin.h"
27
28#include <limits>
29#include <cstdio>
30#include <vector>
31
32using namespace Myth;
33
34void __tokenize(const std::string& str, const char *delimiters, std::vector<std::string>& tokens, bool trimnull = false)
35{
36 std::string::size_type pa = 0, pb = 0;
37 unsigned n = 0;
38 // Counter n will break infinite loop. Max count is 255 tokens
39 while ((pb = str.find_first_of(delimiters, pb)) != std::string::npos && ++n < 255)
40 {
41 tokens.push_back(str.substr(pa, pb - pa));
42 do
43 {
44 pa = ++pb;
45 }
46 while (trimnull && str.find_first_of(delimiters, pb) == pb);
47 }
48 tokens.push_back(str.substr(pa));
49}
50
55
56ProtoEvent::ProtoEvent(const std::string& server, unsigned port)
57: ProtoBase(server, port)
58{
59}
60
61bool ProtoEvent::Open()
62{
63 bool ok = false;
64
65 if (!OpenConnection(PROTO_EVENT_RCVBUF))
66 return false;
67
68 if (m_protoVersion >= 75)
69 ok = Announce75();
70
71 if (ok)
72 return true;
73 Close();
74 return false;
75}
76
77void ProtoEvent::Close()
78{
79 ProtoBase::Close();
80 // Clean hanging and disable retry
81 m_tainted = m_hang = false;
82}
83
84bool ProtoEvent::Announce75()
85{
86 OS::WriteLock lock(*m_latch);
87
88 std::string cmd("ANN Monitor ");
89 cmd.append(m_socket->GetMyHostName()).append(" 1");
90 if (!SendCommand(cmd.c_str()))
91 return false;
92
93 std::string field;
94 if (!ReadField(field) || !IsMessageOK(field))
95 goto out;
96 return true;
97
98out:
99 FlushMessage();
100 return false;
101}
102
103SignalStatusPtr ProtoEvent::RcvSignalStatus()
104{
105 SignalStatusPtr signal(new SignalStatus()); // Using default constructor
106 std::string field;
107 while (ReadField(field))
108 {
109 std::vector<std::string> tokens;
110 // Tokenize the content
111 __tokenize(field, " ", tokens, false);
112 // Fill my signal
113 if (tokens.size() > 1)
114 {
115 int64_t tmpi;
116 if (tokens[0] == "slock")
117 signal->lock = (tokens[1] == "1" ? true : false);
118 else if (tokens[0] == "signal")
119 signal->signal = (0 == string_to_int64(tokens[1].c_str(), &tmpi) ? (int)tmpi : 0);
120 else if (tokens[0] == "snr")
121 signal->snr = (0 == string_to_int64(tokens[1].c_str(), &tmpi) ? (int)tmpi : 0);
122 else if (tokens[0] == "ber")
123 signal->ber = (0 == string_to_int64(tokens[1].c_str(), &tmpi) ? (long)tmpi : 0);
124 else if (tokens[0] == "ucb")
125 signal->ucb = (0 == string_to_int64(tokens[1].c_str(), &tmpi) ? (long)tmpi : 0);
126 }
127 }
128 return signal;
129}
130
131int ProtoEvent::RcvBackendMessage(unsigned timeout, EventMessage **msg)
132{
133 OS::WriteLock lock(*m_latch);
134 struct timeval tv;
135 tv.tv_sec = timeout;
136 tv.tv_usec = 0;
137 int r = m_socket->Listen(&tv);
138 if (r > 0)
139 {
140 std::string field;
141 EventMessage *pmsg = new EventMessage();
142 pmsg->event = EVENT_UNKNOWN;
143 pmsg->subject.clear();
144 pmsg->program.reset();
145 pmsg->signal.reset();
146 if (RcvMessageLength() && ReadField(field) && field == "BACKEND_MESSAGE")
147 {
148 unsigned n = 0;
149 ReadField(field);
150 // Tokenize the subject
151 __tokenize(field, " ", pmsg->subject, false);
152 n = (unsigned)pmsg->subject.size();
153 DBG(DBG_DEBUG, "%s: %s (%u)\n", __FUNCTION__, field.c_str(), n);
154
155 if (pmsg->subject[0] == "UPDATE_FILE_SIZE")
156 pmsg->event = EVENT_UPDATE_FILE_SIZE;
157 else if (pmsg->subject[0] == "DONE_RECORDING")
158 pmsg->event = EVENT_DONE_RECORDING;
159 else if (pmsg->subject[0] == "QUIT_LIVETV")
160 pmsg->event = EVENT_QUIT_LIVETV;
161 else if (pmsg->subject[0] == "LIVETV_WATCH")
162 pmsg->event = EVENT_LIVETV_WATCH;
163 else if (pmsg->subject[0] == "LIVETV_CHAIN")
164 pmsg->event = EVENT_LIVETV_CHAIN;
165 else if (pmsg->subject[0] == "SIGNAL")
166 {
167 pmsg->event = EVENT_SIGNAL;
168 pmsg->signal = RcvSignalStatus();
169 }
170 else if (pmsg->subject[0] == "RECORDING_LIST_CHANGE")
171 {
172 pmsg->event = EVENT_RECORDING_LIST_CHANGE;
173 if (n > 1 && pmsg->subject[1] == "UPDATE")
174 pmsg->program = RcvProgramInfo();
175 }
176 else if (pmsg->subject[0] == "SCHEDULE_CHANGE")
177 pmsg->event = EVENT_SCHEDULE_CHANGE;
178 else if (pmsg->subject[0] == "ASK_RECORDING")
179 {
180 pmsg->event = EVENT_ASK_RECORDING;
181 pmsg->program = RcvProgramInfo();
182 }
183 else if (pmsg->subject[0] == "CLEAR_SETTINGS_CACHE")
184 pmsg->event = EVENT_CLEAR_SETTINGS_CACHE;
185 else if (pmsg->subject[0] == "GENERATED_PIXMAP")
186 pmsg->event = EVENT_GENERATED_PIXMAP;
187 else if (pmsg->subject[0] == "SYSTEM_EVENT")
188 pmsg->event = EVENT_SYSTEM_EVENT;
189 else
190 pmsg->event = EVENT_UNKNOWN;
191 }
192
193 FlushMessage();
194 *msg = pmsg;
195 return (m_hang ? -(ENOTCONN) : 1);
196 }
197 else if (r < 0)
198 return r;
199
200 return ((ProtoBase::IsOpen() && !m_hang) ? 0 : -(ENOTCONN));
201}
bool m_tainted
Connection has hung since last reset.
bool ReadField(std::string &field)
bool m_hang
Connection hang: while true allow retry.
int RcvBackendMessage(unsigned timeout, EventMessage **msg)
Wait for new backend message from event connection.
This is the main namespace that encloses all public classes.
Definition mythcontrol.h:30