blob: f98efe46fb6a3350f4b9c88b8585038c2a7f1dd6 [file] [log] [blame]
/*
#
#
# Task Subprogram
#
# SUBPROGRAM NAME: PINGPONG.C
#
# REQUIRED PARAMETERS:
# Calling Procedure: pingpong HOST SIZE PACKETS
# HOST - Current host
# SIZE - Size of each packet
# PACKETS - the number of packets across the network
#
# SETUP REQUIRED:
# o This task must be run as root.
# o TCP/IP must be configured before executing this task.
#
# DESCRIPTION:
# Purpose:To generate lan traffic with ICMP echo packet
# Command: None
# Subcommand:None
# Design:
# Create raw socket
# spawn child process to send echo ICMP packet
# the child process build echo packet and send to network
# repeat n times
# the parent goes on to receive the reply
# when finish print # of packets sent & # pf packets received
#
#
#===========================================================================
*/
#define PS2
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include "test.h"
#include "usctest.h"
#define MAXPACKET 4096 /* max packet size */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
int pfd[2];
int fdstr[10];
int verbose;
int count;
u_char packet[MAXPACKET];
int options;
extern int errno;
int s; /* Socket file descriptor */
struct hostent *hp; /* Pointer to host info */
struct timezone tz; /* leftover */
struct sockaddr whereto;/* Who to pingpong */
int datalen; /* How much data */
char *hostname;
char hnamebuf[MAXHOSTNAMELEN];
int npackets=1;
int ntransmitted = 0; /* sequence # for outbound packets = #sent */
int ident;
int nreceived = 0; /* # of packets we got back */
int timing = 0;
void finish(int);
int nwrite;
char *TCID = "perf_lan";
int TST_TOTAL = 1;
extern int Tst_count;
/*
* M A I N
*/
main(argc, argv)
char *argv[];
{
struct sockaddr_in from;
char **av = argv;
int nrcv;
struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
int on = 1;
int rc = 0;
struct protoent *proto;
tst_resm (TINFO, "Starting pingpong - to send / receive packets from host \n");
/* Get Host net address */
tst_resm (TINFO, "Get host net address for sending packets \n");
bzero( (char *)&whereto, sizeof(struct sockaddr) );
to->sin_family = AF_INET;
to->sin_addr.s_addr = inet_addr(av[1]);
if (to->sin_addr.s_addr != -1) {
strcpy(hnamebuf, av[1]);
hostname = hnamebuf;
} else {
hp = gethostbyname(av[1]);
if (hp) {
to->sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
hostname = hp->h_name;
} else {
tst_resm (TINFO, "%s: unknown host, couldn't get address\n",argv[0]);
exit(1);
}
}
/* Determine Packet Size - either use what was passed in or default */
tst_resm (TINFO, "Determine packet size \n");
if( argc >= 3 )
datalen = atoi( av[2] );
else
datalen = 64-8;
if (datalen > MAXPACKET) {
tst_resm (TINFO, "Pingpong: packet size too large\n");
exit(1);
}
if (datalen >= sizeof(struct timeval))
timing = 1;
/* Set number of packets to be sent */
tst_resm (TINFO, "Determine number of packets to send \n");
if (argc >= 4)
npackets = atoi(av[3]);
/* Get PID of current process */
ident = getpid() & 0xFFFF;
/* Get network protocol to use (check /etc/protocol) */
if ((proto = getprotobyname("icmp")) == NULL) {
tst_resm (TINFO, "ICMP: unknown protocol\n");
exit(10);
}
/* Create a socket endpoint for communications - returns a descriptor */
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
tst_resm (TINFO, "Pingpong: socket - could not create link \n");
exit(5);
}
tst_resm (TINFO, "echoing %s: %d data bytes\n", hostname, datalen );
setlinebuf( stdout );
/* Setup traps */
signal( SIGINT, finish );
signal( SIGCLD, finish );
/* Fork a child process to continue sending packets */
tst_resm (TINFO, "Create a child process to continue to send packets \n");
switch (fork()) {
case -1:
tst_resm (TINFO, "ERROR when forking a new process\n");
exit(1);
case 0:
/* Child's work */
ntransmitted=echopkt(datalen,npackets);
tst_resm (TINFO, "%d packets transmitted, ",ntransmitted);
sleep(10);
break;
default:
tst_resm (TINFO, "Parent started - to receive packets \n");
/* Parent's work - receive packets back from child */
for (;;) {
int len = sizeof (packet);
unsigned int fromlen = sizeof (from);
#ifdef __64BIT__
long cc;
#else
int cc;
#endif
/* Receive packet from socket */
tst_resm (TINFO, "Receiving packet \n");
fromlen = sizeof (from);
if ( (cc=recvfrom(s, packet, len, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
tst_resm (TINFO, "ERROR in recvfrom\n");
}
/* Verify contents of packet */
if ((rc = ck_packet (packet, cc, &from)) != 0) {
tst_resm (TINFO, "ERROR - network garbled packet\n");
}
else {
nreceived++;
}
}
}
}
echopkt(datalen,npackets)
int datalen;
int npackets;
{
int count=0;
static u_char outpack[MAXPACKET];
register struct icmp *icp = (struct icmp *) outpack;
int i;
#ifdef __64BIT__
long cc;
#else
int cc;
#endif
register struct timeval *tp = (struct timeval *) &outpack[8];
register u_char *datap = &outpack[8+sizeof(struct timeval)];
/* Setup the packet structure */
tst_resm (TINFO, "Setup ICMP packet structure to send to host \n");
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_id = ident; /* ID */
cc = datalen+8; /* skips ICMP portion */
/* Add time stamp and user data */
tst_resm (TINFO, "Add time stamp, user data, and check sum to packet. \n");
if (timing)
gettimeofday( tp, &tz );
for( i=8; i<datalen; i++) { /* skip 8 for time */
*datap++ = i;
}
/* Compute ICMP checksum here */
icp->icmp_cksum = in_cksum( icp, cc );
/* cc = sendto(s, msg, len, flags, to, tolen) */
ntransmitted=0;
while (count < npackets) {
count++;
/* Send packet through socket created */
tst_resm (TINFO, "Sending packet through created socket \n");
i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
if( i < 0 || i != cc ) {
if( i<0 ) perror("sendto");
tst_resm (TINFO, "pingpong: wrote %s %d chars, ret=%d\n",hostname,cc,i);
fflush(stdout);
}
}
/* sleep(30); */
return(count);
}
/*
* I N _ C K S U M
*
* Checksum routine for Internet Protocol family headers (C Version)
*
*/
in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr, tmp;
register int sum = 0;
register u_short answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
tmp = *(u_char *)w;
sum += (tmp << 8);
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
/*
* T V S U B
*
* Subtract 2 timeval structs: out = out - in.
*
* Out is assumed to be >= in.
*tvsub( out, in )
*register struct timeval *out, *in;
*{
* if( (out->tv_usec -= in->tv_usec) < 0 ) {
* out->tv_sec--;
* out->tv_usec += 1000000;
* }
* out->tv_sec -= in->tv_sec;
*}
*/
/*
* F I N I S H
*
* Outputs packet information to confirm transmission and reception.
*/
void finish(int n)
{
tst_resm (TINFO, "%d packets received, \n", nreceived );
exit(0);
}
/*
* C K _ P A C K E T
*
* Checks contents of packet to verify information did not get destroyed
*/
ck_packet (buf, cc, from)
char *buf; /* pointer to start of IP header */
int cc; /* total size of received packet */
struct sockaddr_in *from; /* address of sender */
{
u_char i;
int iphdrlen;
struct ip *ip = (struct ip *) buf; /* pointer to IP header */
register struct icmp *icp; /* ptr to ICMP */
struct timeval *tp = (struct timeval *) &buf[8];
u_char *datap ;
from->sin_addr.s_addr = ntohl(from->sin_addr.s_addr);
iphdrlen = ip->ip_hl << 2; /* Convert # 16-bit words to #bytes */
cc -= iphdrlen;
icp = (struct icmp *) (buf + iphdrlen);
datap = (u_char *)icp + sizeof(struct timeval) + 8;
if (icp->icmp_type != ICMP_ECHOREPLY) {
return(0); /* Not your packet 'cause not an echo */
}
if (icp->icmp_id != ident) {
return(0); /* Sent to us by someone else */
}
/* Verify data in packet */
tst_resm (TINFO, "Verify data in packet after returned from sender \n");
if ( datalen > 118 ) {
datalen=118;
}
tst_resm (TINFO, "Checking Data.\n");
for( i=8; i<datalen; i++) { /* skip 8 for time */
if ( i != (*datap)) {
tst_resm (TINFO, "Data cannot be validated. \n");
}
datap++;
}
return(0);
}