Having DSS compiles on Solaris 10 [part 6] - DSS and Multicast streams
juil 13th, 2007 by Prune
And here we go again with DSS !
This time it’s not a real compilation problem and is not only Solaris related.
The best thing you can do with DSS, when you own the source part of the stream, is to use multicast. This way, you stream once from your encoder, and many DSS servers can access the stream and reflect it as unicast to your customers.
Once said, this sounds good and simple. In fact, not that simple if your DSS server is “multi homed”.
Multi homed is the way you say your server is using multiples IP on different networks, VLAN and/or NICs.
Our servers une MANY networks. One on the first NIC (nic 0) for admin tasks. NICs 1 and 2 are aggregated to have 2Gb bandwidth for data. On this Aggregated interface, we have many IP set on different networks and VLANs.
To cut the story short, the multicast stream comes on interface aggr543510 (vlan 543 on aggregated interface 510). Clients connect to admin NIC for test, and aggr536510 (vlan 536).
By default, DSS, when reflecting a multicast stream, bind any IP on the port supplied in the SDP file and subscribe to the multicast stream. This is pretty usual, and any other application would do the same.
The troubles comes when you are using multiple NICs. The bind is effectylevly done on * (any IP), but the multicast subscribe is done on ONLY ONE INTERFACE !
Let’s have a netstat -g (works on Solaris, on OS X, use netstat -a -i and try to find out the info on your own)
# netstat -g Group Memberships: IPv4 Interface Group RefCnt --------- -------------------- ------ lo0 ALL-SYSTEMS.MCAST.NET 1 e1000g0 224.1.1.9 1 e1000g0 ALL-SYSTEMS.MCAST.NET 1 e1000g34001:1 ALL-SYSTEMS.MCAST.NET 1 e1000g34001:2 ALL-SYSTEMS.MCAST.NET 1 e1000g36001:1 ALL-SYSTEMS.MCAST.NET 1 e1000g36001:2 ALL-SYSTEMS.MCAST.NET 1 e1000g244001 ALL-SYSTEMS.MCAST.NET 1 e1000g543001:1 ALL-SYSTEMS.MCAST.NET 1
The important line is the one with “e1000g0 224.1.1.9 “. There you can see that Multicast Network 224.1.1.9 is subscribed on interface e1000g0.
But e1000g0 is our admin interface !!!
So DSS will never see any data to reflect. And your client will be set to pause.
I Called Sun Support yesterday to have them comment about this. As I said, this is not really DSS related. It comed from the way the OS (every UNIX os ?) deals the multicast subscription. No news yet. I’m pretty I’ll be told that it is a normal behaviour.
…
Once that said, what will I do to have DSS work on my architecture ?
The key lies in CommonUtilitiesLib/UDPSocket.cpp
YES, we are back again to C++ programming !
The original source code says :
OS_Error UDPSocket::JoinMulticast(UInt32 inRemoteAddr) { struct ip_mreq theMulti; UInt32 localAddr = fLocalAddr.sin_addr.s_addr; // Already in network byte order #if __solaris__ if( localAddr == htonl(INADDR_ANY) ) localAddr = htonl(SocketUtils::GetIPAddr(0)); #endif theMulti.imr_multiaddr.s_addr = htonl(inRemoteAddr); theMulti.imr_interface.s_addr = localAddr; int err = setsockopt(fFileDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti)); //AssertV(err == 0, OSThread::GetErrno()); if (err == -1) return (OS_Error)OSThread::GetErrno(); else return OS_NoErr; }
There you can see 2 things :
As I already said I’m not C++ expert. I just changed the code so the IP to subscribe, defined in “localAddr”, is set to the IP I need to subscribe on :
OS_Error UDPSocket::JoinMulticast(UInt32 inRemoteAddr) { struct ip_mreq theMulti; UInt32 localAddr = fLocalAddr.sin_addr.s_addr; // Already in network byte order /* #if __solaris__ if( localAddr == htonl(INADDR_ANY) ) localAddr = htonl(SocketUtils::GetIPAddr(0)); #endif */ // Set by Prune - 20070712 localAddr = htonl(0x0a10f07b); theMulti.imr_multiaddr.s_addr = htonl(inRemoteAddr); theMulti.imr_interface.s_addr = localAddr; // Set by Prune - 20070712 qtss_printf("Multicast local %x\n", localAddr); qtss_printf("Multicast remote %x\n", htonl(inRemoteAddr)); int err = setsockopt(fFileDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti)); //AssertV(err == 0, OSThread::GetErrno()); if (err == -1) return (OS_Error)OSThread::GetErrno(); else return OS_NoErr; }
So the local IP is set to “localAddr = htonl(0×0a10f07b);” where 0a10f07b is the hexa value of IP 10.16.240.123
I also add some debug that you can see if you start DSS with the -d option.
Then everything is OK and you have the right interface subscribed :
# netstat -g Group Memberships: IPv4 Interface Group RefCnt --------- -------------------- ------ lo0 ALL-SYSTEMS.MCAST.NET 1 e1000g0 ALL-SYSTEMS.MCAST.NET 1 e1000g34001:1 ALL-SYSTEMS.MCAST.NET 1 e1000g34001:2 ALL-SYSTEMS.MCAST.NET 1 e1000g36001:1 ALL-SYSTEMS.MCAST.NET 1 e1000g36001:2 ALL-SYSTEMS.MCAST.NET 1 e1000g244001 ALL-SYSTEMS.MCAST.NET 1 e1000g543001:1 224.1.1.9 1 e1000g543001:1 ALL-SYSTEMS.MCAST.NET 1
OK, I have to do it better, like getting the interface to bind from the config file. This was just a late night test
But what is the right way to do it ?
The server (DSS process) can’t know what interface to subscribe to. Does it have to subscribe it on all interfaces ? This does not seem possible other than opening many sockets. So the server will then have to decide which one to use. tricky isn’t it ?
That is where I am actualy. No real good solution but a hack to have it working.
Then, what will happen if one day I want another multicast stream coming from another network ? …
Keep reading here as I’ll post any information I have if Sun or DSS mailing list answer me.