1
0
mirror of https://github.com/rofafor/vdr-plugin-satip.git synced 2023-10-10 13:37:42 +02:00

Add a preliminary multicast support.

This commit is contained in:
Rolf Ahrenberg 2016-12-11 01:18:12 +02:00
parent 6ed729c153
commit 48862f99d3
17 changed files with 294 additions and 43 deletions

5
README
View File

@ -116,6 +116,11 @@ Setup menu:
"Disable filter" options which allow you "Disable filter" options which allow you
to disable the individual section filters. to disable the individual section filters.
Valid range: "none" = 0 ... 7 Valid range: "none" = 0 ... 7
- Transport mode = unicast If you want to use the non-standard
multicast RTP-over-TCP transport mode, set this option
rtp-o-tcp accordingly. Otherwise, the transport
mode will be RTP-over-UDP via unicast or
multicast.
- [Red:Scan] Forces network scanning of SAT>IP hardware. - [Red:Scan] Forces network scanning of SAT>IP hardware.
- [Yellow:Devices] Opens SAT>IP device status menu. - [Yellow:Devices] Opens SAT>IP device status menu.
- [Blue:Info] Opens SAT>IP information/statistics menu. - [Blue:Info] Opens SAT>IP information/statistics menu.

View File

@ -19,7 +19,7 @@ cSatipConfig::cSatipConfig(void)
useBytesM(1), useBytesM(1),
portRangeStartM(0), portRangeStartM(0),
portRangeStopM(0), portRangeStopM(0),
useRtpOverTcpM(false), transportModeM(eTransportModeUnicast),
detachedModeM(false), detachedModeM(false),
disableServerQuirksM(false), disableServerQuirksM(false),
useSingleModelServersM(false) useSingleModelServersM(false)

View File

@ -21,7 +21,7 @@ private:
unsigned int useBytesM; unsigned int useBytesM;
unsigned int portRangeStartM; unsigned int portRangeStartM;
unsigned int portRangeStopM; unsigned int portRangeStopM;
bool useRtpOverTcpM; unsigned int transportModeM;
bool detachedModeM; bool detachedModeM;
bool disableServerQuirksM; bool disableServerQuirksM;
bool useSingleModelServersM; bool useSingleModelServersM;
@ -37,6 +37,12 @@ public:
eOperatingModeHigh, eOperatingModeHigh,
eOperatingModeCount eOperatingModeCount
}; };
enum eTransportMode {
eTransportModeUnicast = 0,
eTransportModeMulticast,
eTransportModeRtpOverTcp,
eTransportModeCount
};
enum eTraceMode { enum eTraceMode {
eTraceModeNormal = 0x0000, eTraceModeNormal = 0x0000,
eTraceModeDebug1 = 0x0001, eTraceModeDebug1 = 0x0001,
@ -70,7 +76,10 @@ public:
int GetCICAM(unsigned int indexP) const; int GetCICAM(unsigned int indexP) const;
unsigned int GetEITScan(void) const { return eitScanM; } unsigned int GetEITScan(void) const { return eitScanM; }
unsigned int GetUseBytes(void) const { return useBytesM; } unsigned int GetUseBytes(void) const { return useBytesM; }
bool GetUseRtpOverTcp(void) const { return useRtpOverTcpM; } unsigned int GetTransportMode(void) const { return transportModeM; }
bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); }
bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); }
bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); }
bool GetDetachedMode(void) const { return detachedModeM; } bool GetDetachedMode(void) const { return detachedModeM; }
bool GetDisableServerQuirks(void) const { return disableServerQuirksM; } bool GetDisableServerQuirks(void) const { return disableServerQuirksM; }
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; } bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
@ -87,7 +96,7 @@ public:
void SetCICAM(unsigned int indexP, int cicamP); void SetCICAM(unsigned int indexP, int cicamP);
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
void SetUseRtpOverTcp(bool onOffP) { useRtpOverTcpM = onOffP; } void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; }
void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; } void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; }
void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; } void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; }
void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; } void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; }

View File

@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alt" msgstr "Alt"
msgid "Unicast"
msgstr ""
msgid "Multicast"
msgstr ""
msgid "RTP-over-TCP"
msgstr ""
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Dispositius" msgstr "Dispositius"
@ -178,13 +187,13 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Definir un filtre mal comportar a la llista negra." msgstr "Definir un filtre mal comportar a la llista negra."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr ""
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"

View File

@ -85,6 +85,15 @@ msgstr "normal"
msgid "high" msgid "high"
msgstr "hoch" msgstr "hoch"
msgid "Unicast"
msgstr ""
msgid "Multicast"
msgstr ""
msgid "RTP-over-TCP"
msgstr ""
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Geräte" msgstr "Geräte"
@ -178,13 +187,13 @@ msgstr "Filter"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll." msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr ""
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"

