/* * Copyright (C) 2005, 2006 Stig Venaas * $Id:$ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" extern int optind; extern char *optarg; int main(int argc, char **argv) { int famarg, family, ver, s, ndesc, cnt, count, countarg; char *addr1, *addr2, *srv, recvbuf[65535]; uint16_t runtime, rate; uint32_t intface; int32_t hops; struct sockaddr_storage ucaddr, mcaddr; size_t namelen, recvbuflen; uint32_t firstbytes, bytes; struct timeval now, rcvtime, firsttime, endtime, jointime, tstamp, diff; fd_set readfds; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); double msecs; gettime(&endtime); #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); WSAStartup(wVersionRequested, &wsaData); /* lots of complicated Win32 error checking expected - sigh - */ #endif parseargs(argc, argv, FIRSTMODE, &famarg, &ver, NULL, &intface, &countarg, &addr1, &addr2, &runtime, &rate, &srv); if (runtime) endtime.tv_sec += runtime; family = famarg; /* addr2 next addr1 in order to request mc if only one arg */ if (names2addrsocks(&s, NULL, addr2, addr1, srv, &family, &ucaddr, &mcaddr)) { if (addr2) errx("Failed to create socket for %s %s", addr1, addr2); else errx("Failed to create socket for %s", addr1); } prep_sock(family, s); setvbuf(stdout, NULL, _IONBF, 0); namelen = mcaddr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); #ifdef WIN32 { struct sockaddr_storage any = mcaddr; setaddr(&any, NULL, "::", "0.0.0.0"); if (bind(s, (struct sockaddr *)&any, namelen) < 0) errx("bind [INADDR_ANY]"); } #else if (bind(s, (struct sockaddr *)&mcaddr, namelen) < 0) errx("bind [multicast]"); #endif /* using name to specify interface is wrong, only problem for old API */ recvbuflen = sizeof(recvbuf); if (addr2) { joinchannel(s, (struct sockaddr *)&ucaddr, (struct sockaddr *)&mcaddr, intface, NULL); printf("mcfirst joined (S,G) = (%s,%s)\n", addr2string((struct sockaddr *)&ucaddr, namelen), addr2string((struct sockaddr *)&mcaddr, namelen)); } else { joingroup(s, (struct sockaddr *)&mcaddr, intface, NULL); printf("mcfirst joined (*,G) = (*,%s)\n", addr2string((struct sockaddr *)&mcaddr, namelen)); } gettime(&jointime); if (!runtime && !countarg) countarg = 1; bytes = 0; for (count = 0; !countarg || count < countarg; count++) { for(;;) { FD_ZERO(&readfds); FD_SET(s, &readfds); gettime(&now); timediff(&diff, &now, &endtime); ndesc = select(s + 1, &readfds, (fd_set *)0, (fd_set *)0, &diff); gettime(&now); if (runtime && (timecmp(&endtime, &now) <= 0)) goto done; if (ndesc < 1) continue; cnt = recvfromhopstime(s, (void *)&recvbuf, recvbuflen, 0, (struct sockaddr *)&from, &fromlen, &hops, &tstamp, NULL); if (cnt == -1) { err("recv failed"); continue; } break; } rcvtime = tstamp.tv_sec ? tstamp : now; if (!count) { firsttime = rcvtime; firstbytes = cnt; } bytes += cnt; if (!rate) { fromlen = from.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); timediff(&diff, &jointime, &rcvtime); printf("Received %d bytes from %s after %ld.%03ld ms (ttl/hops %d)\n", cnt, addr2string((struct sockaddr *) &from, fromlen), diff.tv_sec * 1000 + diff.tv_usec / 1000, diff.tv_usec % 1000, hops); } } done: printf("%d bytes (payload) and %d packets received in %d seconds\n", bytes, count, runtime); if (count < 2) return 0; timediff(&diff, &firsttime, &rcvtime); msecs = (double)diff.tv_sec * 1000 + (double)diff.tv_usec / 1000; if (!msecs) return 0; bytes -= firstbytes; printf("Average rate: %.3f kbits of payload per second\n", (double)bytes / msecs * 8); /* estimate bytes including minimum packet headers */ bytes += (count - 1) * (mcaddr.ss_family == AF_INET ? 28 : 48); printf("Estimated average rate including all headers: %.3f kbits per second\n", (double)bytes / msecs * 8); return 0; }