00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include <errno.h>
00014 #include "mythconfig.h"
00015
00016 #ifdef _WIN32
00017 # include <winsock2.h>
00018 # include <ws2tcpip.h>
00019 # define GET_SOCKET_ERROR WSAGetLastError()
00020 #else
00021 # include <sys/socket.h>
00022 # include <netinet/in.h>
00023 # include <arpa/inet.h>
00024 # define GET_SOCKET_ERROR errno
00025 #endif
00026
00027 #if CONFIG_DARWIN
00028 #include <unistd.h>
00029 #endif
00030
00031
00032 #include <QStringList>
00033
00034
00035 #include "mmulticastsocketdevice.h"
00036 #include "mythlogging.h"
00037
00038 #define LOC QString("MMulticastSocketDevice(%1:%2): ") \
00039 .arg(m_address.toString()).arg(socket())
00040
00041 MMulticastSocketDevice::MMulticastSocketDevice(
00042 QString sAddress, quint16 nPort, u_char ttl) :
00043 MSocketDevice(MSocketDevice::Datagram),
00044 m_address(sAddress), m_port(nPort)
00045 {
00046 #if 0
00047 ttl = UPnp::GetConfiguration()->GetValue( "UPnP/TTL", 4 );
00048 #endif
00049
00050 if (ttl == 0)
00051 ttl = 4;
00052
00053 setProtocol(IPv4);
00054 setSocket(createNewSocket(), MSocketDevice::Datagram);
00055
00056 m_imr.imr_multiaddr.s_addr = inet_addr(sAddress.toAscii().constData());
00057 m_imr.imr_interface.s_addr = htonl(INADDR_ANY);
00058
00059 if (setsockopt(socket(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
00060 &m_imr, sizeof( m_imr )) < 0)
00061 {
00062 LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_ADD_MEMBERSHIP " + ENO);
00063 }
00064
00065 if (setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_TTL,
00066 &ttl, sizeof(ttl)) < 0)
00067 {
00068 LOG(VB_GENERAL, LOG_ERR, LOC + "setsockopt - IP_MULTICAST_TTL " + ENO);
00069 }
00070
00071 setAddressReusable(true);
00072
00073 if (bind(m_address, m_port) < 0)
00074 LOG(VB_GENERAL, LOG_ERR, LOC + "bind failed " + ENO);
00075 }
00076
00077 MMulticastSocketDevice::~MMulticastSocketDevice()
00078 {
00079 if (!m_address.isNull() &&
00080 (setsockopt(socket(), IPPROTO_IP, IP_DROP_MEMBERSHIP,
00081 (char*)(&m_imr), sizeof(m_imr) < 0)))
00082 {
00083
00084
00085 LOG(VB_GENERAL, LOG_DEBUG, LOC + "setsockopt - IP_DROP_MEMBERSHIP " +
00086 ENO);
00087 }
00088 }
00089
00090 qint64 MMulticastSocketDevice::writeBlock(
00091 const char *data, quint64 len,
00092 const QHostAddress & host, quint16 port)
00093 {
00094 #ifdef IP_MULTICAST_IF
00095 if (host.toString() == "239.255.255.250")
00096 {
00097 QList<QHostAddress>::const_iterator it = m_local_addresses.begin();
00098 int retx = 0;
00099 for (; it != m_local_addresses.end(); ++it)
00100 {
00101 if ((*it).protocol() != QAbstractSocket::IPv4Protocol)
00102 continue;
00103
00104 QString addr = (*it).toString();
00105 if (addr == "127.0.0.1")
00106 continue;
00107
00108 uint32_t interface_addr = (*it).toIPv4Address();
00109 setsockopt(socket(), IPPROTO_IP, IP_MULTICAST_IF,
00110 &interface_addr, sizeof(interface_addr));
00111 retx = MSocketDevice::writeBlock(data, len, host, port);
00112 #if 0
00113 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("writeBlock on %1 %2")
00114 .arg((*it).toString()).arg((retx==(int)len)?"ok":"err"));
00115 #endif
00116 usleep(5000 + (random() % 5000));
00117 }
00118 return retx;
00119 }
00120 #endif
00121
00122 return MSocketDevice::writeBlock(data, len, host, port);
00123 }