2 Copyright 2004-2020 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
31 #include "vserverselect.h"
32 #include "messagequeue.h"
37 static const char* TAG = "VConnect";
41 boxstack = BoxStack::getInstance();
42 vdr = VDR::getInstance();
43 logger = LogNT::getInstance();
47 if (Video::getInstance()->getFormat() == Video::PAL)
49 setPosition(170, 200);
53 setPosition(160, 150);
69 logger->debug(TAG, "Draw done");
72 int VConnect::handleCommand(int /* command */)
74 return BoxStack::ABANDON_COMMAND;
80 threadReqQuit = false;
81 connectThread = std::thread([this]
94 vdr->abortConnect(); // If this and vdr are connecting, cancel it
95 threadCond.notify_one();
100 void VConnect::processMessage(Message* m)
102 if (m->message == Message::SERVER_SELECTED)
104 serverSelectResponse = m->parameter;
105 threadCond.notify_one();
109 void VConnect::threadMethod()
111 logger->debug(TAG, "start threadMethod");
112 Config* config = Config::getInstance();
114 // Try to get server and port from config. If successful then
115 // either a server &? port was supplied in config.json or
116 // overridden by command line args
118 VDRServer serverFromConfig;
119 if (config->getString("server", "address", serverFromConfig.ip))
121 logger->debug(TAG, "Server read from config: {}", serverFromConfig.ip);
122 serverFromConfig.port = 3024;
123 int newPort; // copy around because of type mismatch
124 if (config->getInt("server", "port", newPort))
126 serverFromConfig.port = static_cast<USHORT>(newPort);
127 logger->debug(TAG, "Port read fron config: {}", serverFromConfig.port);
130 while(1) // Only attempt connection to this server from config
132 if (threadReqQuit) return;
133 if (attemptConnect(&serverFromConfig)) return;
137 // No config server. Start VDPC
139 setOneLiner(tr("Locating server"));
141 boxstack->update(this);
143 if (threadReqQuit) return;
147 logger->crit(TAG, "Failed to init VDPC");
153 if (threadReqQuit) return;
154 int numServers = vdpc.go();
155 if (threadReqQuit) return;
159 logger->crit(TAG, "VDPC returned 0 servers");
163 // Now we have > 0 servers found
165 for (int i = 0; i < numServers; i++)
166 logger->info(TAG, "Found server: {} {} {} {}", vdpc[i].ipVersion, vdpc[i].ip.c_str(), vdpc[i].name.c_str(), vdpc[i].port, vdpc[i].version);
170 if (threadReqQuit) return;
171 if (attemptConnect(&vdpc[0])) return; // successful connect
172 continue; // restart discovery
175 // Multiple servers found
177 // Special case: If there are two servers returned and they only differ by IP version and IP, select one and connect automatically
179 if ( (numServers == 2)
180 && !vdpc[0].name.compare(vdpc[1].name) // if the names are the same...
181 && (vdpc[0].port == vdpc[1].port) // and the port number is the same...
182 && (vdpc[0].ipVersion != vdpc[1].ipVersion) // and the IP versions DO NOT match...
183 /* and the IPs don't match - they can't if ipVersions are different */
187 config->getInt("server-discovery", "prefer-ipv", which);
189 logger->debug(TAG, "Auto select IPv{}", which);
191 const VDRServer* selected;
192 if (vdpc[0].ipVersion == which) selected = &vdpc[0];
193 else selected = &vdpc[1];
195 if (attemptConnect(selected)) return; // successful connect
197 // Try the other IPv ?!
198 logger->warn(TAG, "Switching IPv");
200 if (vdpc[0].ipVersion == which) selected = &vdpc[1];
201 else selected = &vdpc[0];
203 if (attemptConnect(selected)) return; // successful connect
205 continue; // restart discovery
208 // Now numServers > 1
210 VServerSelect* vs = new VServerSelect(vdpc, this); // deleted by handleCommand returning BoxStack::DELETE_ME
213 boxstack->update(vs);
216 std::unique_lock<std::mutex> ul(threadMutex);
217 if (threadReqQuit) return;
219 // This thread has been notified by VServerSelect. serverSelectResponse is now an index into vdpc of the chosen server
222 if (threadReqQuit) return;
224 if (attemptConnect(&vdpc[serverSelectResponse])) return; // successful connect
225 continue; // restart discovery
229 bool VConnect::attemptConnect(const VDRServer* vdrServer)
231 logger->info(TAG, "Attempting connect to {} {}", vdrServer->ip, vdrServer->port);
233 vdr->setServerIP(vdrServer->ip.c_str());
234 vdr->setServerPort(vdrServer->port);
236 if (threadReqQuit) return false;
238 setOneLiner(tr("Connecting to VDR"));
240 boxstack->update(this);
242 bool connectSuccess = vdr->connect();
251 setOneLiner(tr("Connection failed"));
253 boxstack->update(this);
255 std::unique_lock<std::mutex> ul(threadMutex);
256 if (threadReqQuit) return false;
257 threadCond.wait_for(ul, std::chrono::milliseconds(3000), [this]{ return threadReqQuit; });
262 logger->debug(TAG, "Connected ok, doing login");
264 // FIXME - what is all this? Can it be moved to NCONFIG?
265 unsigned int version_server_min, version_server_max, version_client;
267 bool loginSuccess = vdr->doLogin(&version_server_min, &version_server_max, &version_client, Control::getInstance()->getASLList(), subtitles);
272 if ((version_server_min > version_client) || (version_client > version_server_max))
275 sprintf(buffer, "Version error: s min: %x s max: %x c: %x", version_server_min, version_server_max, version_client);
280 setOneLiner(tr("Login failed"));
284 boxstack->update(this);
287 std::unique_lock<std::mutex> ul(threadMutex);
288 if (threadReqQuit) return false;
289 threadCond.wait_for(ul, std::chrono::milliseconds(3000), [this]{ return threadReqQuit; });
295 logger->debug(TAG, "VDR login ok");
297 Config::getInstance()->set("subtitles", "default", subtitles); // FIXME move this directly into vdr.cc ?
298 Wol::getInstance()->setWakeUpIP(vdrServer->ip.c_str());
300 logger->info(TAG, "Send VDR connected message");
301 Message* m = new Message(); // Must be done after this thread ends
303 m->p_to = Message::CONTROL;
304 m->message = Message::VDR_CONNECTED;
305 MessageQueue::getInstance()->postMessage(m);