<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Hi,<div><br></div><div>We're experiencing a strange behaviour with multicast igmp using udpcast.</div><div>- sender (quite old 20081213) is running on a Linux SLES 11 64 bit on a VMware ESX guest</div><div>- receivers (same version) are running on WinPE 2.0 x86 computers.</div><div>- sender and receivers are on the same vlan</div><div><br></div><div>This use to work amazingly well until for some reasons (correcting a bug actually), there was a firmware update on a 10GB Dell switch where the blade server is running all the VMware VMs.</div><div>Now it doesn't work anymore:</div><div>- the CMD_HELLO  part woks as espected, and receivers are given their ID and the multicast data adress to join in.</div><div>- then when the receiver actually sends CMD_GO, receivers don't even see the transfer has yet begun and sender finally quit after the normal timeout with no answer from participants.</div><div><br></div><div>It seems clients never receive data sent to the multicast data address.</div><div>So we made some tests using iperf as a multicast packet generator and rtpqual as a receiver; we could see that rtpqual was able to receive the packets only if we were also running an rtpqual on the machine we were generating the packet with iperf !</div><div>Then we made the same test with udp-sender and udp-receiver (2 receivers) and guess what ? it started to work as soon as we started an rtpqual process on the sender side !</div><div><br></div><div>we could observe that when rtpqual is not running on the sender machine igmp cuts the tree on the Dell switch and receivers aren't getting the stream anymore.</div><div><br></div><div>It seems udp-sender should also bind to the multicast data address and portbase.</div><div>Seen on udpcast source code (socklib.c):</div><div><br></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">/**</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * Set socket to listen on given multicast address Not 100% clean, it</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * would be preferable to make a new socket, and not only subscribe it</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * to the multicast address but also _bind_ to it. Indeed, subscribing</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * alone is not enough, as we may get traffic destined to multicast</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * address subscribed to by other apps on the machine. However, for</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * the moment, we skip this concern, as udpcast's main usage is</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * software installation, and in that case it runs on an otherwise</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> * quiet system.</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;"> */</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">static int mcastListen(int sock, net_if_t *net_if, struct sockaddr_in *addr) {</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">    return mcastOp(sock, net_if, getSinAddr(addr), IP_ADD_MEMBERSHIP,</span></font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">              </span></font></span><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">   "Subscribe to multicast group");</span></font></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">}</span></font></div><div><br></div><div>However mcastListen is called from makeSocket() (socklib.c) which actually binds the socket.</div><div>Latest version of udpcast (20100130) doesn't seem to bring any change and behaves the same.</div><div><br></div><div><br></div><div>So, I tried to create an additional socket in startSender() (udps_negociate.c) and bind to RECEIVER_PORT(portBase):</div><div><br></div><div><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">mysock = makeSocket(ADDR_TYPE_MCAST,</span></font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">    </span></font></span><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">net_config->net_if,</span></font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">     </span></font></span><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">net_config->dataMcastAddr,</span></font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">      </span></font></span><font class="Apple-style-span" face="'Courier New'" size="3"><span class="Apple-style-span" style="font-size: 12px;">RECEIVER_PORT(net_config->portBase));</span></font></div><div>   <br><div apple-content-edited="true"> <span class="Apple-style-span" style="font-size: 12px; "><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div>But I got the same behaviour :(</div><div><br></div><div>So I pasted the whole openMC() function from rtpqual.c to socklib.c:</div><div><br></div><div><font class="Apple-style-span" face="'Courier New'">#define NOERROR(val,msg) {if (((int)(val)) < 0) {perror(msg);exit(1);}}</font></div><div><div><font class="Apple-style-span" face="'Courier New'">int openMC(name, port)</font></div><div><font class="Apple-style-span" face="'Courier New'">char *name;</font></div><div><font class="Apple-style-span" face="'Courier New'">int port;</font></div><div><font class="Apple-style-span" face="'Courier New'">{</font></div><div><font class="Apple-style-span" face="'Courier New'">  struct sockaddr_in sin;</font></div><div><font class="Apple-style-span" face="'Courier New'">  struct ip_mreq mreq;</font></div><div><font class="Apple-style-span" face="'Courier New'">  struct hostent *hp;</font></div><div><font class="Apple-style-span" face="'Courier New'">  int fd, one=1;</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  bzero(&sin, sizeof(struct sockaddr_in));</font></div><div><font class="Apple-style-span" face="'Courier New'">  if (isdigit(*name)) {</font></div><div><font class="Apple-style-span" face="'Courier New'">    sin.sin_addr.s_addr = inet_addr(name);</font></div><div><font class="Apple-style-span" face="'Courier New'">  }</font></div><div><font class="Apple-style-span" face="'Courier New'">  else if (hp = gethostbyname(name)) {</font></div><div><font class="Apple-style-span" face="'Courier New'">    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);</font></div><div><font class="Apple-style-span" face="'Courier New'">  }</font></div><div><font class="Apple-style-span" face="'Courier New'">  else {</font></div><div><font class="Apple-style-span" face="'Courier New'">    printf("I Don't understand session name %s\n",name);</font></div><div><font class="Apple-style-span" face="'Courier New'">    exit(1);</font></div><div><font class="Apple-style-span" face="'Courier New'">  }</font></div><div><font class="Apple-style-span" face="'Courier New'">  sin.sin_family = AF_INET;</font></div><div><font class="Apple-style-span" face="'Courier New'">  sin.sin_port = port;</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  if (!IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {</font></div><div><font class="Apple-style-span" face="'Courier New'">    printf("%s is not a multicast session\n", name);</font></div><div><font class="Apple-style-span" face="'Courier New'">    exit(1);</font></div><div><font class="Apple-style-span" face="'Courier New'">  }</font></div><div><font class="Apple-style-span" face="'Courier New'">  mreq.imr_multiaddr = sin.sin_addr;</font></div><div><font class="Apple-style-span" face="'Courier New'">  mreq.imr_interface.s_addr = INADDR_ANY;</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  NOERROR(fd = socket(AF_INET, SOCK_DGRAM, 0), "socket");</font></div><div><font class="Apple-style-span" face="'Courier New'">  NOERROR(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)),</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'">    </font></span><font class="Apple-style-span" face="'Courier New'">  "SO_REUSEADDR");</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  if (bind(fd, (const struct sockaddr *) &sin, sizeof(sin)) == -1) {</font></div><div><font class="Apple-style-span" face="'Courier New'">    perror("Using INADDR_ANY because");</font></div><div><font class="Apple-style-span" face="'Courier New'">    sin.sin_addr.s_addr = INADDR_ANY;</font></div><div><font class="Apple-style-span" face="'Courier New'">    NOERROR(bind(fd, (const struct sockaddr *) &sin, sizeof(sin)), "bind");</font></div><div><font class="Apple-style-span" face="'Courier New'">  }</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  NOERROR(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)),</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'">    </font></span><font class="Apple-style-span" face="'Courier New'">  "IP_ADD_MEMBERSHIP");</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">  return(fd);</font></div><div><font class="Apple-style-span" face="'Courier New'">}</font></div><div><br></div></div><div>And called it from the main() function from udp-sender.c</div><div>myMcastDataAddr is a string copy from the command line argument because net_config structure only stores the sock_addr_in values and so that I can directly use the openMC() function without any modification.</div><div><br></div><div><div><font class="Apple-style-span" face="'Courier New'">/* -- */</font></div><div><font class="Apple-style-span" face="'Courier New'">printf("addr = %s\n", myMcastDataAddr);</font></div><div><font class="Apple-style-span" face="'Courier New'">printf("port = %d\n", RECEIVER_PORT(net_config.portBase));</font></div><div><font class="Apple-style-span" face="'Courier New'">printf("openMC()\n");</font></div><div><font class="Apple-style-span" face="'Courier New'">mysock = openMC(myMcastDataAddr, RECEIVER_PORT(net_config.portBase));</font></div><div><font class="Apple-style-span" face="'Courier New'">/* -- */</font></div></div><div><br></div><div>Indeed, it works now, despite this is a really ugly hack!</div><div>However openMC() seems to do the same as makeSocket do: create the socket, bind to the specified multicast address and port and call a setsockopt for IP_ADD_MEMBERSHIP.</div><div><br></div><div>So now it works for me, but it would be great if the correct patch (not mine) was integrated to the source code (maybe others would need it).</div><div><br></div><div>EDIT: it works with makeSocket only if I call htons() to the port number:</div><div><br></div><div><div><font class="Apple-style-span" face="'Courier New'">mysock = makeSocket(ADDR_TYPE_MCAST,</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'">                  </font></span><font class="Apple-style-span" face="'Courier New'">net_config->net_if,</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'">                 </font></span><font class="Apple-style-span" face="'Courier New'">&net_config->dataMcastAddr,</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font class="Apple-style-span" face="'Courier New'">                     </font></span><font class="Apple-style-span" face="'Courier New'">htons(RECEIVER_PORT(net_config->portBase)));</font></div></div><div><br></div><div>Other calls to makeSocket() doesn't use htons to swap the bytes so I initially I wasn't doing either ...</div><div><br></div><div><br></div><div><br></div><div>thanks</div><div>Alban</div><div><br></div><div><br class="Apple-interchange-newline">--</div><div>Alban Rodriguez</div><div>Centre de Ressources Informatiques</div><div>Université de La Rochelle</div><div><a href="http://cri.univ-lr.fr">http://cri.univ-lr.fr</a></div><div><br></div><div><br></div></div></span><br class="Apple-interchange-newline"><br class="Apple-interchange-newline"> </div><br></div></body></html>