/* * Send / receive TCP or UDP echos in any of a number of bizzare ways. * * Joel P. Bion, March 1990 * Copyright (c) 1990 cisco Systems. All rights reserved. * * This "tuecho" program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Prompts as: * Host: -- host to send echos to -- can be name or a.b.c.d -- * Enter protocol (0 = UDP, 1 = TCP) [0]: -- UDP or TCP * Size of data portion (bytes) [100]: -- bytes in data, excluding headers -- * Number of bursts [5]: -- number of bursts of packets to send -- * Packets per burst [1]: -- packets per burst, all sent AT ONCE -- * Timeout (seconds) [2]: -- how long to wait for data * Pause interval (seconds) [0]: -- Pause interval between bursts of frames * Type of pattern (specify = 0, increment = 1) [1]: * -- if 0 specified, allow you to specify a 16bit pattern as four * -- hex digits (see below). If 1, will create a "incrementing", * -- cycling pattern from 0x0000 -> 0xffff ->. * Enter pattern (hex value) [abcd]: -- if "0" specified above */ #include #include #include #include #include #include #include #include extern void printf(), fflush(), exit(), bzero(), perror(), strcpy(), setbuf(), sscanf(), bcopy(), close(), fprintf(); extern int write(), read(), select(), atoi(), socket(), connect(); /* Maximum packet size (integer) */ #define MAXBUF (2000) #define MAXBYTES (MAXBUF * 4) /* Special patterns... */ #define SPECIAL_NONE (0) #define SPECIAL_COUNTER (SPECIAL_NONE + 1) #define SPECIAL_MAX (SPECIAL_COUNTER) /* Protocols */ #define PROTO_UDP (0) #define PROTO_TCP (PROTO_UDP + 1) #define PROTO_MAX (PROTO_TCP) /* Global, because interrupt routine references them */ int lost, /* Packets whose echos are not received */ good, /* We received a good reply */ corrupted, /* We received a bad reply */ sentout, /* How many we sent out */ outc; /* How many chars out */ /* Guarantee CRs at random times */ void cprint(c) char c; { printf("%c", c); if (++outc == 70) { printf("\n"); outc = 0; } fflush(stdout); } void cprintcr() { if (outc != 0) printf("\n"); } unsigned getint(prompt, defa, fc) char *prompt; unsigned defa; char fc; { char s[1000]; unsigned u; if (fc == 'x') printf("%s [%x]: ", prompt, defa); else printf("%s [%d]: ", prompt, defa); fgets(s, 999, stdin); if ((s[0] == '\0') || (s[0] == '\n')) return(defa); else { if (fc == 'x') sscanf(s,"%x", &u); else sscanf(s,"%d", &u); return(u); } } void outhere() { cprintcr(); printf("\nAt end, sent out = %d, good = %d, lost = %d, corrupted = %d.\n", sentout, good, lost, corrupted); } void outhere_exit() { outhere(); exit(0); } void usage_exit() { printf("usage: tuecho\n"); printf(" with no parameters will prompt you for information, or another form:\n"); printf("\n tuecho host proto size nbursts ppburst timeout pauseint ptype\n"); printf(" [pattern] (on same command line as above)\n"); printf("\n"); printf(" Where:\n"); printf(" host: host to receive your echos. (can be name or a.b.c.d form)\n"); printf(" proto: 0 for UDP, 1 for TCP\n"); printf(" size: size of echo packet, excluding headers\n"); printf(" nbursts: total number of \"bursts\" of echo packets to send\n"); printf(" ppburst: how many echo packets should be in each burst\n"); printf(" timeout: how many seconds to wait for the reply (allow more time for bursts)\n"); printf(" pauseint: Pause interval, in seconds, between bursts\n"); printf(" ptype: 0 to allow you to specify a hex pattern as the final \"pattern\" parameter\n"); printf(" 1 for \"increasing cyclic\" 16-bit pattern going from 0x0000 to 0xffff\n"); printf(" and back again, until each echo packet is filled\n"); printf(" pattern: four character hex pattern (no leading 0x), if ptype = 1, to insert repeatedly\n"); printf(" in the echo packets\n"); exit(0); } void sendrecvechos(sock, ptype, pattern, bufsize, bursts, burstsize, timeout, pause_int) int sock; /* Socket to send / receive from */ int ptype; /* Pattern type (normal, or a special) */ int pattern; /* Pattern (if normal) */ int bufsize; /* Buffer size to send */ int bursts; /* Number of bursts */ int burstsize; /* Size of bursts */ struct timeval timeout; /* Timeout */ int pause_int; /* Pause interval */ { int i, j, k, ok, readin; int nb; unsigned int bufo[MAXBUF]; /* Packet to send out */ unsigned int bufi[MAXBUF]; /* Packet to accept */ fd_set readmask; /* For "select" call */ /* Set up select mask */ FD_ZERO(&readmask); FD_SET(sock, &readmask); /* Set up the pattern. Check for specials... */ switch (ptype) { case SPECIAL_COUNTER: for (i = 0; i < (bufsize / 4); i++) bufo[i] = i; break; case SPECIAL_NONE: default: for (i = 0; i < (bufsize / 4); i++) bufo[i] = pattern; break; } for (i = 0; (i < bursts); i++) { if (pause_int) sleep(pause_int); if (ptype == SPECIAL_COUNTER) bufo[0] = i; for (j = 0; j < burstsize; j++) { if (write(sock, (char *) bufo, bufsize) < 0) { perror("writing on datagram socket."); outhere(); exit(1); } sentout++; } for (j = 0; j < burstsize; j++) { nb = select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &timeout); if (nb <= 0) { lost++; cprint('.'); FD_SET(sock, &readmask); continue; } if (FD_ISSET(sock, &readmask)) { bzero((char *) bufi, bufsize); if ((readin = read(sock, (char *) bufi, bufsize)) < 0) { perror("Reading on datagram socket."); outhere(); exit(1); } else { ok = 1; for (k = 0; ((k < (bufsize / 4)) && (ok)); k++) ok = (bufo[k] == bufi[k]); if (!(ok)) { corrupted++; cprint('*'); continue; } else { good++; cprint('!'); continue; } } } } } outhere(); } void printinfo(ptype, pattern, bufsize, bursts, burstsize, timeout, server, proto, pause_int) int ptype; /* Pattern type (normal, or a special) */ int pattern; /* Pattern (if normal) */ int bufsize; /* Buffer size to send */ int bursts; /* Number of bursts */ int burstsize; /* Size of bursts */ struct timeval timeout; /* Timeout */ struct sockaddr_in server; /* Remote server IP address */ int proto; /* Protocol */ int pause_int; { printf("\nSending %d bursts of %d %s packets, data portions being %d bytes,\n", bursts, burstsize, ((proto == PROTO_TCP) ? ("TCP") : ("UDP")), bufsize); printf("with a timeout of %d seconds,\nthe pattern being ", timeout.tv_sec); switch (ptype) { case SPECIAL_COUNTER: printf("an incrementing value in the packet"); break; case SPECIAL_NONE: default: printf("0x%x in each four bytes", pattern); break; } printf("\n"); printf("Pause interval: %d seconds\n", pause_int); printf("Sending to IP address %u.%u.%u.%u...\n", (unsigned) server.sin_addr.S_un.S_un_b.s_b1, (unsigned) server.sin_addr.S_un.S_un_b.s_b2, (unsigned)server.sin_addr.S_un.S_un_b.s_b3, (unsigned) server.sin_addr.S_un.S_un_b.s_b4); } void askinfo(argc, argv, hostname, proto, bufsize, bursts, burstsize, timeout, ptype, pattern, pause_int) int argc; char **argv, *hostname; int *proto, *bufsize, *bursts, *burstsize; struct timeval *timeout; int *ptype; unsigned *pattern; int *pause_int; { if ((argc > 9) || ((argc == 2) && (argv[1][0] == '-') && (argv[1][1] == 'h'))) usage_exit(); if (argc > 1) strcpy(hostname, argv[1]); else { printf("Host: "); gets(hostname); } *proto = ((argc > 2) ? (atoi(argv[2])) : (int) getint("Enter protocol (0 = UDP, 1 = TCP)", 0, 'd')); *bufsize = ((argc > 3) ? (atoi(argv[3])) : (int) getint("Size of data portion (bytes)", 100, 'd')); *bursts = ((argc > 4) ? (atoi(argv[4])) : (int) getint("Number of bursts", 5, 'd')); *burstsize = ((argc > 5) ? (atoi(argv[5])) : (int) getint("Packets per burst", 1, 'd')); timeout->tv_sec = ((argc > 6) ? (atoi(argv[6])) : (int) getint("Timeout (seconds)", 2, 'd')); *pause_int = ((argc > 7) ? (atoi(argv[7])) : (int) getint("Enter pause interval", 0, 'd')); *ptype = ((argc > 8) ? (atoi(argv[8])) : (int) getint("Type of pattern (specify = 0, increment = 1)", 1, 'd')); if (*ptype == SPECIAL_NONE) if (argc > 9) sscanf(argv[9], "%x", pattern); else *pattern = getint("Enter pattern (hex value)", 0xabcd, 'x'); } void init() { setbuf(stdout, NULL); good = sentout = corrupted = lost = outc = 0; } void main(argc, argv) int argc; char **argv; { char hostname[1000]; int bufsize, bursts, proto, ptype, burstsize, sock; struct hostent *hp, *gethostbyname(); struct in_addr ip; struct sockaddr_in server; struct timeval timeout; unsigned int pattern, pause_int; askinfo(argc, argv, hostname, &proto, &bufsize, &bursts, &burstsize, &timeout, &ptype, &pattern, &pause_int); signal(SIGINT, outhere_exit); ip.s_addr = inet_addr(hostname); if (ip.s_addr == -1) { hp = gethostbyname(hostname); if (hp == NULL) { fprintf(stderr, "%s: %s: unknown host\n", argv[0], argv[1]); exit(1); } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); } else bcopy(&ip, &server.sin_addr, sizeof(ip)); printinfo(ptype, pattern, bufsize, bursts, burstsize, timeout, server, proto, pause_int); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("Opening stream socket."); exit(1); } server.sin_family = AF_INET; server.sin_port = htons(((struct servent *) getservbyname("echo",((proto == PROTO_UDP) ? ("udp") : ("tcp") )))->s_port); if (connect(sock, &server, sizeof(server)) < 0) { perror("connecting stream socket"); exit(1); } sendrecvechos(sock, ptype, pattern, bufsize, bursts, burstsize, timeout, pause_int); close(sock); exit(0); }