Date: Tue, 3 Feb 2009 10:13:54 +0000 (GMT) From: Robert Watson <rwatson@FreeBSD.org> To: Derek Tattersall <dlt@mebtel.net> Cc: freebsd-net@FreeBSD.org Subject: Re: Multicast source address in recvfrom() Message-ID: <alpine.BSF.2.00.0902031011380.46498@fledge.watson.org> In-Reply-To: <20090202222414.GA59860@oriental.arm.org> References: <20090201183057.GA47405@oriental.arm.org> <alpine.BSF.2.00.0902021827470.77103@fledge.watson.org> <20090202222414.GA59860@oriental.arm.org>
next in thread | previous in thread | raw e-mail | index | archive | help
> * Robert Watson <rwatson@FreeBSD.org> [090202 17:06]: >> On Sun, 1 Feb 2009, Derek Tattersall wrote: >> >>> In order to become familiar with multicast implementation using FreeBSD, I >>> found via Google a pair of test programs which multicast sent a simple >>> text message and received the text message. I added some code to report >>> the source address, because none of the references that I looked at >>> specified the source IP address in the frame. >>> >>> I ran the sender on A -current system, AMD64 vintage last week. The >>> receiver was on a -current system I386 vintage last week. TCPDUMP shows >>> the source IP address in the frame as (correctly) 192.168.0.15. The >>> receiver reports the source IP address as 200.231.191.191. I have also >>> run the same test with an OpenBSD 4.4 Release I386 system as the receiver. >>> The openBSD system reports the sender as 192.168.0.15. A Fedora 10 system >>> reported the source IP address as 0.0.0.0. >>> >>> Googling the RFCs and other information and referring to Comer's and >>> Stevens' books on TCPIP I can't determine what should be reported. Does >>> anybody have clue for me? >> >> It might depend on how you're querying the source address. Could you post >> a code excerpt? > > It's a straightforward test program. Your assumption, that the address returned from recvfrom(2) should be correct, seems generally right to me. However, it looks like you may not be initializing senderLen to the size of senderAddr, which means that the size getting passed in may be random stack garbage. In which case what you find in the sockaddr_in might also be random stack garbage, or might be the address, depending on whether the uninitialized length was long enough to fit an IP address in. Could you try adding something like: senderLen = sizeof(senderAddr); before the call to recvfrom(2)? Thanks, Robert N M Watson Computer Laboratory University of Cambridge > > /********************************************************************** > * > * MulticastReceiver.c: Receive a multicast message > * > * Copyright (C) 2009 Derek Tattersall. > * > * See the COPYING file for license information. > * > * Author: Derek Tattersall > * > * Latest Revision: Sat Jan 31 07:21:04 2009 > * > **********************************************************************/ > > /* Includes***********************************************************/ > #include <stdio.h> /* for printf() and fprintf() */ > #include <sys/socket.h> /* for socket(), connect(), sendto(), and recvfrom() */ > #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */ > #include <netinet/in.h> /* for IPPROTO_UDP */ > #include <stdlib.h> /* for atoi() and exit() */ > #include <string.h> /* for memset() */ > #include <unistd.h> /* for close() */ > > > /* Defines ***********************************************************/ > #define MAXRECVSTRING 255 /* Longest string to receive */ > > /* Type Definitions **************************************************/ > > /* Function Declarations *********************************************/ > void DieWithError(char *errorMessage); /* External error handling function */ > > /* Global Variables **************************************************/ > > /* Function Implementations ******************************************/ > int main(int argc, char *argv[]) > { > int sock; /* Socket */ > struct sockaddr_in multicastAddr; /* Multicast Address */ > char *multicastIP; /* IP Multicast Address */ > unsigned short multicastPort; /* Port */ > struct sockaddr_in senderAddr; /* Sender Address */ > int senderLen; /* length of sender address socket */ > char senderAddrBuf[INET_ADDRSTRLEN]; /* conversion buffer */ > char recvString[MAXRECVSTRING+1]; /* Buffer for received string */ > int recvStringLen; /* Length of received string */ > struct ip_mreq multicastRequest; /* Multicast address join structure */ > > if (argc != 3) /* Test for correct number of arguments */ > { > fprintf(stderr,"Usage: %s <Multicast IP> <Multicast Port>\n", argv[0]); > exit(1); > } > > multicastIP = argv[1]; /* First arg: Multicast IP address (dotted quad) */ > multicastPort = atoi(argv[2]);/* Second arg: Multicast port */ > > /* Create a best-effort datagram socket using UDP */ > if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) > DieWithError("socket() failed"); > > /* Construct bind structure */ > memset(&multicastAddr, 0, sizeof(multicastAddr)); /* Zero out structure */ > multicastAddr.sin_family = AF_INET; /* Internet address family */ > multicastAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ > multicastAddr.sin_port = htons(multicastPort); /* Multicast port */ > > /* Bind to the multicast port */ > if (bind(sock, (struct sockaddr *) &multicastAddr, sizeof(multicastAddr)) < 0) > DieWithError("bind() failed"); > > /* Specify the multicast group */ > multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastIP); > /* Accept multicast from any interface */ > multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY); > /* Join the multicast address */ > if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &multicastRequest, > sizeof(multicastRequest)) < 0) > DieWithError("setsockopt() failed"); > > /* Receive a single datagram from the server */ > if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, (struct sockaddr *)&senderAddr, (socklen_t *)&senderLen)) < 0) > DieWithError("recvfrom() failed"); > > if ((inet_ntop(AF_INET, &senderAddr.sin_addr.s_addr, senderAddrBuf, INET_ADDRSTRLEN)) == 0) > senderAddrBuf[0] = '\0'; > recvString[recvStringLen] = '\0'; > printf("Received from %s: %s\n", senderAddrBuf, recvString); /* Print the received string */ > > close(sock); > exit(0); > } > > /* vim: set sts=0 sw=8 ts=8: *****************************************/ > Note that the sender's address is taken from the recvfrom call per the > man page and printed via inet_ntop call. The DieWithError routine is a > simple print error message and exit with a 1. I have used similar code > with UDP recieving apps before. > -- > Best regards, > Derek Tattersall > dlt@mebtel.net dlt666@yahoo.com dtatters@gmail.com >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?alpine.BSF.2.00.0902031011380.46498>