MythTV  master
mmulticastsocketdevice.cpp
Go to the documentation of this file.
1 // 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 COPYING for details
10 //
12 
13 #include <cerrno>
14 #include "mythconfig.h"
15 
16 #ifdef _WIN32
17 # include <winsock2.h>
18 # include <ws2tcpip.h>
19 # define GET_SOCKET_ERROR WSAGetLastError()
20 #else
21 # include <sys/socket.h>
22 # include <netinet/in.h>
23 # include <arpa/inet.h>
24 # define GET_SOCKET_ERROR errno
25 #endif
26 
27 #include <chrono> // for milliseconds
28 #include <thread> // for sleep_for
29 
30 // Qt headers
31 #include <QStringList>
32 
33 // MythTV headers
34 #include "mythmiscutil.h"
35 #include "mmulticastsocketdevice.h"
36 #include "mythlogging.h"
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 = UPnp::GetConfiguration()->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 : qAsConst(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(5 + (MythRandom() % 5)));
121  }
122  return retx;
123  }
124 #endif
125 
126  return MSocketDevice::writeBlock(data, len, host, port);
127 }
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
MMulticastSocketDevice::writeBlock
qint64 writeBlock(const char *data, quint64 len, const QHostAddress &host, quint16 port) override
Definition: mmulticastsocketdevice.cpp:90
arg
arg(title).arg(filename).arg(doDelete))
MMulticastSocketDevice::port
quint16 port() const override
Definition: mmulticastsocketdevice.h:63
MMulticastSocketDevice::address
QHostAddress address() const override
Definition: mmulticastsocketdevice.h:61
MMulticastSocketDevice::~MMulticastSocketDevice
~MMulticastSocketDevice() override
Definition: mmulticastsocketdevice.cpp:77
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
LOC
#define LOC
Definition: mmulticastsocketdevice.cpp:38
MMulticastSocketDevice::m_imr
Definition: mmulticastsocketdevice.h:70
mythlogging.h
MMulticastSocketDevice::m_port
quint16 m_port
Definition: mmulticastsocketdevice.h:69
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:24
MMulticastSocketDevice::m_localAddresses
QList< QHostAddress > m_localAddresses
Definition: mmulticastsocketdevice.h:67
MMulticastSocketDevice::m_address
QHostAddress m_address
Definition: mmulticastsocketdevice.h:68
mythmiscutil.h
MMulticastSocketDevice::MMulticastSocketDevice
MMulticastSocketDevice()
Definition: mmulticastsocketdevice.h:50
Configuration::GetValue
virtual int GetValue(const QString &sSetting, int Default)=0
mmulticastsocketdevice.h
UPnp::GetConfiguration
static Configuration * GetConfiguration()
Definition: upnp.cpp:84