View File

@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alto" msgstr "Alto"
msgid "Unicast"
msgstr ""
msgid "Multicast"
msgstr ""
msgid "RTP-over-TCP"
msgstr ""
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Dispositivos" msgstr "Dispositivos"
@ -178,13 +187,13 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Define un filtro para poner en la lista negra." msgstr "Define un filtro para poner en la lista negra."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr ""
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"

View File

@ -85,6 +85,15 @@ msgstr "normaali"
msgid "high" msgid "high"
msgstr "korkea" msgstr "korkea"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Laitteet" msgstr "Laitteet"
@ -177,17 +186,17 @@ msgstr "Suodatin"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle." msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "Käytä RTP-over-TCP -moodia" msgstr "Siirtoyhteystapa"
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
"Määrittele RTP-over-TCP -moodin käyttöönotto.\n" "Määrittele käytettävä siirtoyhteystapa.\n"
"\n" "\n"
"Tämä asetus vaikuttaa vain SAT>IP-laitteisiin, jotka tukevat kyseistä ominaisuutta." "Unicast, Multicast, RTP-over-TCP"
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"
msgstr "Aktiiviset SAT>IP-palvelimet:" msgstr "Aktiiviset SAT>IP-palvelimet:"

30
rtsp.c
View File

@ -17,7 +17,6 @@ cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
: tunerM(tunerP), : tunerM(tunerP),
headerBufferM(), headerBufferM(),
dataBufferM(), dataBufferM(),
modeM(cmUnicast),
handleM(NULL), handleM(NULL),
headerListM(NULL), headerListM(NULL),
errorNoMoreM(""), errorNoMoreM(""),
@ -182,13 +181,12 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
cTimeMs processing(0); cTimeMs processing(0);
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
switch (modeM) { switch (SatipConfig.GetTransportMode()) {
case cmMulticast: case cSatipConfig::eTransportModeMulticast:
// RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl> // RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>]
transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP); transport = cString::sprintf("RTP/AVP;multicast");
break; break;
default: default:
case cmUnicast:
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
// RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port> // RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port>
transport = cString::sprintf("RTP/AVP%s;unicast;client_port=%d-%d", useTcpP ? "/TCP" : "", rtpPortP, rtcpPortP); transport = cString::sprintf("RTP/AVP%s;unicast;client_port=%d-%d", useTcpP ? "/TCP" : "", rtpPortP, rtcpPortP);
@ -352,6 +350,26 @@ void cSatipRtsp::ParseHeader(void)
tunerM.SetSessionTimeout(skipspace(session), -1); tunerM.SetSessionTimeout(skipspace(session), -1);
FREE_POINTER(session); FREE_POINTER(session);
} }
else if (strstr(r, "Transport:")) {
int rtp = -1, rtcp = -1, ttl = -1;
char *tmp = NULL, *destination = NULL, *source = NULL;
if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3)
tunerM.SetupTransport(rtp, rtcp, NULL, NULL);
else if (sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d;source=%m[^;]", &tmp, &destination, &rtp, &rtcp, &ttl, &source) == 6 ||
sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5)
tunerM.SetupTransport(rtp, rtcp, destination, source);
// TODO: else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3)
// Stream data such as RTP packets is encapsulated by an ASCII dollar
// sign (24 hexadecimal), followed by a one-byte channel identifier,
// followed by the length of the encapsulated binary data as a binary,
// two-byte integer in network byte order. The stream data follows
// immediately afterwards, without a CRLF, but including the upper-layer
// protocol headers. Each $ block contains exactly one upper-layer
// protocol data unit, e.g., one RTP packet.
FREE_POINTER(tmp);
FREE_POINTER(destination);
FREE_POINTER(source);
}
r = strtok_r(NULL, "\r\n", &s); r = strtok_r(NULL, "\r\n", &s);
} }
} }

2
rtsp.h
View File

@ -27,12 +27,10 @@ private:
enum { enum {
eConnectTimeoutMs = 1500, // in milliseconds eConnectTimeoutMs = 1500, // in milliseconds
}; };
enum eCommunicationMode { cmUnicast, cmMulticast };
cSatipTunerIf &tunerM; cSatipTunerIf &tunerM;
cSatipMemoryBuffer headerBufferM; cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM; cSatipMemoryBuffer dataBufferM;
eCommunicationMode modeM;
CURL *handleM; CURL *handleM;
struct curl_slist *headerListM; struct curl_slist *headerListM;
cString errorNoMoreM; cString errorNoMoreM;

