blob: 177d705dfec804039d659009383c47ed40729fb5 [file] [log] [blame]
/* -*- linux-c -*- */
/*
*
*
* Copyright (c) International Business Machines Corp., 2000
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This 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. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*/
/*
* ltpClient.c
*
* LTP Network Socket Test Client
*
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <resolv.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#define LOCAL_UDP_SERVER_PORT 10000
#define LOCAL_TCP_SERVER_PORT 10001
#define LOCAL_MCAST_SERVER_PORT 10002
#define MAX_MSG_LEN 256
#define TIMETOLIVE 10
#define PACKETSIZE 64
#define NET_ERROR -1
#define PACKET_LEN 1024 /* 1K should be plenty */
#define TRUE 1
#define FALSE 0
struct protoent *protocol = NULL;
struct packet
{
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};
/*
* Function Prototypes
*/
int ltp_run_ping_tests (char * hostName);
int ltp_run_traceroute_tests (char * hostName);
void ping_network (struct sockaddr_in *rawAddr, int pid);
void output_to_display (void *netPacket, int bytes, int pid);
unsigned short checksum (void *netPacket, int len);
int network_listener (char * hostname, int pid);
void ltp_traceroute (struct sockaddr_in *rawTraceAddr, char * hostName, int pid);
/*******************************************************************
* Function: Main
*
* Main will run the tests in this order.
* UDP, TCP and Multicast will be run first, if multicast is enabled.
* If multicast is not enabled, the UDP/TCP tests will continue.
* Once those tests complete, the ping and then traceroute tests will run.
*
********************************************************************/
int main(int argc, char *argv[]) {
int udpSocketHandle,
tcpSocketHandle,
mcastSocketHandle,
rc, i;
struct sockaddr_in udpClientAddr,
udpRemoteServerAddr,
tcpClientAddr,
tcpRemoteServerAddr,
mcastClientAddr,
mcastRemoteServerAddr;
struct hostent *hostEntry;
char hostName [MAX_MSG_LEN],
progName [MAX_MSG_LEN],
traceName [MAX_MSG_LEN],
multiCast = TRUE;
unsigned char ttl = 1;
mcastSocketHandle = -1;
/* check command line args */
if (argc < 4) {
printf("usage :<server-hostname> <trace-hostName> <data1> ... <dataN> \n");
exit(1);
}
strncpy(progName, argv[0], MAX_MSG_LEN);
strncpy(hostName, argv[1], MAX_MSG_LEN);
strncpy(traceName, argv[2], MAX_MSG_LEN);
/* get server IP address (no check if input is IP address or DNS name */
hostEntry = gethostbyname(hostName);
if (hostEntry == NULL) {
printf("%s: unknown host passed'%s' \n", progName, hostName);
exit(1);
}
printf("%s: sending data to '%s' (IP : %s) \n", progName, hostEntry->h_name,
inet_ntoa(*(struct in_addr *)hostEntry->h_addr_list[0]));
/* Setup UDP data packets */
udpRemoteServerAddr.sin_family = hostEntry->h_addrtype;
memcpy((char *) &udpRemoteServerAddr.sin_addr.s_addr, hostEntry->h_addr_list[0], hostEntry->h_length);
udpRemoteServerAddr.sin_port = htons(LOCAL_UDP_SERVER_PORT);
/* Setup TCP data packets */
tcpRemoteServerAddr.sin_family = hostEntry->h_addrtype;
memcpy((char *) &tcpRemoteServerAddr.sin_addr.s_addr, hostEntry->h_addr_list[0], hostEntry->h_length);
tcpRemoteServerAddr.sin_port = htons(LOCAL_TCP_SERVER_PORT);
/* Setup multiCast data packets */
mcastRemoteServerAddr.sin_family = hostEntry->h_addrtype;
memcpy((char *) &mcastRemoteServerAddr.sin_addr.s_addr, hostEntry->h_addr_list[0], hostEntry->h_length);
mcastRemoteServerAddr.sin_port = htons(LOCAL_MCAST_SERVER_PORT);
/* socket creation */
udpSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
tcpSocketHandle = socket(AF_INET, SOCK_STREAM, 0);
if (udpSocketHandle < 0) {
printf("%s: Error: cannot open UDP socket \n",progName);
}
if (tcpSocketHandle < 0) {
printf("%s: Error: cannot open TCP socket \n",progName);
}
/* bind any UDP port */
udpClientAddr.sin_family = AF_INET;
udpClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
udpClientAddr.sin_port = htons(0);
/* bind any TCP port */
tcpClientAddr.sin_family = AF_INET;
tcpClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
tcpClientAddr.sin_port = htons(0);
if (udpSocketHandle > 0) {
rc = bind(udpSocketHandle, (struct sockaddr *) &udpClientAddr, sizeof(udpClientAddr));
if (rc < 0) {
printf("%s: Error: cannot bind UDP port\n", progName);
}
}
if (tcpSocketHandle > 0) {
rc = bind(tcpSocketHandle, (struct sockaddr *) &tcpClientAddr, sizeof(tcpClientAddr));
if (rc < 0) {
printf("%s: Error: cannot bind TCP port\n", progName);
} else {
/* connect to server */
rc = connect(tcpSocketHandle, (struct sockaddr *) &tcpRemoteServerAddr, sizeof(tcpRemoteServerAddr));
if (rc < 0) {
printf("Error: cannot connect tp TCP Server \n");
}
}
}
/* check given address is multicast */
if (!IN_MULTICAST(ntohl(mcastRemoteServerAddr.sin_addr.s_addr))) {
printf("%s : Hostname [%s] passed [%s] is not a multicast server\n",progName, hostName,
inet_ntoa(mcastRemoteServerAddr.sin_addr));
printf("The multiCast Server will not be started \n");
multiCast = FALSE;
}
else {
/* create socket */
mcastSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
if (mcastSocketHandle < 0) {
printf("Error: %s : cannot open mulitCast socket\n", progName);
multiCast = FALSE;
}
/* bind any port number */
mcastClientAddr.sin_family = AF_INET;
mcastClientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
mcastClientAddr.sin_port = htons(0);
if (bind(mcastSocketHandle, (struct sockaddr *) &mcastClientAddr,sizeof(mcastClientAddr))<0) {
printf("Error: binding multiCast socket");
multiCast = FALSE;
}
if (setsockopt(mcastSocketHandle, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
printf("Error: %s : cannot set ttl = %d \n",progName, ttl);
multiCast = FALSE;
}
printf("%s : sending data on multicast group '%s' (%s)\n",progName,
hostEntry->h_name, inet_ntoa(*(struct in_addr *) hostEntry->h_addr_list[0]));
}
/* Skip over the program and hostnames and just send data */
for (i = 3; i < argc; i++) {
if (udpSocketHandle > 0) {
rc = sendto(udpSocketHandle, argv[i], strlen(argv[i])+1, 0,
(struct sockaddr *) &udpRemoteServerAddr,
sizeof(udpRemoteServerAddr));
if (rc < 0) {
printf("%s: cannot send UDP data %d \n",progName,i-1);
close(udpSocketHandle);
} else {
printf("%s: UDP data%u sent (%s)\n",progName,i-1,argv[i]);
}
} else {
printf("%s UDP Socket not open for send \n", hostName);
}
if (tcpSocketHandle > 0) {
rc = send(tcpSocketHandle, argv[i], strlen(argv[i]) + 1, 0);
if (rc < 0) {
printf("cannot send TCP data ");
close(tcpSocketHandle);
} else {
printf("%s: TCP data%u sent (%s)\n",progName,i-1,argv[i]);
}
} else {
printf("%s TCP Socket not open for send \n", hostName);
}
if (multiCast) {
rc = sendto(mcastSocketHandle, argv[i], strlen(argv[i])+1, 0,
(struct sockaddr *) &mcastRemoteServerAddr, sizeof(mcastRemoteServerAddr));
if (rc < 0) {
printf("%s : cannot send multiCast data %d\n",progName,i-1);
close(mcastSocketHandle);
multiCast = FALSE;
}
}
}
sleep(5);
ltp_run_traceroute_tests(traceName);
ltp_run_ping_tests(hostName);
return 0;
}
/*****************************************************************************
* Function: ltp_run_traceroute_tests - host look up and start traceroute processes
*
******************************************************************************/
int ltp_run_traceroute_tests(char * hostName)
{
struct hostent *hostEntry;
struct sockaddr_in rawTraceAddr;
int pid = -1;
pid = getpid();
protocol = getprotobyname("ICMP");
hostEntry = gethostbyname(hostName);
memset(&rawTraceAddr, 0, sizeof(rawTraceAddr));
rawTraceAddr.sin_family = hostEntry->h_addrtype;
rawTraceAddr.sin_port = 0;
rawTraceAddr.sin_addr.s_addr = *(long*)hostEntry->h_addr;
ltp_traceroute(&rawTraceAddr, hostName, pid);
return 0;
}
/**********************************************************************
* Function: ltp_run_ping_tests - host look up and start ping processes
*
***********************************************************************/
int ltp_run_ping_tests(char * hostName)
{
struct hostent *hostEntry;
struct sockaddr_in rawAddr;
int pid = -1;
pid = getpid();
protocol = getprotobyname("ICMP");
hostEntry = gethostbyname(hostName);
memset(&rawAddr, 0, sizeof(rawAddr));
rawAddr.sin_family = hostEntry->h_addrtype;
rawAddr.sin_port = 0;
rawAddr.sin_addr.s_addr = *(long*)hostEntry->h_addr;
if (fork() == 0) {
network_listener(hostName, pid);
} else {
ping_network(&rawAddr, pid);
}
return 0;
}
/******************************************************************************
* Function: network_listener - separate process to listen for and collect messages
*
*******************************************************************************/
int network_listener(char * hostName, int pid)
{
int rawSocket,
count,
value = TIMETOLIVE;
struct sockaddr_in rawAddr;
unsigned char packet[PACKET_LEN];
rawSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
count = 0;
if (rawSocket < 0)
{
printf("%s: Error: cannot open RAW socket \n", hostName);
return(NET_ERROR);
}
while (1) /* loop forever */
{
int bytes;
socklen_t len = sizeof(rawAddr);
memset(packet, 0, sizeof(packet));
bytes = recvfrom(rawSocket, packet, sizeof(packet), 0, (struct sockaddr*)&rawAddr, &len);
if (bytes > 0)
output_to_display(packet, bytes, pid);
else {
printf("%s : cannot receive data\n", hostName);
break;
}
count++;
if (value == count) {
printf("Exiting the network_listener...\n");
}
}
return(0);
}
/****************************************************************
* Function: checksum - standard 1s complement checksum
*
*****************************************************************/
unsigned short checksum(void *netPacket, int len)
{
unsigned short *packetPtr = netPacket,
result;
unsigned int sum = 0;
for (sum = 0; len > 1; len -= 2) {
sum += *packetPtr++;
}
if (len == 1) {
sum += *(unsigned char*)packetPtr;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
/*****************************************************************
* Function: output_to_display - Output to display info. from the
* listener
******************************************************************/
void output_to_display(void *netPacket, int bytes, int pid)
{
int i;
struct iphdr *ip = netPacket;
struct icmphdr *icmpPtr = netPacket + ip->ihl*4;
struct in_addr tmp_addr;
printf("\n************** -- Ping Tests - **********************************************\n");
for (i = 0; i < bytes; i++)
{
if (!(i & 15)) {
printf("\n[%d]: ", i);
}
printf("[%d] ", ((unsigned char*)netPacket)[i]);
}
printf("\n");
tmp_addr.s_addr = ip->saddr;
printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s ",
ip->version, ip->ihl*4, ntohs(ip->tot_len), ip->protocol,
ip->ttl, inet_ntoa(tmp_addr));
tmp_addr.s_addr = ip->daddr;
printf("dst=%s\n", inet_ntoa(tmp_addr));
if (icmpPtr->un.echo.id == pid) {
printf("ICMP: type[%d/%d] checksum[%d] id[%d] seq[%d]\n\n",
icmpPtr->type, icmpPtr->code, ntohs(icmpPtr->checksum),
icmpPtr->un.echo.id, icmpPtr->un.echo.sequence);
}
}
/***********************************************************************
* Function: ping_network - Build a message and send it.
*
*
***********************************************************************/
void ping_network(struct sockaddr_in *rawAddr, int pid)
{
const int value = TIMETOLIVE;
int i,
rawSocket,
count = 1;
struct packet rawPacket;
struct sockaddr_in r_addr;
rawSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
if (rawSocket < 0) {
printf("Error: cannot open RAW socket %d\n", rawSocket);
return;
}
if (setsockopt(rawSocket, SOL_IP, IP_TTL, &value, sizeof(value)) != 0) {
printf("ERROR: Setting TimeToLive option");
}
else{
printf("The test will run for [%d] iterations -- Ctrl-C to interupt \n", value);
sleep(3);
}
if (fcntl(rawSocket, F_SETFL, O_NONBLOCK) != 0) {
printf("ERROR: Failed request nonblocking I/O");
}
while (1) {
socklen_t msgLength=sizeof(r_addr);
printf("Message ID #:%d \n", count);
if (recvfrom(rawSocket, &rawPacket, sizeof(rawPacket), 0, (struct sockaddr*)&r_addr, &msgLength) > 0) {
printf("*** -- Message Received -- ***\n");
}
memset(&rawPacket, 0, sizeof(rawPacket));
rawPacket.hdr.type = ICMP_ECHO;
rawPacket.hdr.un.echo.id = pid;
for (i = 0; i < sizeof(rawPacket.msg)-1; i++) {
rawPacket.msg[i] = i + '0';
}
rawPacket.msg[i] = 0;
rawPacket.hdr.un.echo.sequence = count++;
rawPacket.hdr.checksum = checksum(&rawPacket, sizeof(rawPacket));
if (sendto(rawSocket, &rawPacket, sizeof(rawPacket), 0, (struct sockaddr*)rawAddr, sizeof(*rawAddr)) <= 0)
printf("ERROR: sendto failed !!");
sleep(1);
if (value == count) {
printf("Exiting ping test...\n");
break;
}
}
}
/**********************************************************************
* Function: ltp_traceroute
* try to reach the destination
* while outputting hops along the route
***********************************************************************/
void ltp_traceroute(struct sockaddr_in *rawTraceAddr, char * hostName, int pid)
{
const int flag = TRUE;
int TimeToLive = 0;
int i, rawTraceSocket, count = 1;
socklen_t length;
struct packet rawTracePacket;
unsigned char tracePacket[PACKET_LEN];
struct sockaddr_in rawReceiveAddr;
struct hostent *hostEntry2;
struct in_addr tmp_addr;
printf("\n************** -- Trace Route Tests - **********************************************\n");
rawTraceSocket = socket(PF_INET, SOCK_RAW, protocol->p_proto);
if (rawTraceSocket < 0)
{
printf("Error: cannot open RAW socket %d\n", rawTraceSocket);
return;
}
if (setsockopt(rawTraceSocket, SOL_IP, SO_ERROR, &flag, sizeof(flag)) != 0)
printf("ERROR: Setting socket options");
do
{
struct iphdr *ip;
length = sizeof(rawReceiveAddr);
TimeToLive++;
if (setsockopt(rawTraceSocket, SOL_IP, IP_TTL, &TimeToLive, sizeof(TimeToLive)) != 0) {
printf("ERROR: Setting TimeToLive option");
}
memset(&rawTracePacket, 0, sizeof(rawTracePacket));
rawTracePacket.hdr.type = ICMP_ECHO;
rawTracePacket.hdr.un.echo.id = pid;
for (i = 0; i < sizeof(rawTracePacket.msg)-1; i++) {
rawTracePacket.msg[i] = i+'0';
}
rawTracePacket.msg[i] = 0;
rawTracePacket.hdr.un.echo.sequence = count++;
rawTracePacket.hdr.checksum = checksum(&rawTracePacket, sizeof(rawTracePacket));
if (sendto(rawTraceSocket, &rawTracePacket, sizeof(rawTracePacket), 0, (struct sockaddr*)rawTraceAddr, sizeof(*rawTraceAddr)) <= 0) {
printf("ERROR: sendto failed !!");
}
sleep(1);
if (recvfrom(rawTraceSocket, tracePacket, sizeof(tracePacket), MSG_DONTWAIT, (struct sockaddr*)&rawReceiveAddr, &length) > 0)
{
ip = (void*)tracePacket;
tmp_addr.s_addr = ip->saddr;
printf("Host IP:#%d: %s \n", count-1, inet_ntoa(tmp_addr));
hostEntry2 = gethostbyaddr((void*)&rawReceiveAddr, length, rawReceiveAddr.sin_family);
if (hostEntry2 != NULL)
printf("(%s)\n", hostEntry2->h_name);
else
perror("Name: ");
} else{
printf("%s : data send complete...\n", hostName);
break;
}
}
while (rawReceiveAddr.sin_addr.s_addr != rawTraceAddr->sin_addr.s_addr);
printf("\n************** -- End Trace Route Tests - ******************************************\n");
close(rawTraceSocket);
}