2 Copyright 2019 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
26 #include <sys/types.h>
27 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include <sys/ioctl.h>
37 DatagramSocket6::DatagramSocket6()
39 addrlen = sizeof(struct sockaddr_in6);
40 log = Log::getInstance();
44 DatagramSocket6::~DatagramSocket6()
49 bool DatagramSocket6::init(USHORT port)
51 if ((socketnum = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1)
53 log->log("UDP6", Log::CRIT, "Socket error");
58 if (setsockopt(socketnum, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
60 log->log("UDP6", Log::CRIT, "Reuse addr fail");
64 struct sockaddr_in6 saddr;
65 memset(&saddr, 0, sizeof(saddr));
66 saddr.sin6_family = AF_INET6;
67 saddr.sin6_port = htons(port);
68 saddr.sin6_addr = in6addr_any;
70 if (bind(socketnum, (struct sockaddr *)&saddr, addrlen) == -1)
72 log->log("UDP6", Log::CRIT, "Bind error %u", port);
80 log->log("UDP6", Log::CRIT, "getifaddrs error");
85 struct if_nameindex* ifs = if_nameindex();
86 std::vector<unsigned int> mcastIndexes;
88 struct ifaddrs* ifaNext = ifas;
89 for(int i = 0; ifaNext; i++)
91 if ((ifaNext->ifa_flags & IFF_MULTICAST) && (ifaNext->ifa_addr->sa_family == AF_INET6))
93 for(int i = 0; ifs[i].if_index > 0; i++)
95 if (!strcmp(ifaNext->ifa_name, ifs[i].if_name))
97 mcastIndexes.push_back(ifs[i].if_index);
102 ifaNext = ifaNext->ifa_next;
106 if_freenameindex(ifs);
109 std::sort(mcastIndexes.begin(), mcastIndexes.end());
110 auto last = std::unique(mcastIndexes.begin(), mcastIndexes.end());
111 mcastIndexes.erase(last, mcastIndexes.end());
114 for(auto mif : mcastIndexes)
116 //log->log("UDP6", Log::DEBUG, "To listen on index %u", mif);
118 struct ipv6_mreq mGroup;
119 inet_pton(AF_INET6, "ff15:766f:6d70:2064:6973:636f:7665:7279", &mGroup.ipv6mr_multiaddr);
120 mGroup.ipv6mr_interface = mif;
122 if (!setsockopt(socketnum, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mGroup, sizeof(mGroup)))
123 log->log("UDP6", Log::DEBUG, "Listening on IF %u", mif);
125 log->log("UDP6", Log::ERR, "Cannot listen on IF %u", mif);
130 FD_SET(socketnum, &readfds);
138 void DatagramSocket6::shutdown()
140 if (initted) close(socketnum);
144 unsigned char DatagramSocket6::waitforMessage(unsigned char how)
146 if (!initted) return 0;
149 how = 1 - start new wait
150 how = 2 - continue wait
153 struct timeval* passToSelect = NULL;
168 if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0
176 FD_SET(socketnum, &readfds);
178 if (select(socketnum + 1, &readfds, NULL, NULL, passToSelect) <= 0) return 1;
180 struct sockaddr_in6 theirAddr;
181 if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0, (struct sockaddr *)&theirAddr, &addrlen)) == -1)
183 log->log("UDP6", Log::DEBUG, "recvfrom error");
188 memset(&buf[mlength], 0, MAXBUFLEN - mlength);
189 inet_ntop(AF_INET6, &theirAddr.sin6_addr, fromIPA, 40);
190 fromPort = ntohs(theirAddr.sin6_port);
191 log->log("UDP", Log::DEBUG, "%s:%i received length %i", fromIPA, fromPort, mlength);
196 Return 1, nothing happened, timer expired
197 Return 2, packet arrived (timer not expired)
201 void DatagramSocket6::send(const char *ipa, USHORT port, char *message, int length)
205 struct sockaddr_in6 theirAddr;
206 memset(&theirAddr, 0, sizeof(struct sockaddr_in6));
208 theirAddr.sin6_family = AF_INET6;
209 theirAddr.sin6_port = htons(port);
210 inet_pton(AF_INET6, ipa, &theirAddr.sin6_addr);
212 sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen);
213 if (sentLength == length)
215 log->log("UDP", Log::DEBUG, "%s:%u sent length %i", ipa, port, length);
219 log->log("UDP", Log::DEBUG, "%s:%u send failed %i", ipa, port, length);
221 sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen);
222 if (sentLength == length)
224 log->log("UDP", Log::DEBUG, "%s:%u sent length %i 2nd try", ipa, port, length);
228 log->log("UDP", Log::DEBUG, "%s:%u send failed %i 2nd try", ipa, port, length);