Tools for multicast testing (msend and mreceive)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

249 lines
6.5 KiB

/*
* mreceive.c -- Prints UDP messages received from a multicast group.
*
* (c) Jianping Wang, Yvan Pointurier, Jorg Liebeherr, 2002
* Multimedia Networks Group, University of Virginia
*
* SOURCE CODE RELEASED TO THE PUBLIC DOMAIN
*
* version 2.0 - 5/20/2002
* version 2.1 - 12/4/2002
* Update version display.
* version 2.2 - 05/17/2003
* Assign default values to parameters . The usage information is
* changed according to README_mreceive.txt
*
* Based on this public domain program:
* u_mctest.c (c) Bob Quinn 2/4/97
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define TRUE 1
#define FALSE 0
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR -1
#endif
#define BUFSIZE 1024
#define TTL_VALUE 2
#define LOOPMAX 20
#define MAXIP 16
char *TEST_ADDR = "224.1.1.1";
int TEST_PORT = 4444;
unsigned long IP[MAXIP];
int NUM = 0;
void printHelp(void)
{
printf("mreceive version %s\n\
Usage: mreceive [-g GROUP] [-p PORT] [-i ADDRESS ] ... [-i ADDRESS] [-n]\n\
mreceive [-v | -h]\n\
\n\
-g GROUP IP multicast group address to listen to. Default: 224.1.1.1\n\
-p PORT UDP port number used in the multicast packets. Default: 4444\n\
-i ADDRESS IP addresses of one or more interfaces to listen for the given\n\
multicast group. Default: the system default interface.\n\
-n Interpret the contents of the message as a number instead of\n\
a string of characters. Use this with `msend -n`\n\
-v Print version information.\n\
-h Print the command usage.\n\n", VERSION);
}
int main(int argc, char *argv[])
{
struct sockaddr_in stLocal, stFrom;
unsigned char achIn[BUFSIZE];
int s, i;
struct ip_mreq stMreq;
int iTmp, iRet;
int ipnum = 0;
int ii;
unsigned int numreceived;
int rcvCountOld = 0;
int rcvCountNew = 1;
int starttime;
int curtime;
struct timeval tv;
/*
if( argc < 2 ) {
printHelp();
return 1;
}
*/
ii = 1;
if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) {
printf("mreceive version 2.2\n");
return 0;
}
if ((argc == 2) && (strcmp(argv[ii], "-h") == 0)) {
printHelp();
return 0;
}
while (ii < argc) {
if (strcmp(argv[ii], "-g") == 0) {
ii++;
if ((ii < argc) && !(strchr(argv[ii], '-'))) {
TEST_ADDR = argv[ii];
ii++;
}
} else if (strcmp(argv[ii], "-p") == 0) {
ii++;
if ((ii < argc) && !(strchr(argv[ii], '-'))) {
TEST_PORT = atoi(argv[ii]);
ii++;
}
} else if (strcmp(argv[ii], "-i") == 0) {
ii++;
if ((ii < argc) && !(strchr(argv[ii], '-'))) {
IP[ipnum] = inet_addr(argv[ii]);
ii++;
ipnum++;
}
} else if (strcmp(argv[ii], "-n") == 0) {
ii++;
NUM = 1;
} else {
printf("wrong parameters!\n\n");
printHelp();
return 1;
}
}
/* get a datagram socket */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == INVALID_SOCKET) {
printf("socket() failed.\n");
exit(1);
}
/* avoid EADDRINUSE error on bind() */
iTmp = TRUE;
iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp));
if (iRet == SOCKET_ERROR) {
printf("setsockopt() SO_REUSEADDR failed.\n");
exit(1);
}
/* name the socket */
stLocal.sin_family = AF_INET;
stLocal.sin_addr.s_addr = htonl(INADDR_ANY);
stLocal.sin_port = htons(TEST_PORT);
iRet = bind(s, (struct sockaddr *)&stLocal, sizeof(stLocal));
if (iRet == SOCKET_ERROR) {
printf("bind() failed.\n");
exit(1);
}
/* join the multicast group. */
if (!ipnum) { /* single interface */
stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
stMreq.imr_interface.s_addr = INADDR_ANY;
iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq));
if (iRet == SOCKET_ERROR) {
printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n");
exit(1);
}
} else {
for (i = 0; i < ipnum; i++) {
stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
stMreq.imr_interface.s_addr = IP[i];
iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq));
if (iRet == SOCKET_ERROR) {
printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n");
exit(1);
}
}
}
/* set TTL to traverse up to multiple routers */
iTmp = TTL_VALUE;
iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp));
if (iRet == SOCKET_ERROR) {
printf("setsockopt() IP_MULTICAST_TTL failed.\n");
exit(1);
}
/* disable loopback */
/* iTmp = TRUE; */
iTmp = FALSE;
iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp));
if (iRet == SOCKET_ERROR) {
printf("setsockopt() IP_MULTICAST_LOOP failed.\n");
exit(1);
}
printf("Now receiving from multicast group: %s\n", TEST_ADDR);
for (i = 0;; i++) {
socklen_t addr_size = sizeof(struct sockaddr_in);
static int iCounter = 1;
/* receive from the multicast address */
iRet = recvfrom(s, achIn, BUFSIZE, 0, (struct sockaddr *)&stFrom, &addr_size);
if (iRet < 0) {
printf("recvfrom() failed.\n");
exit(1);
}
if (NUM) {
gettimeofday(&tv, NULL);
if (i == 0)
starttime = tv.tv_sec * 1000000 + tv.tv_usec;
curtime = tv.tv_sec * 1000000 + tv.tv_usec - starttime;
numreceived =
(unsigned int)achIn[0] + ((unsigned int)(achIn[1]) << 8) + ((unsigned int)(achIn[2]) << 16) +
((unsigned int)(achIn[3]) >> 24);
fprintf(stdout, "%5d\t%s:%5d\t%d.%03d\t%5d\n", iCounter, inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port),
curtime / 1000000, (curtime % 1000000) / 1000, numreceived);
fflush(stdout);
rcvCountNew = numreceived;
if (rcvCountNew > rcvCountOld + 1) {
if (rcvCountOld + 1 == rcvCountNew - 1)
printf("****************\nMessage not received: %d\n****************\n", rcvCountOld + 1);
else
printf("****************\nMessages not received: %d to %d\n****************\n",
rcvCountOld + 1, rcvCountNew - 1);
}
if (rcvCountNew == rcvCountOld) {
printf("Duplicate message received: %d\n", rcvCountNew);
}
if (rcvCountNew < rcvCountOld) {
printf("****************\nGap detected: %d from %d\n****************\n", rcvCountNew, rcvCountOld);
}
rcvCountOld = rcvCountNew;
} else {
printf("Receive msg %d from %s:%d: %s\n",
iCounter, inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), achIn);
}
iCounter++;
}
return 0;
} /* end main() */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/