| /* -*- 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); |
| } |