11
satip.c
View File

@ -305,7 +305,12 @@ void cPluginSatip::ParsePortRange(const char *paramP)
rangeStart = 0; rangeStart = 0;
rangeStop = 0; rangeStop = 0;
} }
if (rangeStop - rangeStart + 1 < deviceCountM * 2) { if (rangeStart % 2) {
error("The given range start port must be even!");
rangeStart = 0;
rangeStop = 0;
}
else if (rangeStop - rangeStart + 1 < deviceCountM * 2) {
error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2); error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2);
rangeStart = 0; rangeStart = 0;
rangeStop = 0; rangeStop = 0;
@ -401,8 +406,8 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
for (unsigned int i = 0; i < DisabledFiltersCount; ++i) for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
SatipConfig.SetDisabledFilters(i, DisabledFilters[i]); SatipConfig.SetDisabledFilters(i, DisabledFilters[i]);
} }
else if (!strcasecmp(nameP, "UseRtpOverTcp")) else if (!strcasecmp(nameP, "TransportMode"))
SatipConfig.SetUseRtpOverTcp(atoi(valueP)); SatipConfig.SetTransportMode(atoi(valueP));
else else
return false; return false;
return true; return true;

13
setup.c
View File

@ -344,8 +344,8 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
cSatipPluginSetup::cSatipPluginSetup() cSatipPluginSetup::cSatipPluginSetup()
: detachedModeM(SatipConfig.GetDetachedMode()), : detachedModeM(SatipConfig.GetDetachedMode()),
deviceCountM(0), deviceCountM(0),
useRtpOverTcpM(SatipConfig.GetUseRtpOverTcp()),
operatingModeM(SatipConfig.GetOperatingMode()), operatingModeM(SatipConfig.GetOperatingMode()),
transportModeM(SatipConfig.GetTransportMode()),
ciExtensionM(SatipConfig.GetCIExtension()), ciExtensionM(SatipConfig.GetCIExtension()),
eitScanM(SatipConfig.GetEITScan()), eitScanM(SatipConfig.GetEITScan()),
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()), numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
@ -356,6 +356,9 @@ cSatipPluginSetup::cSatipPluginSetup()
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low"); operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal"); operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high"); operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
transportModeTextsM[cSatipConfig::eTransportModeUnicast] = tr("Unicast");
transportModeTextsM[cSatipConfig::eTransportModeMulticast] = tr("Multicast");
transportModeTextsM[cSatipConfig::eTransportModeRtpOverTcp] = tr("RTP-over-TCP");
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i) for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
cicamsM[i] = SatipConfig.GetCICAM(i); cicamsM[i] = SatipConfig.GetCICAM(i);
for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i) for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i)
@ -413,8 +416,8 @@ void cSatipPluginSetup::Setup(void)
helpM.Append(tr("Define an ill-behaving filter to be blacklisted.")); helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
} }
} }
Add(new cMenuEditBoolItem(tr("Use RTP-over-TCP mode"), &useRtpOverTcpM)); Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM) - 1, transportModeTextsM)); // TODO: RTP-over-TCP
helpM.Append(tr("Define whether the RTP-over-TCP mode shall be used.\n\nThis setting affects only SAT>IP devices supporting the feature.")); helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP"));
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false)); Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
helpM.Append(""); helpM.Append("");
@ -563,16 +566,16 @@ void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP)
void cSatipPluginSetup::Store(void) void cSatipPluginSetup::Store(void)
{ {
// Store values into setup.conf // Store values into setup.conf
SetupStore("UseRtpOverTcp", useRtpOverTcpM);
SetupStore("OperatingMode", operatingModeM); SetupStore("OperatingMode", operatingModeM);
SetupStore("TransportMode", transportModeM);
SetupStore("EnableCIExtension", ciExtensionM); SetupStore("EnableCIExtension", ciExtensionM);
SetupStore("EnableEITScan", eitScanM); SetupStore("EnableEITScan", eitScanM);
StoreCicams("CICAM", cicamsM); StoreCicams("CICAM", cicamsM);
StoreSources("DisabledSources", disabledSourcesM); StoreSources("DisabledSources", disabledSourcesM);
StoreFilters("DisabledFilters", disabledFilterIndexesM); StoreFilters("DisabledFilters", disabledFilterIndexesM);
// Update global config // Update global config
SatipConfig.SetUseRtpOverTcp(useRtpOverTcpM);
SatipConfig.SetOperatingMode(operatingModeM); SatipConfig.SetOperatingMode(operatingModeM);
SatipConfig.SetTransportMode(transportModeM);
SatipConfig.SetCIExtension(ciExtensionM); SatipConfig.SetCIExtension(ciExtensionM);
SatipConfig.SetEITScan(eitScanM); SatipConfig.SetEITScan(eitScanM);
for (int i = 0; i < MAX_CICAM_COUNT; ++i) for (int i = 0; i < MAX_CICAM_COUNT; ++i)

View File

@ -17,9 +17,10 @@ class cSatipPluginSetup : public cMenuSetupPage
private: private:
bool detachedModeM; bool detachedModeM;
int deviceCountM; int deviceCountM;
int useRtpOverTcpM;
int operatingModeM; int operatingModeM;
int transportModeM;
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount]; const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
const char *transportModeTextsM[cSatipConfig::eTransportModeCount];
int ciExtensionM; int ciExtensionM;
int cicamsM[MAX_CICAM_COUNT]; int cicamsM[MAX_CICAM_COUNT];
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE]; const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];

