From 3d4f2f5f417d6d20c6eda7d3562701422e3655e1 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 15 Oct 2019 17:08:39 +0100 Subject: [PATCH] IPv6 support for discovery protocol --- GNUmakefile | 2 +- objects.mk | 36 +++++-------- tcp.cc | 1 + vdp6.cc | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vdp6.h | 57 ++++++++++++++++++++ vdr.cc | 46 ++++++++++++++-- vdr.h | 2 +- 7 files changed, 266 insertions(+), 27 deletions(-) create mode 100644 vdp6.cc create mode 100644 vdp6.h diff --git a/GNUmakefile b/GNUmakefile index d841611..82fd3e0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,7 +3,7 @@ vomp_platform=$(shell ./select-platform) #vomp_platform=crossraspberry $(info selected $(vomp_platform)) -vomp_options= +vomp_options=-DIPV6 # uncomment the line below if you want to build vomp application without a reboot option, automatically set for windows! #vomp_options+= -DVOMP_HAS_EXIT diff --git a/objects.mk b/objects.mk index a2563da..77dc1d7 100644 --- a/objects.mk +++ b/objects.mk @@ -1,28 +1,20 @@ -OBJECTS1 = command.o tcp.o dsock.o thread.o timers.o i18n.o \ - message.o messagequeue.o udp.o wol.o audio.o video.o log.o mutex.o \ +OBJECTS1 = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o \ + message.o messagequeue.o udp.o wol.o audio.o video.o log.o mutex.o \ vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \ - directory.o mark.o option.o \ - player.o playerradio.o vfeed.o afeed.o \ - demuxer.o demuxervdr.o demuxerts.o stream.o \ - region.o colour.o boxstack.o boxx.o tbboxx.o \ - vinfo.o vquestion.o vrecordinglist.o vrecordinglistclassic.o vrecordinglistadvanced.o vrecording.o \ - vepgsummary.o vepglistadvanced.o \ + directory.o mark.o option.o player.o playerradio.o vfeed.o afeed.o \ + demuxer.o demuxervdr.o demuxerts.o stream.o \ + region.o colour.o boxstack.o boxx.o tbboxx.o vrecording.o \ + vinfo.o vquestion.o vrecordinglist.o vrecordinglistclassic.o \ + vrecordinglistadvanced.o vepgsummary.o vepglistadvanced.o \ vmute.o vvolume.o vtimerlist.o vtimeredit.o vrecordingmenu.o \ vchannellist.o vwelcome.o vvideorec.o vepgsettimer.o \ vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \ vradiorec.o vaudioselector.o vscreensaver.o vopts.o \ - wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o \ - woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o \ - remote.o led.o mtd.o osd.o surface.o \ - vpicturebanner.o \ - abstractoption.o \ + wselectlist.o wjpeg.o wsymbol.o wbutton.o wtextbox.o \ + woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o led.o \ + remote.o mtd.o osd.o surface.o vpicturebanner.o abstractoption.o \ eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o \ - vvideolivetv.o vsleeptimer.o \ - playerlivetv.o playerliveradio.o \ - wprogressbar.o \ - bitmap.o dvbsubtitles.o \ - tfeed.o vteletextview.o teletextdecodervbiebu.o \ - teletxt/txtfont.o movieinfo.o seriesinfo.o wmovieview.o wseriesview.o tvmedia.o wtvmedia.o\ - wpictureview.o - - + vvideolivetv.o vsleeptimer.o playerlivetv.o playerliveradio.o \ + wprogressbar.o bitmap.o dvbsubtitles.o tfeed.o vteletextview.o \ + teletextdecodervbiebu.o teletxt/txtfont.o movieinfo.o seriesinfo.o \ + wmovieview.o wseriesview.o tvmedia.o wtvmedia.o wpictureview.o diff --git a/tcp.cc b/tcp.cc index 43f8e13..fb66ace 100644 --- a/tcp.cc +++ b/tcp.cc @@ -150,6 +150,7 @@ int TCP::connectTo(char* host, unsigned short port) hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, portstring, &hints, &res)) { + //printf("[%s] [%s]\n", host, portstring); return 0; } diff --git a/vdp6.cc b/vdp6.cc new file mode 100644 index 0000000..69d70d3 --- /dev/null +++ b/vdp6.cc @@ -0,0 +1,149 @@ +/* + 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "vdr.h" +#include "log.h" +#include "vdp6.h" + +#if IPV6 + +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, (struct sockaddr *)&theirAddr, &addrlen); + if (mlength == -1) + { + logger->log("VDP6", Log::ERR, "recvfrom error"); + break; + } + + VDRServer newServer; + // FIXME upgrade this to look for a return IP in the reply packet + newServer.ip = new char[40]; + inet_ntop(AF_INET6, &theirAddr.sin6_addr, newServer.ip, sizeof(theirAddr)); + + USHORT tempPort; + memcpy(&tempPort, &vdpreply[26], 2); + newServer.port = ntohs(tempPort); + + ULONG newServerVersion; + memcpy(&newServerVersion, &vdpreply[28], 4); + newServer.version = ntohl(newServerVersion); + + int newServerNameLength = mlength - 32; + newServer.name = new char[newServerNameLength]; + strcpy(newServer.name, &vdpreply[32]); + + logger->log("VDP6", Log::INFO, "Got response: %s %u %s %lx", newServer.ip, newServer.port, newServer.name, newServer.version); + servers.push_back(newServer); + } + }); + + char message[15]; + memset(message, 0, 15); + strcpy(message, "VDP-0001"); + + struct if_nameindex* ifs = if_nameindex(); + int 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, (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); +} + +int 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 new file mode 100644 index 0000000..8a4869d --- /dev/null +++ b/vdp6.h @@ -0,0 +1,57 @@ +/* + 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 + +#include +#include + +#if IPV6 + +class 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(); + int numFound(); + vector* getServers() { return &servers; } + + private: + int pfds[2]; + int sock; + std::thread receiveThread; + vector servers; +}; + +#endif + + + +#endif diff --git a/vdr.cc b/vdr.cc index e8da606..438aec1 100644 --- a/vdr.cc +++ b/vdr.cc @@ -14,8 +14,7 @@ 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 "vdr.h" @@ -31,6 +30,7 @@ #include "vdrrequestpacket.h" #include "vdrresponsepacket.h" #include "command.h" +#include "vdp6.h" #ifdef VOMP_MEDIAPLAYER #include "media.h" #include "mediaprovider.h" @@ -171,6 +171,15 @@ void VDR::findServers(vector& servers) 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; @@ -223,6 +232,10 @@ void VDR::findServers(vector& servers) else { if (haveAtLeastOne) break; +#if IPV6 + if (vdp6.numFound()) break; +#endif + waitType = 1; firstloop = false; /* For DEBUGGING * @@ -234,12 +247,39 @@ void VDR::findServers(vector& servers) servers.push_back(newServer); waitType = 2; haveAtLeastOne = 1;}/ * */ + } + } + logger->log("VDR", Log::NOTICE, "END loop"); +#if IPV6 + vdp6.stop(); + vector* servers6 = vdp6.getServers(); + + // Add IPv6 found servers to servers vector, if not in servers already + // Free buffers from VDRServer objects if not taken. (Itching for that rewrite already). + + for(auto i6 = servers6->begin(); i6 != servers6->end(); i6++) + { + bool found = false; + for(auto i4 = servers.begin(); i4 != servers.end(); i4++) + { + if (!strcmp(i4->name, i6->name)) { found = true; break; } + } + if (found) + { + delete[] i6->name; + delete[] i6->ip; + } + else + { + servers.push_back(*i6); } } - logger->log("VDR", Log::NOTICE, "END loop"); + +#endif + sort(servers.begin(), servers.end(), ServerSorter()); } diff --git a/vdr.h b/vdr.h index 0994cb0..dce28c1 100644 --- a/vdr.h +++ b/vdr.h @@ -253,7 +253,7 @@ public ExternLogger int findingServer; TCP* tcp; int port; - char serverIP[16]; + char serverIP[40]; USHORT serverPort; bool connected; ULONG maxChannelNumber; -- 2.39.2