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 LICENSE for details
10 //
12 
13 #include <cerrno>
14 #include "libmythbase/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
35 #include "libmythbase/mythrandom.h"
36 
37 #include "mmulticastsocketdevice.h"
38 
39 #define LOC QString("MMulticastSocketDevice(%1:%2): ") \
40  .arg(m_address.toString()).arg(socket())
41 
43  const QString& sAddress, quint16 nPort, u_char ttl) :
44  MSocketDevice(MSocketDevice::Datagram),
45  m_address(sAddress), m_port(nPort)
46 {
47 #if 0
48  ttl = gCoreContext->GetConfiguration()->GetValue( "UPnP/TTL", 4 );
49 #endif
50 
51  if (ttl == 0)
52  ttl = 4;
53 
54  setProtocol(IPv4);
55  setSocket(createNewSocket(), MSocketDevice::Datagram);
56 
57  m_imr.imr_multiaddr.s_addr = inet_addr(sAddress.toLatin1().constData());
58  m_imr.imr_interface.s_addr = htonl(INADDR_ANY);
59 
60  if (setsockopt(socket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
61  (const char *)&m_imr, sizeof( m_imr )) < 0)
62  {
63  LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_ADD_MEMBERSHIP " + ENO);
64  }
65 
66  if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_TTL,
67  (const char *)&ttl, sizeof(ttl)) < 0)
68  {
69  LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_MULTICAST_TTL " + ENO);
70  }
71 
72  setAddressReusable(true);
73 
74  if (!bind(m_address, m_port))
75  LOG(VB_GENERAL, LOG_ERR, LOC + "bind failed");
76 }
77 
79 {
80  if (!m_address.isNull() &&
81  (setsockopt(socket(), IPPROTO_IP, IP_DROP_MEMBERSHIP,
82  (char*)(&m_imr), sizeof(m_imr)) < 0))
83  {
84  // This isn't really an error, we will drop out of
85  // the group anyway when we close the socket.
86  LOG(VB_GENERAL, LOG_DEBUG, LOC + "setsockopt - IP_DROP_MEMBERSHIP " +
87  ENO);
88  }
89 }
90 
92  const char *data, quint64 len,
93  const QHostAddress & host, quint16 port)
94 {
95 #ifdef IP_MULTICAST_IF
96  if (host.toString() == "239.255.255.250")
97  {
98  int retx = 0;
99  for (const auto & address : qAsConst(m_localAddresses))
100  {
101  if (address.protocol() != QAbstractSocket::IPv4Protocol)
102  continue; // skip IPv6 addresses
103 
104  QString addr = address.toString();
105  if (addr == "127.0.0.1")
106  continue; // skip localhost address
107 
108  uint32_t interface_addr = address.toIPv4Address();
109  if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_IF,
110  (const char *)&interface_addr,
111  sizeof(interface_addr)) < 0)
112  {
113  LOG(VB_GENERAL, LOG_DEBUG, LOC +
114  "setsockopt - IP_MULTICAST_IF " + ENO);
115  }
116  retx = MSocketDevice::writeBlock(data, len, host, port);
117 #if 0
118  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("writeBlock on %1 %2")
119  .arg((*it).toString()).arg((retx==(int)len)?"ok":"err"));
120 #endif
121  std::this_thread::sleep_for(std::chrono::milliseconds(MythRandom(5, 9)));
122  }
123  return retx;
124  }
125 #endif
126 
127  return MSocketDevice::writeBlock(data, len, host, port);
128 }
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:91
mythrandom.h
MMulticastSocketDevice::port
quint16 port() const override
Definition: mmulticastsocketdevice.h:64
MMulticastSocketDevice::address
QHostAddress address() const override
Definition: mmulticastsocketdevice.h:62
MMulticastSocketDevice::~MMulticastSocketDevice
~MMulticastSocketDevice() override
Definition: mmulticastsocketdevice.cpp:78
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
LOC
#define LOC
Definition: mmulticastsocketdevice.cpp:39
MMulticastSocketDevice::m_imr
Definition: mmulticastsocketdevice.h:71
mythlogging.h
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:61
MMulticastSocketDevice::m_port
quint16 m_port
Definition: mmulticastsocketdevice.h:70
MMulticastSocketDevice::m_localAddresses
QList< QHostAddress > m_localAddresses
Definition: mmulticastsocketdevice.h:68
MMulticastSocketDevice::m_address
QHostAddress m_address
Definition: mmulticastsocketdevice.h:69
MMulticastSocketDevice::MMulticastSocketDevice
MMulticastSocketDevice()
Definition: mmulticastsocketdevice.h:51
Configuration::GetValue
virtual int GetValue(const QString &sSetting, int Default)=0
mmulticastsocketdevice.h
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
MythCoreContext::GetConfiguration
static Configuration * GetConfiguration()
Definition: mythcorecontext.cpp:1838