netblast.c revision 141761
1136274Srwatson/*- 2136274Srwatson * Copyright (c) 2004 Robert N. M. Watson 3136274Srwatson * All rights reserved. 4136274Srwatson * 5136274Srwatson * Redistribution and use in source and binary forms, with or without 6136274Srwatson * modification, are permitted provided that the following conditions 7136274Srwatson * are met: 8136274Srwatson * 1. Redistributions of source code must retain the above copyright 9136274Srwatson * notice, this list of conditions and the following disclaimer. 10136274Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11136274Srwatson * notice, this list of conditions and the following disclaimer in the 12136274Srwatson * documentation and/or other materials provided with the distribution. 13136274Srwatson * 14136274Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15136274Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16136274Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17136274Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18136274Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19136274Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20136274Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21136274Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22136274Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23136274Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24136274Srwatson * SUCH DAMAGE. 25136274Srwatson * 26136274Srwatson * $FreeBSD: head/tools/tools/netrate/netblast/netblast.c 141761 2005-02-12 20:03:30Z rwatson $ 27136274Srwatson */ 28136274Srwatson 29136274Srwatson#include <sys/types.h> 30136274Srwatson#include <sys/socket.h> 31136274Srwatson#include <sys/time.h> 32136274Srwatson 33136274Srwatson#include <netinet/in.h> 34136274Srwatson 35136274Srwatson#include <arpa/inet.h> 36136274Srwatson 37136274Srwatson#include <signal.h> 38136274Srwatson#include <stdio.h> 39136274Srwatson#include <stdlib.h> 40136274Srwatson#include <string.h> 41136274Srwatson 42136274Srwatsonstatic void 43136274Srwatsonusage(void) 44136274Srwatson{ 45136274Srwatson 46136274Srwatson fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n"); 47136274Srwatson exit(-1); 48136274Srwatson} 49136274Srwatson 50136274Srwatsonstatic int global_stop_flag; 51136274Srwatson 52136274Srwatsonstatic void 53141761Srwatsonsignal_handler(int signum __unused) 54136274Srwatson{ 55136274Srwatson 56136274Srwatson global_stop_flag = 1; 57136274Srwatson} 58136274Srwatson 59136274Srwatson/* 60136274Srwatson * Loop that blasts packets: begin by recording time information, resetting 61136274Srwatson * stats. Set the interval timer for when we want to wake up. Then go. 62136274Srwatson * SIGALRM will set a flag indicating it's time to stop. Note that there's 63136274Srwatson * some overhead to the signal and timer setup, so the smaller the duration, 64136274Srwatson * the higher the relative overhead. 65136274Srwatson */ 66136274Srwatsonstatic int 67136274Srwatsonblast_loop(int s, long duration, u_char *packet, u_int packet_len) 68136274Srwatson{ 69136274Srwatson struct timespec starttime, tmptime; 70136274Srwatson struct itimerval it; 71136274Srwatson u_int32_t counter; 72136274Srwatson int send_errors, send_calls; 73136274Srwatson 74136274Srwatson if (signal(SIGALRM, signal_handler) == SIG_ERR) { 75136274Srwatson perror("signal"); 76136274Srwatson return (-1); 77136274Srwatson } 78136274Srwatson 79136274Srwatson if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { 80136274Srwatson perror("clock_getres"); 81136274Srwatson return (-1); 82136274Srwatson } 83136274Srwatson 84136274Srwatson if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { 85136274Srwatson perror("clock_gettime"); 86136274Srwatson return (-1); 87136274Srwatson } 88136274Srwatson 89136274Srwatson it.it_interval.tv_sec = 0; 90136274Srwatson it.it_interval.tv_usec = 0; 91136274Srwatson it.it_value.tv_sec = duration; 92136274Srwatson it.it_value.tv_usec = 0; 93136274Srwatson 94136274Srwatson if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 95136274Srwatson perror("setitimer"); 96136274Srwatson return (-1); 97136274Srwatson } 98136274Srwatson 99136274Srwatson send_errors = send_calls = 0; 100136274Srwatson counter = 0; 101136274Srwatson while (global_stop_flag == 0) { 102136274Srwatson /* 103136274Srwatson * We maintain and, if there's room, send a counter. Note 104136274Srwatson * that even if the error is purely local, we still increment 105136274Srwatson * the counter, so missing sequence numbers on the receive 106136274Srwatson * side should not be assumed to be packets lost in transit. 107136274Srwatson * For example, if the UDP socket gets back an ICMP from a 108136274Srwatson * previous send, the error will turn up the current send 109136274Srwatson * operation, causing the current sequence number also to be 110136274Srwatson * skipped. 111136274Srwatson * 112136274Srwatson * XXXRW: Note alignment assumption. 113136274Srwatson */ 114136274Srwatson if (packet_len >= 4) { 115136274Srwatson *((u_int32_t *)packet) = htonl(counter); 116136274Srwatson counter++; 117136274Srwatson } 118136274Srwatson if (send(s, packet, packet_len, 0) < 0) 119136274Srwatson send_errors++; 120136274Srwatson send_calls++; 121136274Srwatson } 122136274Srwatson 123136274Srwatson if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { 124136274Srwatson perror("clock_gettime"); 125136274Srwatson return (-1); 126136274Srwatson } 127136274Srwatson 128136274Srwatson printf("\n"); 129136274Srwatson printf("start: %d.%09lu\n", starttime.tv_sec, 130136274Srwatson starttime.tv_nsec); 131136274Srwatson printf("finish: %d.%09lu\n", tmptime.tv_sec, 132136274Srwatson tmptime.tv_nsec); 133136274Srwatson printf("send calls: %d\n", send_calls); 134136274Srwatson printf("send errors: %d\n", send_errors); 135136274Srwatson printf("approx send rate: %ld\n", (send_calls - send_errors) / 136136274Srwatson duration); 137136274Srwatson printf("approx error rate: %d\n", (send_errors / send_calls)); 138136274Srwatson 139136274Srwatson return (0); 140136274Srwatson} 141136274Srwatson 142136274Srwatsonint 143136274Srwatsonmain(int argc, char *argv[]) 144136274Srwatson{ 145136274Srwatson long payloadsize, port, duration; 146136274Srwatson struct sockaddr_in sin; 147136274Srwatson char *dummy, *packet; 148136274Srwatson int s; 149136274Srwatson 150136274Srwatson if (argc != 5) 151136274Srwatson usage(); 152136274Srwatson 153136274Srwatson bzero(&sin, sizeof(sin)); 154136274Srwatson sin.sin_len = sizeof(sin); 155136274Srwatson sin.sin_family = AF_INET; 156136274Srwatson if (inet_aton(argv[1], &sin.sin_addr) == 0) { 157136274Srwatson perror(argv[1]); 158136274Srwatson return (-1); 159136274Srwatson } 160136274Srwatson 161136274Srwatson port = strtoul(argv[2], &dummy, 10); 162136274Srwatson if (port < 1 || port > 65535 || *dummy != '\0') 163136274Srwatson usage(); 164136274Srwatson sin.sin_port = htons(port); 165136274Srwatson 166136274Srwatson payloadsize = strtoul(argv[3], &dummy, 10); 167136274Srwatson if (payloadsize < 0 || *dummy != '\0') 168136274Srwatson usage(); 169136274Srwatson if (payloadsize > 32768) { 170136274Srwatson fprintf(stderr, "payloadsize > 32768\n"); 171136274Srwatson return (-1); 172136274Srwatson } 173136274Srwatson 174136274Srwatson duration = strtoul(argv[4], &dummy, 10); 175136274Srwatson if (duration < 0 || *dummy != '\0') 176136274Srwatson usage(); 177136274Srwatson 178136274Srwatson packet = malloc(payloadsize); 179136274Srwatson if (packet == NULL) { 180136274Srwatson perror("malloc"); 181136274Srwatson return (-1); 182136274Srwatson } 183136274Srwatson bzero(packet, payloadsize); 184136274Srwatson 185136274Srwatson s = socket(PF_INET, SOCK_DGRAM, 0); 186136274Srwatson if (s == -1) { 187136274Srwatson perror("socket"); 188136274Srwatson return (-1); 189136274Srwatson } 190136274Srwatson 191136274Srwatson if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 192136274Srwatson perror("connect"); 193136274Srwatson return (-1); 194136274Srwatson } 195136274Srwatson 196136274Srwatson return (blast_loop(s, duration, packet, payloadsize)); 197136274Srwatson} 198