netblast.c revision 225334
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 225334 2011-09-02 16:40:18Z marius $ 27136274Srwatson */ 28136274Srwatson 29225334Smarius#include <sys/endian.h> 30136274Srwatson#include <sys/types.h> 31136274Srwatson#include <sys/socket.h> 32136274Srwatson#include <sys/time.h> 33136274Srwatson 34136274Srwatson#include <netinet/in.h> 35136274Srwatson 36136274Srwatson#include <arpa/inet.h> 37136274Srwatson 38136274Srwatson#include <signal.h> 39136274Srwatson#include <stdio.h> 40136274Srwatson#include <stdlib.h> 41136274Srwatson#include <string.h> 42136274Srwatson 43136274Srwatsonstatic void 44136274Srwatsonusage(void) 45136274Srwatson{ 46136274Srwatson 47136274Srwatson fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n"); 48136274Srwatson exit(-1); 49136274Srwatson} 50136274Srwatson 51136274Srwatsonstatic int global_stop_flag; 52136274Srwatson 53136274Srwatsonstatic void 54141761Srwatsonsignal_handler(int signum __unused) 55136274Srwatson{ 56136274Srwatson 57136274Srwatson global_stop_flag = 1; 58136274Srwatson} 59136274Srwatson 60136274Srwatson/* 61136274Srwatson * Loop that blasts packets: begin by recording time information, resetting 62136274Srwatson * stats. Set the interval timer for when we want to wake up. Then go. 63136274Srwatson * SIGALRM will set a flag indicating it's time to stop. Note that there's 64136274Srwatson * some overhead to the signal and timer setup, so the smaller the duration, 65136274Srwatson * the higher the relative overhead. 66136274Srwatson */ 67136274Srwatsonstatic int 68136274Srwatsonblast_loop(int s, long duration, u_char *packet, u_int packet_len) 69136274Srwatson{ 70136274Srwatson struct timespec starttime, tmptime; 71136274Srwatson struct itimerval it; 72136274Srwatson u_int32_t counter; 73136274Srwatson int send_errors, send_calls; 74136274Srwatson 75136274Srwatson if (signal(SIGALRM, signal_handler) == SIG_ERR) { 76136274Srwatson perror("signal"); 77136274Srwatson return (-1); 78136274Srwatson } 79136274Srwatson 80136274Srwatson if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { 81136274Srwatson perror("clock_getres"); 82136274Srwatson return (-1); 83136274Srwatson } 84136274Srwatson 85136274Srwatson if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { 86136274Srwatson perror("clock_gettime"); 87136274Srwatson return (-1); 88136274Srwatson } 89136274Srwatson 90136274Srwatson it.it_interval.tv_sec = 0; 91136274Srwatson it.it_interval.tv_usec = 0; 92136274Srwatson it.it_value.tv_sec = duration; 93136274Srwatson it.it_value.tv_usec = 0; 94136274Srwatson 95136274Srwatson if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 96136274Srwatson perror("setitimer"); 97136274Srwatson return (-1); 98136274Srwatson } 99136274Srwatson 100136274Srwatson send_errors = send_calls = 0; 101136274Srwatson counter = 0; 102136274Srwatson while (global_stop_flag == 0) { 103136274Srwatson /* 104136274Srwatson * We maintain and, if there's room, send a counter. Note 105136274Srwatson * that even if the error is purely local, we still increment 106136274Srwatson * the counter, so missing sequence numbers on the receive 107136274Srwatson * side should not be assumed to be packets lost in transit. 108136274Srwatson * For example, if the UDP socket gets back an ICMP from a 109136274Srwatson * previous send, the error will turn up the current send 110136274Srwatson * operation, causing the current sequence number also to be 111136274Srwatson * skipped. 112136274Srwatson */ 113136274Srwatson if (packet_len >= 4) { 114225334Smarius be32enc(packet, counter); 115136274Srwatson counter++; 116136274Srwatson } 117136274Srwatson if (send(s, packet, packet_len, 0) < 0) 118136274Srwatson send_errors++; 119136274Srwatson send_calls++; 120136274Srwatson } 121136274Srwatson 122136274Srwatson if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { 123136274Srwatson perror("clock_gettime"); 124136274Srwatson return (-1); 125136274Srwatson } 126136274Srwatson 127136274Srwatson printf("\n"); 128153470Sscottl printf("start: %zd.%09lu\n", starttime.tv_sec, 129136274Srwatson starttime.tv_nsec); 130153470Sscottl printf("finish: %zd.%09lu\n", tmptime.tv_sec, 131136274Srwatson tmptime.tv_nsec); 132136274Srwatson printf("send calls: %d\n", send_calls); 133136274Srwatson printf("send errors: %d\n", send_errors); 134136274Srwatson printf("approx send rate: %ld\n", (send_calls - send_errors) / 135136274Srwatson duration); 136136274Srwatson printf("approx error rate: %d\n", (send_errors / send_calls)); 137136274Srwatson 138136274Srwatson return (0); 139136274Srwatson} 140136274Srwatson 141136274Srwatsonint 142136274Srwatsonmain(int argc, char *argv[]) 143136274Srwatson{ 144136274Srwatson long payloadsize, port, duration; 145136274Srwatson struct sockaddr_in sin; 146136274Srwatson char *dummy, *packet; 147136274Srwatson int s; 148136274Srwatson 149136274Srwatson if (argc != 5) 150136274Srwatson usage(); 151136274Srwatson 152136274Srwatson bzero(&sin, sizeof(sin)); 153136274Srwatson sin.sin_len = sizeof(sin); 154136274Srwatson sin.sin_family = AF_INET; 155136274Srwatson if (inet_aton(argv[1], &sin.sin_addr) == 0) { 156136274Srwatson perror(argv[1]); 157136274Srwatson return (-1); 158136274Srwatson } 159136274Srwatson 160136274Srwatson port = strtoul(argv[2], &dummy, 10); 161136274Srwatson if (port < 1 || port > 65535 || *dummy != '\0') 162136274Srwatson usage(); 163136274Srwatson sin.sin_port = htons(port); 164136274Srwatson 165136274Srwatson payloadsize = strtoul(argv[3], &dummy, 10); 166136274Srwatson if (payloadsize < 0 || *dummy != '\0') 167136274Srwatson usage(); 168136274Srwatson if (payloadsize > 32768) { 169136274Srwatson fprintf(stderr, "payloadsize > 32768\n"); 170136274Srwatson return (-1); 171136274Srwatson } 172136274Srwatson 173136274Srwatson duration = strtoul(argv[4], &dummy, 10); 174136274Srwatson if (duration < 0 || *dummy != '\0') 175136274Srwatson usage(); 176136274Srwatson 177136274Srwatson packet = malloc(payloadsize); 178136274Srwatson if (packet == NULL) { 179136274Srwatson perror("malloc"); 180136274Srwatson return (-1); 181136274Srwatson } 182136274Srwatson bzero(packet, payloadsize); 183136274Srwatson 184136274Srwatson s = socket(PF_INET, SOCK_DGRAM, 0); 185136274Srwatson if (s == -1) { 186136274Srwatson perror("socket"); 187136274Srwatson return (-1); 188136274Srwatson } 189136274Srwatson 190136274Srwatson if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 191136274Srwatson perror("connect"); 192136274Srwatson return (-1); 193136274Srwatson } 194136274Srwatson 195136274Srwatson return (blast_loop(s, duration, packet, payloadsize)); 196136274Srwatson} 197