MythTV master
mmulticastsocketdevice.cpp
Go to the documentation of this file.
1
2// Program Name: mmulticastsocketdevice.cpp
3// Created : Oct. 1, 2005
4//
5// Purpose : Multicast QSocketDevice Implmenetation
6//
7// Copyright (c) 2005 David Blain <dblain@mythtv.org>
8//
9// Licensed under the GPL v2 or later, see LICENSE for details
10//
13
14#include <cerrno>
15#include "libmythbase/mythconfig.h"
16
17#ifdef _WIN32
18# include <winsock2.h>
19# include <ws2tcpip.h>
20# define GET_SOCKET_ERROR WSAGetLastError()
21#else
22# include <sys/socket.h>
23# include <netinet/in.h>
24# include <arpa/inet.h>
25# define GET_SOCKET_ERROR errno
26#endif
27
28#include <chrono> // for milliseconds
29#include <thread> // for sleep_for
30
31// Qt headers
32#include <QStringList>
33
34// MythTV headers
37
38#define LOC QString("MMulticastSocketDevice(%1:%2): ") \
39 .arg(m_address.toString()).arg(socket())
40
42 const QString& sAddress, quint16 nPort, u_char ttl) :
43 MSocketDevice(MSocketDevice::Datagram),
44 m_address(sAddress), m_port(nPort)
45{
46#if 0
47 ttl = XmlConfiguration().GetValue( "UPnP/TTL", 4 );
48#endif
49
50 if (ttl == 0)
51 ttl = 4;
52
53 setProtocol(IPv4);
54 setSocket(createNewSocket(), MSocketDevice::Datagram);
55
56 m_imr.imr_multiaddr.s_addr = inet_addr(sAddress.toLatin1().constData());
57 m_imr.imr_interface.s_addr = htonl(INADDR_ANY);
58
59 if (setsockopt(socket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
60 (const char *)&m_imr, sizeof( m_imr )) < 0)
61 {
62 LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_ADD_MEMBERSHIP " + ENO);
63 }
64
65 if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_TTL,
66 (const char *)&ttl, sizeof(ttl)) < 0)
67 {
68 LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_MULTICAST_TTL " + ENO);
69 }
70
71 setAddressReusable(true);
72
73 if (!bind(m_address, m_port))
74 LOG(VB_GENERAL, LOG_ERR, LOC + "bind failed");
75}
76
78{
79 if (!m_address.isNull() &&
80 (setsockopt(socket(), IPPROTO_IP, IP_DROP_MEMBERSHIP,
81 (char*)(&m_imr), sizeof(m_imr)) < 0))
82 {
83 // This isn't really an error, we will drop out of
84 // the group anyway when we close the socket.
85 LOG(VB_GENERAL, LOG_DEBUG, LOC + "setsockopt - IP_DROP_MEMBERSHIP " +
86 ENO);
87 }
88}
89
91 const char *data, quint64 len,
92 const QHostAddress & host, quint16 port)
93{
94#ifdef IP_MULTICAST_IF
95 if (host.toString() == "239.255.255.250")
96 {
97 int retx = 0;
98 for (const auto & address : std::as_const(m_localAddresses))
99 {
100 if (address.protocol() != QAbstractSocket::IPv4Protocol)
101 continue; // skip IPv6 addresses
102
103 QString addr = address.toString();
104 if (addr == "127.0.0.1")
105 continue; // skip localhost address
106
107 uint32_t interface_addr = address.toIPv4Address();
108 if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_IF,
109 (const char *)&interface_addr,
110 sizeof(interface_addr)) < 0)
111 {
112 LOG(VB_GENERAL, LOG_DEBUG, LOC +
113 "setsockopt - IP_MULTICAST_IF " + ENO);
114 }
115 retx = MSocketDevice::writeBlock(data, len, host, port);
116#if 0
117 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("writeBlock on %1 %2")
118 .arg((*it).toString()).arg((retx==(int)len)?"ok":"err"));
119#endif
120 std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(5, 9)));
121 }
122 return retx;
123 }
124#endif
125
126 return MSocketDevice::writeBlock(data, len, host, port);
127}
QList< QHostAddress > m_localAddresses
QHostAddress address() const override
qint64 writeBlock(const char *data, quint64 len, const QHostAddress &host, quint16 port) override
quint16 port() const override
QString GetValue(const QString &setting)
#define LOC
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
Convenience inline random number generator functions.
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20