netblast.c revision 153470
1202188Sed/*- 2202188Sed * Copyright (c) 2004 Robert N. M. Watson 3202188Sed * All rights reserved. 4202188Sed * 5202188Sed * Redistribution and use in source and binary forms, with or without 6202188Sed * modification, are permitted provided that the following conditions 7202188Sed * are met: 8202188Sed * 1. Redistributions of source code must retain the above copyright 9202188Sed * notice, this list of conditions and the following disclaimer. 10202188Sed * 2. Redistributions in binary form must reproduce the above copyright 11202188Sed * notice, this list of conditions and the following disclaimer in the 12202188Sed * documentation and/or other materials provided with the distribution. 13202188Sed * 14202188Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15202188Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16202188Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17202188Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18202188Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19202188Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202188Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202188Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22202188Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23202188Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24202188Sed * SUCH DAMAGE. 25202188Sed * 26202188Sed * $FreeBSD: head/tools/tools/netrate/netblast/netblast.c 153470 2005-12-16 06:02:44Z scottl $ 27202188Sed */ 28202188Sed 29202188Sed#include <sys/types.h> 30202188Sed#include <sys/socket.h> 31202188Sed#include <sys/time.h> 32202188Sed 33202188Sed#include <netinet/in.h> 34202188Sed 35202188Sed#include <arpa/inet.h> 36202188Sed 37202188Sed#include <signal.h> 38202188Sed#include <stdio.h> 39202188Sed#include <stdlib.h> 40202188Sed#include <string.h> 41202188Sed 42202188Sedstatic void 43202188Sedusage(void) 44202188Sed{ 45202188Sed 46202188Sed fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n"); 47202188Sed exit(-1); 48202188Sed} 49202188Sed 50202188Sedstatic int global_stop_flag; 51202188Sed 52202188Sedstatic void 53202188Sedsignal_handler(int signum __unused) 54202188Sed{ 55202188Sed 56202188Sed global_stop_flag = 1; 57202188Sed} 58202188Sed 59202188Sed/* 60202188Sed * Loop that blasts packets: begin by recording time information, resetting 61202188Sed * stats. Set the interval timer for when we want to wake up. Then go. 62202188Sed * SIGALRM will set a flag indicating it's time to stop. Note that there's 63202188Sed * some overhead to the signal and timer setup, so the smaller the duration, 64202188Sed * the higher the relative overhead. 65202188Sed */ 66202188Sedstatic int 67202188Sedblast_loop(int s, long duration, u_char *packet, u_int packet_len) 68202188Sed{ 69202188Sed struct timespec starttime, tmptime; 70202188Sed struct itimerval it; 71202188Sed u_int32_t counter; 72202188Sed int send_errors, send_calls; 73202188Sed 74202188Sed if (signal(SIGALRM, signal_handler) == SIG_ERR) { 75202188Sed perror("signal"); 76202188Sed return (-1); 77202188Sed } 78202188Sed 79202188Sed if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { 80202188Sed perror("clock_getres"); 81202188Sed return (-1); 82202188Sed } 83202188Sed 84202188Sed if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { 85202188Sed perror("clock_gettime"); 86202188Sed return (-1); 87202188Sed } 88202188Sed 89 it.it_interval.tv_sec = 0; 90 it.it_interval.tv_usec = 0; 91 it.it_value.tv_sec = duration; 92 it.it_value.tv_usec = 0; 93 94 if (setitimer(ITIMER_REAL, &it, NULL) < 0) { 95 perror("setitimer"); 96 return (-1); 97 } 98 99 send_errors = send_calls = 0; 100 counter = 0; 101 while (global_stop_flag == 0) { 102 /* 103 * We maintain and, if there's room, send a counter. Note 104 * that even if the error is purely local, we still increment 105 * the counter, so missing sequence numbers on the receive 106 * side should not be assumed to be packets lost in transit. 107 * For example, if the UDP socket gets back an ICMP from a 108 * previous send, the error will turn up the current send 109 * operation, causing the current sequence number also to be 110 * skipped. 111 * 112 * XXXRW: Note alignment assumption. 113 */ 114 if (packet_len >= 4) { 115 *((u_int32_t *)packet) = htonl(counter); 116 counter++; 117 } 118 if (send(s, packet, packet_len, 0) < 0) 119 send_errors++; 120 send_calls++; 121 } 122 123 if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { 124 perror("clock_gettime"); 125 return (-1); 126 } 127 128 printf("\n"); 129 printf("start: %zd.%09lu\n", starttime.tv_sec, 130 starttime.tv_nsec); 131 printf("finish: %zd.%09lu\n", tmptime.tv_sec, 132 tmptime.tv_nsec); 133 printf("send calls: %d\n", send_calls); 134 printf("send errors: %d\n", send_errors); 135 printf("approx send rate: %ld\n", (send_calls - send_errors) / 136 duration); 137 printf("approx error rate: %d\n", (send_errors / send_calls)); 138 139 return (0); 140} 141 142int 143main(int argc, char *argv[]) 144{ 145 long payloadsize, port, duration; 146 struct sockaddr_in sin; 147 char *dummy, *packet; 148 int s; 149 150 if (argc != 5) 151 usage(); 152 153 bzero(&sin, sizeof(sin)); 154 sin.sin_len = sizeof(sin); 155 sin.sin_family = AF_INET; 156 if (inet_aton(argv[1], &sin.sin_addr) == 0) { 157 perror(argv[1]); 158 return (-1); 159 } 160 161 port = strtoul(argv[2], &dummy, 10); 162 if (port < 1 || port > 65535 || *dummy != '\0') 163 usage(); 164 sin.sin_port = htons(port); 165 166 payloadsize = strtoul(argv[3], &dummy, 10); 167 if (payloadsize < 0 || *dummy != '\0') 168 usage(); 169 if (payloadsize > 32768) { 170 fprintf(stderr, "payloadsize > 32768\n"); 171 return (-1); 172 } 173 174 duration = strtoul(argv[4], &dummy, 10); 175 if (duration < 0 || *dummy != '\0') 176 usage(); 177 178 packet = malloc(payloadsize); 179 if (packet == NULL) { 180 perror("malloc"); 181 return (-1); 182 } 183 bzero(packet, payloadsize); 184 185 s = socket(PF_INET, SOCK_DGRAM, 0); 186 if (s == -1) { 187 perror("socket"); 188 return (-1); 189 } 190 191 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 192 perror("connect"); 193 return (-1); 194 } 195 196 return (blast_loop(s, duration, packet, payloadsize)); 197} 198