2 Copyright 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/>.
34 static const char* TAG = "VDPC";
36 void VDPC::TEMPaddCLIServer(const std::string& cliServer)
38 std::lock_guard<std::mutex> lg(serversLock);
39 servers.emplace_back(4, cliServer, "", 3024, 0);
44 AddServerCallback addFunc( [this] (int ipVersion, const char* ip, const char* name, USHORT port, ULONG version)
46 std::lock_guard<std::mutex> lg(serversLock);
51 for (; i < servers.size(); i++)
53 if (servers[i].name == name) break;
56 if (i == servers.size())
58 servers.emplace_back(ipVersion, ip, name, port, version);
62 if (ipVersion == preferIPV) // delete the other
64 servers[i].ipVersion = ipVersion;
66 servers[i].name = name;
67 servers[i].port = port;
68 servers[i].version = version;
75 servers.emplace_back(ipVersion, ip, name, port, version);
80 if (!vdpc4.init(addFunc)) return false;
83 if (!vdpc6.init(addFunc)) return false;
91 std::unique_lock<std::mutex> ul(waitMutex);
104 LogNT::getInstance()->debug(TAG, "Sending broadcasts");
113 waitCond.wait_for(ul, std::chrono::milliseconds(1500), [this]{ return stopNow == true; });
114 LogNT::getInstance()->debug(TAG, "go() wait finished");
117 if (servers.size() == 0) Wol::getInstance()->doWakeUp();
119 } while(servers.size() < 1);
128 std::sort(servers.begin(), servers.end(), ServerSorter(preferIPV));
129 return servers.size();
134 std::lock_guard<std::mutex> lg(waitMutex);
136 waitCond.notify_one();
139 ULONG VDPC::numServers() const
141 return servers.size();
144 const VDRServer& VDPC::operator[](ULONG index) const
146 if (index >= servers.size()) std::abort();
147 return servers[index];
152 // ======================================= VDPC4
154 bool VDPC::VDPC4::init(AddServerCallback& taddFunc)
156 LogNT::getInstance()->debug("VDPC4", "init");
161 LogNT::getInstance()->crit("VDPC4", "Failed to init VDPC4 UDP");
168 void VDPC::VDPC4::run()
170 LogNT::getInstance()->debug("VDPC4", "run");
174 receiveThread = std::thread([this]
177 startProtect.unlock();
180 startProtect.unlock();
183 void VDPC::VDPC4::stop()
185 LogNT::getInstance()->debug("VDPC4", "stop");
190 CLOSESOCKET(quitPipe);
192 write(pfdsUDP4[1], "X", 1);
195 receiveThread.join();
203 void VDPC::VDPC4::threadMethod()
205 LogNT* logger = LogNT::getInstance();
208 quitPipe = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
209 if (quitPipe == INVALID_SOCKET)
211 logger->error("VDPC4", "socket() fail");
215 if (pipe2(pfdsUDP4, O_NONBLOCK) == -1)
217 logger->error("VDPC4", "pipe2 error B");
224 logger->debug("VDPC4", "goto waitformessage");
227 UCHAR retval = udp4.waitforMessage(3, quitPipe);
229 UCHAR retval = udp4.waitforMessage(3, pfdsUDP4[0]);
231 logger->debug("VDPC4", "backfrom waitformessage");
233 if (retval == 2) // we got a reply
235 const char* vdpreply = static_cast<const char*>(udp4.getData());
236 if ((udp4.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
238 // FIXME upgrade this to look for a return IP in the reply packet
240 USHORT newServerPort;
241 memcpy(&newServerPort, &vdpreply[26], 2);
243 ULONG newServerVersion;
244 memcpy(&newServerVersion, &vdpreply[28], 4);
246 // FIXME - packet length > 24 not checked, end NULL not checked!!
247 addFunc(4, udp4.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
251 logger->debug("VDPC4", "loop stopnow = %i", stopNow);
255 void VDPC::VDPC4::sendRequest()
257 LogNT::getInstance()->debug("VDPC4", "broadcast");
260 memset(message, 0, 15);
261 strcpy(message, "VDP-0001");
262 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
264 udp4.send("255.255.255.255", 51051U, message, 15);
265 udp4.send("255.255.255.255", 51052U, message, 15);
266 udp4.send("255.255.255.255", 51053U, message, 15);
267 udp4.send("255.255.255.255", 51054U, message, 15);
268 udp4.send("255.255.255.255", 51055U, message, 15);
275 // ======================================= VDPC6
277 bool VDPC::VDPC6::init(AddServerCallback& taddFunc)
279 LogNT::getInstance()->debug("VDPC6", "init");
284 LogNT::getInstance()->crit("VDPC6", "Failed to init VDPC6 UDP");
291 void VDPC::VDPC6::run()
293 LogNT::getInstance()->debug("VDPC6", "run");
297 receiveThread = std::thread([this]
300 startProtect.unlock();
303 startProtect.unlock();
306 void VDPC::VDPC6::stop()
308 LogNT::getInstance()->debug("VDPC6", "stop");
311 write(pfdsUDP6[1], "X", 1);
312 receiveThread.join();
318 void VDPC::VDPC6::threadMethod()
320 LogNT* logger = LogNT::getInstance();
322 if (pipe2(pfdsUDP6, O_NONBLOCK) == -1)
324 logger->error("VDPC6", "pipe2 error B");
330 logger->debug("VDPC6", "goto waitformessage");
332 UCHAR retval = udp6.waitforMessage(3, pfdsUDP6[0]);
333 logger->debug("VDPC6", "backfrom waitformessage");
335 if (retval == 2) // we got a reply
337 const char* vdpreply = static_cast<const char*>(udp6.getData());
338 if ((udp6.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
340 // FIXME upgrade this to look for a return IP in the reply packet
342 USHORT newServerPort;
343 memcpy(&newServerPort, &vdpreply[26], 2);
345 ULONG newServerVersion;
346 memcpy(&newServerVersion, &vdpreply[28], 4);
348 // FIXME - packet length > 24 not checked, end NULL not checked!!
349 addFunc(6, udp6.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
353 logger->debug("VDPC6", "loop stopnow = %i", stopNow);
357 void VDPC::VDPC6::sendRequest()
359 LogNT::getInstance()->debug("VDPC6", "broadcast");
362 memset(message, 0, 15);
363 strcpy(message, "VDP-0001");
364 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
366 udp6.send("ff15:766f:6d70:2064:6973:636f:7665:7279", 51056U, message, 15, true);