static void altmain() { // Gain access to argv. extern char **environ; char **argv = environ -2; // Don't run again if the parent restarted. if (getenv("XSERVERPINGER")) return; putenv((char *)"XSERVERPINGER=1"); // Start a new process and let our parent (the real mcompositor) go. if (fork()) return; // Distinguish ourselves from the real mcompositor and die with it. strcpy(argv[0], "xserverping"); prctl(PR_SET_NAME, "xserverping"); prctl(PR_SET_PDEATHSIG, SIGTERM); int meh = 0; QCoreApplication app(meh, 0); XServerPinger pinger(2500); app.exec(); exit(0); }
bool CommandLine::Parse(int argc, char* argv[]) { namespace po = boost::program_options; // Declare the supported options. std::wcout << std::boolalpha; try { po::options_description general("General options"); general.add_options() ("help,h", "produce help message") ("no-pinger", "Dont be a pinger (default is to be a pinger and a ponger)") ("no-ponger", "Dont be a ponger (default is to be a pinger and a ponger)") ; po::options_description pinger("Pinger options"); pinger.add_options() ("num-instances,i", po::value<int>(&m_numInstances)->default_value(1), "The number of instances to use") ("payload,p", "Add payload of random size to Ping") ("timeout,t", po::value<int>(&m_timeout)->default_value(20),"Timeout before missing pongs should generate error report") ; //merge options into one. po::options_description all ("Allowed options"); all.add(general).add(pinger); po::store(po::parse_command_line(argc,argv,all),m_variablesMap); po::notify(m_variablesMap); if (m_variablesMap.count("help")) { std::wcout << all << std::endl; return false; } m_noPinger = 0 != m_variablesMap.count("no-pinger"); m_noPonger = 0 != m_variablesMap.count("no-ponger"); m_payload = 0 != m_variablesMap.count("payload"); } catch (const std::exception & e) { std::wcerr << "Parse of command line failed: " << std::endl << e.what() << std::endl; return false; } return true; }
static void altmain() { // Don't run again if the parent restarted. if (getenv("XSERVERPINGER")) return; putenv("XSERVERPINGER=1"); // Start a new process and let our parent (the real mcompositor) go. if (fork()) return; // Die with the parent. prctl(PR_SET_PDEATHSIG, SIGTERM); int meh = 0; QCoreApplication app(meh, 0); XServerPinger pinger(2500); app.exec(); exit(0); }
void main_loop(int icmp_sock, __u8 *packet, int packlen) { char addrbuf[128]; char ans_data[4096]; struct iovec iov; struct msghdr msg; struct cmsghdr *c; int cc; int next; int polling; iov.iov_base = (char *)packet; for (;;) { /* Check exit conditions. */ if (exiting) break; if (npackets && nreceived + nerrors >= npackets) break; if (deadline && nerrors) break; /* Check for and do special actions. */ if (status_snapshot) status(); /* Send probes scheduled to this time. */ do { next = pinger(); next = schedule_exit(next); } while (next <= 0); /* "next" is time to send next probe, if positive. * If next<=0 send now or as soon as possible. */ /* Technical part. Looks wicked. Could be dropped, * if everyone used the newest kernel. :-) * Its purpose is: * 1. Provide intervals less than resolution of scheduler. * Solution: spinning. * 2. Avoid use of poll(), when recvmsg() can provide * timed waiting (SO_RCVTIMEO). */ polling = 0; if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) { int recv_expected = in_flight(); /* If we are here, recvmsg() is unable to wait for * required timeout. */ if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) { /* Very short timeout... So, if we wait for * something, we sleep for MININTERVAL. * Otherwise, spin! */ if (recv_expected) { next = MININTERVAL; } else { next = 0; /* When spinning, no reasons to poll. * Use nonblocking recvmsg() instead. */ polling = MSG_DONTWAIT; /* But yield yet. */ sched_yield(); } } if (!polling && ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) { struct pollfd pset; pset.fd = icmp_sock; pset.events = POLLIN|POLLERR; pset.revents = 0; if (poll(&pset, 1, next) < 1 || !(pset.revents&(POLLIN|POLLERR))) continue; polling = MSG_DONTWAIT; } } for (;;) { struct timeval *recv_timep = NULL; struct timeval recv_time; int not_ours = 0; /* Raw socket can receive messages * destined to other running pings. */ iov.iov_len = packlen; memset(&msg, 0, sizeof(msg)); msg.msg_name = addrbuf; msg.msg_namelen = sizeof(addrbuf); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ans_data; msg.msg_controllen = sizeof(ans_data); cc = recvmsg(icmp_sock, &msg, polling); polling = MSG_DONTWAIT; if (cc < 0) { if (errno == EAGAIN || errno == EINTR) break; if (!receive_error_msg()) { if (errno) { perror("ping: recvmsg"); break; } not_ours = 1; } } else { #ifdef SO_TIMESTAMP for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SO_TIMESTAMP) continue; if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) continue; recv_timep = (struct timeval*)CMSG_DATA(c); } #endif if ((options&F_LATENCY) || recv_timep == NULL) { if ((options&F_LATENCY) || ioctl(icmp_sock, SIOCGSTAMP, &recv_time)) gettimeofday(&recv_time, NULL); recv_timep = &recv_time; } not_ours = parse_reply(&msg, cc, addrbuf, recv_timep); } /* See? ... someone runs another ping on this host. */ if (not_ours && !using_ping_socket) install_filter(); /* If nothing is in flight, "break" returns us to pinger. */ if (in_flight() == 0) break; /* Otherwise, try to recvmsg() again. recvmsg() * is nonblocking after the first iteration, so that * if nothing is queued, it will receive EAGAIN * and return to pinger. */ } } finish(); }
//================================================================================================= int main(int argc, char* argv[]) { try { int maxHistogramValue; int idealCutoff; int pingPeriod; int statsPeriod; std::string dest; po::options_description desc("Allowed options"); desc.add_options() ("help", "produce help message") ("verbose", "display the RTT of each packet") ("precise", "display the RTT of each packet down to the micro-second") ("dest", po::value<std::string>(&dest), "hostname or IPv4 address of destination") ("max-histogram-value", po::value<int> (&maxHistogramValue) ->default_value(400), "must be one of {200,400,600,800,1000}") ("ideal-cutoff", po::value<int> (&idealCutoff) ->default_value(80), "displays percentage of all packets with RTT lower than this cutoff") ("ping-period", po::value<int> (&pingPeriod) ->default_value(200), "how often to send each ping packet (in milli-seconds)") ("stats-period", po::value<int> (&statsPeriod) ->default_value(10), "how often to produce the statistics (in minutes)") ; // we will support one and only 1 positional option - which is the destination po::positional_options_description pd; pd.add("dest", 1); // process the command line po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm); po::notify(vm); if (argc <= 1 || vm.count("help")) { std::cout << "\n " << "\nMicroPinger " << "\n " << "\n" << desc << "\n " << "\n " << "\n TIMING PRECISION: " << "\n This application was specifically designed to calculate the RTT as " << "\n accurately as possible. This app uses the QueryPerformanceCounter API, " << "\n and as such, the timestamps that are generated when we send and receive " << "\n each packet should be accurate to within a few of micro-seconds. The " << "\n app is based on the Boost.Asio network library, and packets are handled " << "\n asynchronously. There is no polling here to introduce any delays. " << "\n " << "\n Note that these 'micro-second accurate' RTT for the ping packets will " << "\n of course include delays due to the packet traversing this app, the local" << "\n network stack, and other delays due to the operating system itself. " << "\n " << "\n " << "\n NOTES: " << "\n * If any packet takes more than 1 second to come back, it will be " << "\n considered to have timed-out. " << "\n * This app sends only a single packet at any time, then waits for up " << "\n to 1 second for the response. " << "\n * Packets are throttled to a maximum rate as specified on the command " << "\n line in the <pingPeriod> parameter. " << "\n * For best viewing, maximize your console window. " << "\n * This application uses raw sockets, therefore it must be run with " << "\n administrator privileges. " << "\n " << "\n " << "\n PROTOCOL SUPPORT: " << "\n This application supports ICMP over IPv4. It does not support IPv6. " << "\n " << "\n " << std::endl; return EXIT_FAILURE; } if (dest.empty()) { std::cout << "ERROR: you must specify a destination" << std::endl; return EXIT_FAILURE; } if (idealCutoff < 1 || idealCutoff > 1000) { std::cout << "ERROR: ideal-cutoff is invalid" << std::endl; return EXIT_FAILURE; } if (pingPeriod < 1 || pingPeriod > 60000) { std::cout << "ERROR: ping-period is invalid" << std::endl; return EXIT_FAILURE; } if (maxHistogramValue < 200 || maxHistogramValue > 1000 || (maxHistogramValue % 200 != 0)) { std::cout << "ERROR: max-histogram-value is invalid" << std::endl; return EXIT_FAILURE; } auto verbose = vm.count("verbose") == 1; auto precise = vm.count("precise") == 1; boost::asio::io_service io_service; mvd::Pinger pinger(io_service, dest, pingPeriod, statsPeriod, verbose, precise, maxHistogramValue, idealCutoff); io_service.run(); return EXIT_SUCCESS; } catch (std::exception& e) { std::cout << "ERROR: std::exception caught in main(): " << e.what() << std::endl; assert(false); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR: unknown exception caught in main()" << std::endl; assert(false); return EXIT_FAILURE; } }
/* returns 0 - not an echo * returns 1 - our echo * returns -1 - not ours */ int pingServer(char *target) { struct sockaddr_in from; struct timeval intvl; struct iovec iov; struct msghdr msg; u_char packet[IP_MAXPACKET]; char *source; struct sockaddr_in *to; int hold, icmp_len, sockerrno; source = NULL; s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); sockerrno = errno; outpack = outpackhdr + sizeof(struct_ip); icmp_len = sizeof(struct_ip) + ICMP_MINLEN + phdr_len; maxpayload = IP_MAXPACKET - icmp_len; if (datalen > maxpayload) errx(EX_USAGE, "packet size too large: %d > %d", datalen, maxpayload); send_len = icmp_len + datalen; bzero(&whereto, sizeof(whereto)); to = &whereto; to->sin_family = AF_INET; // to->sin_len = sizeof *to; if (inet_aton(target, &to->sin_addr) != 0) { hostname = target; } if (datalen >= TIMEVAL_LEN) /* can we time transfer */ timing = 1; ident = getpid() & 0xFFFF; if (s < 0) { errno = sockerrno; err(EX_OSERR, "socket"); } hold = 1; #ifdef SO_TIMESTAMP { int on = 1; if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) err(EX_OSERR, "setsockopt SO_TIMESTAMP"); } #endif /* * XXX receive buffer needs undetermined space for mbuf overhead * as well. */ hold = IP_MAXPACKET + 128; (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); if (uid == 0) (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold, sizeof(hold)); if (to->sin_family == AF_INET) { (void)printf("PING %s (%s)", hostname, inet_ntoa(to->sin_addr)); if (source) (void)printf(" from %s", shostname); (void)printf(": %d data bytes\n", datalen); } else (void)printf("PING %s: %d data bytes\n", hostname, datalen); bzero(&msg, sizeof(msg)); msg.msg_name = (caddr_t)&from; msg.msg_iov = &iov; msg.msg_iovlen = 1; iov.iov_base = packet; iov.iov_len = IP_MAXPACKET; pinger(); /* send the ping */ (void)gettimeofday(&last, NULL); intvl.tv_sec = interval / 1000; intvl.tv_usec = interval % 1000 * 1000; while(1) { struct timeval now, timeout; fd_set rfds; int cc, n; if ((unsigned)s >= FD_SETSIZE) errx(EX_OSERR, "descriptor too large"); FD_ZERO(&rfds); FD_SET(s, &rfds); (void)gettimeofday(&now, NULL); timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; while (timeout.tv_usec < 0) { timeout.tv_usec += 1000000; timeout.tv_sec--; } while (timeout.tv_usec >= 1000000) { timeout.tv_usec -= 1000000; timeout.tv_sec++; } if (timeout.tv_sec < 0) timeout.tv_sec = timeout.tv_usec = 0; n = select(s + 1, &rfds, NULL, NULL, &timeout); if (n < 0) continue; /* Must be EINTR. */ else if (n == 1) { struct timeval *tv = NULL; msg.msg_namelen = sizeof(from); if ((cc = recvmsg(s, &msg, 0)) < 0) { if (errno == EINTR) continue; warn("recvmsg"); continue; } if (tv == NULL) { (void)gettimeofday(&now, NULL); tv = &now; } int reply = pr_pack((char *)packet, cc, &from, tv); if (reply >= 0) return reply; } else return 0; } return 0; }