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
+++ /dev/null
-/*
- Copyright 2004-2005 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 <https://www.gnu.org/licenses/>.
-*/
-
-#include "dsock.h"
-
-DatagramSocket::DatagramSocket(short port)
-: myPort(port)
-{
- addrlen = sizeof(struct sockaddr);
-}
-
-DatagramSocket::~DatagramSocket()
-{
- if (initted) shutdown();
-}
-
-int DatagramSocket::init()
-{
- if (initted) return 0;
-
- if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
- { perror("socket"); return 0; }
-
- myAddr.sin_family = AF_INET; // host byte order
- myAddr.sin_port = htons(myPort); // short, network byte order
- myAddr.sin_addr.s_addr = getIPNumber(iterate_ip++); // auto-fill with my IP
- memset(&(myAddr.sin_zero), 0, 8); // zero the rest of the struct
-
- if (bind(socketnum, reinterpret_cast<struct sockaddr *>(&myAddr), addrlen) == -1)
- { perror("bind"); return 0; }
-
- FD_ZERO(&readfds);
- FD_SET(socketnum, &readfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- int allowed = 1;
-
-#ifdef WIN32
- setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&allowed), sizeof(allowed));
-#else
- setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, static_cast<void*>(&allowed), sizeof(allowed));
-#endif
-
- initted = true;
-
- return 1;
-}
-
-void DatagramSocket::shutdown()
-{
- if (!initted) return;
- CLOSESOCKET(socketnum);
- initted = false;
-}
-
-#ifdef WIN32
-unsigned char DatagramSocket::waitforMessage(unsigned char how, SOCKET quitPipe)
-#else
-unsigned char DatagramSocket::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<struct sockaddr *>(&theirAddr), &addrlen)) == -1)
- { perror("recvfrom"); return 0; }
- else
- {
- memset(&buf[mlength], 0, MAXBUFLEN - mlength);
- 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<unsigned char>(buf[k]));
- printf("\n");
- }
- return 2;
- }
-
- /* Return 0, failure
- Return 1, nothing happened, timer expired
- Return 2, packet arrived (timer not expired)
- */
-}
-
-UINT DatagramSocket::getDataLength(void) const
-{
- return static_cast<UINT>(mlength);
-}
-
-const void* DatagramSocket::getData() const { return buf; }
-const char* DatagramSocket::getFromIPA() const { return fromIPA; }
-short DatagramSocket::getFromPort() const { return fromPort; }
-
-void DatagramSocket::send(const char *ipa, short 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<UCHAR>(message[k]); printf("%u ", l); }
- }
-
- 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
- tad.s_addr = inet_addr(ipa);
- theirAddr.sin_addr = tad; // address
- memset(&(theirAddr.sin_zero), 0, 8); // zero the rest of the struct
-
- errno = 0;
-
- sentLength = sendto(socketnum, message, length, 0, reinterpret_cast<struct sockaddr *>(&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<struct sockaddr *>(&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");
-
- }
- }
- }
-}
-
-#ifndef WIN32
-ULONG DatagramSocket::getIPNumber(ULONG)
-{
- return INADDR_ANY;
-}
-#else
-ULONG DatagramSocket::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
+++ /dev/null
-/*
- Copyright 2004-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 <https://www.gnu.org/licenses/>.
-*/
-
-#ifndef DSOCK_H
-#define DSOCK_H
-
-#ifndef WIN32
-#include <netinet/in.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/time.h>
-#define SOCKET_ERROR 0
-#else
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-#include <sys/timeb.h>
-#endif
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "defines.h"
-
-#define MAXBUFLEN 2000
-
-class DatagramSocket
-{
- public:
- DatagramSocket(short); // port
- ~DatagramSocket();
- int init();
- 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;
- void send(const char *, short, 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
- struct sockaddr_in myAddr; // My address
- struct sockaddr_in theirAddr; // User address
- socklen_t addrlen; // length of sockaddr struct
- char buf[MAXBUFLEN]; // main data buffer
- char fromIPA[20]; // from string (ip address)
- short fromPort; // which port user sent on
- int mlength; // length of message
- struct timeval tv;
- fd_set readfds;
-};
-
-#endif
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; }
#include <unistd.h>
#endif
-#include "dsock.h"
#include "log.h"
#include "inputudp.h"
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;
}
{
Log::getInstance()->log("InputUDP", Log::ERR, "pipe2() fail");
#endif
- ds->shutdown();
- delete ds;
+ udp4.shutdown();
initted = false;
return false;
}
CLOSESOCKET(quitPipe);
#endif
-
- ds->shutdown();
- delete ds;
+ udp4.shutdown();
#ifndef WIN32
CLOSESOCKET(pfds[1]);
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
{
#endif
#include "defines.h"
+#include "udp4.h"
#include "input.h"
-class DatagramSocket;
class Log;
class InputUDP : public Input
const char* modName() { return myModName; }
bool initted{};
- DatagramSocket* ds{};
+ UDP4 udp4;
Log* log{};
std::thread listenThread;
-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 \
--- /dev/null
+/*
+ Copyright 2004-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 <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef WIN32
+#include <netdb.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#define SOCKET_ERROR 0
+#else
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <sys/timeb.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "defines.h"
+#include "log.h"
+
+#include "udp4.h"
+
+UDP4::~UDP4()
+{
+ if (initted) shutdown();
+}
+
+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; }
+
+ myAddr.sin_family = AF_INET; // host byte order
+ myAddr.sin_port = htons(myPort); // short, network byte order
+ myAddr.sin_addr.s_addr = getIPNumber(iterate_ip++); // auto-fill with my IP
+ memset(&(myAddr.sin_zero), 0, 8); // zero the rest of the struct
+
+ if (bind(socketnum, reinterpret_cast<struct sockaddr *>(&myAddr), addrlen) == -1)
+ { perror("bind"); return 0; }
+
+ FD_ZERO(&readfds);
+ FD_SET(socketnum, &readfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ int allowed = 1;
+
+#ifdef WIN32
+ setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&allowed), sizeof(allowed));
+#else
+ setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, static_cast<void*>(&allowed), sizeof(allowed));
+#endif
+
+ initted = true;
+
+ return 1;
+}
+
+void UDP4::shutdown()
+{
+ if (!initted) return;
+ CLOSESOCKET(socketnum);
+ initted = false;
+}
+
+#ifdef WIN32
+unsigned char UDP4::waitforMessage(unsigned char how, SOCKET quitPipe)
+#else
+unsigned char UDP4::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<struct sockaddr *>(&theirAddr), &addrlen)) == -1)
+ { perror("recvfrom"); return 0; }
+ else
+ {
+ memset(&buf[mlength], 0, MAXBUFLEN - mlength);
+ strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr));
+ fromPort = ntohs(theirAddr.sin_port);
+
+ return 2;
+ }
+
+ /* Return 0, failure
+ Return 1, nothing happened, timer expired
+ Return 2, packet arrived (timer not expired)
+ */
+}
+
+UINT UDP4::getDataLength(void) const
+{
+ return static_cast<UINT>(mlength);
+}
+
+const void* UDP4::getData() const { return buf; }
+const char* UDP4::getFromIPA() const { return fromIPA; }
+short UDP4::getFromPort() const { return fromPort; }
+
+bool UDP4::send(const char *ipa, USHORT port, char *message, int length)
+{
+ if (!initted) return false;
+
+ int sentLength = 0;
+
+ 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);
+ 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<struct sockaddr *>(&sendAddr), addrlen);
+ if (sentLength == length) return true;
+ Log::getInstance()->log("UDP6", Log::ERR, "sendto failed, errno = %i", errno);
+ return false;
+}
+
+#ifndef WIN32
+ULONG UDP4::getIPNumber(ULONG)
+{
+ return INADDR_ANY;
+}
+#else
+ULONG UDP4::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
--- /dev/null
+/*
+ Copyright 2004-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 <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef DSOCK_H
+#define DSOCK_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include "defines.h"
+
+#define MAXBUFLEN 2000
+
+class UDP4
+{
+ public:
+ ~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
+#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); // send wants: IP Address ddn style, port, data, length of data
+
+ private:
+ bool initted{};
+ ULONG getIPNumber(ULONG num);
+ ULONG iterate_ip{};
+ int socketnum; // Socket descriptor
+ USHORT myPort{}; // My port number
+ struct sockaddr_in myAddr; // My address
+ struct sockaddr_in theirAddr; // User address
+ socklen_t addrlen; // length of sockaddr struct
+ char buf[MAXBUFLEN]; // main data buffer
+ char fromIPA[20]; // from string (ip address)
+ short fromPort; // which port user sent on
+ int mlength; // length of message
+ struct timeval tv;
+ fd_set readfds;
+};
+
+#endif
--- /dev/null
+/*
+ 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 <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef WIN32
+#include <netdb.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#define SOCKET_ERROR 0
+#else
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <sys/timeb.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <net/if.h>
+#include <fcntl.h>
+
+#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<struct sockaddr *>(&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<struct sockaddr *>(&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<UINT>(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<struct sockaddr *>(&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<struct sockaddr *>(&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
--- /dev/null
+/*
+ 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 <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef UDP6_H
+#define UDP6_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#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
#include "boxstack.h"
#include "message.h"
#include "log.h"
+#include "vdr.h"
#include "wol.h"
#include "vserverselect.h"
#include "messagequeue.h"
VConnect::~VConnect()
{
threadReqQuit = true;
- vdr->cancelFindingServer();
+ vdpc.stop();
stop();
}
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);
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();
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");
#ifndef VCONNECT_H
#define VCONNECT_H
-#include <vector>
#include <mutex>
#include <thread>
#include <condition_variable>
#include "vinfo.h"
-#include "vdr.h"
+#include "vdpc.h"
class Log;
class BoxStack;
void run();
private:
-
- void clearServerIPs();
-
BoxStack* boxstack;
- VDR* vdr;
Log* logger;
- std::vector<VDRServer> servers;
+ VDPC vdpc;
+ VDR* vdr;
+
int selectedServer;
std::thread connectThread;
+++ /dev/null
-/*
- 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 <https://www.gnu.org/licenses/>.
-*/
-
-#if IPV6
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#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<struct sockaddr *>(&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<struct sockaddr *>(&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
+++ /dev/null
-/*
- 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 <https://www.gnu.org/licenses/>.
-*/
-
-#ifndef VDP_H
-#define VDP_H
-
-#if IPV6
-
-#include <thread>
-#include <vector>
-
-#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<VDRServer>* getServers() { return &servers; }
-
- private:
- int pfds[2];
- int sock;
- std::thread receiveThread;
- std::vector<VDRServer> servers;
-};
-
-#endif
-
-
-
-#endif
--- /dev/null
+/*
+ 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 <https://www.gnu.org/licenses/>.
+*/
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <cstdlib>
+#include <chrono>
+#include <algorithm>
+
+#include "log.h"
+#include "wol.h"
+
+#include "vdpc.h"
+
+void VDPC::TEMPaddCLIServer(const std::string& cliServer)
+{
+ std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<const char*>(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<const char*>(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
--- /dev/null
+/*
+ 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 <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef VDPC_H
+#define VDPC_H
+
+// Vomp Discovery Protocol Client
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include <thread>
+#include <condition_variable>
+#include <functional>
+
+#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<void(int, const char*, const char*, USHORT, ULONG)> 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<VDRServer> 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
#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"
return buf;
}
-
-
//deserialize a received response
//delete the package
//return !=0 on error
return 1;
}
-void VDR::findServers(std::vector<VDRServer>& 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<const char*>(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<VDRServer>* 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);
typedef std::vector<Channel*> ChannelList;
typedef std::vector<RecTimer*> 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<double, double, bool>
{
bool operator() (const RecTimer* a, const RecTimer* b)
}
};
-struct ServerSorter
-{
- bool operator() (const VDRServer& a, const VDRServer& b)
- {
- return a.name < b.name;
- }
-};
-
class StreamReceiver
{
public:
int init();
int shutdown();
+ /*
void findServers(std::vector<VDRServer>& servers);
void cancelFindingServer();
+ */
+
void setServerIP(const char*);
void setServerPort(USHORT);
void setReceiveWindow(size_t size);
/*
- Copyright 2004-2005 Chris Tallon
+ Copyright 2004-2020 Chris Tallon
This file is part of VOMP.
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 <https://www.gnu.org/licenses/>.
*/
-#include "vserverselect.h"
-
#include "defines.h"
#include "input.h"
#include "colour.h"
#include "i18n.h"
#include "messagequeue.h"
+#include "vserverselect.h"
-VServerSelect::VServerSelect(std::vector<VDRServer>& 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)
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);
}
/*
- Copyright 2004-2005 Chris Tallon
+ Copyright 2004-2020 Chris Tallon
This file is part of VOMP.
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 <https://www.gnu.org/licenses/>.
*/
#ifndef VSERVERSELECT_H
#define VSERVERSELECT_H
-#include <stdio.h>
-#include <string.h>
-#include <vector>
-
#include "tbboxx.h"
-#include "vdr.h"
+#include "vdpc.h"
#include "wselectlist.h"
class Message;
class VServerSelect : public TBBoxx
{
public:
- VServerSelect(std::vector<VDRServer>& servers, void* replyTo);
+ VServerSelect(const VDPC&, void* replyTo);
~VServerSelect();
int handleCommand(int command);