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 void VDPC::TEMPaddCLIServer(const std::string& cliServer)
36 std::lock_guard<std::mutex> lg(serversLock);
37 servers.emplace_back(4, cliServer, "", 3024, 0);
42 AddServerCallback addFunc( [this] (int ipVersion, const char* ip, const char* name, USHORT port, ULONG version)
44 std::lock_guard<std::mutex> lg(serversLock);
49 for (; i < servers.size(); i++)
51 if (servers[i].name == name) break;
54 if (i == servers.size())
56 servers.emplace_back(ipVersion, ip, name, port, version);
60 if (ipVersion == preferIPV) // delete the other
62 servers[i].ipVersion = ipVersion;
64 servers[i].name = name;
65 servers[i].port = port;
66 servers[i].version = version;
73 servers.emplace_back(ipVersion, ip, name, port, version);
78 if (!vdpc4.init(addFunc)) return false;
81 if (!vdpc6.init(addFunc)) return false;
89 std::unique_lock<std::mutex> ul(waitMutex);
102 Log::getInstance()->log("VDPC", Log::DEBUG, "Sending broadcasts");
111 waitCond.wait_for(ul, std::chrono::milliseconds(1500), [this]{ return stopNow == true; });
112 Log::getInstance()->log("VDPC", Log::DEBUG, "go() wait finished");
115 if (servers.size() == 0) Wol::getInstance()->doWakeUp();
117 } while(servers.size() < 1);
126 std::sort(servers.begin(), servers.end(), ServerSorter(preferIPV));
127 return servers.size();
132 std::lock_guard<std::mutex> lg(waitMutex);
134 waitCond.notify_one();
137 ULONG VDPC::numServers() const
139 return servers.size();
142 const VDRServer& VDPC::operator[](ULONG index) const
144 if (index >= servers.size()) std::abort();
145 return servers[index];
150 // ======================================= VDPC4
152 bool VDPC::VDPC4::init(AddServerCallback& taddFunc)
154 Log::getInstance()->log("VDPC4", Log::DEBUG, "init");
159 Log::getInstance()->log("VDPC4", Log::CRIT, "Failed to init VDPC4 UDP");
166 void VDPC::VDPC4::run()
168 Log::getInstance()->log("VDPC4", Log::DEBUG, "run");
172 receiveThread = std::thread([this]
175 startProtect.unlock();
178 startProtect.unlock();
181 void VDPC::VDPC4::stop()
183 Log::getInstance()->log("VDPC4", Log::DEBUG, "stop");
188 CLOSESOCKET(quitPipe);
190 write(pfdsUDP4[1], "X", 1);
193 receiveThread.join();
201 void VDPC::VDPC4::threadMethod()
203 Log* logger = Log::getInstance();
206 quitPipe = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
207 if (quitPipe == INVALID_SOCKET)
209 logger->log("VDPC4", Log::ERR, "socket() fail");
213 if (pipe2(pfdsUDP4, O_NONBLOCK) == -1)
215 logger->log("VDPC4", Log::ERR, "pipe2 error B");
222 Log::getInstance()->log("VDPC4", Log::DEBUG, "goto waitformessage");
225 UCHAR retval = udp4.waitforMessage(3, quitPipe);
227 UCHAR retval = udp4.waitforMessage(3, pfdsUDP4[0]);
229 Log::getInstance()->log("VDPC4", Log::DEBUG, "backfrom waitformessage");
231 if (retval == 2) // we got a reply
233 const char* vdpreply = static_cast<const char*>(udp4.getData());
234 if ((udp4.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
236 // FIXME upgrade this to look for a return IP in the reply packet
238 USHORT newServerPort;
239 memcpy(&newServerPort, &vdpreply[26], 2);
241 ULONG newServerVersion;
242 memcpy(&newServerVersion, &vdpreply[28], 4);
244 // FIXME - packet length > 24 not checked, end NULL not checked!!
245 addFunc(4, udp4.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
249 Log::getInstance()->log("VDPC4", Log::DEBUG, "loop stopnow = %i", stopNow);
253 void VDPC::VDPC4::sendRequest()
255 Log::getInstance()->log("VDPC4", Log::DEBUG, "broadcast");
258 memset(message, 0, 15);
259 strcpy(message, "VDP-0001");
260 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
262 udp4.send("255.255.255.255", 51051U, message, 15);
263 udp4.send("255.255.255.255", 51052U, message, 15);
264 udp4.send("255.255.255.255", 51053U, message, 15);
265 udp4.send("255.255.255.255", 51054U, message, 15);
266 udp4.send("255.255.255.255", 51055U, message, 15);
273 // ======================================= VDPC6
275 bool VDPC::VDPC6::init(AddServerCallback& taddFunc)
277 Log::getInstance()->log("VDPC6", Log::DEBUG, "init");
282 Log::getInstance()->log("VDPC6", Log::CRIT, "Failed to init VDPC6 UDP");
289 void VDPC::VDPC6::run()
291 Log::getInstance()->log("VDPC6", Log::DEBUG, "run");
295 receiveThread = std::thread([this]
298 startProtect.unlock();
301 startProtect.unlock();
304 void VDPC::VDPC6::stop()
306 Log::getInstance()->log("VDPC6", Log::DEBUG, "stop");
309 write(pfdsUDP6[1], "X", 1);
310 receiveThread.join();
316 void VDPC::VDPC6::threadMethod()
318 Log* logger = Log::getInstance();
320 if (pipe2(pfdsUDP6, O_NONBLOCK) == -1)
322 logger->log("VDPC6", Log::ERR, "pipe2 error B");
328 Log::getInstance()->log("VDPC6", Log::DEBUG, "goto waitformessage");
330 UCHAR retval = udp6.waitforMessage(3, pfdsUDP6[0]);
331 Log::getInstance()->log("VDPC6", Log::DEBUG, "backfrom waitformessage");
333 if (retval == 2) // we got a reply
335 const char* vdpreply = static_cast<const char*>(udp6.getData());
336 if ((udp6.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
338 // FIXME upgrade this to look for a return IP in the reply packet
340 USHORT newServerPort;
341 memcpy(&newServerPort, &vdpreply[26], 2);
343 ULONG newServerVersion;
344 memcpy(&newServerVersion, &vdpreply[28], 4);
346 // FIXME - packet length > 24 not checked, end NULL not checked!!
347 addFunc(6, udp6.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
351 Log::getInstance()->log("VDPC6", Log::DEBUG, "loop stopnow = %i", stopNow);
355 void VDPC::VDPC6::sendRequest()
357 Log::getInstance()->log("VDPC6", Log::DEBUG, "broadcast");
360 memset(message, 0, 15);
361 strcpy(message, "VDP-0001");
362 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
364 udp6.send("ff15:766f:6d70:2064:6973:636f:7665:7279", 51056U, message, 15, true);