141
socket.c
View File

@ -21,7 +21,11 @@
cSatipSocket::cSatipSocket() cSatipSocket::cSatipSocket()
: socketPortM(0), : socketPortM(0),
socketDescM(-1) socketDescM(-1),
isMulticastM(false),
useSsmM(false),
streamAddrM(htonl(INADDR_ANY)),
sourceAddrM(htonl(INADDR_ANY))
{ {
debug1("%s", __PRETTY_FUNCTION__); debug1("%s", __PRETTY_FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
@ -36,6 +40,12 @@ cSatipSocket::~cSatipSocket()
bool cSatipSocket::Open(const int portP, const bool reuseP) bool cSatipSocket::Open(const int portP, const bool reuseP)
{ {
// If socket is there already and it is bound to a different port, it must
// be closed first
if (portP != socketPortM) {
debug1("%s (%d, %d) Socket tear-down", __PRETTY_FUNCTION__, portP, reuseP);
Close();
}
// Bind to the socket if it is not active already // Bind to the socket if it is not active already
if (socketDescM < 0) { if (socketDescM < 0) {
int yes; int yes;
@ -55,6 +65,11 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT, ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT,
"setsockopt(SO_REUSEPORT)", Close(), return false); "setsockopt(SO_REUSEPORT)", Close(), return false);
#endif #endif
#ifndef __FreeBSD__
// Allow packet information to be fetched
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0,
"setsockopt(IP_PKTINFO)", Close(), return false);
#endif // __FreeBSD__
// Bind socket // Bind socket
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
sockAddrM.sin_family = AF_INET; sockAddrM.sin_family = AF_INET;
@ -66,20 +81,38 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0, ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0,
"getsockname()", Close(), return false); "getsockname()", Close(), return false);
socketPortM = ntohs(sockAddrM.sin_port); socketPortM = ntohs(sockAddrM.sin_port);
isMulticastM = false;
} }
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM); debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
return true; return true;
} }
bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP)
{
debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP);
if (Open(portP)) {
CheckAddress(streamAddrP, &streamAddrM);
if (!isempty(sourceAddrP))
useSsmM = CheckAddress(sourceAddrP, &sourceAddrM);
return Join();
}
return false;
}
void cSatipSocket::Close(void) void cSatipSocket::Close(void)
{ {
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM); debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
// Check if socket exists // Check if socket exists
if (socketDescM >= 0) { if (socketDescM >= 0) {
Leave();
close(socketDescM); close(socketDescM);
socketDescM = -1; socketDescM = -1;
socketPortM = 0; socketPortM = 0;
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
streamAddrM = htonl(INADDR_ANY);
sourceAddrM = htonl(INADDR_ANY);
isMulticastM = false;
useSsmM = false;
} }
} }
@ -102,6 +135,96 @@ bool cSatipSocket::Flush(void)
return false; return false;
} }
bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
{
if (inAddrP) {
// First try only the IP address
*inAddrP = inet_addr(addrP);
if (*inAddrP == htonl(INADDR_NONE)) {
debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP);
// It may be a host name, get the name
struct hostent *host = gethostbyname(addrP);
if (!host) {
char tmp[64];
error("gethostbyname() failed: %s is not valid address: %s", addrP,
strerror_r(h_errno, tmp, sizeof(tmp)));
return false;
}
*inAddrP = inet_addr(*host->h_addr_list);
}
return true;
}
return false;
}
bool cSatipSocket::Join(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && !isMulticastM) {
// Join a new multicast group
if (useSsmM) {
// 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 = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, 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 = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = true;
}
return true;
}
bool cSatipSocket::Leave(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && isMulticastM) {
// Leave the existing multicast group
if (useSsmM) {
// 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 = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, 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 = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = false;
}
return true;
}
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
{ {
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
@ -132,8 +255,22 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
if (socketDescM && bufferAddrP && (bufferLenP > 0)) if (socketDescM && bufferAddrP && (bufferLenP > 0))
len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT); len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT);
if (len > 0) if (len > 0) {
#ifndef __FreeBSD__
if (isMulticastM) {
// Process auxiliary received data and validate source address
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 == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM))
return len; return len;
}
}
}
else
#endif // __FreeBSD__
return len;
}
} while (len > 0); } while (len > 0);
ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1); ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
return 0; return 0;

