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";
38 AddServerCallback addFunc( [this] (int ipVersion, const char* ip, const char* name, USHORT port, ULONG version)
40 std::lock_guard<std::mutex> lg(serversLock);
45 for (; i < servers.size(); i++)
47 if (servers[i].name == name) break;
50 if (i == servers.size())
52 servers.emplace_back(ipVersion, ip, name, port, version);
56 if (ipVersion == preferIPV) // delete the other
58 servers[i].ipVersion = ipVersion;
60 servers[i].name = name;
61 servers[i].port = port;
62 servers[i].version = version;
69 servers.emplace_back(ipVersion, ip, name, port, version);
74 if (!vdpc4.init(addFunc)) return false;
77 if (!vdpc6.init(addFunc)) return false;
85 std::unique_lock<std::mutex> ul(waitMutex);
98 LogNT::getInstance()->debug(TAG, "Sending broadcasts");
107 waitCond.wait_for(ul, std::chrono::milliseconds(1500), [this]{ return stopNow == true; });
108 LogNT::getInstance()->debug(TAG, "go() wait finished");
111 if (servers.size() == 0) Wol::getInstance()->doWakeUp();
113 } while(servers.size() < 1);
122 std::sort(servers.begin(), servers.end(), ServerSorter(preferIPV));
123 return servers.size();
128 std::lock_guard<std::mutex> lg(waitMutex);
130 waitCond.notify_one();
133 ULONG VDPC::numServers() const
135 return servers.size();
138 const VDRServer& VDPC::operator[](ULONG index) const
140 if (index >= servers.size()) std::abort();
141 return servers[index];
146 // ======================================= VDPC4
148 bool VDPC::VDPC4::init(AddServerCallback& taddFunc)
150 LogNT::getInstance()->debug("VDPC4", "init");
155 LogNT::getInstance()->crit("VDPC4", "Failed to init VDPC4 UDP");
162 void VDPC::VDPC4::run()
164 LogNT::getInstance()->debug("VDPC4", "run");
168 receiveThread = std::thread([this]
171 startProtect.unlock();
174 startProtect.unlock();
177 void VDPC::VDPC4::stop()
179 LogNT::getInstance()->debug("VDPC4", "stop");
184 CLOSESOCKET(quitPipe);
186 write(pfdsUDP4[1], "X", 1);
189 receiveThread.join();
197 void VDPC::VDPC4::threadMethod()
199 LogNT* logger = LogNT::getInstance();
202 quitPipe = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
203 if (quitPipe == INVALID_SOCKET)
205 logger->error("VDPC4", "socket() fail");
209 if (pipe2(pfdsUDP4, O_NONBLOCK) == -1)
211 logger->error("VDPC4", "pipe2 error B");
218 logger->debug("VDPC4", "goto waitformessage");
221 UCHAR retval = udp4.waitforMessage(3, quitPipe);
223 UCHAR retval = udp4.waitforMessage(3, pfdsUDP4[0]);
225 logger->debug("VDPC4", "backfrom waitformessage");
227 if (retval == 2) // we got a reply
229 const char* vdpreply = static_cast<const char*>(udp4.getData());
230 if ((udp4.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
232 // FIXME upgrade this to look for a return IP in the reply packet
234 USHORT newServerPort;
235 memcpy(&newServerPort, &vdpreply[26], 2);
237 ULONG newServerVersion;
238 memcpy(&newServerVersion, &vdpreply[28], 4);
240 // FIXME - packet length > 24 not checked, end NULL not checked!!
241 addFunc(4, udp4.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
245 logger->debug("VDPC4", "loop stopnow = %i", stopNow);
249 void VDPC::VDPC4::sendRequest()
251 LogNT::getInstance()->debug("VDPC4", "broadcast");
254 memset(message, 0, 15);
255 strcpy(message, "VDP-0001");
256 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
258 udp4.send("255.255.255.255", 51051U, message, 15);
259 udp4.send("255.255.255.255", 51052U, message, 15);
260 udp4.send("255.255.255.255", 51053U, message, 15);
261 udp4.send("255.255.255.255", 51054U, message, 15);
262 udp4.send("255.255.255.255", 51055U, message, 15);
269 // ======================================= VDPC6
271 bool VDPC::VDPC6::init(AddServerCallback& taddFunc)
273 LogNT::getInstance()->debug("VDPC6", "init");
278 LogNT::getInstance()->crit("VDPC6", "Failed to init VDPC6 UDP");
285 void VDPC::VDPC6::run()
287 LogNT::getInstance()->debug("VDPC6", "run");
291 receiveThread = std::thread([this]
294 startProtect.unlock();
297 startProtect.unlock();
300 void VDPC::VDPC6::stop()
302 LogNT::getInstance()->debug("VDPC6", "stop");
305 write(pfdsUDP6[1], "X", 1);
306 receiveThread.join();
312 void VDPC::VDPC6::threadMethod()
314 LogNT* logger = LogNT::getInstance();
316 if (pipe2(pfdsUDP6, O_NONBLOCK) == -1)
318 logger->error("VDPC6", "pipe2 error B");
324 logger->debug("VDPC6", "goto waitformessage");
326 UCHAR retval = udp6.waitforMessage(3, pfdsUDP6[0]);
327 logger->debug("VDPC6", "backfrom waitformessage");
329 if (retval == 2) // we got a reply
331 const char* vdpreply = static_cast<const char*>(udp6.getData());
332 if ((udp6.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
334 // FIXME upgrade this to look for a return IP in the reply packet
336 USHORT newServerPort;
337 memcpy(&newServerPort, &vdpreply[26], 2);
339 ULONG newServerVersion;
340 memcpy(&newServerVersion, &vdpreply[28], 4);
342 // FIXME - packet length > 24 not checked, end NULL not checked!!
343 addFunc(6, udp6.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion));
347 logger->debug("VDPC6", "loop stopnow = %i", stopNow);
351 void VDPC::VDPC6::sendRequest()
353 LogNT::getInstance()->debug("VDPC6", "broadcast");
356 memset(message, 0, 15);
357 strcpy(message, "VDP-0001");
358 /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
360 udp6.send("ff15:766f:6d70:2064:6973:636f:7665:7279", 51056U, message, 15, true);