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<u2>(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
180 // Special case: If there are two servers returned and they only differ by IP version and IP, select one and connect automatically
182 if ( (numServers == 2)
183 && !vdpc[0].name.compare(vdpc[1].name) // if the names are the same...
184 && (vdpc[0].port == vdpc[1].port) // and the port number is the same...
185 && (vdpc[0].ipVersion != vdpc[1].ipVersion) // and the IP versions DO NOT match...
186 / * and the IPs don't match - they can't if ipVersions are different * /
190 config->getInt("server-discovery", "prefer-ipv", which);
192 logger->debug(TAG, "Auto select IPv{}", which);
194 const VDRServer* selected;
195 if (vdpc[0].ipVersion == which) selected = &vdpc[0];
196 else selected = &vdpc[1];
198 if (attemptConnect(selected)) return; // successful connect
200 // Try the other IPv ?!
201 logger->warn(TAG, "Switching IPv");
203 if (vdpc[0].ipVersion == which) selected = &vdpc[1];
204 else selected = &vdpc[0];
206 if (attemptConnect(selected)) return; // successful connect
208 continue; // restart discovery
214 // Now numServers > 1
216 VServerSelect* vs = new VServerSelect(vdpc, this); // deleted by handleCommand returning BoxStack::DELETE_ME
219 boxstack->update(vs);
222 std::unique_lock<std::mutex> ul(threadMutex);
223 if (threadReqQuit) return;
225 // This thread has been notified by VServerSelect. serverSelectResponse is now an index into vdpc of the chosen server
228 if (threadReqQuit) return;
230 if (attemptConnect(&vdpc[serverSelectResponse])) return; // successful connect
231 continue; // restart discovery
235 bool VConnect::attemptConnect(const VDRServer* vdrServer)
237 logger->info(TAG, "Attempting connect to {} {}", vdrServer->ip, vdrServer->port);
239 vdr->setServerIP(vdrServer->ip.c_str());
240 vdr->setServerPort(vdrServer->port);
242 if (threadReqQuit) return false;
244 setOneLiner(tr("Connecting to VDR"));
246 boxstack->update(this);
248 bool connectSuccess = vdr->connect();
257 std::stringstream connFailedString;
258 connFailedString << tr("Connection failed") << " to " << vdrServer->ip << " port " << vdrServer->port;
259 setOneLiner(connFailedString.str());
261 boxstack->update(this);
263 std::unique_lock<std::mutex> ul(threadMutex);
264 if (threadReqQuit) return false;
265 threadCond.wait_for(ul, std::chrono::milliseconds(3000), [this]{ return threadReqQuit; });
270 logger->debug(TAG, "Connected ok, doing login");
272 // FIXME - what is all this? Can it be moved to NCONFIG?
273 unsigned int version_server_min, version_server_max, version_client;
275 bool loginSuccess = vdr->doLogin(&version_server_min, &version_server_max, &version_client, Control::getInstance()->getASLList(), subtitles);
280 if ((version_server_min > version_client) || (version_client > version_server_max))
283 sprintf(buffer, "Version error: s min: %x s max: %x c: %x", version_server_min, version_server_max, version_client);
288 setOneLiner(tr("Login failed"));
292 boxstack->update(this);
295 std::unique_lock<std::mutex> ul(threadMutex);
296 if (threadReqQuit) return false;
297 threadCond.wait_for(ul, std::chrono::milliseconds(3000), [this]{ return threadReqQuit; });
303 logger->debug(TAG, "VDR login ok");
305 Config::getInstance()->set("subtitles", "default", subtitles); // FIXME move this directly into vdr.cc ?
306 Wol::getInstance()->setWakeUpIP(vdrServer->ip.c_str());
308 logger->info(TAG, "Send VDR connected message");
309 Message* m = new Message(); // Must be done after this thread ends
311 m->p_to = Message::CONTROL;
312 m->message = Message::VDR_CONNECTED;
313 MessageQueue::getInstance()->postMessage(m);