-
Notifications
You must be signed in to change notification settings - Fork 345
/
mmulticastsocketdevice.cpp
123 lines (104 loc) · 3.72 KB
/
mmulticastsocketdevice.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//////////////////////////////////////////////////////////////////////////////
// Program Name: mmulticastsocketdevice.cpp
// Created : Oct. 1, 2005
//
// Purpose : Multicast QSocketDevice Implmenetation
//
// Copyright (c) 2005 David Blain <dblain@mythtv.org>
//
// Licensed under the GPL v2 or later, see COPYING for details
//
//////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include "mythconfig.h"
#ifdef _WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
# define GET_SOCKET_ERROR WSAGetLastError()
#else
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# define GET_SOCKET_ERROR errno
#endif
#if CONFIG_DARWIN
#include <unistd.h>
#endif
// Qt headers
#include <QStringList>
// MythTV headers
#include "mmulticastsocketdevice.h"
#include "mythlogging.h"
#define LOC QString("MMulticastSocketDevice(%1:%2): ") \
.arg(m_address.toString()).arg(socket())
MMulticastSocketDevice::MMulticastSocketDevice(
QString sAddress, quint16 nPort, u_char ttl) :
MSocketDevice(MSocketDevice::Datagram),
m_address(sAddress), m_port(nPort)
{
#if 0
ttl = UPnp::GetConfiguration()->GetValue( "UPnP/TTL", 4 );
#endif
if (ttl == 0)
ttl = 4;
setProtocol(IPv4);
setSocket(createNewSocket(), MSocketDevice::Datagram);
m_imr.imr_multiaddr.s_addr = inet_addr(sAddress.toAscii().constData());
m_imr.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(socket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&m_imr, sizeof( m_imr )) < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_ADD_MEMBERSHIP " + ENO);
}
if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_TTL,
(const char *)&ttl, sizeof(ttl)) < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_MULTICAST_TTL " + ENO);
}
setAddressReusable(true);
if (!bind(m_address, m_port))
LOG(VB_GENERAL, LOG_ERR, LOC + "bind failed");
}
MMulticastSocketDevice::~MMulticastSocketDevice()
{
if (!m_address.isNull() &&
(setsockopt(socket(), IPPROTO_IP, IP_DROP_MEMBERSHIP,
(char*)(&m_imr), sizeof(m_imr) < 0)))
{
// This isn't really an error, we will drop out of
// the group anyway when we close the socket.
LOG(VB_GENERAL, LOG_DEBUG, LOC + "setsockopt - IP_DROP_MEMBERSHIP " +
ENO);
}
}
qint64 MMulticastSocketDevice::writeBlock(
const char *data, quint64 len,
const QHostAddress & host, quint16 port)
{
#ifdef IP_MULTICAST_IF
if (host.toString() == "239.255.255.250")
{
QList<QHostAddress>::const_iterator it = m_local_addresses.begin();
int retx = 0;
for (; it != m_local_addresses.end(); ++it)
{
if ((*it).protocol() != QAbstractSocket::IPv4Protocol)
continue; // skip IPv6 addresses
QString addr = (*it).toString();
if (addr == "127.0.0.1")
continue; // skip localhost address
uint32_t interface_addr = (*it).toIPv4Address();
setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_IF,
(const char *)&interface_addr, sizeof(interface_addr));
retx = MSocketDevice::writeBlock(data, len, host, port);
#if 0
LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("writeBlock on %1 %2")
.arg((*it).toString()).arg((retx==(int)len)?"ok":"err"));
#endif
usleep(5000 + (random() % 5000));
}
return retx;
}
#endif
return MSocketDevice::writeBlock(data, len, host, port);
}