diff --git a/HISTORY b/HISTORY index b339021..f027b34 100644 --- a/HISTORY +++ b/HISTORY @@ -181,3 +181,10 @@ VDR Plugin 'iptv' Revision History 2012-07-10: Version 1.0.1 - Added FreeBSD support (Thanks to Jürgen Lock). + +2012-09-30: Version 1.1.0 + +- Updated for vdr-1.7.30. +- Added support for source-specific multicasts (SSM). +- Changed default external script directory from the + configuration to the resource. diff --git a/README b/README index af0ab39..9145e5d 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ cd /put/your/path/here/VDR/PLUGINS/src tar -xzf /put/your/path/here/vdr-iptv-X.Y.Z.tgz ln -s iptv-X.Y.Z iptv cd /put/your/path/here/VDR -cp -R PLUGINS/src/iptv/iptv /path/to/vdrconf/plugins/ +cp -R PLUGINS/src/iptv/iptv /path/to/vdrresource/plugins/ make make plugins ./vdr -P iptv @@ -91,14 +91,15 @@ Configuration: TV4;IPTV:40:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0 TV3;IPTV:30:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0 TV2;IPTV:20:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0 + TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 ^ ^ ^ ^ ^ ^ ^ | | | | | | Source type ("I") | | | | | Stream parameter (multicast port | | | | | number, HTTP port number, file delay | | | | | (ms), script parameter) - | | | | Stream address (multicast address, URL, file - | | | | location, script location) + | | | | Stream address (multicast source@group address, + | | | | URL, file location, script location) | | | Stream protocol ("UDP", "HTTP", "FILE", "EXT") | | Pid scanner ("0" disable, "1" enable) | Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable) @@ -119,9 +120,9 @@ External streaming: - To watch an externally received channel add an EXT entry to channels.conf and specify a script name and parameter. The specified script is executed - from plugin configuration directory when VDR tunes to the channel. The - specified script parameter is passed to the script and it can be used to - select for example between different URLs. + from plugin resource directory when VDR tunes to the channel. The specified + script parameter is passed to the script and it can be used to select for + example between different URLs. - When an EXT channel is opened the IPTV plugin opens an UDP listening port on the localhost. The external script is responsible for supplying IPTV @@ -167,6 +168,11 @@ Notes: - Section id and pid scanners should be disabled after the correct data is found. This can be made via VDR's channel editor. +- Source-specific multicast (SSM) can be enabled by defining both the source + address and the group address separated by a '@' character. This will use + IGMP v3 protocol: + "U=@" + Acknowledgements: - The IPTV section filtering code is derived from Linux kernel. diff --git a/device.c b/device.c index ef5aee1..8757189 100644 --- a/device.c +++ b/device.c @@ -343,26 +343,37 @@ int cIptvDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { if (!secfilters[i]) { //debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i); - secfilters[i] = new cIptvSectionFilter(deviceIndex, i, Pid, Tid, Mask); - return secfilters[i]->GetReadDesc(); + secfilters[i] = new cIptvSectionFilter(deviceIndex, Pid, Tid, Mask); + if (secfilters[i]) + return i; + break; } } // No free filter slot found return -1; } +int cIptvDevice::ReadFilter(int Handle, void *Buffer, size_t Length) +{ + // Lock + cMutexLock MutexLock(&mutex); + // ... and load + if (secfilters[Handle]) { + return secfilters[Handle]->Read(Buffer, Length); + //debug("cIptvDevice::ReadFilter(%d): %d %d\n", deviceIndex, Handle, Length); + } + return 0; +} + void cIptvDevice::CloseFilter(int Handle) { // Lock cMutexLock MutexLock(&mutex); - // Search the filter for deletion - for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { - if (secfilters[i] && (Handle == secfilters[i]->GetReadDesc())) { - //debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle); - DeleteFilter(i); - break; - } - } + // ... and load + if (secfilters[Handle]) { + //debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle); + DeleteFilter(Handle); + } } bool cIptvDevice::OpenDvr(void) @@ -395,6 +406,12 @@ bool cIptvDevice::HasLock(int TimeoutMs) return (!IsBuffering()); } +bool cIptvDevice::HasInternalCam(void) +{ + //debug("cIptvDevice::HasInternalCam(%d)\n", deviceIndex); + return true; +} + void cIptvDevice::ResetBuffering(void) { debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex); diff --git a/device.h b/device.h index b23f741..1899727 100644 --- a/device.h +++ b/device.h @@ -76,6 +76,7 @@ private: bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const; // for channel info +public: virtual cString DeviceType(void) const; virtual cString DeviceName(void) const; virtual int SignalStrength(void) const; @@ -101,11 +102,16 @@ protected: // for section filtering public: virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask); + virtual int ReadFilter(int Handle, void *Buffer, size_t Length); virtual void CloseFilter(int Handle); // for transponder lock public: virtual bool HasLock(int); + + // for common interface +public: + virtual bool HasInternalCam(void); }; #endif // __IPTV_DEVICE_H diff --git a/iptv.c b/iptv.c index ed12f10..acb6e3a 100644 --- a/iptv.c +++ b/iptv.c @@ -13,15 +13,15 @@ #include "device.h" #include "iptvservice.h" -#if defined(APIVERSNUM) && APIVERSNUM < 10727 -#error "VDR-1.7.27 API version or greater is required!" +#if defined(APIVERSNUM) && APIVERSNUM < 10730 +#error "VDR-1.7.30 API version or greater is required!" #endif #ifndef GITVERSION #define GITVERSION "" #endif - const char VERSION[] = "1.0.1" GITVERSION; + const char VERSION[] = "1.1.0" GITVERSION; static const char DESCRIPTION[] = trNOOP("Experience the IPTV"); class cPluginIptv : public cPlugin { @@ -99,7 +99,7 @@ bool cPluginIptv::Initialize(void) { debug("cPluginIptv::Initialize()\n"); // Initialize any background activities the plugin shall perform. - IptvConfig.SetConfigDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N)); + IptvConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N)); return cIptvDevice::Initialize(deviceCount); } diff --git a/protocoludp.c b/protocoludp.c index 03cd8e6..b2e19e5 100644 --- a/protocoludp.c +++ b/protocoludp.c @@ -19,7 +19,9 @@ #include "socket.h" cIptvProtocolUdp::cIptvProtocolUdp() -: streamAddr(strdup("")), +: isIGMPv3(false), + sourceAddr(strdup("")), + streamAddr(strdup("")), streamPort(0) { debug("cIptvProtocolUdp::cIptvProtocolUdp()\n"); @@ -32,12 +34,13 @@ cIptvProtocolUdp::~cIptvProtocolUdp() cIptvProtocolUdp::Close(); // Free allocated memory free(streamAddr); + free(sourceAddr); } bool cIptvProtocolUdp::Open(void) { debug("cIptvProtocolUdp::Open(): streamAddr=%s\n", streamAddr); - OpenSocket(streamPort, inet_addr(streamAddr)); + OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3); if (!isempty(streamAddr)) { // Join a new multicast group JoinMulticast(); @@ -50,12 +53,13 @@ bool cIptvProtocolUdp::Close(void) debug("cIptvProtocolUdp::Close(): streamAddr=%s\n", streamAddr); if (!isempty(streamAddr)) { // Drop the multicast group - OpenSocket(streamPort, inet_addr(streamAddr)); + OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3); DropMulticast(); } // Close the socket CloseSocket(); // Do NOT reset stream and source addresses + //sourceAddr = strcpyrealloc(sourceAddr, ""); //streamAddr = strcpyrealloc(streamAddr, ""); //streamPort = 0; return true; @@ -72,15 +76,27 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int if (!isempty(Location)) { // Drop the multicast group if (!isempty(streamAddr)) { - OpenSocket(streamPort, inet_addr(streamAddr)); + OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3); DropMulticast(); } // Update stream address and port streamAddr = strcpyrealloc(streamAddr, Location); + // or @ + char *p = strstr(streamAddr, "@"); + if (p) { + *p = 0; + sourceAddr = strcpyrealloc(sourceAddr, streamAddr); + streamAddr = strcpyrealloc(streamAddr, p + 1); + isIGMPv3 = true; + } + else { + sourceAddr = strcpyrealloc(sourceAddr, streamAddr); + isIGMPv3 = false; + } streamPort = Parameter; // Join a new multicast group if (!isempty(streamAddr)) { - OpenSocket(streamPort, inet_addr(streamAddr)); + OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3); JoinMulticast(); } } @@ -90,5 +106,7 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int cString cIptvProtocolUdp::GetInformation(void) { //debug("cIptvProtocolUdp::GetInformation()"); + if (isIGMPv3) + return cString::sprintf("udp://%s@%s:%d", sourceAddr, streamAddr, streamPort); return cString::sprintf("udp://%s:%d", streamAddr, streamPort); } diff --git a/protocoludp.h b/protocoludp.h index 0a8fcca..69adbb5 100644 --- a/protocoludp.h +++ b/protocoludp.h @@ -14,6 +14,8 @@ class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf { private: + bool isIGMPv3; + char* sourceAddr; char* streamAddr; int streamPort; diff --git a/sectionfilter.c b/sectionfilter.c index 988f940..99aec78 100644 --- a/sectionfilter.c +++ b/sectionfilter.c @@ -5,10 +5,10 @@ * */ +#include "config.h" #include "sectionfilter.h" -cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index, - uint16_t Pid, uint8_t Tid, uint8_t Mask) +cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, uint16_t Pid, uint8_t Tid, uint8_t Mask) : pusi_seen(0), feedcc(0), doneq(0), @@ -17,10 +17,9 @@ cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index, seclen(0), tsfeedp(0), pid(Pid), - devid(DeviceIndex), - id(Index) + devid(DeviceIndex) { - //debug("cIptvSectionFilter::cIptvSectionFilter(%d, %d)\n", devid, id); + //debug("cIptvSectionFilter::cIptvSectionFilter(%d, %d)\n", devid, pid); int i; memset(secbuf_base, '\0', sizeof(secbuf_base)); @@ -47,35 +46,30 @@ cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index, } doneq = local_doneq ? 1 : 0; - // Create sockets - socket[0] = socket[1] = -1; - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socket) != 0) { - char tmp[64]; - error("Opening section filter sockets failed (device=%d id=%d): %s\n", devid, id, strerror_r(errno, tmp, sizeof(tmp))); - } - else if ((fcntl(socket[0], F_SETFL, O_NONBLOCK) != 0) || (fcntl(socket[1], F_SETFL, O_NONBLOCK) != 0)) { - char tmp[64]; - error("Setting section filter socket to non-blocking mode failed (device=%d id=%d): %s", devid, id, strerror_r(errno, tmp, sizeof(tmp))); - } + // Create filtering buffer + ringbuffer = new cRingBufferLinear(KILOBYTE(128), 0, false, *cString::sprintf("IPTV SECTION %d/%d", devid, pid)); + if (ringbuffer) + ringbuffer->SetTimeouts(10, 10); + else + error("Failed to allocate buffer for section filter (device=%d pid=%d): ", devid, pid); } cIptvSectionFilter::~cIptvSectionFilter() { - //debug("cIptvSectionFilter::~cIptvSectionfilter(%d, %d)\n", devid, id); - int tmp = socket[1]; - socket[1] = -1; - if (tmp >= 0) - close(tmp); - tmp = socket[0]; - socket[0] = -1; - if (tmp >= 0) - close(tmp); + //debug("cIptvSectionFilter::~cIptvSectionfilter(%d, %d)\n", devid, pid); + DELETE_POINTER(ringbuffer); secbuf = NULL; } -int cIptvSectionFilter::GetReadDesc(void) +int cIptvSectionFilter::Read(void *Data, size_t Length) { - return socket[0]; + int count = 0; + uchar *p = ringbuffer->Get(count); + if (p && count > 0) { + memcpy(Data, p, count); + ringbuffer->Del(count); + } + return count; } inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *Data) @@ -105,10 +99,10 @@ int cIptvSectionFilter::Filter(void) if (doneq && !neq) return 0; - // There is no data in the read socket, more can be written - if ((socket[0] >= 0) && (socket[1] >= 0) /*&& !select_single_desc(socket[0], 0, false)*/) { - ssize_t len = write(socket[1], secbuf, seclen); - ERROR_IF(len < 0, "write()"); + if (ringbuffer) { + int len = ringbuffer->Put(secbuf, seclen); + if (len != seclen) + ringbuffer->ReportOverflow(seclen - len); // Update statistics AddSectionStatistic(len, 1); } diff --git a/sectionfilter.h b/sectionfilter.h index 28247aa..ce08cb5 100644 --- a/sectionfilter.h +++ b/sectionfilter.h @@ -36,8 +36,6 @@ private: uint16_t pid; int devid; - int id; - int socket[2]; uint8_t filter_value[DMX_MAX_FILTER_SIZE]; uint8_t filter_mask[DMX_MAX_FILTER_SIZE]; @@ -46,6 +44,8 @@ private: uint8_t maskandmode[DMX_MAX_FILTER_SIZE]; uint8_t maskandnotmode[DMX_MAX_FILTER_SIZE]; + cRingBufferLinear *ringbuffer; + inline uint16_t GetLength(const uint8_t *Data); void New(void); int Filter(void); @@ -54,11 +54,10 @@ private: public: // constructor & destructor - cIptvSectionFilter(int Index, int DeviceIndex, uint16_t Pid, - uint8_t Tid, uint8_t Mask); + cIptvSectionFilter(int DeviceIndex, uint16_t Pid, uint8_t Tid, uint8_t Mask); virtual ~cIptvSectionFilter(); void Process(const uint8_t* Data); - int GetReadDesc(void); + int Read(void *Buffer, size_t Length); uint16_t GetPid(void) const { return pid; } }; diff --git a/socket.c b/socket.c index cd5f697..5c4b8c1 100644 --- a/socket.c +++ b/socket.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -63,7 +64,7 @@ bool cIptvSocket::OpenSocket(const int Port, const bool isUdp) CloseSocket(), return false); #endif // __FreeBSD__ // Bind socket - memset(&sockAddr, '\0', sizeof(sockAddr)); + memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF)); sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); @@ -89,9 +90,33 @@ void cIptvSocket::CloseSocket(void) } } +bool cIptvSocket::CheckAddress(const char *Addr, in_addr_t *InAddr) +{ + if (InAddr) { + // First try only the IP address + *InAddr = htonl(inet_addr(Addr)); + if (*InAddr == htonl(INADDR_NONE)) { + debug("Cannot convert %s directly to internet address\n", Addr); + // It may be a host name, get the name + struct hostent *host; + host = gethostbyname(Addr); + if (!host) { + char tmp[64]; + error("gethostbyname() failed: %s is not valid address: %s", Addr, strerror_r(h_errno, tmp, sizeof(tmp))); + return false; + } + *InAddr = htonl(inet_addr(*host->h_addr_list)); + } + return true; + } + return false; +} + // UDP socket class cIptvUdpSocket::cIptvUdpSocket() -: streamAddr(INADDR_ANY) +: streamAddr(htonl(INADDR_ANY)), + sourceAddr(htonl(INADDR_ANY)), + useIGMPv3(false) { debug("cIptvUdpSocket::cIptvUdpSocket()\n"); } @@ -101,17 +126,30 @@ cIptvUdpSocket::~cIptvUdpSocket() debug("cIptvUdpSocket::~cIptvUdpSocket()\n"); } -bool cIptvUdpSocket::OpenSocket(const int Port, const in_addr_t StreamAddr) +bool cIptvUdpSocket::OpenSocket(const int Port) { debug("cIptvUdpSocket::OpenSocket()\n"); - streamAddr = StreamAddr; + streamAddr = htonl(INADDR_ANY); + sourceAddr = htonl(INADDR_ANY); + useIGMPv3 = false; + return cIptvSocket::OpenSocket(Port, true); +} + +bool cIptvUdpSocket::OpenSocket(const int Port, const char *StreamAddr, const char *SourceAddr, bool UseIGMPv3) +{ + debug("cIptvUdpSocket::OpenSocket()\n"); + CheckAddress(StreamAddr, &streamAddr); + CheckAddress(SourceAddr, &sourceAddr); + useIGMPv3 = UseIGMPv3; return cIptvSocket::OpenSocket(Port, true); } void cIptvUdpSocket::CloseSocket(void) { debug("cIptvUdpSocket::CloseSocket()\n"); - streamAddr = INADDR_ANY; + streamAddr = htonl(INADDR_ANY); + sourceAddr = htonl(INADDR_ANY); + useIGMPv3 = false; cIptvSocket::CloseSocket(); } @@ -121,10 +159,28 @@ bool cIptvUdpSocket::JoinMulticast(void) // Check if socket exists if (!isActive && (socketDesc >= 0)) { // Join a new multicast group - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = streamAddr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - ERROR_IF_RET(setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false); + if (useIGMPv3) { + // Source-specific multicast (SSM) is used + struct group_source_req gsr; + struct sockaddr_in *grp; + struct sockaddr_in *src; + gsr.gsr_interface = 0; // if_nametoindex("any") ? + grp = (struct sockaddr_in*)&gsr.gsr_group; + grp->sin_family = AF_INET; + grp->sin_addr.s_addr = streamAddr; + grp->sin_port = 0; + src = (struct sockaddr_in*)&gsr.gsr_source; + src->sin_family = AF_INET; + src->sin_addr.s_addr = sourceAddr; + src->sin_port = 0; + ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false); + } + else { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = streamAddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false); + } // Update multicasting flag isActive = true; } @@ -137,10 +193,28 @@ bool cIptvUdpSocket::DropMulticast(void) // Check if socket exists if (isActive && (socketDesc >= 0)) { // Drop the existing multicast group - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = streamAddr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - ERROR_IF_RET(setsockopt(socketDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false); + if (useIGMPv3) { + // Source-specific multicast (SSM) is used + struct group_source_req gsr; + struct sockaddr_in *grp; + struct sockaddr_in *src; + gsr.gsr_interface = 0; // if_nametoindex("any") ? + grp = (struct sockaddr_in*)&gsr.gsr_group; + grp->sin_family = AF_INET; + grp->sin_addr.s_addr = streamAddr; + grp->sin_port = 0; + src = (struct sockaddr_in*)&gsr.gsr_source; + src->sin_family = AF_INET; + src->sin_addr.s_addr = sourceAddr; + src->sin_port = 0; + ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false); + } + else { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = streamAddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false); + } // Update multicasting flag isActive = false; } @@ -161,7 +235,6 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) do { socklen_t addrlen = sizeof(sockAddr); struct msghdr msgh; - struct cmsghdr *cmsg; struct iovec iov; char cbuf[256]; len = 0; @@ -184,10 +257,10 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) if (len > 0) { #ifndef __FreeBSD__ // Process auxiliary received data and validate source address - for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); - if ((i->ipi_addr.s_addr == streamAddr) || (INADDR_ANY == streamAddr)) { + if ((i->ipi_addr.s_addr == streamAddr) || (htonl(INADDR_ANY) == streamAddr)) { #endif // __FreeBSD__ if (BufferAddr[0] == TS_SYNC_BYTE) return len; @@ -245,29 +318,8 @@ cIptvTcpSocket::~cIptvTcpSocket() bool cIptvTcpSocket::OpenSocket(const int Port, const char *StreamAddr) { debug("cIptvTcpSocket::OpenSocket()\n"); - // Socket must be opened before setting the host address - bool retval = cIptvSocket::OpenSocket(Port, false); - - // First try only the IP address - sockAddr.sin_addr.s_addr = inet_addr(StreamAddr); - - if (sockAddr.sin_addr.s_addr == INADDR_NONE) { - debug("Cannot convert %s directly to internet address\n", StreamAddr); - - // It may be a host name, get the name - struct hostent *host; - host = gethostbyname(StreamAddr); - if (!host) { - char tmp[64]; - error("gethostbyname() failed: %s is not valid address: %s", StreamAddr, strerror_r(h_errno, tmp, sizeof(tmp))); - return false; - } - - sockAddr.sin_addr.s_addr = inet_addr(*host->h_addr_list); - } - - return retval; + return (cIptvSocket::OpenSocket(Port, false) && CheckAddress(StreamAddr, &sockAddr.sin_addr.s_addr)); } void cIptvTcpSocket::CloseSocket(void) diff --git a/socket.h b/socket.h index 7cec2cf..0d3fe58 100644 --- a/socket.h +++ b/socket.h @@ -25,6 +25,7 @@ protected: protected: bool OpenSocket(const int Port, const bool isUdp); void CloseSocket(void); + bool CheckAddress(const char *Addr, in_addr_t *InAddr); public: cIptvSocket(); @@ -34,12 +35,15 @@ public: class cIptvUdpSocket : public cIptvSocket { private: in_addr_t streamAddr; + in_addr_t sourceAddr; + bool useIGMPv3; public: cIptvUdpSocket(); virtual ~cIptvUdpSocket(); virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen); - bool OpenSocket(const int Port, const in_addr_t StreamAddr = INADDR_ANY); + bool OpenSocket(const int Port); + bool OpenSocket(const int Port, const char *StreamAddr, const char *SourceAddr, bool UseIGMPv3); void CloseSocket(void); bool JoinMulticast(void); bool DropMulticast(void);