From 4bfc4222ee831c551fb132fbb061104f3824db38 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 28 Mar 2020 15:25:00 +0000 Subject: [PATCH] Rewrite server discovery code. Move from VDR to new VDPC class --- GNUmakefile | 2 +- inputman.cc | 2 + inputudp.cc | 20 +-- inputudp.h | 4 +- objects.mk | 2 +- dsock.cc => udp4.cc | 127 +++++++--------- dsock.h => udp4.h | 31 +--- udp6.cc | 236 ++++++++++++++++++++++++++++++ udp6.h | 64 +++++++++ vconnect.cc | 33 +++-- vconnect.h | 11 +- vdp6.cc | 141 ------------------ vdp6.h | 59 -------- vdpc.cc | 344 ++++++++++++++++++++++++++++++++++++++++++++ vdpc.h | 147 +++++++++++++++++++ vdr.cc | 105 -------------- vdr.h | 22 +-- vserverselect.cc | 17 +-- vserverselect.h | 13 +- 19 files changed, 896 insertions(+), 484 deletions(-) rename dsock.cc => udp4.cc (59%) rename dsock.h => udp4.h (76%) create mode 100644 udp6.cc create mode 100644 udp6.h delete mode 100644 vdp6.cc delete mode 100644 vdp6.h create mode 100644 vdpc.cc create mode 100644 vdpc.h diff --git a/GNUmakefile b/GNUmakefile index bec5864..8b8579f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -55,7 +55,7 @@ LD=g++ LDFLAGS = -fuse-ld=gold $(PICTURES) #-fuse-ld=gold -vomp_options += -DIPV6 +vomp_options += -DIPV4 -DIPV6 LIBPATHS = -L/opt/vc/lib -L/usr/lib/arm-linux-gnueabihf LIBS = -lpthread -lrt -lbrcmEGL -lbrcmOpenVG -lopenmaxil -lbcm_host -lavformat -lavcodec -lavutil -lavresample LIBS += -ldl -lfontconfig -lfreetype -lMagick++-6.Q16 diff --git a/inputman.cc b/inputman.cc index 5aab2f7..25a81a1 100644 --- a/inputman.cc +++ b/inputman.cc @@ -59,6 +59,8 @@ bool InputMan::init() i1 = inputLinux->init(); if (!i1) { delete inputLinux; inputLinux = NULL; } + // FIXME enable modules by new config system + // inputCEC = new InputCEC(); // i2 = inputCEC->init(); // if (!i2) { delete inputCEC; inputCEC = NULL; } diff --git a/inputudp.cc b/inputudp.cc index 1834e1a..6b26064 100644 --- a/inputudp.cc +++ b/inputudp.cc @@ -22,7 +22,6 @@ #include #endif -#include "dsock.h" #include "log.h" #include "inputudp.h" @@ -36,11 +35,9 @@ bool InputUDP::init() log = Log::getInstance(); log->log("InputUDP", Log::DEBUG, "Starting InputUDP command server"); - ds = new DatagramSocket(2000); - if (!ds->init()) + if (!udp4.init(2000)) { - log->log("InputUDP", Log::DEBUG, "DSock init error"); - delete ds; + log->log("InputUDP", Log::DEBUG, "UDP4 init error"); initted = false; return false; } @@ -55,8 +52,7 @@ bool InputUDP::init() { Log::getInstance()->log("InputUDP", Log::ERR, "pipe2() fail"); #endif - ds->shutdown(); - delete ds; + udp4.shutdown(); initted = false; return false; } @@ -70,9 +66,7 @@ void InputUDP::shutdown() CLOSESOCKET(quitPipe); #endif - - ds->shutdown(); - delete ds; + udp4.shutdown(); #ifndef WIN32 CLOSESOCKET(pfds[1]); @@ -122,15 +116,15 @@ void InputUDP::listenLoop() while(1) { #ifdef WIN32 - retval = ds->waitforMessage(3, quitPipe); + retval = udp4.waitforMessage(3, quitPipe); #else - retval = ds->waitforMessage(3, pfds[0]); + retval = udp4.waitforMessage(3, pfds[0]); #endif Log::getInstance()->log("InputUDP", Log::DEBUG, "Back from waitForMessage"); if (retval == 2) { - processRequest(ds->getData(), ds->getDataLength()); + processRequest(udp4.getData(), udp4.getDataLength()); } else if (retval == 3) // quit { diff --git a/inputudp.h b/inputudp.h index 45a0146..151227e 100644 --- a/inputudp.h +++ b/inputudp.h @@ -29,9 +29,9 @@ #endif #include "defines.h" +#include "udp4.h" #include "input.h" -class DatagramSocket; class Log; class InputUDP : public Input @@ -54,7 +54,7 @@ class InputUDP : public Input const char* modName() { return myModName; } bool initted{}; - DatagramSocket* ds{}; + UDP4 udp4; Log* log{}; std::thread listenThread; diff --git a/objects.mk b/objects.mk index 8be3227..a7b6201 100644 --- a/objects.mk +++ b/objects.mk @@ -1,4 +1,4 @@ -OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o \ +OBJ_COMMON = command.o thread.o timers.o i18n.o tcp.o udp4.o udp6.o vdpc.o \ message.o messagequeue.o wol.o audio.o video.o log.o \ vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \ directory.o mark.o option.o vfeed.o afeed.o \ diff --git a/dsock.cc b/udp4.cc similarity index 59% rename from dsock.cc rename to udp4.cc index c371009..1382b7f 100644 --- a/dsock.cc +++ b/udp4.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2020 Chris Tallon This file is part of VOMP. @@ -17,22 +17,40 @@ along with VOMP. If not, see . */ -#include "dsock.h" +#ifndef WIN32 +#include +#include +#include +#include +#define SOCKET_ERROR 0 +#else +#include +#include +#include +#endif -DatagramSocket::DatagramSocket(short port) -: myPort(port) -{ - addrlen = sizeof(struct sockaddr); -} +#include +#include +#include +#include +#include + +#include "defines.h" +#include "log.h" -DatagramSocket::~DatagramSocket() +#include "udp4.h" + +UDP4::~UDP4() { if (initted) shutdown(); } -int DatagramSocket::init() +int UDP4::init(USHORT tport) { if (initted) return 0; + + myPort = tport; + addrlen = sizeof(struct sockaddr); if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("socket"); return 0; } @@ -63,7 +81,7 @@ int DatagramSocket::init() return 1; } -void DatagramSocket::shutdown() +void UDP4::shutdown() { if (!initted) return; CLOSESOCKET(socketnum); @@ -71,9 +89,9 @@ void DatagramSocket::shutdown() } #ifdef WIN32 -unsigned char DatagramSocket::waitforMessage(unsigned char how, SOCKET quitPipe) +unsigned char UDP4::waitforMessage(unsigned char how, SOCKET quitPipe) #else -unsigned char DatagramSocket::waitforMessage(unsigned char how, int quitPipe) +unsigned char UDP4::waitforMessage(unsigned char how, int quitPipe) #endif { if (!initted) return 0; @@ -127,14 +145,6 @@ unsigned char DatagramSocket::waitforMessage(unsigned char how, int quitPipe) strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr)); fromPort = ntohs(theirAddr.sin_port); - if (DSOCKDEBUG) - { - //printf("%s:%i\tIN %i\t", fromIPA, fromPort, mlength); - int k; - for(k = 0; k < mlength; k++) - printf("%u ", static_cast(buf[k])); - printf("\n"); - } return 2; } @@ -144,85 +154,44 @@ unsigned char DatagramSocket::waitforMessage(unsigned char how, int quitPipe) */ } -UINT DatagramSocket::getDataLength(void) const +UINT UDP4::getDataLength(void) const { return static_cast(mlength); } -const void* DatagramSocket::getData() const { return buf; } -const char* DatagramSocket::getFromIPA() const { return fromIPA; } -short DatagramSocket::getFromPort() const { return fromPort; } +const void* UDP4::getData() const { return buf; } +const char* UDP4::getFromIPA() const { return fromIPA; } +short UDP4::getFromPort() const { return fromPort; } -void DatagramSocket::send(const char *ipa, short port, char *message, int length) +bool UDP4::send(const char *ipa, USHORT port, char *message, int length) { - if (!initted) return; - - if (DSOCKDEBUG) - { - printf("%s:%i\tOUT %i\t", ipa, port, length); - int k; - UCHAR l; - for (k = 0; k < length; k++) - { l = static_cast(message[k]); printf("%u ", l); } - } + if (!initted) return false; int sentLength = 0; - theirAddr.sin_family = AF_INET; // host byte order - theirAddr.sin_port = htons(port); // short, network byte order - struct in_addr tad; // temp struct tad needed to pass to theirAddr.sin_addr + struct sockaddr_in sendAddr; + sendAddr.sin_family = AF_INET; // host byte order + sendAddr.sin_port = htons(port); // short, network byte order + struct in_addr tad; // temp struct tad needed to pass to sendAddr.sin_addr tad.s_addr = inet_addr(ipa); - theirAddr.sin_addr = tad; // address - memset(&(theirAddr.sin_zero), 0, 8); // zero the rest of the struct + sendAddr.sin_addr = tad; // address + memset(&(sendAddr.sin_zero), 0, 8); // zero the rest of the struct errno = 0; - sentLength = sendto(socketnum, message, length, 0, reinterpret_cast(&theirAddr), addrlen); - if (sentLength == length) - { - if (DSOCKDEBUG) printf(" GOOD\n"); - } - else - { - if (DSOCKDEBUG) - { - printf(" --BAD--"); fflush(stdout); - } - sentLength = sendto(socketnum, message, length, 0, reinterpret_cast(&theirAddr), addrlen); - if (sentLength == length) - { - if (DSOCKDEBUG) printf(" GOOD\n"); - } - else - { - if (DSOCKDEBUG && (sentLength != length)) - { - - printf(" -#-FAILED-#-\n"); - printf("--------------\n"); - printf("Sendto failure\n"); - printf("--------------\n"); - printf("%s:%i\tOUT %i %i ...\n", ipa, port, length, sentLength); - perror("Perror reports"); - printf("errno value: %d\n", errno); - printf("errno translated: %s\n", strerror(errno)); - // printf("h_errno value: %d\n", h_errno); - // printf("\nActual address: %s\n", inet_ntoa(tad)); - // printf("Actual port: %i\n", ntohs(theirAddr.sin_port)); - printf("continuing...\n\n"); - - } - } - } + sentLength = sendto(socketnum, message, length, 0, reinterpret_cast(&sendAddr), addrlen); + if (sentLength == length) return true; + Log::getInstance()->log("UDP6", Log::ERR, "sendto failed, errno = %i", errno); + return false; } #ifndef WIN32 -ULONG DatagramSocket::getIPNumber(ULONG) +ULONG UDP4::getIPNumber(ULONG) { return INADDR_ANY; } #else -ULONG DatagramSocket::getIPNumber(ULONG num) +ULONG UDP4::getIPNumber(ULONG num) { char buffer[100]; ULONG returnaddress; diff --git a/dsock.h b/udp4.h similarity index 76% rename from dsock.h rename to udp4.h index 03fe7b4..63e7da5 100644 --- a/dsock.h +++ b/udp4.h @@ -20,35 +20,19 @@ #ifndef DSOCK_H #define DSOCK_H -#ifndef WIN32 -#include -#include #include -#include -#include -#include -#define SOCKET_ERROR 0 -#else -#include -#include -#include -#endif +#include +#include -#include -#include -#include -#include -#include #include "defines.h" #define MAXBUFLEN 2000 -class DatagramSocket +class UDP4 { public: - DatagramSocket(short); // port - ~DatagramSocket(); - int init(); + ~UDP4(); + int init(USHORT port); void shutdown(); #ifdef WIN32 unsigned char waitforMessage(unsigned char, SOCKET quitPipe = 0); // uchar =0-block =1-new wait =2-continue wait @@ -59,15 +43,14 @@ class DatagramSocket const void* getData() const; // returns a pointer to the data const char* getFromIPA() const; // returns a pointer to from IP address short getFromPort() const; - void send(const char *, short, char *, int); // send wants: IP Address ddn style, port, data, length of data + bool send(const char *, USHORT, char *, int); // send wants: IP Address ddn style, port, data, length of data private: bool initted{}; ULONG getIPNumber(ULONG num); ULONG iterate_ip{}; - const static char DSOCKDEBUG = 0; int socketnum; // Socket descriptor - short myPort; // My port number + USHORT myPort{}; // My port number struct sockaddr_in myAddr; // My address struct sockaddr_in theirAddr; // User address socklen_t addrlen; // length of sockaddr struct diff --git a/udp6.cc b/udp6.cc new file mode 100644 index 0000000..9e9e402 --- /dev/null +++ b/udp6.cc @@ -0,0 +1,236 @@ +/* + Copyright 2020 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef WIN32 +#include +#include +#include +#include +#define SOCKET_ERROR 0 +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +#include "udp6.h" + +UDP6::~UDP6() +{ + if (initted) shutdown(); +} + +int UDP6::init(USHORT tPort) +{ + if (initted) return 0; + myPort = tPort; + addrlen = sizeof(struct sockaddr_in6); + + if ((socketnum = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) + { perror("socket"); return 0; } + + // FIXME - implement server side + + /* + + memset(&myAddr, 0, sizeof(myAddr)); + myAddr.sin6_family = AF_INET6; // host byte order + myAddr.sin6_port = htons(myPort); // short, network byte order + +// myAddr.sin_addr.s_addr = getIPNumber(iterate_ip++); // auto-fill with my IP + + inet_pton(AF_INET6, "", &myAddr.sin6_addr); + +/ * + if (bind(socketnum, reinterpret_cast(&myAddr), addrlen) == -1) + { perror("bind"); return 0; } +* / + +*/ + + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + initted = true; + + return 1; +} + +void UDP6::shutdown() +{ + if (!initted) return; + CLOSESOCKET(socketnum); + initted = false; +} + +#ifdef WIN32 +unsigned char UDP6::waitforMessage(unsigned char how, SOCKET quitPipe) +#else +unsigned char UDP6::waitforMessage(unsigned char how, int quitPipe) +#endif +{ + if (!initted) return 0; + + /* how = 0 - block + how = 1 - start new wait + how = 2 - continue wait + how = 3 - block, return on byte from quitPipe + */ + + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + + struct timeval* passToSelect = NULL; + + int sockMaxP1 = socketnum + 1; + + if (how == 1) + { + tv.tv_sec = 1; + tv.tv_usec = 500000; + passToSelect = &tv; + } + else if (how == 2) + { + if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0 + { + tv.tv_sec = 1; + tv.tv_usec = 500000; + } + passToSelect = &tv; + } + else if (how == 3) + { + FD_SET(quitPipe, &readfds); + if (quitPipe > socketnum) sockMaxP1 = quitPipe + 1; + } + + + if (select(sockMaxP1, &readfds, NULL, NULL, passToSelect) <= 0) + { return 1; } + + if ((how == 3) && FD_ISSET(quitPipe, &readfds)) return 3; + + if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0, + reinterpret_cast(&theirAddr), &addrlen)) == -1) + { perror("recvfrom"); return 0; } + else + { + memset(&buf[mlength], 0, MAXBUFLEN - mlength); + inet_ntop(AF_INET6, &theirAddr.sin6_addr, fromIPA, 40); + fromPort = ntohs(theirAddr.sin6_port); + return 2; + } + + /* Return 0, failure + Return 1, nothing happened, timer expired + Return 2, packet arrived (timer not expired) + */ +} + +UINT UDP6::getDataLength(void) const +{ + return static_cast(mlength); +} + +const void* UDP6::getData() const { return buf; } +const char* UDP6::getFromIPA() const { return fromIPA; } +short UDP6::getFromPort() const { return fromPort; } + +bool UDP6::send(const char *ipa, USHORT port, char *message, int length, bool mcast) +{ + if (!initted) return false; + int sentLength = 0; + errno = 0; + + struct sockaddr_in6 sendAddr; + memset(&sendAddr, 0, sizeof(struct sockaddr_in6)); + sendAddr.sin6_family = AF_INET6; + inet_pton(AF_INET6, ipa, &sendAddr.sin6_addr); + sendAddr.sin6_port = htons(port); + + if (mcast) + { + struct if_nameindex* ifs = if_nameindex(); + UINT ifIndex; + + for(int i = 0; ifs[i].if_index > 0; i++) + { + ifIndex = ifs[i].if_index; + int res = setsockopt(socketnum, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, sizeof(ifIndex)); + Log::getInstance()->log("UDP6", Log::DEBUG, "Transmitting IPv6 MC UDP on %s", ifs[i].if_name); + res = sendto(socketnum, message, length, 0, reinterpret_cast(&sendAddr), addrlen); + Log::getInstance()->log("UDP6", Log::DEBUG, "Result: %i. Errno: %i", res, errno); + errno = 0; + } + + if_freenameindex(ifs); + } + else + { + sentLength = sendto(socketnum, message, length, 0, reinterpret_cast(&sendAddr), addrlen); + if (sentLength == length) return true; + Log::getInstance()->log("UDP6", Log::ERR, "sendto failed, errno = %i", errno); + } + + return false; +} + +#ifndef WIN32 +ULONG UDP6::getIPNumber(ULONG) +{ + return INADDR_ANY; +} +#else +ULONG UDP6::getIPNumber(ULONG num) +{ + char buffer[100]; + ULONG returnaddress; + + if (gethostname(buffer,sizeof(buffer))==SOCKET_ERROR) + { + return INADDR_ANY; //well take any address, if we fail + } + + struct hostent *hosts=gethostbyname(buffer); + if (hosts==NULL) + { + return INADDR_ANY; //well take any address, if we fail + } + + int num_ip=0; + for (num_ip=0;hosts->h_addr_list[num_ip]!=NULL;num_ip++); + + int get_ip=(num%num_ip);//Just wrap around, if no interface are present any more + memcpy(&returnaddress, hosts->h_addr_list[get_ip], sizeof(ULONG)); + return returnaddress; +} +#endif diff --git a/udp6.h b/udp6.h new file mode 100644 index 0000000..bebd3bf --- /dev/null +++ b/udp6.h @@ -0,0 +1,64 @@ +/* + Copyright 2020 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef UDP6_H +#define UDP6_H + +#include +#include + +#include "defines.h" + +#define MAXBUFLEN 2000 + +class UDP6 +{ + public: + ~UDP6(); + int init(USHORT port); + void shutdown(); +#ifdef WIN32 + unsigned char waitforMessage(unsigned char, SOCKET quitPipe = 0); // uchar =0-block =1-new wait =2-continue wait +#else + unsigned char waitforMessage(unsigned char, int quitPipe = 0); // uchar =0-block =1-new wait =2-continue wait +#endif + UINT getDataLength() const; + const void* getData() const; // returns a pointer to the data + const char* getFromIPA() const; // returns a pointer to from IP address + short getFromPort() const; + bool send(const char *, USHORT, char *, int, bool mcast = false); // send wants: text IP, port, data, length of data, is_mcast + + private: + bool initted{}; + ULONG getIPNumber(ULONG num); + ULONG iterate_ip{}; + int socketnum; // Socket descriptor + USHORT myPort{}; // My port number +// struct sockaddr_in6 myAddr; // My address + struct sockaddr_in6 theirAddr; // User address + socklen_t addrlen; // length of sockaddr struct + char buf[MAXBUFLEN]; // main data buffer + char fromIPA[40]; // from string (ip address) + short fromPort; // which port user sent on + int mlength; // length of message + struct timeval tv; + fd_set readfds; +}; + +#endif diff --git a/vconnect.cc b/vconnect.cc index c31cb09..1d31768 100644 --- a/vconnect.cc +++ b/vconnect.cc @@ -25,6 +25,7 @@ #include "boxstack.h" #include "message.h" #include "log.h" +#include "vdr.h" #include "wol.h" #include "vserverselect.h" #include "messagequeue.h" @@ -54,7 +55,7 @@ VConnect::VConnect() VConnect::~VConnect() { threadReqQuit = true; - vdr->cancelFindingServer(); + vdpc.stop(); stop(); } @@ -100,29 +101,40 @@ void VConnect::threadMethod() const std::string& commandLineServer = getCommandLineServer(); + if (!vdpc.init()) + { + logger->log("VConnect", Log::CRIT, "Failed to init VDPC"); + return; + } + do { if (!commandLineServer.empty()) // Server is specified, fake a servers array { - servers.emplace_back(commandLineServer, "", 3024, 0); + //servers.emplace_back(commandLineServer, "", 3024, 0); + + vdpc.TEMPaddCLIServer(commandLineServer); // FIXME move to new config system NCONFIG } else { setOneLiner(tr("Locating server")); draw(); boxstack->update(this); - vdr->findServers(servers); + vdpc.go(); if (threadReqQuit) return; } - if (servers.size() == 1) + for (ULONG i = 0; i < vdpc.numServers(); i++) + logger->log("VConnect", Log::INFO, "Found server: %i %s %s %u", vdpc[i].ipVersion, vdpc[i].ip.c_str(), vdpc[i].name.c_str(), vdpc[i].port, vdpc[i].version); + + if (vdpc.numServers() == 1) { selectedServer = 0; } else { selectedServer = -1; - VServerSelect* vs = new VServerSelect(servers, this); + VServerSelect* vs = new VServerSelect(vdpc, this); vs->draw(); boxstack->add(vs); boxstack->update(vs); @@ -135,10 +147,10 @@ void VConnect::threadMethod() if (threadReqQuit) return; - logger->log("VConnect", Log::NOTICE, "Connecting to server at %s %u", servers[selectedServer].ip.c_str(), servers[selectedServer].port); - Wol::getInstance()->setWakeUpIP(servers[selectedServer].ip.c_str()); - vdr->setServerIP(servers[selectedServer].ip.c_str()); - vdr->setServerPort(servers[selectedServer].port); + logger->log("VConnect", Log::NOTICE, "Connecting to server at %s %u", vdpc[selectedServer].ip.c_str(), vdpc[selectedServer].port); + Wol::getInstance()->setWakeUpIP(vdpc[selectedServer].ip.c_str()); + vdr->setServerIP(vdpc[selectedServer].ip.c_str()); + vdr->setServerPort(vdpc[selectedServer].port); setOneLiner(tr("Connecting to VDR")); draw(); @@ -175,9 +187,6 @@ void VConnect::threadMethod() draw(); boxstack->update(this); MILLISLEEP(delay); - - servers.clear(); // In case we're going around - } while(!success); logger->log("VConnect", Log::INFO, "Send VDR connected message"); diff --git a/vconnect.h b/vconnect.h index 3ea21ce..2558029 100644 --- a/vconnect.h +++ b/vconnect.h @@ -20,13 +20,12 @@ #ifndef VCONNECT_H #define VCONNECT_H -#include #include #include #include #include "vinfo.h" -#include "vdr.h" +#include "vdpc.h" class Log; class BoxStack; @@ -45,13 +44,11 @@ class VConnect : public VInfo void run(); private: - - void clearServerIPs(); - BoxStack* boxstack; - VDR* vdr; Log* logger; - std::vector servers; + VDPC vdpc; + VDR* vdr; + int selectedServer; std::thread connectThread; diff --git a/vdp6.cc b/vdp6.cc deleted file mode 100644 index 0dfa21f..0000000 --- a/vdp6.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - Copyright 2019 Chris Tallon - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP. If not, see . -*/ - -#if IPV6 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vdr.h" -#include "log.h" -#include "vdp6.h" - -VDP6::VDP6() -{ -} - -void VDP6::run() -{ - Log* logger = Log::getInstance(); - - if (pipe2(pfds, O_NONBLOCK) == -1) - { - logger->log("VDP6", Log::ERR, "pipe2 error"); - return; - } - - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) - { - logger->log("VDP6", Log::ERR, "socket error"); - return; - } - - struct sockaddr_in6 saddr; - memset(&saddr, 0, sizeof(saddr)); - saddr.sin6_family = AF_INET6; - inet_pton(AF_INET6, "ff15:766f:6d70:2064:6973:636f:7665:7279", &saddr.sin6_addr); - saddr.sin6_port = htons(51056); - - receiveThread = std::thread( [this, logger] - { - socklen_t addrlen = sizeof(struct sockaddr_in6); - char vdpreply[1000]; - fd_set readfds; - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 500000; - - while(1) - { - FD_ZERO(&readfds); - FD_SET(sock, &readfds); - FD_SET(pfds[0], &readfds); - - int sresult = select(((sock > pfds[0]) ? sock : pfds[0]) + 1, &readfds, NULL, NULL, &timeout); - if (sresult < 1) break; - - if (FD_ISSET(pfds[0], &readfds)) break; - - int mlength; - struct sockaddr_in6 theirAddr; - mlength = recvfrom(sock, vdpreply, 1000, 0, reinterpret_cast(&theirAddr), &addrlen); - if (mlength == -1) - { - logger->log("VDP6", Log::ERR, "recvfrom error"); - break; - } - - // FIXME upgrade this to look for a return IP in the reply packet - char tempStringIP[40]; - inet_ntop(AF_INET6, &theirAddr.sin6_addr, tempStringIP, sizeof(theirAddr)); - - USHORT tempPort; - memcpy(&tempPort, &vdpreply[26], 2); - - ULONG newServerVersion; - memcpy(&newServerVersion, &vdpreply[28], 4); - - //logger->log("VDP6", Log::INFO, "Got response: %s %u %s %lx", newServer.ip, newServer.port, newServer.name, newServer.version); - servers.emplace_back(tempStringIP, &vdpreply[32], ntohs(tempPort), ntohl(newServerVersion)); - } - }); - - char message[15]; - memset(message, 0, 15); - strcpy(message, "VDP-0001"); - - struct if_nameindex* ifs = if_nameindex(); - UINT ifIndex; - - for(int i = 0; ifs[i].if_index > 0; i++) - { - ifIndex = ifs[i].if_index; - int d = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, sizeof(ifIndex)); - d = sendto(sock, message, 15, 0, reinterpret_cast(&saddr), sizeof(saddr)); - if (d > 0) logger->log("VDP6", Log::DEBUG, "Transmitted IPv6 MC UDP on %s", ifs[i].if_name); - } - - if_freenameindex(ifs); -} - -UINT VDP6::numFound() -{ - return servers.size(); -} - -void VDP6::stop() -{ - write(pfds[1], "X", 1); - receiveThread.join(); - - close(pfds[0]); - close(pfds[1]); - close(sock); -} - -#endif diff --git a/vdp6.h b/vdp6.h deleted file mode 100644 index d213dea..0000000 --- a/vdp6.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2019 Chris Tallon - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP. If not, see . -*/ - -#ifndef VDP_H -#define VDP_H - -#if IPV6 - -#include -#include - -#include "defines.h" - -struct VDRServer; - -/* - * Until VDP is reorganised, getServers must be called after stop - * and the buffers pointed to by the VDRServer structs must be freed - * by the caller. - */ - -class VDP6 -{ - public: - VDP6(); - - void run(); - void stop(); - UINT numFound(); - std::vector* getServers() { return &servers; } - - private: - int pfds[2]; - int sock; - std::thread receiveThread; - std::vector servers; -}; - -#endif - - - -#endif diff --git a/vdpc.cc b/vdpc.cc new file mode 100644 index 0000000..b2adead --- /dev/null +++ b/vdpc.cc @@ -0,0 +1,344 @@ +/* + Copyright 2020 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#include +#include + +#include +#include +#include + +#include "log.h" +#include "wol.h" + +#include "vdpc.h" + +void VDPC::TEMPaddCLIServer(const std::string& cliServer) +{ + std::lock_guard lg(serversLock); + servers.emplace_back(4, cliServer, "", 3024, 0); +} + +bool VDPC::init() +{ + AddServerCallback addFunc( [this] (int ipVersion, const char* ip, const char* name, USHORT port, ULONG version) + { + std::lock_guard lg(serversLock); + + if (dedupServers) + { + UINT i = 0; + for (; i < servers.size(); i++) + { + if (servers[i].name == name) break; + } + + if (i == servers.size()) + { + servers.emplace_back(ipVersion, ip, name, port, version); + } + else + { + if (ipVersion == preferIPV) // delete the other + { + servers[i].ipVersion = ipVersion; + servers[i].ip = ip; + servers[i].name = name; + servers[i].port = port; + servers[i].version = version; + } + } + + } + else + { + servers.emplace_back(ipVersion, ip, name, port, version); + } + }); + +#ifdef IPV4 + if (!vdpc4.init(addFunc)) return false; +#endif +#ifdef IPV6 + if (!vdpc6.init(addFunc)) return false; +#endif + + return true; +} + +int VDPC::go() +{ + std::unique_lock ul(waitMutex); + + servers.clear(); + +#ifdef IPV4 + vdpc4.run(); +#endif +#ifdef IPV6 + vdpc6.run(); +#endif + + do + { + Log::getInstance()->log("VDPC", Log::DEBUG, "Sending broadcasts"); + +#ifdef IPV4 + vdpc4.sendRequest(); +#endif +#ifdef IPV6 + vdpc6.sendRequest(); +#endif + + waitCond.wait_for(ul, std::chrono::milliseconds(1500), [this]{ return stopNow == true; }); + Log::getInstance()->log("VDPC", Log::DEBUG, "go() wait finished"); + + if (stopNow) break; + if (servers.size() == 0) Wol::getInstance()->doWakeUp(); + + } while(servers.size() < 1); + +#ifdef IPV4 + vdpc4.stop(); +#endif +#ifdef IPV6 + vdpc6.stop(); +#endif + + std::sort(servers.begin(), servers.end(), ServerSorter(preferIPV)); + return servers.size(); +} + +void VDPC::stop() +{ + std::lock_guard lg(waitMutex); + stopNow = true; + waitCond.notify_one(); +} + +ULONG VDPC::numServers() const +{ + return servers.size(); +} + +const VDRServer& VDPC::operator[](ULONG index) const +{ + if (index >= servers.size()) std::abort(); + return servers[index]; +} + +#ifdef IPV4 + +// ======================================= VDPC4 + +bool VDPC::VDPC4::init(AddServerCallback& taddFunc) +{ + Log::getInstance()->log("VDPC4", Log::DEBUG, "init"); + addFunc = taddFunc; + + if (!udp4.init(0)) + { + Log::getInstance()->log("VDPC4", Log::CRIT, "Failed to init VDPC4 UDP"); + return false; + } + + return true; +} + +void VDPC::VDPC4::run() +{ + Log::getInstance()->log("VDPC4", Log::DEBUG, "run"); + stopNow = false; + + startProtect.lock(); + receiveThread = std::thread([this] + { + startProtect.lock(); + startProtect.unlock(); + threadMethod(); + }); + startProtect.unlock(); +} + +void VDPC::VDPC4::stop() +{ + Log::getInstance()->log("VDPC4", Log::DEBUG, "stop"); + + stopNow = true; + write(pfdsUDP4[1], "X", 1); + receiveThread.join(); + + close(pfdsUDP4[0]); + close(pfdsUDP4[1]); +} + +void VDPC::VDPC4::threadMethod() +{ + Log* logger = Log::getInstance(); + + if (pipe2(pfdsUDP4, O_NONBLOCK) == -1) + { + logger->log("VDPC4", Log::ERR, "pipe2 error B"); + return; + } + + while (!stopNow) + { + Log::getInstance()->log("VDPC4", Log::DEBUG, "goto waitformessage"); + + UCHAR retval = udp4.waitforMessage(3, pfdsUDP4[0]); + Log::getInstance()->log("VDPC4", Log::DEBUG, "backfrom waitformessage"); + + if (retval == 2) // we got a reply + { + const char* vdpreply = static_cast(udp4.getData()); + if ((udp4.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8)) + { + // FIXME upgrade this to look for a return IP in the reply packet + + USHORT newServerPort; + memcpy(&newServerPort, &vdpreply[26], 2); + + ULONG newServerVersion; + memcpy(&newServerVersion, &vdpreply[28], 4); + + // FIXME - packet length > 24 not checked, end NULL not checked!! + addFunc(4, udp4.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion)); + } + } + + Log::getInstance()->log("VDPC4", Log::DEBUG, "loop stopnow = %i", stopNow); + } +} + +void VDPC::VDPC4::sendRequest() +{ + Log::getInstance()->log("VDPC4", Log::DEBUG, "broadcast"); + + char message[15]; + memset(message, 0, 15); + strcpy(message, "VDP-0001"); + /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/ + + udp4.send("255.255.255.255", 51051U, message, 15); + udp4.send("255.255.255.255", 51052U, message, 15); + udp4.send("255.255.255.255", 51053U, message, 15); + udp4.send("255.255.255.255", 51054U, message, 15); + udp4.send("255.255.255.255", 51055U, message, 15); +} + +#endif + +#ifdef IPV6 + +// ======================================= VDPC6 + +bool VDPC::VDPC6::init(AddServerCallback& taddFunc) +{ + Log::getInstance()->log("VDPC6", Log::DEBUG, "init"); + addFunc = taddFunc; + + if (!udp6.init(0)) + { + Log::getInstance()->log("VDPC6", Log::CRIT, "Failed to init VDPC6 UDP"); + return false; + } + + return true; +} + +void VDPC::VDPC6::run() +{ + Log::getInstance()->log("VDPC6", Log::DEBUG, "run"); + stopNow = false; + + startProtect.lock(); + receiveThread = std::thread([this] + { + startProtect.lock(); + startProtect.unlock(); + threadMethod(); + }); + startProtect.unlock(); +} + +void VDPC::VDPC6::stop() +{ + Log::getInstance()->log("VDPC6", Log::DEBUG, "stop"); + + stopNow = true; + write(pfdsUDP6[1], "X", 1); + receiveThread.join(); + + close(pfdsUDP6[0]); + close(pfdsUDP6[1]); +} + +void VDPC::VDPC6::threadMethod() +{ + Log* logger = Log::getInstance(); + + if (pipe2(pfdsUDP6, O_NONBLOCK) == -1) + { + logger->log("VDPC6", Log::ERR, "pipe2 error B"); + return; + } + + while (!stopNow) + { + Log::getInstance()->log("VDPC6", Log::DEBUG, "goto waitformessage"); + + UCHAR retval = udp6.waitforMessage(3, pfdsUDP6[0]); + Log::getInstance()->log("VDPC6", Log::DEBUG, "backfrom waitformessage"); + + if (retval == 2) // we got a reply + { + const char* vdpreply = static_cast(udp6.getData()); + if ((udp6.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8)) + { + // FIXME upgrade this to look for a return IP in the reply packet + + USHORT newServerPort; + memcpy(&newServerPort, &vdpreply[26], 2); + + ULONG newServerVersion; + memcpy(&newServerVersion, &vdpreply[28], 4); + + // FIXME - packet length > 24 not checked, end NULL not checked!! + addFunc(6, udp6.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion)); + } + } + + Log::getInstance()->log("VDPC6", Log::DEBUG, "loop stopnow = %i", stopNow); + } +} + +void VDPC::VDPC6::sendRequest() +{ + Log::getInstance()->log("VDPC6", Log::DEBUG, "broadcast"); + + char message[15]; + memset(message, 0, 15); + strcpy(message, "VDP-0001"); + /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/ + + udp6.send("ff15:766f:6d70:2064:6973:636f:7665:7279", 51056U, message, 15, true); +} + +#endif diff --git a/vdpc.h b/vdpc.h new file mode 100644 index 0000000..e196302 --- /dev/null +++ b/vdpc.h @@ -0,0 +1,147 @@ +/* + Copyright 2020 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#ifndef VDPC_H +#define VDPC_H + +// Vomp Discovery Protocol Client + +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +#ifdef IPV4 +#include "udp4.h" +#endif +#ifdef IPV6 +#include "udp6.h" +#endif + +struct VDRServer +{ + int ipVersion; + std::string ip; + std::string name; + USHORT port; + ULONG version; + + VDRServer(int tipVersion, const std::string tip, const std::string tname, USHORT tport, ULONG tversion) + : ipVersion(tipVersion), ip(tip), name(tname), port(tport), version(tversion) {} +}; + +class ServerSorter +{ + public: + ServerSorter(int tipPreferred) : ipPreferred(tipPreferred) {} + bool operator() (const VDRServer& a, const VDRServer& b) + { + if (a.name == b.name) + return a.ipVersion == ipPreferred; + else + return a.name < b.name; + } + private: + int ipPreferred; +}; + +class VDPC +{ + private: + typedef std::function AddServerCallback; + + // Nested classes +#ifdef IPV4 + class VDPC4 + { + public: + bool init(AddServerCallback& taddFunc); + void run(); // blocks + void stop(); + void sendRequest(); + + private: + int pfdsUDP4[2]; + + std::mutex startProtect; + std::thread receiveThread; + bool stopNow{}; + void threadMethod(); + + UDP4 udp4; + AddServerCallback addFunc; + }; +#endif + +#ifdef IPV6 + class VDPC6 + { + public: + bool init(AddServerCallback& taddFunc); + void run(); // blocks + void stop(); + void sendRequest(); + + private: + int pfdsUDP6[2]; + + std::mutex startProtect; + std::thread receiveThread; + bool stopNow{}; + void threadMethod(); + + UDP6 udp6; + AddServerCallback addFunc; + }; +#endif + + public: + bool init(); + int go(); + void stop(); + ULONG numServers() const; + const VDRServer& operator[](ULONG index) const; + + void TEMPaddCLIServer(const std::string&); // FIXME NCONFIG + + private: + std::vector servers; + std::mutex serversLock; + + std::condition_variable waitCond; + std::mutex waitMutex; + bool stopNow{}; + + // FIXME retrieve from new config system NCONFIG + bool dedupServers{true}; + int preferIPV{4}; + +#ifdef IPV4 + VDPC4 vdpc4; +#endif +#ifdef IPV6 + VDPC6 vdpc6; +#endif +}; + +#endif diff --git a/vdr.cc b/vdr.cc index db620a4..958ef6f 100644 --- a/vdr.cc +++ b/vdr.cc @@ -23,14 +23,12 @@ #include "tcp.h" #include "log.h" #include "recinfo.h" -#include "dsock.h" #include "channel.h" #include "event.h" #include "wol.h" #include "vdrrequestpacket.h" #include "vdrresponsepacket.h" #include "command.h" -#include "vdp6.h" #ifdef VOMP_MEDIAPLAYER #include "media.h" #include "mediaprovider.h" @@ -92,8 +90,6 @@ SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) { return buf; } - - //deserialize a received response //delete the package //return !=0 on error @@ -155,107 +151,6 @@ int VDR::shutdown() return 1; } -void VDR::findServers(std::vector& servers) -{ - Wol* wol = Wol::getInstance(); - findingServer = 1; - char message[15]; - memset(message, 0, 15); - strcpy(message, "VDP-0001"); - /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/ - -#if IPV6 - // FIXME Horrible hack. Rewrite all this. - // Change away from relying on the dsock select to do the timing - // Do timing here and let UDP4 / UDP6 objects/threads just wait - // for responses - VDP6 vdp6; - vdp6.run(); -#endif - - DatagramSocket ds(0); - int haveAtLeastOne = 0; - int retval; - UCHAR waitType = 1; - bool firstloop = true; - while(findingServer) - { - if (waitType == 1) - { - ds.shutdown(); - ds.init(); - logger->log("VDR", Log::NOTICE, "Broadcasting for server"); - ds.send("255.255.255.255", 51051U, message, 15); - ds.send("255.255.255.255", 51052U, message, 15); - ds.send("255.255.255.255", 51053U, message, 15); - ds.send("255.255.255.255", 51054U, message, 15); - ds.send("255.255.255.255", 51055U, message, 15); - if(!firstloop) wol->doWakeUp(); - } - retval = ds.waitforMessage(waitType); - - if (retval == 2) // we got a reply - { - waitType = 2; - - const char* vdpreply = static_cast(ds.getData()); - if ((ds.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8)) - { - // FIXME upgrade this to look for a return IP in the reply packet - - USHORT newServerPort; - memcpy(&newServerPort, &vdpreply[26], 2); - - ULONG newServerVersion; - memcpy(&newServerVersion, &vdpreply[28], 4); - haveAtLeastOne = 1; - - // FIXME - packet length > 24 not checked, end NULL not checked!! - // FIXME mutex protection ?? Nope this is a separate vector currently - servers.emplace_back(ds.getFromIPA(), &vdpreply[32], ntohs(newServerPort), ntohl(newServerVersion)); - } - } - else - { - if (haveAtLeastOne) break; -#if IPV6 - if (vdp6.numFound()) break; -#endif - - waitType = 1; - firstloop = false; - } - } - logger->log("VDR", Log::NOTICE, "END loop"); - -#if IPV6 - vdp6.stop(); - std::vector* servers6 = vdp6.getServers(); - - // Add IPv6 found servers to servers vector, if not in servers already - - for(auto i6 = servers6->begin(); i6 != servers6->end(); i6++) - { - bool found = false; - - for(auto i4 = servers.begin(); i4 != servers.end(); i4++) - if (i4->name == i6->name) { found = true; break; } - - if (found) continue; // Don't add - - servers.push_back(std::move(*i6)); // VDP6 is stopped, the vector owner only goes out of scope after this method - } - -#endif - - sort(servers.begin(), servers.end(), ServerSorter()); -} - -void VDR::cancelFindingServer() -{ - findingServer = 0; -} - void VDR::setServerIP(const char* newIP) { strcpy(serverIP, newIP); diff --git a/vdr.h b/vdr.h index 27ea09b..6e4dd30 100644 --- a/vdr.h +++ b/vdr.h @@ -61,17 +61,6 @@ typedef std::vector EventList; typedef std::vector ChannelList; typedef std::vector RecTimerList; -struct VDRServer -{ - std::string ip; - std::string name; - USHORT port; - ULONG version; - - VDRServer(const std::string tip, const std::string tname, USHORT tport, ULONG tversion) - : ip(tip), name(tname), port(tport), version(tversion) {} -}; - struct RecTimerSorter // : public binary_function { bool operator() (const RecTimer* a, const RecTimer* b) @@ -80,14 +69,6 @@ struct RecTimerSorter // : public binary_function } }; -struct ServerSorter -{ - bool operator() (const VDRServer& a, const VDRServer& b) - { - return a.name < b.name; - } -}; - class StreamReceiver { public: @@ -140,8 +121,11 @@ public ExternLogger int init(); int shutdown(); + /* void findServers(std::vector& servers); void cancelFindingServer(); + */ + void setServerIP(const char*); void setServerPort(USHORT); void setReceiveWindow(size_t size); diff --git a/vserverselect.cc b/vserverselect.cc index 09da0a3..767a556 100644 --- a/vserverselect.cc +++ b/vserverselect.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2020 Chris Tallon This file is part of VOMP. @@ -14,12 +14,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ -#include "vserverselect.h" - #include "defines.h" #include "input.h" #include "colour.h" @@ -28,14 +25,10 @@ #include "i18n.h" #include "messagequeue.h" +#include "vserverselect.h" -VServerSelect::VServerSelect(std::vector& servers, void* treplyTo) +VServerSelect::VServerSelect(const VDPC& servers, void* treplyTo) { - // I tried the whole passing using a reference here, but - // the program segfaulted when settitletext tried to new - // a char array. so now we have the messy dereferencing... - // anyway, now it doesn't use a object wide reference. - setSize(300, 200); createBuffer(); if (Video::getInstance()->getFormat() == Video::PAL) @@ -56,7 +49,7 @@ VServerSelect::VServerSelect(std::vector& servers, void* treplyTo) add(&sl); sl.addOption(servers[0].name.c_str(), 0, 1); - for(UINT k = 1; k < servers.size(); k++) + for(UINT k = 1; k < servers.numServers(); k++) { sl.addOption(servers[k].name.c_str(), 0, 0); } diff --git a/vserverselect.h b/vserverselect.h index 2a4a022..650a751 100644 --- a/vserverselect.h +++ b/vserverselect.h @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2004-2020 Chris Tallon This file is part of VOMP. @@ -14,19 +14,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + along with VOMP. If not, see . */ #ifndef VSERVERSELECT_H #define VSERVERSELECT_H -#include -#include -#include - #include "tbboxx.h" -#include "vdr.h" +#include "vdpc.h" #include "wselectlist.h" class Message; @@ -34,7 +29,7 @@ class Message; class VServerSelect : public TBBoxx { public: - VServerSelect(std::vector& servers, void* replyTo); + VServerSelect(const VDPC&, void* replyTo); ~VServerSelect(); int handleCommand(int command); -- 2.39.2