View File

@ -15,14 +15,23 @@ private:
int socketPortM; int socketPortM;
int socketDescM; int socketDescM;
struct sockaddr_in sockAddrM; struct sockaddr_in sockAddrM;
bool isMulticastM;
bool useSsmM;
in_addr_t streamAddrM;
in_addr_t sourceAddrM;
bool CheckAddress(const char *addrP, in_addr_t *inAddrP);
bool Join(void);
bool Leave(void);
public: public:
cSatipSocket(); cSatipSocket();
virtual ~cSatipSocket(); virtual ~cSatipSocket();
bool Open(const int portP = 0, const bool reuseP = false); bool Open(const int portP = 0, const bool reuseP = false);
bool OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP);
virtual void Close(void); virtual void Close(void);
int Fd(void) { return socketDescM; } int Fd(void) { return socketDescM; }
int Port(void) { return socketPortM; } int Port(void) { return socketPortM; }
bool IsMulticast(void) { return isMulticastM; }
bool IsOpen(void) { return (socketDescM >= 0); } bool IsOpen(void) { return (socketDescM >= 0); }
bool Flush(void); bool Flush(void);
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP); int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);

34
tuner.c
View File

@ -55,12 +55,13 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100; int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100;
int port = SatipConfig.GetPortRangeStart(); int port = SatipConfig.GetPortRangeStart();
while (i-- > 0) { while (i-- > 0) {
if (rtpM.Open(port) && rtcpM.Open(rtpM.Port() + 1)) // RTP must use an even port number
if (rtpM.Open(port) && (rtpM.Port() % 2 == 0) && rtcpM.Open(rtpM.Port() + 1))
break; break;
rtpM.Close(); rtpM.Close();
rtcpM.Close(); rtcpM.Close();
if (SatipConfig.GetPortRangeStart()) if (SatipConfig.GetPortRangeStart())
++port; port += 2;
} }
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) { if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM); error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
@ -223,7 +224,7 @@ bool cSatipTuner::Connect(void)
} }
else if (rtspM.Options(*connectionUri)) { else if (rtspM.Options(*connectionUri)) {
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM); cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
bool useTcp = SatipConfig.GetUseRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp); bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp);
// Flush any old content // Flush any old content
//rtpM.Flush(); //rtpM.Flush();
//rtcpM.Flush(); //rtcpM.Flush();
@ -366,6 +367,33 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs; timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
} }
void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP)
{
cMutexLock MutexLock(&mutexM);
debug1("%s (%d, %d, %s, %s) [device %d]", __PRETTY_FUNCTION__, rtpPortP, rtcpPortP, streamAddrP, sourceAddrP, deviceIdM);
bool multicast = !isempty(streamAddrP);
// Adapt RTP to any transport media change
if (multicast != rtpM.IsMulticast() || rtpPortP != rtpM.Port()) {
cSatipPoller::GetInstance()->Unregister(rtpM);
rtpM.Close();
if (multicast)
rtpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtpM);
}
// Adapt RTCP to any transport media change
if (multicast != rtcpM.IsMulticast() || rtcpPortP != rtcpM.Port()) {
cSatipPoller::GetInstance()->Unregister(rtcpM);
rtcpM.Close();
if (multicast)
rtcpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtcpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtcpM);
}
}
cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP) cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP)
{ {
debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM); debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM);

View File

@ -159,6 +159,7 @@ public:
virtual void ProcessApplicationData(u_char *bufferP, int lengthP); virtual void ProcessApplicationData(u_char *bufferP, int lengthP);
virtual void SetStreamId(int streamIdP); virtual void SetStreamId(int streamIdP);
virtual void SetSessionTimeout(const char *sessionP, int timeoutP); virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP);
virtual int GetId(void); virtual int GetId(void);
}; };

View File

@ -16,6 +16,7 @@ public:
virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0; virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0;
virtual void SetStreamId(int streamIdP) = 0; virtual void SetStreamId(int streamIdP) = 0;
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0; virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0;
virtual int GetId(void) = 0; virtual int GetId(void) = 0;
private: private: