]> git.vomp.tv Git - vompclient.git/blob - vdp6.cc
Convert PlayerRadioRec to std::thread
[vompclient.git] / vdp6.cc
1 /*
2     Copyright 2019 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #if IPV6
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <net/if.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32
33 #include "vdr.h"
34 #include "log.h"
35 #include "vdp6.h"
36
37 VDP6::VDP6()
38 {
39 }
40
41 void VDP6::run()
42 {
43   Log* logger = Log::getInstance();
44
45   if (pipe2(pfds, O_NONBLOCK) == -1)
46   {
47     logger->log("VDP6", Log::ERR, "pipe2 error");
48     return;
49   }
50   
51   sock = socket(AF_INET6, SOCK_DGRAM, 0);
52   if (sock < 0)
53   {
54     logger->log("VDP6", Log::ERR, "socket error");
55     return;
56   }
57
58   struct sockaddr_in6 saddr;
59   memset(&saddr, 0, sizeof(saddr));
60   saddr.sin6_family = AF_INET6;
61   inet_pton(AF_INET6, "ff15:766f:6d70:2064:6973:636f:7665:7279", &saddr.sin6_addr);
62   saddr.sin6_port = htons(51056);
63
64   receiveThread = std::thread( [this, logger]
65   {
66     socklen_t addrlen = sizeof(struct sockaddr_in6);
67     char vdpreply[1000];
68     fd_set readfds;
69     struct timeval timeout;
70     timeout.tv_sec = 1;
71     timeout.tv_usec = 500000;
72
73     while(1)
74     {
75       FD_ZERO(&readfds);
76       FD_SET(sock, &readfds);
77       FD_SET(pfds[0], &readfds);
78
79       int sresult = select(((sock > pfds[0]) ? sock : pfds[0]) + 1, &readfds, NULL, NULL, &timeout);
80       if (sresult < 1) break;
81
82       if (FD_ISSET(pfds[0], &readfds)) break;                        
83                               
84       int mlength;
85       struct sockaddr_in6 theirAddr;
86       mlength = recvfrom(sock, vdpreply, 1000, 0, reinterpret_cast<struct sockaddr *>(&theirAddr), &addrlen);
87       if (mlength == -1)
88       {
89         logger->log("VDP6", Log::ERR, "recvfrom error");
90         break;
91       }
92       
93       VDRServer newServer;
94       // FIXME upgrade this to look for a return IP in the reply packet
95       newServer.ip = new char[40];
96       inet_ntop(AF_INET6, &theirAddr.sin6_addr, newServer.ip, sizeof(theirAddr));
97
98       USHORT tempPort;
99       memcpy(&tempPort, &vdpreply[26], 2);
100       newServer.port = ntohs(tempPort);
101
102       ULONG newServerVersion;
103       memcpy(&newServerVersion, &vdpreply[28], 4);
104       newServer.version = ntohl(newServerVersion);
105
106       UINT newServerNameLength = static_cast<UINT>(mlength - 32);
107       newServer.name = new char[newServerNameLength];
108       strcpy(newServer.name, &vdpreply[32]);
109
110       logger->log("VDP6", Log::INFO, "Got response: %s %u %s %lx", newServer.ip, newServer.port, newServer.name, newServer.version);
111       servers.push_back(newServer);
112     }
113   });
114
115   char message[15];
116   memset(message, 0, 15);
117   strcpy(message, "VDP-0001");
118
119   struct if_nameindex* ifs = if_nameindex();
120   UINT ifIndex;
121
122   for(int i = 0; ifs[i].if_index > 0; i++)
123   {
124     ifIndex = ifs[i].if_index;
125     int d = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, sizeof(ifIndex));
126     d = sendto(sock, message, 15, 0, reinterpret_cast<struct sockaddr *>(&saddr), sizeof(saddr));
127     if (d > 0) logger->log("VDP6", Log::DEBUG, "Transmitted IPv6 MC UDP on %s", ifs[i].if_name);
128   }
129
130   if_freenameindex(ifs);
131 }
132
133 UINT VDP6::numFound()
134 {
135   return servers.size();
136 }
137
138 void VDP6::stop()
139 {
140   write(pfds[1], "X", 1);
141   receiveThread.join();
142   
143   close(pfds[0]);
144   close(pfds[1]);
145   close(sock);
146 }
147
148 #endif