#include <sys/endian.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void
usage(void)
{
fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
exit(-1);
}
static int global_stop_flag;
static void
signal_handler(int signum __unused)
{
global_stop_flag = 1;
}
static int
blast_loop(int s, long duration, u_char *packet, u_int packet_len)
{
struct timespec starttime, tmptime;
struct itimerval it;
u_int32_t counter;
int send_errors, send_calls;
if (signal(SIGALRM, signal_handler) == SIG_ERR) {
perror("signal");
return (-1);
}
if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
perror("clock_getres");
return (-1);
}
if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
perror("clock_gettime");
return (-1);
}
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = duration;
it.it_value.tv_usec = 0;
if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
perror("setitimer");
return (-1);
}
send_errors = send_calls = 0;
counter = 0;
while (global_stop_flag == 0) {
if (packet_len >= 4) {
be32enc(packet, counter);
counter++;
}
if (send(s, packet, packet_len, 0) < 0)
send_errors++;
send_calls++;
}
if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
perror("clock_gettime");
return (-1);
}
printf("\n");
printf("start: %zd.%09lu\n", starttime.tv_sec,
starttime.tv_nsec);
printf("finish: %zd.%09lu\n", tmptime.tv_sec,
tmptime.tv_nsec);
printf("send calls: %d\n", send_calls);
printf("send errors: %d\n", send_errors);
printf("approx send rate: %ld\n", (send_calls - send_errors) /
duration);
printf("approx error rate: %d\n", (send_errors / send_calls));
return (0);
}
int
main(int argc, char *argv[])
{
long payloadsize, duration;
struct addrinfo hints, *res, *res0;
char *dummy, *packet;
int port, s, error;
const char *cause = NULL;
if (argc != 5)
usage();
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
port = strtoul(argv[2], &dummy, 10);
if (port < 1 || port > 65535 || *dummy != '\0') {
fprintf(stderr, "Invalid port number: %s\n", argv[2]);
usage();
}
payloadsize = strtoul(argv[3], &dummy, 10);
if (payloadsize < 0 || *dummy != '\0')
usage();
if (payloadsize > 32768) {
fprintf(stderr, "payloadsize > 32768\n");
return (-1);
}
duration = strtoul(argv[4], &dummy, 10);
if (duration < 0 || *dummy != '\0') {
fprintf(stderr, "Invalid duration time: %s\n", argv[4]);
usage();
}
packet = malloc(payloadsize);
if (packet == NULL) {
perror("malloc");
return (-1);
}
bzero(packet, payloadsize);
error = getaddrinfo(argv[1],argv[2], &hints, &res0);
if (error) {
perror(gai_strerror(error));
return (-1);
}
s = -1;
for (res = res0; res; res = res->ai_next) {
s = socket(res->ai_family, res->ai_socktype, 0);
if (s < 0) {
cause = "socket";
continue;
}
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
cause = "connect";
close(s);
s = -1;
continue;
}
break;
}
if (s < 0) {
perror(cause);
return (-1);
}
freeaddrinfo(res0);
return (blast_loop(s, duration, packet, payloadsize));
}