RE: Multicast: receiving my own streams

From: Kulkarni, Mayuresh \(IDEAS\)
Date: Fri Apr 17 2009 - 11:33:58 EST


There is socket option - IP_MULTICAST_LOOP which is probably what you
are looking for?

Regards,
Mayuresh.


>-----Original Message-----
>From: linux-net-owner@xxxxxxxxxxxxxxx
>[mailto:linux-net-owner@xxxxxxxxxxxxxxx] On Behalf Of Alex Gonzalez
>Sent: Friday, April 17, 2009 11:08 AM
>To: linux-net@xxxxxxxxxxxxxxx
>Subject: Multicast: receiving my own streams
>
>Hi,
>
>Please redirect me to another list if this is not the
>correct place to ask.
>
>I am seeing an issue with multicast routing which I didn't
>expect and
>can't explain. Basically, I have an application which receives a
>multicast stream and resends it to another multicast address.
>
>If the application then tries to listen on the new stream it just
>generated, the kernel routes the stream back again to the
>application
>layer. Note that the source ip address for this new stream
>is my own
>ip address.
>
>Is this expected behaviour? Is there any way to avoid the
>kernel from
>sending back packets which originated locally (apart from
>iptables or
>source address filtering at the application layer).
>
>I enclose a short snippet which can reproduce it.
>
>Regards,
>Alex
>
>------------------------------------------------------------------
>
>#define _GNU_SOURCE
>#include <stdio.h>
>#include <getopt.h>
>#include <stdlib.h>
>#include <errno.h>
>#include <string.h>
>#include <unistd.h>
>#include "signal.h"
>#include <sys/socket.h>
>#include <resolv.h>
>#include <arpa/inet.h>
>#include <unistd.h>
>#include <fcntl.h>
>
>#define TX_MC_IP "225.4.3.1"
>#define TX_MC_PORT 5001
>
>#define RX_MC_IP "225.5.1.4"
>#define RX_MC_PORT 5001
>
>int rx_sd;
>int tx_sd;
>
>int sd;
>
>int skt_open( char * ip , int port , int rx )
> {
> int sd;
> char ipstr[strlen("xxx.yyy.zzz.yyy")];
> unsigned char * poctet = NULL;
> int ttl = 64;
> int ttl_size = sizeof(ttl);
> struct sockaddr_in addr;
>
> memset(&addr, 0, sizeof(addr));
>
> sd = socket(AF_INET, SOCK_DGRAM, 0);
> if (sd >= 0)
> {
> int value = 1;
> setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value,
>sizeof(value));
> }
> else
> {
> printf("Cannot open socket: %s\n",strerror(errno));
> return(errno);
> }
>
> if( fcntl( sd , F_SETFL , O_NONBLOCK ) < 0 )
> {
> printf("Unable to make socket %d non blocking:
>%s\n",sd,strerror(errno));
> return errno;
> }
>
> addr.sin_family = AF_INET;
> addr.sin_port = htons(port);
> addr.sin_addr.s_addr = inet_addr(ip);
> printf("Binding skt %d to %s:%d\n",sd,ip,port);
>
> if( bind(sd, (struct sockaddr *) &addr, sizeof(addr)) != 0 )
> {
> printf("Error binding socket %d: %s\n",sd,strerror(errno) );
> return(errno);
> }
>
> if(rx)
> {
> poctet = (unsigned char *)&addr.sin_addr.s_addr;
> if( (*poctet > 0xE0) && (*poctet < 0xEF) )
> {
> struct ip_mreq mreq;
>
> inet_aton(ip, &mreq.imr_multiaddr);
> mreq.imr_interface.s_addr = INADDR_ANY;
> if( setsockopt(sd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
>sizeof(mreq)) == 0 )
> {
> printf("Joined multicast group for %s\n",ip);
> }
> else
> {
> printf("Unable to join multicast group for
>%s\n",ip);
> }
> }
> }
> else
> {
> int ttl_type = IP_TTL;
> poctet = (unsigned char *)&addr.sin_addr.s_addr;
> if( (*poctet > 0xE0) && (*poctet < 0xEF) )
> ttl_type = IP_MULTICAST_TTL;
> if( 0 != setsockopt( sd , SOL_IP , ttl_type ,
>(void *)&ttl
>, ttl_size ) )
> {
> ttl = -1;
> getsockopt( sd , SOL_IP , IP_TTL , (void *)&ttl ,
>(socklen_t *)&ttl_size);
> printf("Unable to set ttl %s - default %d
>hops\n",strerror(errno),ttl);
> }
> else
> {
> ttl = -1;
> getsockopt( sd , SOL_IP , IP_TTL ,
>(void *)&ttl ,
>(socklen_t *)&ttl_size);
> printf("Set ttl %d hops\n",ttl);
> }
> }
> printf("Opened socket %d for %s:%d\n",sd,ip,port);
> return sd;
> }
>
> static void skt_print( int signo , siginfo_t *info , void
>*context )
> {
> struct sockaddr_in addr;
> int addr_len = sizeof(addr);
> char buffer[1400] = "";
> int length = 0;
> static int count = 0;
>
> memset(&addr, 0, sizeof(addr));
>
> if( info->si_code != POLL_IN )
> {
> printf("Unhandled event %d\r\n", (int)info->si_band);
> return;
> }
>
> if ( length = recvfrom(info->si_fd, buffer, sizeof(buffer), 0,
>(struct sockaddr *) &addr, (socklen_t*)&addr_len) )
> {
> if( count == 0 || count >= 10000 )
> {
> printf("Seeing packets from socket %d:
>%08x:%d\n",info->si_fd,addr.sin_addr.s_addr,addr.sin_port);
> count = 0;
> }
> count ++;
> }
> return;
> }
>
> static void skt_rx( int signo , siginfo_t *info , void *context )
> {
> struct sockaddr_in addr;
> int addr_len = sizeof(addr);
> char buffer[1400] = "";
> int length = 0;
>
> memset(&addr, 0, sizeof(addr));
>
> if( info->si_code != POLL_IN )
> {
> printf("Unhandled event %d\r\n", (int)info->si_band);
> return;
> }
>
> if ( length = recvfrom(info->si_fd, buffer, sizeof(buffer), 0,
>(struct sockaddr *) &addr, (socklen_t*)&addr_len) )
> {
> addr.sin_family = AF_INET;
> addr.sin_port = htons(TX_MC_PORT);
> addr.sin_addr.s_addr = inet_addr(TX_MC_IP);
> if( length != sendto(tx_sd, buffer, length, MSG_DONTWAIT ,
>(struct sockaddr *) &addr, sizeof(addr)) )
> printf("Send to %d failed\n",tx_sd);
> }
> return;
> }
>
> int receivefrom( unsigned int skt , void(*fcn)(int,
>siginfo_t *, void
>*) , int signo )
> {
> struct sigaction signal_action;
> int flags;
>
> /* Set socket flags to asynchronous */
> flags = fcntl(skt, F_GETFL);
> if( fcntl(skt, F_SETFL, flags | O_ASYNC) < 0 )
> {
> printf("Unable to make socket %d non blocking:
>%s\n",skt,strerror(errno));
> return errno;
> }
>
> // Request packet signal handler
> signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
> signal_action.sa_sigaction = fcn;
> sigemptyset(&signal_action.sa_mask);
> sigaction(signo, &signal_action, NULL);
>
> /* Set process id to send signal to */
> if( fcntl( skt , F_SETOWN , getpid() ) < 0 )
> {
> printf("Can't adquire SIGIO for skt %d:
>%s\n",skt,strerror(errno));
> return errno;
> }
>
> /* Set signal number >= SIGRTMIN to send a RealTime signal */
> if( fcntl( skt, F_SETSIG, signo) < 0 )
> {
> printf("Can't assign signal to skt %d\n",skt);
> return errno;
> }
> printf("Receiving from socket %d in pid %d\n",skt,getpid());
> return 0;
> }
>
> static void signal_handler( int sig_num )
> {
> close(tx_sd);
> close(rx_sd);
> exit(1);
> }
>
>int main(int argc, char *argv[])
>{
> if(( signal(SIGTERM,&signal_handler) == SIG_ERR ) ||(
>signal(SIGINT, &signal_handler) == SIG_ERR ) )
> printf("Error registering signal.\n");
>
> // Open socket to send to
> tx_sd = skt_open( TX_MC_IP , TX_MC_PORT , 0 /*tx*/ );
> // Open socket to receive on
> rx_sd = skt_open( RX_MC_IP , RX_MC_PORT , 1 /*rx*/ );
> receivefrom(rx_sd , skt_rx , 38);
>
> // Do I see the relay I'm outputting?
> sd = skt_open( TX_MC_IP , TX_MC_PORT , 1 /*rx*/ );
> receivefrom(sd , skt_print, 39);
>
> //Wait for signals
> while (1)
> {
> sched_yield();
> }
> return 0;
>}
>--
>To unsubscribe from this list: send the line "unsubscribe
>linux-net" in
>the body of a message to majordomo@xxxxxxxxxxxxxxx
>More majordomo info at http://vger.kernel.org/majordomo-info.html
>

--------------------------------------------------------------------------
NOTICE: If received in error, please destroy and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error.
--
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html