pchar-1.5000755 002001 000024 00000000000 10203464205 012424 5ustar00bmahstaff000000 000000 pchar-1.5/main.cc000644 002001 000024 00000136106 10203463722 013750 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: main.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: main.cc 1082 2005-02-12 19:40:04Z bmah $ // // main.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Main driver program // #include #ifdef STDC_HEADERS #include #else extern "C" { double atof(const char *); long random(void); } #endif /* STDC_HEADERS */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "Pctest.h" #include "PctestIpv4Udp.h" #include "PctestIpv4Raw.h" #include "PctestIpv4Tcp.h" #include "PctestIpv4Icmp.h" #include "PctestIpv4File.h" #ifdef HAVE_IPV6 #include "PctestIpv6Icmp.h" #include "PctestIpv6Tcp.h" #include "PctestIpv6Udp.h" #include "PctestIpv6File.h" #endif /* HAVE_IPV6 */ #include "ResultTable.h" #include "TestRecord.h" #ifdef HAVE_SNMP #include "GetIfInfo.h" #endif /* HAVE_SNMP */ // // Forward declarations // void DoPchar(Pctest *pct); void DoTrout(Pctest *pct); #ifdef HAVE_SNMP void PrintIfInfo(const GetIfInfo *); #endif /* HAVE_SNMP */ // // Default values // AnalysisType Analysis = AnalysisLeastSquares; unsigned int Burst = 1; bool ChangeFlag = false; bool PcapFlag = false; int DebugLevel = 0; double Gap = 0.25; GapType GapDist = GapFixed; unsigned int Hops = 30; char *Interface = NULL; unsigned int Increment = 32; char *OriginHost = NULL; ModeType Mode = ModePchar; unsigned int Mtu = 1500; NetworkProtocolType NetworkProtocol = NetworkProtocolNone; int NumericFlag = 0; unsigned int Port = 32768; char *ReadFilename = NULL; int QuietFlag = 0; unsigned int Repetitions = 32; #ifdef HAVE_SNMP bool SnmpFlag = false; #endif /* HAVE_SNMP */ unsigned int StartHop = 1; unsigned int Timeout = 3; unsigned int Tos = 0x0; int VerboseFlag = 0; char *WriteFilename = NULL; char *TargetHost = NULL; // // Globals // ResultTable **PartialResults; ResultTable **PartialMins; const int MaxAddressesPerHop = 10; const int MaxSocketAddressLength = 255; #ifdef HAVE_PCAP char PcapErrBuf[PCAP_ERRBUF_SIZE]; #endif /* HAVE_PCAP */ // // Version // // Input: None // // Output: None // // Print version/copyright/build information // void VersionInfo() { extern char *Version, *Copyright, *Build, *DFlags; fprintf(stderr, "%s\n", Version); fprintf(stderr, "%s\n", Copyright); fprintf(stderr, "%s\n", Build); fprintf(stderr, "Compilation flags: %s\n", DFlags); } // // Usage // // Input: program name (argv0) // // Output: None // // Print out invocation information // void Usage(char *argv0) { fprintf(stderr, "Usage: %s [-a analysis] [-b burst] [-c] " #ifdef HAVE_PCAP "[-C] " #endif /* HAVE_PCAP */ "[-d debuglevel] [-g gap] [-G gaptype] [-h] [-H hops] " #ifdef HAVE_PCAP "[-i interface] " #endif /* HAVE_PCAP */ "[-I increment] [-m mtu] [-n] [-p protocol] [-P port] [-q] [-R reps] [-s hop] " #ifdef HAVE_SNMP "[-S] " #endif /* HAVE_SNMP */ "[-t timeout] [-T tos] [-v] [-V] [-w file] -r file | host]\n", argv0); fprintf(stderr, "\t-a analysis\tSet analysis type (default is lsq)\n"); fprintf(stderr, "\t\t\tlsq\tLeast sum of squares linear fit\n"); fprintf(stderr, "\t\t\tkendall\tLinear fit using Kendall's test statistic\n"); fprintf(stderr, "\t\t\tlms\tLeast median of squares linear fit\n"); fprintf(stderr, "\t\t\tlmsint\tLeast median of squares linear fit (integer computations)\n"); fprintf(stderr, "\t-b\t\tBurst size (default = %d)\n", Burst); fprintf(stderr, "\t-c\t\tIgnore route changes\n"); #ifdef HAVE_PCAP fprintf(stderr, "\t-C\t\tUse pcap packet capture facilities\n"); #endif /* HAVE_PCAP */ fprintf(stderr, "\t-d debuglevel\tSet debugging output level\n"); fprintf(stderr, "\t-g gap\t\tInter-test gap in seconds (default = %0.2f)\n", Gap); fprintf(stderr, "\t-G gaptype\tInter-test gap type (default is fixed)\n"); fprintf(stderr, "\t\t\tfixed\tFixed gap\n"); fprintf(stderr, "\t\t\texp\tExponentially distributed random\n"); fprintf(stderr, "\t-H hops\t\tMaximum number of hops (default = %d)\n", Hops); fprintf(stderr, "\t-h\t\tPrint this help information\n"); #ifdef HAVE_PCAP fprintf(stderr, "\t-i interface\tpcap interface\n"); #endif /* HAVE_PCAP */ fprintf(stderr, "\t-I increment\tPacket size increment (default = %d)\n", Increment); fprintf(stderr, "\t-l host\t\tSet origin address of probes (defaults to hostname)\n"); fprintf(stderr, "\t-m mtu\t\tMaximum packet size to check (default = %d)\n", Mtu); fprintf(stderr, "\t-M mode\t\tOperational mode (defaults to pchar)\n"); fprintf(stderr, "\t\t\tpchar\tPath characterization\n"); fprintf(stderr, "\t\t\ttrout\tTiny traceroute\n"); fprintf(stderr, "\t-n\t\tDon't resolve addresses to hostnames\n"); fprintf(stderr, "\t-p protocol\tNetwork protocol (default is ipv4udp)\n"); fprintf(stderr, "\t\t\tipv4udp\t\tUDP over IPv4\n"); fprintf(stderr, "\t\t\tipv4raw\t\tUDP over IPv4 (raw sockets)\n"); #ifdef HAVE_PCAP fprintf(stderr, "\t\t\tipv4tcp\t\tTCP over IPv4 (raw sockets)\n"); #endif /* HAVE_PCAP */ fprintf(stderr, "\t\t\tipv4icmp\tICMP over IPv4 (raw sockets)\n"); #ifdef HAVE_IPV6 fprintf(stderr, "\t\t\tipv6icmp\tICMPv6 over IPv6 (raw sockets)\n"); fprintf(stderr, "\t\t\tipv6tcp\t\tTCP over IPv6\n"); fprintf(stderr, "\t\t\tipv6udp\t\tUDP over IPv6\n"); #endif /* HAVE_IPV6 */ fprintf(stderr, "\t-P port\t\tStarting port number (default = %d)\n", Port); fprintf(stderr, "\t-q\t\tQuiet output\n"); fprintf(stderr, "\t-r file\t\tRead data from a file (- for stdin)\n"); fprintf(stderr, "\t-R reps\t\tRepetitions per hop (default = %d)\n", Repetitions); fprintf(stderr, "\t-s hop\t\tStarting hop number (default = %d)\n", StartHop); #ifdef HAVE_SNMP fprintf(stderr, "\t-S\t\tDo SNMP queries per-hop\n"); #endif /* HAVE_SNMP */ fprintf(stderr, "\t-t timeout\tICMP timeout in seconds (default = %d)\n", Timeout); fprintf(stderr, "\t-T tos\t\tSet IP type-of-service field (default = %d)\n", Tos); fprintf(stderr, "\t-v\t\tVerbose output\n"); fprintf(stderr, "\t-V\t\tPrint version information\n"); fprintf(stderr, "\t-w file\t\tWrite data to a file (- for stdout)\n"); fprintf(stderr, "\n"); } // // GetAddressFamily // // Input: None // // Output: String describing the address family for the tracefile // named by ReadFilename. // // Open, scan, and close ReadFilename for an "addresses" line // and return the parameter associated with that line. // We use this to figure out what kind of a PctestIpv?File // object we need. // char *GetAddressFamily() { FILE *f; // file structure const unsigned int buflen = 1024; // maximum line length char buf[buflen]; // line buffer char *s; // return value from fgets char *af = NULL; // address family string bool done = false; // If the user didn't supply us with a command-line filename, // it's an error. if (!ReadFilename) { fprintf(stderr, "No filename specified for -r\n"); return NULL; } // Try to open the file f = fopen(ReadFilename, "r"); if (!f) { perror("fopen"); return NULL; } // Loop until finished while (!done) { s = fgets(buf, buflen, f); // See if we're done... if (!s) { if (ferror(f)) { // error condition perror("fgets"); exit(1); } done = true; } else { // Process a line. This is a simplified version of the // parser in PctestIpv4File::SetTargetName(). // if (strncasecmp(s, "addresses ", 10) == 0) { af = strdup(s+10); done = true; } } } // Done with file fclose(f); f = NULL; // Return the string we found after "addresses ", if any. return af; } // // GetPrintableNetworkProtocol // // Input: Network protocol // // Output: ASCII representation of network protocol name. // char *GetPrintableNetworkProtocol(NetworkProtocolType np) { switch (np) { case (NetworkProtocolIpv4Udp): return("UDP/IPv4"); break; case (NetworkProtocolIpv4Raw): return("UDP/IPv4 (raw sockets)"); break; case (NetworkProtocolIpv4Tcp): return("TCP/IPv4 (raw sockets)"); break; case (NetworkProtocolIpv4Icmp): return("ICMP/IPv4 (raw sockets)"); break; case (NetworkProtocolIpv4File): return("IPv4 save file"); break; #ifdef HAVE_IPV6 case (NetworkProtocolIpv6Icmp): return("ICMPv6/IPv6"); break; case (NetworkProtocolIpv6Tcp): return("TCP/IPv6"); break; case (NetworkProtocolIpv6Udp): return("UDP/IPv6"); break; case (NetworkProtocolIpv6File): return("IPv6 save file"); break; #endif /* HAVE_IPV6 */ default: return("unknown network protocol"); break; } } // // main // int main(int argc, char **argv) { int c; // getopt Pctest *pct = NULL; // test structure // Parse command-line arguments using getopt while ((c = getopt(argc, argv, "a:b:cCd:g:G:hH:i:I:l:m:M:np:P:qR:r:s:St:T:vVw:")) != -1) { // Check for the different command-line flags we accept switch (c) { // a: set analysis type case 'a': { if (strcasecmp(optarg, "lsq") == 0) { Analysis = AnalysisLeastSquares; } else if (strcasecmp(optarg, "kendall") == 0) { Analysis = AnalysisKendall; } else if (strcasecmp(optarg, "lms") == 0) { Analysis = AnalysisLeastMedianSquares; } else if (strcasecmp(optarg, "lmsint") == 0) { Analysis = AnalysisLeastMedianSquaresIntegers; } else { fprintf(stderr, "Invalid analysis type: %s\n", optarg); Usage(argv[0]); exit(1); } break; } // b: burst size case 'b': { Burst = atoi(optarg); if (Burst < 1) { fprintf(stderr, "Warning: burst size %d too small; resetting to 1\n"); Burst = 1; } break; } // c: ignore route changes case 'c': { ChangeFlag = true; break; } // C: Use pcap packet capture facilities case 'C': { #ifdef HAVE_PCAP PcapFlag = true; break; #else fprintf(stderr, "pcap unavailable in this build"); Usage(argv[0]); exit(1); #endif /* HAVE_PCAP */ } // d: set debugging level case 'd': { DebugLevel = atoi(optarg); break; } // g: inter-test gap case 'g': { Gap = atof(optarg); break; } // G: set gap type case 'G': { if (strcasecmp(optarg, "fixed") == 0) { GapDist = GapFixed; } else if (strcasecmp(optarg, "exp") == 0) { GapDist = GapExponential; } else { fprintf(stderr, "Invalid gap type: %s\n", optarg); Usage(argv[0]); exit(1); } break; } // h: print help info and usage case 'h': { Usage(argv[0]); exit(0); break; }; // H: Maximum hops case 'H': { Hops = atoi(optarg); if (Hops > 255) { fprintf(stdout, "Warning: Maximum hops %d too large, resetting to 30\n", Hops); Hops = 30; } break; } case 'i': { #ifdef HAVE_PCAP Interface = strdup(optarg); if (Interface == NULL) { fprintf(stderr, "Couldn't allocate space for interface name\n"); exit(1); } break; #else fprintf(stderr, "pcap unavailable in this build"); Usage(argv[0]); exit(1); #endif /* HAVE_PCAP */ } // I: set packet size increment case 'I': { Increment = atoi(optarg); break; } // l: set local origin of probes case 'l': { OriginHost = strdup(optarg); if (OriginHost == NULL) { fprintf(stderr, "Couldn't allocate space for origin hostname\n"); exit(1); } break; } // m: MTU size case 'm': { Mtu = atoi(optarg); if (!Mtu) { fprintf(stderr, "Mtu argument must be positive (was %d)\n", Mtu); exit(1); } break; } case 'M': { if ((strcasecmp(optarg, "pchar") == 0) || (strcasecmp(optarg, "pathchar") == 0)) { Mode = ModePchar; } else if (strcasecmp(optarg, "trout") == 0) { Mode = ModeTrout; } else { fprintf(stderr, "Invalid operational mode %s\n", optarg); Usage(argv[0]); exit(1); } break; } // n: don't resolve addresses to hostnames case 'n': { NumericFlag = 1; break; } // p: Network protocol case 'p': { if (strcasecmp(optarg, "ipv4udp") == 0) { NetworkProtocol = NetworkProtocolIpv4Udp; } else if (strcasecmp(optarg, "ipv4raw") == 0) { NetworkProtocol = NetworkProtocolIpv4Raw; } #ifdef HAVE_PCAP else if (strcasecmp(optarg, "ipv4tcp") == 0) { NetworkProtocol = NetworkProtocolIpv4Tcp; } #endif /* HAVE_PCAP */ else if (strcasecmp(optarg, "ipv4icmp") == 0) { NetworkProtocol = NetworkProtocolIpv4Icmp; } #ifdef HAVE_IPV6 else if (strcasecmp(optarg, "ipv6icmp") == 0) { NetworkProtocol = NetworkProtocolIpv6Icmp; } else if (strcasecmp(optarg, "ipv6tcp") == 0) { NetworkProtocol = NetworkProtocolIpv6Tcp; } else if (strcasecmp(optarg, "ipv6udp") == 0) { NetworkProtocol = NetworkProtocolIpv6Udp; } #endif /* HAVE_IPV6 */ else { fprintf(stderr, "Invalid network protocol: %s\n", optarg); Usage(argv[0]); exit(1); } break; } // P: starting port number case 'P': { Port = atoi(optarg); break; } // q: quiet output case 'q': { QuietFlag = 1; VerboseFlag = 0; break; } // r: read from file case 'r': { ReadFilename = strdup(optarg); if (ReadFilename == NULL) { fprintf(stderr, "Couldn't allocate space for statistics filename\n"); exit(1); } if (WriteFilename) { fprintf(stderr, "Warning: both -r and -w specified\n"); } break; } // R: Repetitions per hop case 'R': { Repetitions = atoi(optarg); break; } // s: Starting hop number case 's': { StartHop = atoi(optarg); if (StartHop < 1) { fprintf(stdout, "Warning: starting hop %d too small, resetting to 1\n", StartHop); StartHop = 1; } break; } // S: Enable SNMP queries case 'S': { #ifdef HAVE_SNMP SnmpFlag = true; break; #else fprintf(stderr, "SNMP unavailable in this build"); Usage(argv[0]); exit(1); #endif /* HAVE_SNMP */ } // t: ICMP timeout case 't': { Timeout = atoi(optarg); if (Timeout < 1) { fprintf(stdout, "Warning: timeout value %d too small, resetting to 1\n", Timeout); Timeout = 1; } break; } // T: IP TOS case 'T': { Tos = atoi(optarg); break; } // v: verbose case 'v': { VerboseFlag = 1; QuietFlag = 0; break; } // V: version information case 'V': { VersionInfo(); exit(0); } // w: write statistics to file case 'w': { WriteFilename = strdup(optarg); if (WriteFilename == NULL) { fprintf(stderr, "Couldn't allocate space for statistics filename\n"); exit(1); } if (ReadFilename) { fprintf(stderr, "Warning: both -r and -w specified\n"); } break; } // ? indicates an unrecognized option case '?': { Usage(argv[0]); exit(1); break; } // Didn't know how to handle this case default: { fprintf(stderr, "Received valid, but unknown flag %c\n", c); exit(1); } } } // If we're not reading from a file, we need to get a target host // name, which should be the last word on the command line. if (!ReadFilename) { if (optind != (argc - 1)) { Usage(argv[0]); exit(1); } } TargetHost = argv[optind]; IF_DEBUG(1, fprintf(stderr, "TargetHost %s\n", TargetHost)); // Other initialization before we go off to deal with protocol- // dependent things: Weakly seed process random number generator. srandom(time(NULL)); // Initialize a test structure. Note that reading from a file // is a special case. if (ReadFilename) { char *af; #ifdef WITH_SUID // If we're running SUID root, then we drop privileges // here. We don't want to read random files in the // filesystem, and the main reason we needed superuser // in the first place (raw sockets) doesn't apply. setuid(getuid()); #endif /* WITH_SUID */ // We need to read the file first to figure out what address // family it describes. af = GetAddressFamily(); if (!af) { fprintf(stderr, "Nonexistent address family in tracefile\n"); exit(1); } else { if (strcmp(af, "AF_INET\n") == 0) { NetworkProtocol = NetworkProtocolIpv4File; pct = new PctestIpv4File(); } #ifdef HAVE_IPV6 else if (strcmp(af, "AF_INET6\n") == 0) { NetworkProtocol = NetworkProtocolIpv6File; pct = new PctestIpv6File(); } #endif /* HAVE_IPV6 */ else { fprintf(stderr, "Unknown address family %s in tracefile\n", af); exit(1); } free(af); } } else { // If the user didn't specify a protocol, we have to figure // out a default. For IPv4-only, this trivial. if (NetworkProtocol == NetworkProtocolNone) { #ifdef HAVE_IPV6 // IPv6 available, so we need to do a little work here. // We want to resolve the hostname and figure out what // address family comes back first in the response. // Presumably if we have IPv6 available, we can do // getaddrinfo(). struct addrinfo *host = NULL; struct addrinfo hints; int error_num; // Setup for getaddrinfo() taken from PctestIpv6::SetTargetName() memset(&hints, 0, sizeof(hints)); error_num = getaddrinfo(TargetHost, NULL, &hints, &host); if (host == NULL) { // An error here implies there's going to be an error // later, so we might as well blow up now. fprintf(stderr, "%s: %s\n", TargetHost, gai_strerror(error_num)); exit(1); } // See which protocol family came back first from the // resolver query. We'll use that to determine the // default protocol to use. switch (host->ai_family) { case (AF_INET): NetworkProtocol = NetworkProtocolIpv4Udp; IF_DEBUG(1, fprintf(stderr, "Default protocol UDP/IPv4\n")); break; case (AF_INET6): NetworkProtocol = NetworkProtocolIpv6Udp; IF_DEBUG(1, fprintf(stderr, "Default protocol UDP/IPv6\n")); break; default: // We don't know what this protocol family is. Really // there's a better way to handle this. We should // traverse the linked list of host->ai_next until // we find a host->ai_family that we *do* recognize, // and then use that, and only snarl at the user if // we ran down the entire chain without finding // something. Get the simple and dumb behavior // working first. fprintf(stderr, "%s: Unknown protocol family default\n", TargetHost); exit(1); break; } freeaddrinfo(host); #else // IPv4 only, so use UDP/IPv4 NetworkProtocol = NetworkProtocolIpv4Udp; IF_DEBUG(1, fprintf(stderr, "Default protocol UDP/IPv4\n")); #endif /* HAVE_IPV6 */ } // Normal case is to make a new protocol-dependent structure switch (NetworkProtocol) { case (NetworkProtocolIpv4Udp): pct = new PctestIpv4Udp(Port); break; case (NetworkProtocolIpv4Raw): pct = new PctestIpv4Raw(Port); break; case (NetworkProtocolIpv4Tcp): pct = new PctestIpv4Tcp(Port); break; case (NetworkProtocolIpv4Icmp): pct = new PctestIpv4Icmp(); break; #ifdef HAVE_IPV6 case (NetworkProtocolIpv6Icmp): pct = new PctestIpv6Icmp(); break; case (NetworkProtocolIpv6Tcp): pct = new PctestIpv6Tcp(Port); break; case (NetworkProtocolIpv6Udp): pct = new PctestIpv6Udp(Port); break; #endif /* HAVE_IPV6 */ default: fprintf(stderr, "Unknown protocol type...exiting...\n"); exit(1); } } // Having figured out what the address family is, do the necessary // name resolution to determine the source and destination of // our probe packets. if (pct->SetTargetName(TargetHost) < 0) { exit(1); } if (pct->SetOriginName(OriginHost) < 0) { exit(1); } // Get sockets if (pct->GetSocketOut() < 0) { exit(1); } if (pct->GetSocketIn() < 0) { exit(1); } #ifdef WITH_SUID // If we were running SUID root, then drop privileges here // (assuming we didn't do this already). It's not so great to // run this far into the program with superuser privileges. // At least we give them up in any case before we write to // output files. setuid(getuid()); #endif /* WITH_SUID */ // With all arguments parsed, determine which set of tests // to run and go do it. switch (Mode) { case (ModePchar): DoPchar(pct); break; case (ModeTrout): DoTrout(pct); break; default: fprintf(stderr, "Unknown mode type...exiting...\n"); exit(1); } // Stick a fork in us, we're done. exit(0); } // // DoPchar // // Input: Pctest structure controlling the type of tests to run. // // Output: None. // // Run the original path characterization measurement and analysis // algorithm. // void DoPchar(Pctest *pct) { int i, j, k, l, m; // universal loop counters FILE *df = NULL; // output file // Generate set of packet sizes to test. We'll test packets // from Increment to the maximum multiple of Increment that // that will still fit in Mtu bytes. We weakly randomize // the packet sizes (we just don't want a sequence of // packet sizes that is *too* predictable). // // Note that if increment is small (in particular, if it's // smaller than a UDP/IP header), the protocol-specific code // will refuse to generate packets smaller than the minimum // possible. int testsPerRep = Mtu/Increment; int *packetSize = new int[testsPerRep]; for (i = 0; i < testsPerRep; i++) { packetSize[i] = Increment * (i+1); } for (i = 0; i < testsPerRep; i++) { int swapIndex = random() % testsPerRep; int temp; temp = packetSize[i]; packetSize[i] = packetSize[swapIndex]; packetSize[swapIndex] = temp; } for (i = 0; i < testsPerRep; i++) { IF_DEBUG(3, fprintf(stderr, "packetsize[%d] = %d\n", i, packetSize[i])); } typedef ResultTable *ResultTablePtr; PartialResults = (ResultTable **) calloc(Hops, sizeof(ResultTable *)); PartialMins = (ResultTable **) calloc(Hops, sizeof(ResultTable *)); for (i = 0; i < Hops; i++) { PartialResults[i] = NULL; PartialMins[i] = NULL; } // // Start output // if (!QuietFlag) { fprintf(stdout, "pchar to %s (%s) using %s\n", pct->GetTargetName(), pct->GetPrintableAddress(), GetPrintableNetworkProtocol(NetworkProtocol)); if (PcapFlag) { fprintf(stdout, "Using pcap capture on %s\n", Interface); } else { fprintf(stdout, "Using raw socket input\n"); } fprintf(stdout, "Packet size increments from %d to %d by %d\n", pct->GetMinSize(), Mtu, Increment); fprintf(stdout, "%d test(s) per repetition\n", testsPerRep); fprintf(stdout, "%d repetition(s) per hop\n", Repetitions); } // // If we're probing a real host (as opposed to reading a trace), // do a few pings (using whatever protocol we have selected) to // try to see if the destination host is really up or not. // if (!ReadFilename) { int rc; // syscall return code TestRecord *tr = new TestRecord; // dummy test record int timeouts; // number of timeouts received so far int maxtimeouts = 3; // we'll make three tries to "ping" timeouts = 0; tr->burst = 1; // only need one packet for pings tr->size = 128; // what packet size is best here? if (tr->size < pct->GetMinSize()) { tr->size = pct->GetMinSize(); } while (timeouts < maxtimeouts) { tr->hops = MAXTTL; rc = pct->Test(*tr); // Exit if there was an error. if (rc < 0) { exit(1); } if (tr->result == PctestActionTimeout) { timeouts++; } else { break; } } // If we didn't get a response to // our initial pings, then warn about this fact. if (timeouts >= maxtimeouts) { fprintf(stdout, "Warning: target host did not respond to initial test.\n"); } delete tr; } // Print first-hop output line. Prior versions // of this code were more complex because they used the returned // ICMP packets to figure out the source address. But now we // have that information up-front. if (!QuietFlag) { fprintf(stdout, "%2d: %s ", StartHop - 1, pct->GetPrintableAddress(pct->GetOriginAddress())); if (NumericFlag) { fprintf(stdout, "(%s)", pct->GetPrintableAddress(pct->GetOriginAddress())); } else { fprintf(stdout, "(%s)", pct->GetOriginName()); } fprintf(stdout, "\n"); #ifdef HAVE_SNMP if (!ReadFilename && SnmpFlag) { GetIfInfo *gifp; gifp = new GetIfInfo(pct->GetOriginAddress(), pct); PrintIfInfo(gifp); delete gifp; } #endif /* HAVE_SNMP */ } // Initialize statistics save file and write some stuff out if (WriteFilename) { if (strcmp(WriteFilename, "-") == 0) { df = stdout; } else { df = fopen(WriteFilename, "w"); if (df == NULL) { perror("fopen"); exit(1); } } // Write initial parameters to the file fprintf(df, "addresses %s\n", pct->GetAddressFamilyString()); fprintf(df, "targethost %s\n", pct->GetTargetName()); fprintf(df, "src %s\n", pct->GetPrintableAddress(pct->GetOriginAddress())); fprintf(df, "dest %s\n", pct->GetPrintableAddress()); fprintf(df, "hops %d\n", Hops); fprintf(df, "burst %d\n", Burst); fprintf(df, "minsize %d\n", pct->GetMinSize()); fprintf(df, "increment %d\n", Increment); fprintf(df, "mtu %d\n", Mtu); fprintf(df, "burst %d\n", Burst); fprintf(df, "repetitions %d\n", Repetitions); fprintf(df, "starthop %d\n", StartHop); } // // Begin testing. We increment the hop number, iterating over // the different packet sizes we have available. (Really, we // keep the hop number minus StartHop, and add it back before printing, // since the internal data structures we use start from zero.) // bool firstProbe = true; // first probe flag struct timeval timeFirst, timeLast; // time of first and last probes bool lastHopFlag = true; // *could* be the last hop double aCumulativeLast = 0.0, bCumulativeLast = 0.0, r2CumulativeLast = 0.0; double minBandwidth = -1.0; // minimum bandwidth found so far double queueingTime = 0.0; // total queueing time seen so far int queueingBytes = 0; // total queued bytes estimated so far char *checkAddress[MaxAddressesPerHop]; int checkAddressLength[MaxAddressesPerHop]; for (i = 0; i < MaxAddressesPerHop; i++) { checkAddress[i] = new char[MaxSocketAddressLength]; if (checkAddress[i] == NULL) { fprintf(stderr, "Couldn't allocate space for route change detection\n"); exit(1); } } for (i = 0; i < Hops; i++) { int packetsLost = 0; int packetsSent = 0; unsigned addressesSeen = 0; // for detecting routing changes bool realTimestamp = false; // set true once we've received // real timestamp that didn't need // adjustments PctestActionType pcta; // Initialize statistics structure PartialResults[i] = new ResultTable(Increment, Mtu, Burst, Repetitions); lastHopFlag = true; // Run the correct number of repetitions and iterate over the // packet sizes. for (j = 0; j < Repetitions; j++) { for (k = 0; k < testsPerRep; k++) { for (m = 1; m < Burst + 1; m++) { int rc; // syscall return code double rtt; TestRecord *tr; // test record for this test // Let the user know what we're doing if (VerboseFlag) { fprintf(stderr, " hop %2d rep %3d burst %2d size %5d\r", i+StartHop, j, m, packetSize[k]); } // Set up variables for a test tr = new TestRecord; tr->burst = m; tr->size = packetSize[k]; if (tr->size < pct->GetMinSize()) { // Skip this test if the packet size is too small // for this protocol. delete tr; continue; } tr->hops = i+StartHop; gettimeofday(&tr->tvstart, NULL); rc = pct->Test(*tr); packetsSent++; if (rc < 0) { exit(1); } // Update start and end timestamps for this session if (firstProbe) { timeFirst.tv_sec = tr->tvstart.tv_sec; timeFirst.tv_usec = tr->tvstart.tv_usec; firstProbe = false; } timeLast.tv_sec = tr->tvstart.tv_sec; timeLast.tv_usec = tr->tvstart.tv_usec; // Write to disk if requested if (WriteFilename) { fprintf(df, "%s\n", tr->htoa(pct)); } // Check for a timeout. If we got one, then increment // the appropriate counter and keep going. if (tr->result == PctestActionTimeout) { packetsLost++; delete tr; continue; } // Process the results we got back. rtt = tr->tv.tv_sec + (tr->tv.tv_usec/1000000.0); // Hack for OSF from Jeffrey Mogul . // Tweak null timestamps upwards, but keep track of whether // we've had to do this for every timestamp on a hop or // whether or not we've gotten a real one. if (rtt == 0.0) { rtt = 0.0000001; } else { realTimestamp = true; } IF_DEBUG(2, fprintf(stderr, "bytes = %d, rtt = %f, ip_src = %s, replbytes = %d\n", tr->size, rtt, pct->GetPrintableAddress(tr->icmpSourceAddress), tr->replsize)); // See if we've seen this address before or not. If so, // record it for posterity. for (l = 0; l < addressesSeen; l++) { if ((checkAddressLength[l] == tr->icmpSourceAddressLength) && (memcmp(tr->icmpSourceAddress, checkAddress[l], checkAddressLength[l]) == 0)) { break; } } if (l == addressesSeen) { if (addressesSeen == 1) { if (!QuietFlag) { fprintf(stdout, "Route change detected\n"); } if ((!ChangeFlag) && (ReadFilename)) { exit(1); } } if (addressesSeen < MaxAddressesPerHop) { memcpy(checkAddress[addressesSeen], tr->icmpSourceAddress, tr->icmpSourceAddressLength); checkAddressLength[addressesSeen] = tr->icmpSourceAddressLength; addressesSeen++; } } // Have the Pctest subclass figure out what the ICMP // type and code fields meant (they're kind of protocol- // independent). pcta = tr->result; // If we received a valid (to us) ICMP message, then // attempt to store timing information. if ((pcta == PctestActionValid) || (pcta == PctestActionValidLasthop)) { if ((PartialResults[i]->put( tr->size + tr->replsize, rtt)) < 0) { fprintf(stderr, "Couldn't store result\n"); abort(); } } else if (pcta == PctestActionFiltered) { // We hit a firewall or something that's going // to mess with our packets. Give up now. fprintf(stderr, "ICMP: packet filtered\n"); lastHopFlag = true; goto endreps; } else { // With certain types/codes returned by ICMP, we're also // in trouble. It'd be nice if the protocol-dependent // packet processing threw away everything except // time exceeded and port-unreachable. fprintf(stderr, "Unexpected response to probe\n"); } // If ICMP type was time exceeded, we know this is *not* // the last hop. if (pcta != PctestActionValidLasthop) { lastHopFlag = false; } // If we're not reading from a file, we need to set // the delay between network packets (otherwise, this // is kind of silly) if (!ReadFilename) { // Initialize inter-test gap and other structures struct timeval tvGap; if (GapDist == GapFixed) { tvGap.tv_sec = (long) Gap; tvGap.tv_usec = (long) ((Gap - ((long) Gap)) * 1000000.0); } else if (GapDist == GapExponential) { // Generate exponentially distributed random // value with a mean of Gap. long u; double udub; const double maxudub = pow(2.0, 31.0); // 2^31 double x; u = random(); udub = ((double) u / maxudub); x = - Gap * log(udub); IF_DEBUG(2, fprintf(stderr, "main: exponential gap %f\n", x)); tvGap.tv_sec = (long) x; tvGap.tv_usec = (long) ((x - ((long) x)) * 1000000.0); } else { fprintf(stderr, "Unknown gap type\n"); exit(1); } // Delay for some amount of time. rc = select(0, NULL, NULL, NULL, &tvGap); if (rc < 0) { perror("select"); } } delete tr; } } } endreps: // If we weren't in quiet mode, then clear the line we were on if (VerboseFlag) { fprintf(stdout, "%80s\r", ""); } // If every timestamp got tweaked (on an OSF machine with low // clock resolution, running on a fast link, perhaps), then // print a warning to this effect. if ((!realTimestamp) && (packetsSent > packetsLost)) { fprintf(stdout, "Warning: No non-zero timestamps measured, bumping up to 0.0000001\n"); } // Per-hop processing and statistics. PartialMins[i] = PartialResults[i]->getMin(); double aCumulative, bCumulative, r2Cumulative, aHop, bHop; double sa, sb; double bLower, bUpper; // Get cumulative delay and bandwidth if (Analysis == AnalysisLeastSquares) { PartialMins[i]->slr(aCumulative, bCumulative, r2Cumulative, sa, sb); } else if (Analysis == AnalysisKendall) { PartialMins[i]->tau(aCumulative, bCumulative, bLower, bUpper); } else if (Analysis == AnalysisLeastMedianSquares) { PartialMins[i]->lms(aCumulative, bCumulative, r2Cumulative); } else if (Analysis == AnalysisLeastMedianSquaresIntegers) { PartialMins[i]->lmsint(aCumulative, bCumulative, r2Cumulative); } else { fprintf(stderr, "Unknown statistical analysis type, exiting...\n"); exit(1); } // Figure the per-hop delay and bandwidth. This computation's // correctness relies on aCumulativeLast and bCumulativeLast // being initialized to 0.0. if (bCumulative > 0.0) { aHop = aCumulative - aCumulativeLast; bHop = bCumulative - bCumulativeLast; } else { aHop = 0.0; bHop = 0.0; } // Update our idea of the minimum bandwidth found so far. // Clearly we only take into account hop bandwidths that // make some sense (positive). double hopBandwidth; if (bHop != 0.0) { hopBandwidth = (1.0/bHop) * 8.0 / 1000.0; } else { hopBandwidth = 0.0; } if (((minBandwidth < 0.0) || (minBandwidth > hopBandwidth)) && (hopBandwidth > 0.0)) { minBandwidth = hopBandwidth; } // Compute queueing time statistic(s) double qTime; // estimate of queueing time along path double qTimeHop; // estimate of queueing time this hop int qBytes; // estimate of bytes queued along path qTime = PartialResults[i]->queueing(); qTimeHop = qTime - queueingTime; if ((hopBandwidth > 0.0) && (qTimeHop >= 0.0)) { qBytes = (int) (qTimeHop * (1.0/bHop)); } else { qBytes = 0; } queueingTime = qTime; queueingBytes += qBytes; // Per-hop output if (!QuietFlag) { fprintf(stdout, " Partial loss: %d / %d (%d%%)\n", packetsLost, packetsSent, packetsLost * 100 / packetsSent); if (Analysis == AnalysisLeastSquares) { fprintf(stdout, " Partial char: rtt = %f ms, (b = %f ms/B), r2 = %f\n", aCumulative*1000.0, bCumulative*1000.0, r2Cumulative); fprintf(stdout, " stddev rtt = %f, stddev b = %f\n", sa * 1000.0, sb * 1000.0); } else if (Analysis == AnalysisKendall) { fprintf(stdout, " Partial char: rtt = %f ms, (b = %f ms/B)\n", aCumulative*1000.0, bCumulative*1000.0); fprintf(stdout, " 90%% confidence interval is [%f,%f] ms/B\n", bLower * 1000.0, bUpper * 1000.0); } else if ((Analysis == AnalysisLeastMedianSquares) || (Analysis == AnalysisLeastMedianSquaresIntegers)) { fprintf(stdout, " Partial char: rtt = %f ms, (b = %f ms/B), r2 = %f\n", aCumulative*1000.0, bCumulative*1000.0, r2Cumulative); } else { fprintf(stderr, "Unknown statistical analysis type, exiting...\n"); exit(1); } fprintf(stdout, " Partial queueing: avg = %f ms (%d bytes)\n", qTime, queueingBytes); // Hop characterististics don't make any sense for the first // hop if we start with hop > 1 if ((i > 0) || (StartHop == 1)) { fprintf(stdout, " Hop char: rtt = "); if (aHop >= 0.0) { fprintf(stdout, "%f", aHop*1000.0); } else { fprintf(stdout, "--.---"); } fprintf(stdout, " ms, bw = "); if (hopBandwidth >= 0.0) { fprintf(stdout, "%f", hopBandwidth); } else { fprintf(stdout, "--.---"); } fprintf(stdout, " Kbps\n"); fprintf(stdout, " Hop queueing: avg = %f ms (%d bytes)\n", qTimeHop, qBytes); } if (addressesSeen > 0) { for (m = 0; m < addressesSeen; m++) { fprintf(stdout, "%2d: %s ", i+StartHop, pct->GetPrintableAddress(checkAddress[m])); if (NumericFlag) { fprintf(stdout, "(%s)\n", pct->GetPrintableAddress(checkAddress[m])); } else { fprintf(stdout, "(%s)\n", pct->GetName(checkAddress[m])); } #ifdef HAVE_SNMP if (!ReadFilename && SnmpFlag) { GetIfInfo *gifp; gifp = new GetIfInfo(checkAddress[m], pct); PrintIfInfo(gifp); delete gifp; } #endif /* HAVE_SNMP */ } } else { fprintf(stdout, "%2d: no probe responses\n", i+StartHop); lastHopFlag = false; } } // Update inter-hop state aCumulativeLast = aCumulative; bCumulativeLast = bCumulative; r2CumulativeLast = r2Cumulative; // If all ICMP messages received were "port unreachable", then // we're done. if (lastHopFlag) { break; } } int pathLength = i + StartHop; // End-of-run processing if (!QuietFlag) { if (lastHopFlag) { // fprintf(stdout, " Partial loss: %d / %d (%d%%)\n", packetsLost, packetsSent, packetsLost * 100 / packetsSent); double aPath, bPath, r2Path, qPath; double saPath, sbPath; double bLowerPath, bUpperPath; if (Analysis == AnalysisLeastSquares) { PartialMins[i]->slr(aPath, bPath, r2Path, saPath, sbPath); } else if (Analysis == AnalysisKendall) { PartialMins[i]->tau(aPath, bPath, bLowerPath, bUpperPath); } else if (Analysis == AnalysisLeastMedianSquares) { PartialMins[i]->lms(aPath, bPath, r2Path); } else if (Analysis == AnalysisLeastMedianSquaresIntegers) { PartialMins[i]->lmsint(aPath, bPath, r2Path); } else { fprintf(stderr, "Unknown statistical analysis type, exiting...\n"); exit(1); } qPath = PartialResults[i]->queueing(); fprintf(stdout, " Path length: %d hops\n", pathLength); if (Analysis == AnalysisLeastSquares) { fprintf(stdout, " Path char: rtt = %f ms r2 = %f\n", aPath*1000.0, r2Path); } else if (Analysis == AnalysisKendall) { fprintf(stdout, " Path char: rtt = %f ms\n", aPath*1000.0); } else if ((Analysis == AnalysisLeastMedianSquares) || (Analysis == AnalysisLeastMedianSquaresIntegers)) { fprintf(stdout, " Path char: rtt = %f ms, r2 = %f\n", aPath*1000.0, r2Path); } else { fprintf(stderr, "Unknown statistical analysis type, exiting...\n"); exit(1); } if (minBandwidth > 0.0) { fprintf(stdout, " Path bottleneck: %f Kbps\n", minBandwidth); fprintf(stdout, " Path pipe: %d bytes\n", (int) (aPath * (minBandwidth * 1000.0 / 8.0))); } fprintf(stdout, " Path queueing: average = %f ms (%d bytes)\n", qPath, queueingBytes); } else { fprintf(stdout, " End of path not reached after %d hops\n", pathLength); } // We don't know for sure that a time_t is the same size as // one of the members of a struct timeval. So to make ctime(3) // happy, we'll grab the value we want out of the timeval and // put it in a real time_t before calling. time_t temptime; temptime = timeFirst.tv_sec; fprintf(stdout, " Start time: %s", ctime(&temptime)); temptime = timeLast.tv_sec; fprintf(stdout, " End time: %s", ctime(&temptime)); } // // Free memory, close files, etc. // for (i = 0; i < MaxAddressesPerHop; i++) { delete [] checkAddress[i]; checkAddress[i] = NULL; } if (WriteFilename) { fclose(df); } } // // DoTrout // // Input: Pctest structure controlling the type of tests to run. // // Output: None. // // Run a tiny traceroute (intended for use as a part of a larger // measurement infrastructure). // void DoTrout(Pctest *pct) { int i; // universal loop counters FILE *df = NULL; // output file // // Some of the original pchar parameters may need adjusting... Repetitions = 1; // force repetitions to 1 // // Start output // if (!QuietFlag) { fprintf(stdout, "trout to %s (%s) using %s\n", pct->GetTargetName(), pct->GetPrintableAddress(), GetPrintableNetworkProtocol(NetworkProtocol)); fprintf(stdout, "Packet size increments from %d to %d by %d\n", pct->GetMinSize(), Mtu, Increment); } // Print first-hop output line. if (!QuietFlag) { fprintf(stdout, "%2d: %s ", StartHop - 1, pct->GetPrintableAddress(pct->GetOriginAddress())); if (NumericFlag) { fprintf(stdout, "(%s)", pct->GetPrintableAddress(pct->GetOriginAddress())); } else { fprintf(stdout, "(%s)", pct->GetOriginName()); } fprintf(stdout, "\n"); #ifdef HAVE_SNMP if (!ReadFilename && SnmpFlag) { GetIfInfo *gifp; gifp = new GetIfInfo(pct->GetOriginAddress(), pct); PrintIfInfo(gifp); delete gifp; } #endif /* HAVE_SNMP */ } // Initialize statistics save file and write some stuff out if (WriteFilename) { if (strcmp(WriteFilename, "-") == 0) { df = stdout; } else { df = fopen(WriteFilename, "w"); if (df == NULL) { perror("fopen"); exit(1); } } // Write initial parameters to the file fprintf(df, "addresses %s\n", pct->GetAddressFamilyString()); fprintf(df, "targethost %s\n", pct->GetTargetName()); fprintf(df, "src %s\n", pct->GetPrintableAddress(pct->GetOriginAddress())); fprintf(df, "dest %s\n", pct->GetPrintableAddress()); fprintf(df, "hops %d\n", Hops); fprintf(df, "minsize %d\n", pct->GetMinSize()); fprintf(df, "increment %d\n", Increment); fprintf(df, "mtu %d\n", Mtu); fprintf(df, "repetitions %d\n", Repetitions); fprintf(df, "starthop %d\n", StartHop); } // // Begin testing. We increment the hop number, iterating over // the different packet sizes we have available. (Really, we // keep the hop number minus StartHop, and add it back before printing, // since the internal data structures we use start from zero.) // bool lastHopFlag; // *could* be the last hop int packetsLost = 0; int packetsSent = 0; for (i = 0; i < Hops; i++) { unsigned int packetSize; PctestActionType pcta; lastHopFlag = true; int rc; // syscall return code double rtt; TestRecord *tr; // test record for this test // Generate packet size packetSize = Increment * (random() % (Mtu/Increment)); if (packetSize < pct->GetMinSize()) { packetSize = pct->GetMinSize(); } // Let the user know what we're doing if (VerboseFlag) { fprintf(stderr, " hop %2d size %5d\r", i+StartHop, packetSize); } // Set up variables for a test tr = new TestRecord; tr->burst = 1; tr->size = packetSize; tr->hops = i+StartHop; gettimeofday(&tr->tvstart, NULL); tr->tv.tv_sec = 255; tr->tv.tv_usec = 0; tr->replsize = 0; rc = pct->Test(*tr); packetsSent++; if (rc < 0) { exit(1); } // Write to disk if requested. if (WriteFilename) { fprintf(df, "%s\n", tr->htoa(pct)); } // Check for a timeout. If we got one, then increment // the appropriate counter and keep going. if (tr->result == PctestActionTimeout) { packetsLost++; delete tr; continue; // XXX Do we want to retry this probe? } // Process the results we got back. rtt = tr->tv.tv_sec + (tr->tv.tv_usec/1000000.0); IF_DEBUG(2, fprintf(stderr, "bytes = %d, rtt = %f, ip_src = %s, replbytes = %d\n", tr->size, rtt, pct->GetPrintableAddress(tr->icmpSourceAddress), tr->replsize)); // Have the Pctest subclass figure out what the ICMP // type and code fields meant (they're kind of protocol- // independent). pcta = tr->result; // If we received a valid (to us) ICMP message, then // attempt to store timing information. if ((pcta == PctestActionValid) || (pcta == PctestActionValidLasthop)) { // XXX Do we write out something here? } else if (pcta == PctestActionFiltered) { // We hit a firewall or something that's going // to mess with our packets. Give up now. fprintf(stderr, "ICMP: packet filtered\n"); lastHopFlag = true; goto endreps; } else { // With certain types/codes returned by ICMP, we're also // in trouble. It'd be nice if the protocol-dependent // packet processing threw away everything except // time exceeded and port-unreachable. fprintf(stderr, "Unexpected response to probe\n"); abort(); } // If ICMP type was time exceeded, we know this is *not* // the last hop. if (pcta != PctestActionValidLasthop) { lastHopFlag = false; } // Delay between packets struct timeval tvGap; if (GapDist == GapFixed) { tvGap.tv_sec = (long) Gap; tvGap.tv_usec = (long) ((Gap - ((long) Gap)) * 1000000.0); } else if (GapDist == GapExponential) { // Generate exponentially distributed random // value with a mean of Gap. long u; double udub; const double maxudub = pow(2.0, 31.0); // 2^31 double x; u = random(); udub = ((double) u / maxudub); x = - Gap * log(udub); IF_DEBUG(2, fprintf(stderr, "main: exponential gap %f\n", x)); tvGap.tv_sec = (long) x; tvGap.tv_usec = (long) ((x - ((long) x)) * 1000000.0); } else { fprintf(stderr, "Unknown gap type\n"); exit(1); } // Delay for some amount of time. rc = select(0, NULL, NULL, NULL, &tvGap); if (rc < 0) { perror("select"); } endreps: // If we weren't in quiet mode, then clear the line we were on if (VerboseFlag) { fprintf(stdout, "%80s\r", ""); } // Per-hop output if (!QuietFlag) { fprintf(stdout, "%2d: %s ", i + StartHop, pct->GetPrintableAddress(tr->icmpSourceAddress)); if (NumericFlag) { fprintf(stdout, "(%s)", pct->GetPrintableAddress(tr->icmpSourceAddress)); } else { fprintf(stdout, "(%s)", pct->GetName(tr->icmpSourceAddress)); } fprintf(stdout, " %d -> %d bytes: %0.3f ms\n", tr->size, tr->replsize, rtt * 1000.0); } #ifdef HAVE_SNMP if (!ReadFilename && SnmpFlag) { GetIfInfo *gifp; gifp = new GetIfInfo(tr->icmpSourceAddress, pct); PrintIfInfo(gifp); delete gifp; } #endif /* HAVE_SNMP */ delete tr; // If all ICMP messages received were "port unreachable", then // we're done. if (lastHopFlag) { break; } } // End-of-run processing if (!QuietFlag) { } if (WriteFilename) { fclose(df); } } #ifdef HAVE_SNMP // // PrintIfInfo // void PrintIfInfo(const GetIfInfo *gifp) { if (gifp == NULL) { return; } fprintf(stdout, " Description: %s\n", gifp->GetDescription()); fprintf(stdout, " Name: %s\n", gifp->GetName()); fprintf(stdout, " Contact: %s\n", gifp->GetContact()); fprintf(stdout, " Location: %s\n", gifp->GetLocation()); fprintf(stdout, " IfDescription: %s\n", gifp->GetIfDescription()); fprintf(stdout, " Interface: type = %s(%lu)\n", gifp->GetIfTypeString(), gifp->GetIfType()); fprintf(stdout, " speed = %lu bps, MTU = %lu\n", gifp->GetIfSpeed(), gifp->GetIfMtu()); fflush(stdout); } #endif /* HAVE_SNMP */ pchar-1.5/GetIfInfo.cc000644 002001 000024 00000017773 10203463722 014646 0ustar00bmahstaff000000 000000 // -*- c++ -*- // $Id: GetIfInfo.cc 1082 2005-02-12 19:40:04Z bmah $ // #include #ifdef STDC_HEADERS #include #endif /* STDC_HEADERS */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include #include #include #include #include "pc.h" // UCD SNMP includes #include "ucd-snmp/ucd-snmp-config.h" #include "ucd-snmp/asn1.h" #include "ucd-snmp/snmp_api.h" #include "ucd-snmp/snmp_impl.h" #include "ucd-snmp/snmp_client.h" #include "ucd-snmp/mib.h" #include "ucd-snmp/snmp.h" #include "ucd-snmp/system.h" #include "ucd-snmp/default_store.h" #include "GetIfInfo.h" #include "Pctest.h" static oid *snmp_parse_oid(char *argv, oid *root, size_t *rootlen); oid * snmp_parse_oid(char *argv, oid *root, size_t *rootlen) { size_t savlen = *rootlen; if (read_objid(argv,root,rootlen)) { return root; } *rootlen = savlen; if (get_node(argv,root,rootlen)) { return root; } return NULL; } GetIfInfo::GetIfInfo(void *addr, Pctest *pct) : valid_info(false), Description(NULL), Name(NULL), Contact(NULL), Location(NULL), IfDescription(NULL), IfMtu(0), IfSpeed(0), IfType(0) { struct snmp_session session, *ssess; struct snmp_pdu *pdu; struct snmp_pdu *response; struct variable_list *vars; char *community = "public"; char *intoap; long ifnumber; oid name_oid[MAX_OID_LEN]; int status; size_t name_length; size_t ndx; size_t ilen; char cbuff[128]; typedef enum { SysDescr_AVBI = 0, SysContact_AVBI = 1, SysName_AVBI = 2, SysLocation_AVBI = 3, IfIndex_AVBI = 4, AVBI_COUNT = 5 } query_a_vb_index_e; char *query_A_names[AVBI_COUNT] = { "system.sysDescr.0", "system.sysContact.0", "system.sysName.0", "system.sysLocation.0", 0 }; typedef enum { ifDescr_BVBI = 0, ifType_BVBI = 1, ifMtu_BVBI = 2, ifSpeed_BVBI = 3, BVBI_COUNT = 4 } query_b_vb_index_e; char *query_B_names_master[BVBI_COUNT] = { "interfaces.ifTable.ifEntry.ifDescr.", "interfaces.ifTable.ifEntry.ifType.", "interfaces.ifTable.ifEntry.ifMtu.", "interfaces.ifTable.ifEntry.ifSpeed." }; char *query_B_names[BVBI_COUNT]; /* initialize session to default values */ snmp_sess_init(&session); /* read in MIB database and initialize the snmp library*/ init_snmp("snmpapp"); if (session.version == SNMP_DEFAULT_VERSION) { session.version = ds_get_int(DS_LIBRARY_ID, DS_LIB_SNMPVERSION); } /* make our engineID something other than what the localhost might * be using, otherwise the automatic v3 time-synchronization won't work */ //setup_engineID(NULL, "a bogus text string"); intoap = pct->GetPrintableAddress(addr); session.peername = new char[strlen(intoap)+1]; if (session.peername == NULL) { SOCK_CLEANUP; } strcpy(session.peername, intoap); session.community = (unsigned char *)community; session.community_len = strlen(community); strcpy(cbuff, "ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex."); strcat(cbuff, pct->GetPrintableAddress(addr)); query_A_names[IfIndex_AVBI] = cbuff; SOCK_STARTUP; ssess = snmp_open(&session); if (ssess == NULL) { snmp_sess_perror("snmpget", &session); SOCK_CLEANUP; } pdu = snmp_pdu_create(SNMP_MSG_GET); for (ndx = 0; ndx < AVBI_COUNT; ndx++) { name_length = MAX_OID_LEN; if (!snmp_parse_oid(query_A_names[ndx], name_oid, &name_length)) { snmp_close(ssess); SOCK_CLEANUP; } snmp_add_null_var(pdu, name_oid, name_length); } response = NULL; status = snmp_synch_response(ssess, pdu, &response); if ((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR)) { for (ndx = 0, vars = response->variables; vars; ndx++, vars = vars->next_variable) { if (ndx == IfIndex_AVBI) { ifnumber = *(vars->val.integer); } else { char *nsp; nsp = new char[vars->val_len + 1]; strncpy(nsp, (char *)(vars->val.string), vars->val_len); nsp[vars->val_len] = '\0'; switch (ndx) { case SysDescr_AVBI: Description = nsp; break; case SysContact_AVBI: Contact = nsp; break; case SysName_AVBI: Name = nsp; break; case SysLocation_AVBI: Location = nsp; break; default: delete nsp; } } } sprintf(cbuff, "%lu", ifnumber); ilen = strlen(cbuff); for (ndx = 0; ndx < BVBI_COUNT; ndx++) { query_B_names[ndx] = new char[ilen + strlen(query_B_names_master[ndx]) + 1]; strcpy(query_B_names[ndx], query_B_names_master[ndx]); strcat(query_B_names[ndx], cbuff); } snmp_free_pdu(response); response = NULL; pdu = snmp_pdu_create(SNMP_MSG_GET); for (ndx = 0; ndx < BVBI_COUNT; ndx++) { name_length = MAX_OID_LEN; if (!snmp_parse_oid(query_B_names[ndx], name_oid, &name_length)) { goto cleanup; } snmp_add_null_var(pdu, name_oid, name_length); } status = snmp_synch_response(ssess, pdu, &response); if ((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR)) { for (ndx = 0, vars = response->variables; vars; ndx++, vars = vars->next_variable) { switch (ndx) { case ifDescr_BVBI: IfDescription = new char[vars->val_len + 1]; strncpy(IfDescription, (char *)(vars->val.string), vars->val_len); IfDescription[vars->val_len] = '\0'; break; case ifType_BVBI: IfType = *(vars->val.integer); break; case ifMtu_BVBI: IfMtu = *(vars->val.integer); break; case ifSpeed_BVBI: IfSpeed = *(vars->val.integer); break; } } } valid_info = true; } cleanup: if (response) { snmp_free_pdu(response); } snmp_close(ssess); SOCK_CLEANUP; } GetIfInfo::~GetIfInfo() { if (Description) delete Description; if (Name) delete Name; if (Contact) delete Contact; if (Location) delete Location; if (IfDescription) delete IfDescription; } const char unknown_str[] = "-unknown-"; const char * GetIfInfo::GetDescription(void) const { if (!valid_info) { return unknown_str; } return Description; } const char * GetIfInfo::GetName(void) const { if (!valid_info) { return unknown_str; } return Name; } const char * GetIfInfo::GetContact(void) const { if (!valid_info) { return unknown_str; } return Contact; } const char *GetIfInfo::GetLocation(void) const { if (!valid_info) { return unknown_str; } return Location; } const char * GetIfInfo::GetIfDescription(void) const { if (!valid_info) { return unknown_str; } return IfDescription; } uint32_t GetIfInfo::GetIfMtu(void) const { if (!valid_info) { return 0; } return IfMtu; } uint32_t GetIfInfo::GetIfSpeed(void) const { if (!valid_info) { return 0; } return IfSpeed; } uint32_t GetIfInfo::GetIfType(void) const { if (!valid_info) { return 0; } return IfType; } const char *iftype_strs[] = { "other", // = 1, //-- none of the following "regular1822", // = 2, "hdh1822", // = 3, "ddn-x25", // = 4, "rfc877-x25", // = 5, "ethernet-csmacd", // = 6, "iso88023-csmacd", // = 7, "iso88024-tokenBus", // = 8, "iso88025-tokenRing", // = 9, "iso88026-man", // = 10, "starLan", // = 11, "proteon-10Mbit", // = 12, "proteon-80Mbit", // = 13, "hyperchannel", // = 14, "fddi", // = 15, "lapb", // = 16, "sdlc", // = 17, "ds1", // = 18, // -- T-1 "e1", // = 19, // -- european equiv. of T-1 "basicISDN", // = 20, "primaryISDN", // = 21, // -- proprietary serial "propPointToPointSerial",// = 22, "ppp", // = 23, "softwareLoopback", // = 24, "eon", // = 25, // -- CLNP over IP [11] "ethernet-3Mbit", // = 26, "nsip", // = 27, // -- XNS over IP "slip", // = 28, // -- generic SLIP "ultra", // = 29, // -- ULTRA technologies "ds3", // = 30, // -- T-3 "sip" // = 31 // -- SMDS }; const size_t num_iftype_strs = sizeof(iftype_strs)/sizeof(char *); const char * GetIfInfo::GetIfTypeString(void) const { if (!valid_info) { return unknown_str; } if ((IfType == 0 ) || (IfType > num_iftype_strs)) { return unknown_str; } return iftype_strs[IfType-1]; } pchar-1.5/GetIfInfo.h000644 002001 000024 00000001465 10203463722 014477 0ustar00bmahstaff000000 000000 // -*- c++ -*- // $Id: GetIfInfo.h 1082 2005-02-12 19:40:04Z bmah $ // #ifndef GETIFINFO_H #define GETIFINFO_H #include "Pctest.h" class GetIfInfo { public: GetIfInfo(void *, Pctest *); ~GetIfInfo(); bool IsValid(void); const char * GetDescription(void) const; const char * GetIfInfo::GetName(void) const; const char * GetContact(void) const; const char * GetLocation(void) const; const char * GetIfDescription(void) const; uint32_t GetIfMtu(void) const; uint32_t GetIfSpeed(void) const; uint32_t GetIfType(void) const; const char * GetIfTypeString(void) const; protected: char * Description; char * Name; char * Contact; char * Location; char * IfDescription; uint32_t IfMtu; uint32_t IfSpeed; int IfType; bool valid_info; private: }; #endif /* GETIFINFO_H */ pchar-1.5/Kendall.cc000644 002001 000024 00000006450 10203463722 014374 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: Kendall.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: Kendall.cc 1082 2005-02-12 19:40:04Z bmah $ // // Kendall.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // #include "pc.h" #include "Kendall.h" // Quantiles of the Kendall test statistic T, as taken // from Appendix A11 of W. J. Conover, "Practical // Nonparametric Statistics", Third Edition, John Wiley & // Sons, 1999. KendallLine Kendall::table[] = { { 4, { 4, 4, 6, 6, 6 } }, { 5, { 6, 6, 8, 8, 10 } }, { 6, { 7, 9, 11, 11, 13 } }, { 7, { 9, 11, 13, 15, 17 } }, { 8, { 10, 14, 16, 18, 20 } }, { 9, { 12, 16, 18, 22, 24 } }, { 10, { 15, 19, 21, 25, 27 } }, { 11, { 17, 21, 25, 29, 31 } }, { 12, { 18, 24, 28, 34, 36 } }, { 13, { 22, 26, 32, 38, 42 } }, { 14, { 23, 31, 35, 41, 45 } }, { 15, { 27, 33, 39, 47, 51 } }, { 16, { 28, 36, 44, 50, 56 } }, { 17, { 32, 40, 48, 56, 62 } }, { 19, { 37, 47, 55, 65, 73 } }, { 20, { 40, 50, 60, 70, 78 } }, { 21, { 42, 54, 64, 78, 84 } }, { 22, { 45, 59, 69, 81, 89 } }, { 23, { 49, 63, 73, 87, 97 } }, { 24, { 52, 66, 78, 92, 102 } }, { 25, { 56, 70, 84, 98, 108 } }, { 26, { 59, 75, 89, 105, 115 } }, { 27, { 61, 79, 93, 111, 123 } }, { 28, { 66, 84, 98, 116, 128 } }, { 29, { 68, 88, 104, 124, 136 } }, { 30, { 76, 93, 109, 129, 143 } }, { 31, { 75, 97, 115, 135, 149 } }, { 32, { 80, 102, 120, 142, 158 } }, { 33, { 84, 106, 126, 150, 164 } }, { 34, { 87, 111, 131, 155, 173 } }, { 35, { 91, 115, 137, 163, 179 } }, { 36, { 97, 120, 114, 170, 188 } }, { 37, { 98, 126, 150, 176, 198 } }, { 38, { 103, 131, 155, 183, 203 } }, { 39, { 107, 137, 161, 191, 211 } }, { 40, { 110, 143, 168, 198, 220 } }, { 41, { 114, 143, 174, 206, 228 } }, { 42, { 119, 151, 181, 213, 235 } }, { 43, { 123, 157, 187, 221, 245 } }, { 44, { 128, 162, 194, 228, 252 } }, { 45, { 132, 168, 200, 236, 262 } }, { 46, { 135, 173, 207, 245, 271 } }, { 47, { 141, 179, 213, 254, 279 } }, { 48, { 144, 186, 220, 260, 288 } }, { 49, { 150, 190, 228, 268, 296 } }, { 50, { 153, 197, 233, 277, 305 } }, { 51, { 159, 203, 241, 285, 315 } }, { 52, { 162, 208, 248, 294, 324 } }, { 53, { 168, 214, 256, 302, 334 } }, { 54, { 173, 221, 263, 311, 343 } }, { 55, { 177, 227, 269, 319, 353 } }, { 56, { 182, 232, 276, 328, 362 } }, { 57, { 186, 240, 284, 336, 372 } }, { 58, { 191, 245, 291, 345, 381 } }, { 59, { 197, 251, 299, 355, 391 } }, { 60, { 202, 258, 306, 364, 402 } }, }; // // Kendall::T // // Input: // // Output: // // For a given n and percentile, return the quantile of the // Kendall's T test statistic. 0 is returned for a failed // lookup, where no value could be determined or computed. // unsigned int Kendall::T(unsigned int n, KendallPType p) { int i; // Basically, just a fancy table lookup for (i = 0; i < sizeof(table)/sizeof(KendallLine); i++) { if (table[i].n == n) { return table[i].value[(int) p]; } } return 0; } pchar-1.5/Kendall.h000644 002001 000024 00000001734 10203463722 014236 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: Kendall.h 1082 2005-02-12 19:40:04Z bmah $ // // Kendall.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // typedef enum { KendallP900, KendallP950, KendallP975, KendallP990, KendallP995, KendallPMax } KendallPType; typedef struct { unsigned int n; unsigned int value[KendallPMax]; } KendallLine; class Kendall { public: static unsigned int T(unsigned int n, KendallPType p); private: static KendallLine table[]; }; pchar-1.5/Pctest.cc000644 002001 000024 00000013171 10203463722 014262 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: Pctest.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: Pctest.cc 1082 2005-02-12 19:40:04Z bmah $ // // Pctest.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Placeholder for virtual base class of tests. // #include #ifdef STDC_HEADERS #include #include #endif /* STDC_HEADERS */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #ifdef HAVE_PCAP #include #ifdef __OpenBSD__ #include #include #include #else #include #endif #ifdef HAVE_BPF #include #endif /* HAVE_BPF */ #endif /* HAVE_PCAP */ #include "Pctest.h" // // Pctest::Pctest // // Pctest constructor // Pctest::Pctest() { initialized = 0; TimeSyscall(syscallTime); IF_DEBUG(3, fprintf(stderr, "syscallTime.tv_usec = %ld\n", syscallTime.tv_usec)); #ifdef HAVE_PCAP // If we're running with pcap enabled, set this up. extern bool PcapFlag; extern char PcapErrBuf[]; extern char *Interface; extern unsigned int Mtu; extern unsigned int Timeout; int fileno; if (PcapFlag) { if (Interface == NULL) { Interface = pcap_lookupdev(PcapErrBuf); if (Interface == NULL) { fprintf(stderr, "%s\n", PcapErrBuf); exit(1); } } pc = pcap_open_live(Interface, Mtu, 0, 1000 * Timeout, PcapErrBuf); if (pc == NULL) { fprintf(stderr, "%s\n", PcapErrBuf); exit(1); } if (pcap_lookupnet(Interface, &netp, &maskp, PcapErrBuf) < 0) { fprintf(stderr, "%s\n", PcapErrBuf); exit(1); } fileno = pcap_fileno(pc); if (fileno < 0) { fprintf(stderr, "pcap_fileno() failed\n"); exit(1); } #ifdef HAVE_BPF // Set "immediate" mode in BPF. We need this to avoid libpcap // waiting the entire timeout period before passing any received // packets to us. u_int immediate = 1; if (ioctl(fileno, BIOCIMMEDIATE, &immediate) < 0) { perror("ioctl(BIOCIMMEDIATE)"); exit(1); } #endif /* HAVE_BPF */ } #endif /* HAVE_PCAP */ } // // Pctest::~Pctest // // Pctest destructor // Pctest::~Pctest() { #ifdef HAVE_PCAP extern bool PcapFlag; if (PcapFlag) { if (pc != NULL) { pcap_close(pc); } } #endif /* HAVE_PCAP */ } // // Pctest::TimeSyscall // // Input: None // // Output: timeval to hold gettimeofday overhead // // Determine the gettimeofday() syscall overhead. Probably this is going // to be negligible compared to the data we're getting back from the // network. // void Pctest::TimeSyscall(struct timeval &diff) { struct timeval t1, t2; gettimeofday(&t1, NULL); gettimeofday(&t2, NULL); diff.tv_sec = t2.tv_sec - t1.tv_sec; diff.tv_usec = t2.tv_usec - t1.tv_usec; if (diff.tv_usec < 0) { diff.tv_usec += 1000000; diff.tv_sec--; } } // // Pctest::GeneratePayload // // Input: Number of bytes to get // // Output: Pointer to payload (owned by caller, NULL if an error) // // Generate a random number of bytes in a heap-allocated buffer. // for use as a payload. Having random data in the packet will hopefully // defeat link-level compression. // char *Pctest::GeneratePayload(int size) { char *buf; int i; if (size <= 0) { return NULL; } buf = new char[size]; if (buf == NULL) { return buf; } for (i = 0; i < size; i++) { buf[i] = random() & 0xff; } return buf; } // // Pctest::InCksum // // Input: addr, len (buffer to checksum) // // Output: IP checksum for this buffer in return value // // Compute IP checksum for a buffer. It's put here because it's fairly // general-purpose, and both the IPv4 and IPv6 tests could potentially // make use of it. RFC 1071 has implementation notes, and we use // the sample implementation (essentially unmodified) therein. // u_short Pctest::InCksum(u_short *addr, int len) { register int sum = 0; u_short checksum; while (len > 1) { sum += *addr++; len -= 2; } // Add left-over byte, if any if (len > 0) { sum += * (u_char *) addr; } // fold 32-bit sum to 16 bits while (sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } checksum = ~sum; return(checksum); } #ifdef HAVE_PCAP // // Pctest::callback // // Inputs: Object pointer, pcap_pkthdr pointer, pointer to packet // data. // // Outputs: None. // // pcap callback routine. // // XXX This function needs some work. It only deals with Ethernet- // like datalinks. We need something like what tcpdump's packet- // printing does. // void Pctest::callback(u_char *puc, const struct pcap_pkthdr *ph, const u_char *pd) { Pctest *obj = (Pctest *) puc; obj->tvAfter.tv_sec = ph->ts.tv_sec; obj->tvAfter.tv_usec = ph->ts.tv_usec; obj->packetLength = ph->len; obj->packet = (u_char *) pd; // we need to compute an offset to this switch (pcap_datalink(obj->pc)) { case DLT_NULL: break; case DLT_EN10MB: obj->packetLength -= sizeof(struct ether_header); obj->packet += sizeof(struct ether_header); break; default: fprintf(stderr, "Unknown datalink layer %d\n", pcap_datalink(obj->pc)); exit(1); break; } } #endif /* HAVE_PCAP */ pchar-1.5/Pctest.h000644 002001 000024 00000007327 10203463722 014132 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: Pctest.h 1082 2005-02-12 19:40:04Z bmah $ // // Pctest.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header for virtual base class of tests. A particular protocol (e.g. // IPv4, IPv6) will override the methods of this base class // with protocol-specific implementations. // // #ifndef PCTEST_H #define PCTEST_H #include #if STDC_HEADERS #include #include #endif /* STDC_HEADERS */ #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #if HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" // #include "TestRecord.h" class TestRecord; // Action codes. ICMPv4 and ICMPv6 have different values for their type // and code fields. The Pctest abstracts these differences. typedef enum { PctestActionReserved = 0, // reserved code PctestActionValid = 1, // store valid measurement (e.g. ICMP // time exceeded) PctestActionValidLasthop = 2, // store valid measurement, this // is last hop (e.g. ICMP port unreachable) PctestActionFiltered = 3, // packets filtered, give up (e.g. // ICMP prohibited) PctestActionTimeout = 4, // Timeout PctestActionAbort = 255 // huh? we haven't a clue } PctestActionType; class Pctest { public: Pctest(); virtual ~Pctest(); // Get gettimeofday() system call overhead. virtual void TimeSyscall(struct timeval &diff); // Get random payload buffer virtual char *GeneratePayload(int size); // Determine origin address for our tests (resolve if necessary) virtual int SetOriginName(char *origin) = 0; // Get origin host name and address char *GetOriginName() { return originName; }; virtual void *GetOriginAddress() = 0; // Set target host for our tests (resolve if necessary) virtual int SetTargetName(char *target) = 0; // Get target host name and address char *GetTargetName() { return targetName; }; virtual char *GetPrintableAddress() = 0; virtual char *GetPrintableAddress(void *a) = 0; virtual char *GetName(void *a) = 0; virtual char *GetAddressFamilyString() = 0; virtual int GetAddressFamily() = 0; // Get input and output sockets needed virtual int GetSocketOut() = 0; virtual int GetSocketIn() = 0; // Perform a test and return statistics virtual int Test(TestRecord &tr) = 0; virtual unsigned int GetMinSize() = 0; protected: int initialized; // initialization flag char *originName; // origin hostname char *targetName; // target hostname struct timeval tvBefore, tvAfter; // timestamps struct timeval syscallTime; // estimated overhead for gettimeofday() #if HAVE_PCAP pcap_t *pc; // pcap structure bpf_u_int32 netp, maskp; // net and mask parameters struct bpf_program fp; // filter program // pcap callback static void callback(u_char *puc, const struct pcap_pkthdr *ph, const u_char *pd); // Fields for callback to communicate information back to the // main object's methods u_char *packet; // start of IP packet unsigned int packetLength; // packet length #endif /* HAVE_PCAP */ u_short InCksum(u_short *addr, int len); // IP checksum routine }; #endif /* PCTEST_H */ pchar-1.5/PctestIpv4.cc000644 002001 000024 00000025312 10203463722 015025 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests // #include #include #include #include #include #include #include #include #include #include "pc.h" #include "PctestIpv4.h" extern unsigned int Mtu; // // PctestIpv4::SetOriginName // // Input: origin hostname // // Output: success code (negative if error) // // Attempt to set the origin of probe packets emanating from this host, // for tests where it is applicable, using protocol family-dependent // resolution as necessary. If no origin hostname is given, // then use the target address to compute the correct outgoing interface. // originName and originAddress are set. // int PctestIpv4::SetOriginName(char *o) { // If nothing was passed in, then bind a dummy socket to try // to figure out where packets exit this host. if (o == NULL) { int dummySock; struct sockaddr_in dummyAddr, localAddr; #ifdef HAVE_SOCKLEN_T socklen_t localAddrLength; #else /* HAVE_SOCKLEN_T */ #ifdef NEED_GETSOCKNAME_HACK int localAddrLength; #else /* NEED_GETSOCKNAME_HACK */ size_t localAddrLength; #endif /* NEED_GETSOCKNAME_HACK */ #endif /* HAVE_SOCKLEN_T */ // Create socket, then connect to it, and then read out // the local socket address with a getsockname call. dummySock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (dummySock < 0) { perror("socket"); return -1; } memset((void *) &dummyAddr, 0, sizeof(struct sockaddr_in)); #ifdef HAVE_SOCKADDR_SA_LEN dummyAddr.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_SOCKADDR_SA_LEN */ dummyAddr.sin_family = AF_INET; dummyAddr.sin_port = htons(32768); // port number irrelevant memcpy(&dummyAddr.sin_addr, &targetAddress, sizeof(struct in_addr)); if (connect(dummySock, (sockaddr *) &dummyAddr, sizeof(struct sockaddr_in)) < 0) { perror("connect"); return -1; } localAddrLength = sizeof(sockaddr_in); memset((void *) &localAddr, 0, sizeof(struct sockaddr_in)); if (getsockname(dummySock, (struct sockaddr *) &localAddr, &localAddrLength) < 0) { perror("getsockname"); return -1; } // Got the local address, now do a reverse DNS looup memcpy(&originAddress, &localAddr.sin_addr, sizeof(struct in_addr)); originName = strdup(GetName((char *) &originAddress)); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for origin hostname.\n"); return -1; } close(dummySock); } // User gave a source name/address. Attempt to resolve, if possible. else { struct hostent *host; // resolver host entry host = gethostbyname(o); // Resolver failed if (host == NULL) { #ifdef HAVE_HERROR herror(o); #else fprintf(stderr, "%s: Host not found\n", o); #endif /* HAVE_HERROR */ memset((void *) &originAddress, 0, sizeof(struct in_addr)); originName = strdup(o); if (originName == NULL) { fprintf(stderr, "Couldn't allocate space for origin hostname.\n"); return -1; } return -1; } IF_DEBUG(3, fprintf(stderr, "h_name = %s\n", host->h_name)); IF_DEBUG(3, fprintf(stderr, "h_length = %d\n", host->h_length)); IF_DEBUG(3, fprintf(stderr, "h_addr_list[0] = %x\n", *((int *)(host->h_addr_list[0])))); // Get IP address memcpy(&originAddress, host->h_addr_list[0], host->h_length); // Make a copy of the canonical hostname originName = strdup(host->h_name); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for origin hostname.\n"); return -1; } } return 0; } // // PctestIpv4::SetTargetName // // Input: target hostname (target) // // Output: success code (negative if error) // // Set target name and do protocol-dependent resolving to get a // network address. In case of an error, we're responsible for // printing some error message. // int PctestIpv4::SetTargetName(char *t) { int len; // temporary buffer length struct hostent *host; // resolver host entry // Attempt to resolve, if possible host = gethostbyname(t); // Resolver failed if (host == NULL) { // Some systems don't have herror (non-BSD?), so for those, // we'll cobble together an error message. #ifdef HAVE_HERROR herror(t); #else fprintf(stderr, "%s: Host not found\n", t); #endif /* HAVE_HERROR */ memset((void *) &targetAddress, 0, sizeof(struct in_addr)); targetName = strdup(t); if (targetName == NULL) { fprintf(stderr, "Couldn't allocate memory for target hostname.\n"); return -1; } return -1; } IF_DEBUG(3, fprintf(stderr, "h_name = %s\n", host->h_name)); IF_DEBUG(3, fprintf(stderr, "h_length = %d\n", host->h_length)); IF_DEBUG(3, fprintf(stderr, "h_addr_list[0] = %x\n", *((int *)(host->h_addr_list[0])))); // Get IP address memcpy(&targetAddress, host->h_addr_list[0], host->h_length); memset((void *) &targetSocketAddress, 0, sizeof(struct sockaddr_in)); // Note: Only BSD4.3Reno and later have sin_len in struct // sockaddr_in, so we need to test for it. #ifdef HAVE_SOCKADDR_SA_LEN targetSocketAddress.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_SOCKADDR_SA_LEN */ targetSocketAddress.sin_family = AF_INET; targetSocketAddress.sin_port = htons(0); // set on each test memcpy(&targetSocketAddress.sin_addr, host->h_addr_list[0], host->h_length); // Make a copy of the canonical hostname targetName = strdup(host->h_name); if (targetName == NULL) { fprintf(stderr, "Couldn't allocate memory for target hostname.\n"); return -1; } return 0; } // // GetSocketIn // // Input: None // // Output: In return value, returns socket number. // // Get input socket of an appropriate type. // int PctestIpv4::GetSocketIn() { struct protoent *icmpProto = getprotobyname("icmp"); // be really anal-retentive if (icmpProto == NULL) { fprintf(stderr, "Warning: Couldn't determine ICMP protocol number, using 1\n"); proto = 1; // instance variable of PctestIpv4 } else { proto = icmpProto->p_proto; } socketIn = socket(PF_INET, SOCK_RAW, proto); if (socketIn < 0) { perror("socket"); return socketIn; } return socketIn; } // // PctestIpv4::GetPrintableAddress // // Input: None // // Output: Pointer to ASCII representation of address (in return // value) // char *PctestIpv4::GetPrintableAddress() { return (GetPrintableAddress(&targetAddress)); } // // PctestIpv4::GetPrintableAddress // // Input: Pointer to address structure // // Output: Pointer to ASCII representation of address (in return // value) // char *PctestIpv4::GetPrintableAddress(void *a) { return (inet_ntoa(*((struct in_addr *) a))); } // // PctestIpv4::GetName // // Input: Pointer to address structure // // Output: Pointer to ASCII representation of name (in return // value) // char *PctestIpv4::GetName(void *a) { struct hostent *host; host = gethostbyaddr((char *) a, sizeof(struct in_addr), AF_INET); if (host) { return (host->h_name); } else { return (GetPrintableAddress(a)); } } // // PctestIpv4::GenerateAdvancePacket // // Generate an ICMP throwaway packet, with all headers, owned by // the caller. This is an ICMP echo reply packet, crafted in // such a way that it will (should) travel all the way to its target, // but be dropped by the target without generating anything coming // back at us. In other words, it just occupies bandwidth on links. // char *PctestIpv4::GenerateAdvancePacket(TestRecord &tr) { // Parameters stored as globals extern unsigned int Tos; // If the requested sending size is too small or too large, // then return an error. The caller should have figured out the // minimum sending size by calling Pctest::GetMinSize(). // if ((tr.size < GetMinSize()) || (tr.size > IP_MAXPACKET)) { // fprintf(stderr, "Bad packet size\n"); // return NULL; // } // Make up a ICMP packet to send out. struct ip ipHeader; memset(&ipHeader, 0, sizeof(ipHeader)); #ifdef __osf__ // Tru64 does not declare ip_hl if __STDC__ == 1 ipHeader.ip_vhl = (sizeof(ip) >> 2) | (4 << 4); #else ipHeader.ip_hl = sizeof(ip) >> 2; ipHeader.ip_v = 4; #endif /* __osf__ */ ipHeader.ip_tos = Tos; #ifdef linux ipHeader.ip_len = htons(tr.size); #else ipHeader.ip_len = Mtu; #endif /* linux */ ipHeader.ip_id = htons(0); #ifdef linux ipHeader.ip_off = htons(IP_DF); #else ipHeader.ip_off = IP_DF; #endif /* linux */ ipHeader.ip_ttl = MAXTTL; ipHeader.ip_p = IPPROTO_ICMP; ipHeader.ip_sum = 0; memcpy(&(ipHeader.ip_src), &(originAddress), sizeof(struct in_addr)); memcpy(&(ipHeader.ip_dst), &(targetSocketAddress.sin_addr), sizeof(struct in_addr)); // Make up ICMP header. int icmpPayloadSize = Mtu - sizeof(ip) - ICMP_MINLEN; // need to hardcode size of headers for an ICMP // echo reply packet struct icmp icmpHeader; icmpHeader.icmp_type = ICMP_ECHOREPLY; icmpHeader.icmp_code = 0; icmpHeader.icmp_cksum = htons(0); // compute checksum icmpHeader.icmp_id = htons(icmpId); icmpHeader.icmp_seq = htons(icmpSequence++); // ICMP payload char *icmpPayload; icmpPayload = GeneratePayload(icmpPayloadSize); if (icmpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return NULL; } // Build the packet now. char *ipPacket; int ipPacketSize; ipPacketSize = sizeof(ip) + ICMP_MINLEN + icmpPayloadSize; ipPacket = new char[ipPacketSize]; if (ipPacket == NULL) { fprintf(stderr, "Couldn't allocate space for packet\n"); return NULL; } memcpy(ipPacket, &ipHeader, sizeof(ipHeader)); memcpy(ipPacket + sizeof(ipHeader), &icmpHeader, ICMP_MINLEN); memcpy(ipPacket + sizeof(ipHeader) + ICMP_MINLEN, icmpPayload, icmpPayloadSize); // Compute ICMP checksum. This is much simpler than the TCP or // UDP checksums, because there is no pseudo-header. u_int checksum; checksum = (u_short) InCksum((u_short *) (ipPacket + sizeof(ipHeader)), ICMP_MINLEN + icmpPayloadSize); ((icmp *)(ipPacket + sizeof(ipHeader)))->icmp_cksum = checksum; return ipPacket; } pchar-1.5/PctestIpv4.h000644 002001 000024 00000004720 10203463722 014667 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv4 tests // #ifndef PCTESTIPV4_H #define PCTESTIPV4_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "Pctest.h" #include "TestRecord.h" class PctestIpv4 : public Pctest { public: PctestIpv4() { socketOut = 0; socketIn = 0; destPort = 32768; icmpId = (u_short) getpid(); // cache PID for ICMP ID field icmpSequence = 0; // init sequence number }; PctestIpv4(int p) { socketOut = 0; socketIn = 0; destPort = p; icmpId = (u_short) getpid(); // cache PID for ICMP ID field icmpSequence = 0; // init sequence number }; virtual ~PctestIpv4() { if (socketOut > 0) { close(socketOut); } if (socketIn > 0) { close(socketIn); } }; virtual int SetOriginName(char *origin); virtual void *GetOriginAddress() {return &originAddress;}; virtual int SetTargetName(char *target); virtual int GetSocketIn(); virtual char *GetPrintableAddress(); virtual char *GetPrintableAddress(void *a); virtual char *GetName(void *a); virtual char *GetAddressFamilyString() { return "AF_INET"; }; virtual int GetAddressFamily() { return (AF_INET); }; protected: struct in_addr originAddress; struct in_addr targetAddress; struct sockaddr_in targetSocketAddress; int socketOut; // output socket (RAW) int socketIn; // input socket (ICMP) int proto; // (hopefully) ICMP protocol number int destPort; // destination port number u_short icmpId; // ICMP ID u_short icmpSequence; // ICMP sequence number virtual char *GenerateAdvancePacket(TestRecord &tr); }; #endif /* PCTESTIPV4_H */ pchar-1.5/PctestIpv4File.cc000644 002001 000024 00000017163 10203463722 015632 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4File.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4File.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4File.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests reading test data from previously-saved results // #include #include #include #include #include #include #include #include #include #include "pc.h" #include "PctestIpv4File.h" #include "TestRecord.h" extern unsigned int Mtu; // // PctestIpv4File::GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, but for us it's a no-op. // int PctestIpv4File::GetSocketOut() { return 0; } // // PctestIpv4File::GetSocketIn // // Input: None // // Output: In return value, returns socket number. // // Override the superclass behavior...we don't use sockets. // int PctestIpv4File::GetSocketIn() { return 0; } // // PctestIpv4File::SetOriginName // // Input: ignored // // Output: success code (negative if an error) // // This method exists primarily to override PctestIpv4::SetOriginName // to prevent it from overwriting the originAddress and originName // members, which were set when the trace file was read using // PctestIpv4File::SetTargetName. All we need to do here is a // name lookup. // int PctestIpv4File::SetOriginName(char *t) { struct hostent *host; // resolver hostname entry originName = strdup(GetName((char *) &originAddress)); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for origin hostname.\n"); return -1; } } // // PctestIpv4File::SetTargetName // // Input: ignored // // Output: success code (negative if error) // // For protocols that actually send packets on the network, // do name resolution on the target host. For this case, however, // we read in the savefile, for later use by PctestIpv4File::Test. // As with the other, similar routine(s), we're responsible for // printing any error messages that come up, since they're likely // to be domain-specific. // int PctestIpv4File::SetTargetName(char *t) { extern unsigned int Burst; // maximum burst size extern unsigned int Hops; // number of hops extern unsigned int Increment; // packet size increment extern unsigned int Mtu; // transfer MTU extern char *ReadFilename; // user-supplied filename extern unsigned int Repetitions; // number of repetitions per packet size extern unsigned int StartHop; // starting hop number extern int VerboseFlag; // -v from command-line bool done = false; // done reading? int linenum = 1; // line number const unsigned int buflen = 1024; // maximum line length char buf[buflen]; // line buffer char *s; // return value from fgets TestRecord *tr; // test record read from file TestRecord *trstail = NULL; // If the user didn't supply us with a command-line filename, // it's an error. if (!ReadFilename) { fprintf(stderr, "No filename specified for -r\n"); return -1; } // Try to open the file f = fopen(ReadFilename, "r"); if (!f) { perror("fopen"); return -1; } // Loop until finished while (!done) { s = fgets(buf, buflen, f); // See if we're done... if (!s) { if (ferror(f)) { // error condition perror("fgets"); } done = true; goto doneline; } // Process a line. We're going to make a very simple parser // here and in TestRecord::atoh(). // char *cur; // First, throw out all blank (or almost blank) lines... for (cur = s; *cur != '\0'; cur++) { if (!isspace(*cur)) { break; } } if (*cur == '\0') { goto doneline; } // Then, look for comment lines if (*s == '#') { goto doneline; } if (strncasecmp(s, "probe ", 6) == 0) { tr = TestRecord::atoh(s, this); if (tr == NULL) { return -1; } tr->used = false; // Try to keep the SLL in the same order that we read stuff. // To do this efficiently means we need to (temporarily) // keep a tail pointer. if (trstail) { trstail->next = tr; trstail = tr; tr->next = NULL; } else { trs = tr; trstail = tr; tr->next = NULL; } } else if (strncasecmp(s, "src ", 4) == 0) { char t[128]; sscanf(s, "src %127s", t); originAddress.s_addr = inet_addr(t); } else if (strncasecmp(s, "dest ", 5) == 0) { char t[128]; sscanf(s, "dest %127s", t); targetAddress.s_addr = inet_addr(t); } else if (strncasecmp(s, "burst ", 6) == 0) { sscanf(s, "burst %d", &Burst); } else if (strncasecmp(s, "minsize ", 8) == 0) { sscanf(s, "minsize %d", &minsize); } // hops: else if (strncasecmp(s, "hops ", 5) == 0) { sscanf(s, "hops %d", &Hops); } else if (strncasecmp(s, "increment ", 10) == 0) { sscanf(s, "increment %d", &Increment); } else if (strncasecmp(s, "mtu ", 4) == 0) { sscanf(s, "mtu %d", &Mtu); } else if (strncasecmp(s, "repetitions ", 12) == 0) { sscanf(s, "repetitions %d", &Repetitions); } else if (strncasecmp(s, "starthop ", 9) == 0) { sscanf(s, "starthop %d", &StartHop); } else if (strncasecmp(s, "targethost ", 11) == 0) { char t[128]; sscanf(s, "targethost %127s", t); PctestIpv4::SetTargetName(t); } else if (strncasecmp(s, "addresses ", 10) == 0) { // Ignore lines that look like this; we already parsed // them to select this object. } // We can semi-quietly ignore everything else from this point. // If we're in verbose mode, we can yell about it. else if (VerboseFlag) { fprintf(stderr, "warning: ignoring line %s", s); } doneline: linenum++; } // Done with file fclose(f); f = NULL; return 0; } // // PctestIpv4File::Test // // Input: // // Output: // // A negative icmpCode indicates a timeout. // int PctestIpv4File::Test(TestRecord &tr) { TestRecord *cur; // Loop through our set of TestRecords that we've already read // in, find the first one that matches both the hops and size, // and isn't used yet. for (cur = trs; cur; cur = cur->next) { if ((!cur->used) && (cur->size == tr.size + ((tr.burst - 1) * Mtu)) && (cur->hops == tr.hops)) { // Found one! Now copy everything over from our TestRecord // into the object provided by the caller. tr.tvstart.tv_sec = cur->tvstart.tv_sec; tr.tvstart.tv_usec = cur->tvstart.tv_usec; tr.tv.tv_sec = cur->tv.tv_sec; tr.tv.tv_usec = cur->tv.tv_usec; tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, cur->icmpSourceAddress, sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.size = cur->size; tr.replsize = cur->replsize; tr.result = cur->result; cur->used = true; return 0; } } // Error exit fprintf(stderr, "Couldn't find enough records\n"); return -1; } // // PctestIpv4File::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv4File::GetMinSize() { return (minsize); } pchar-1.5/PctestIpv4File.h000644 002001 000024 00000003254 10203463722 015470 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4File.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4File.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv4 tests reading previously saved data from a file. // #ifndef PCTESTIPV4FILE_H #define PCTESTIPV4FILE_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv4.h" class PctestIpv4File : public PctestIpv4 { public: PctestIpv4File() { PctestIpv4File(0); }; PctestIpv4File(int p) { f = NULL; trs = NULL; }; virtual ~PctestIpv4File() { if (f) { fclose(f); } }; virtual int SetOriginName(char *t); virtual int SetTargetName(char *t); virtual int GetSocketOut(); virtual int GetSocketIn(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); protected: FILE *f; TestRecord *trs; // SLL of records read from the file u_int minsize; // minimum packet size }; #endif /* PCTESTIPV4FILE_H */ pchar-1.5/PctestIpv4Udp.cc000644 002001 000024 00000024155 10203463722 015502 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4Udp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4Udp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Udp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests using UDP // #include #include #include #include #include #include #include #include #include "pc.h" #include "PctestIpv4Udp.h" #include "TestRecord.h" // // GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, store in socketOut. // int PctestIpv4Udp::GetSocketOut() { int rc; socketOut = socket(AF_INET, SOCK_DGRAM, 0); if (socketOut < 0) { perror("socket"); return socketOut; } #ifdef linux // Linux needs SO_BSDCOMPAT enabled on our UDP socket, to avoid // getting ICMP errors when we send packets out. int bsdcompatOption; bsdcompatOption = 1; rc = setsockopt(socketOut, SOL_SOCKET, SO_BSDCOMPAT, &bsdcompatOption, sizeof(bsdcompatOption)); if (rc < 0) { perror("setsockopt(SO_BSDCOMPAT)"); return rc; } #endif /* linux */ // Make up a socket address structure for the source address // and attempt to bind the output socket to it. struct sockaddr_in originSocketAddress; memset((void *) &originSocketAddress, 0, sizeof(struct sockaddr_in)); #ifdef HAVE_SOCKADDR_SA_LEN originSocketAddress.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_SOCKADDR_SA_LEN */ originSocketAddress.sin_family = AF_INET; originSocketAddress.sin_port = htons(0); memcpy(&(originSocketAddress.sin_addr), &originAddress, sizeof(in_addr)); rc = bind(socketOut, (struct sockaddr *) &originSocketAddress, sizeof(originSocketAddress)); if (rc < 0) { perror("bind()"); return rc; } return socketOut; } // // PctestIpv4Udp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv4Udp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; // Parameters stored as globals extern unsigned int Tos; extern int Timeout; // If the requested sending size is too small, then return an // error. The caller should have figured out the minimum sending // size by calling Pctest::GetMinSize(). if (tr.size < GetMinSize()) { return -1; } // This protocol module doesn't support advance packets if (tr.burst > 1) { fprintf(stderr, "Protocol module has no support for burst parameter > 1\n"); return -1; } // Make up a UDP packet to send out. int udpPayloadSize = tr.size - sizeof(ip) - sizeof(udphdr); char *udpPayload; udpPayload = GeneratePayload(udpPayloadSize); if (udpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } targetSocketAddress.sin_port = htons(destPort++); // Set TTL. We sort of need to do a type conversion on hops, since // it gets plugged into a setsockopt argument. rc = setsockopt(socketOut, IPPROTO_IP, IP_TTL, (char *) &tr.hops, sizeof(tr.hops)); if (rc < 0) { perror("setsockopt(IP_TTL)"); return rc; } // Set TOS bits rc = setsockopt(socketOut, IPPROTO_IP, IP_TOS, (char *) &Tos, sizeof(Tos)); if (rc < 0) { perror("setsockopt(IP_TOS)"); return rc; } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmpPacket; icmpPacket = (char *) malloc(IP_MAXPACKET); if (icmpPacket == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } // Set timeout value and socket select parameters timeout.tv_sec = Timeout; timeout.tv_usec = 0; FD_ZERO(&readFds); FD_SET(socketIn, &readFds); // Timestamp before gettimeofday(&tvBefore, NULL); // Send UDP packet rc = sendto(socketOut, udpPayload, udpPayloadSize, 0, (struct sockaddr *) &targetSocketAddress, sizeof(struct sockaddr_in)); if (rc < 0) { perror("sendto"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { // Select and wait for an ICMP response or a timeout rc = select(FD_SETSIZE, &readFds, NULL, NULL, &timeout); if (rc < 0) { perror("select"); goto exittest; } // Timestamp after and update test record timestamp fields gettimeofday(&tvAfter, NULL); tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); rc = read(socketIn, icmpPacket, IP_MAXPACKET); if (rc < 0) { perror("read"); goto exittest; } tr.replsize = rc; // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet.. ip *ipHeader, *ipHeader2; icmp *icmpHeader; udphdr *udpHeader; unsigned int ipHeaderLength, ipHeaderLength2; if (tr.replsize < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete IP packet of %d bytes\n", tr.replsize)); continue; } // Check protocol in IP header ipHeader = (ip *) icmpPacket; if (ipHeader->ip_p != proto) { IF_DEBUG(0, fprintf(stderr, "Received unknown protocol %d in (supposedly) ICMP packet\n", ipHeader->ip_p)); rc = -1; goto exittest; } #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength = (ipHeader->ip_vhl & 0x0f) << 2; #else ipHeaderLength = ipHeader->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength) < ICMP_MINLEN) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMP packet of %d bytes\n", tr.replsize)); continue; } icmpHeader = (icmp *) (((char *) ipHeader) + ipHeaderLength); IF_DEBUG(3, fprintf(stderr, "ICMP type = %d, code = %d\n", icmpHeader->icmp_type, icmpHeader->icmp_code)); // Check ICMP type. Most types (such as echo request/reply, // router adverts, etc.) we ignore. if ((icmpHeader->icmp_type != ICMP_TIMXCEED) && (icmpHeader->icmp_type != ICMP_UNREACH)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet\n")); continue; } if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN) < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IP packet, %d bytes total\n", tr.replsize)); continue; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be 8 bytes past the ICMP header. ipHeader2 = (ip *) ((char *) icmpHeader + ICMP_MINLEN); // Additional checking here...must be UDP if (ipHeader2->ip_p != IPPROTO_UDP) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet for non-UDP packet\n")); continue; } // Align UDP header template. #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength2 = (ipHeader2->ip_vhl & 0x0f) << 2; #else ipHeaderLength2 = ipHeader2->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN + ipHeaderLength2) < sizeof(udphdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner UDP packet, %d bytes total\n", tr.replsize)); continue; } udpHeader = (udphdr *) (((char *) ipHeader2) + ipHeaderLength2); // Check destination UDP port number (we don't know the // source) and UDP (header+payload) length if ((udpHeader->uh_dport != targetSocketAddress.sin_port) || (ntohs(udpHeader->uh_ulen) != udpPayloadSize + sizeof(udphdr))) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet for unknown UDP packet\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeader->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = GetAction(icmpHeader->icmp_type, icmpHeader->icmp_code); done = 1; } else { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: delete [] udpPayload; free(icmpPacket); return rc; } // // PctestIpv4Udp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv4Udp::GetMinSize() { return (sizeof(ip) + sizeof(udphdr) + 4); } // // PctestIpv4Udp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv4 type // and code values. // PctestActionType PctestIpv4Udp::GetAction(int icmpType, int icmpCode) { if (icmpType == ICMP_TIMXCEED) { return PctestActionValid; } else if ((icmpType == ICMP_UNREACH) && (icmpCode == ICMP_UNREACH_PORT)) { return PctestActionValidLasthop; } else if ((icmpType == ICMP_UNREACH) && (icmpCode == ICMP_UNREACH_FILTER_PROHIB)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv4Udp.h000644 002001 000024 00000002632 10203463722 015340 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4Udp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Udp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv4 tests using UDP // #ifndef PCTESTIPV4UDP_H #define PCTESTIPV4UDP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv4.h" class PctestIpv4Udp : public PctestIpv4 { public: PctestIpv4Udp() { }; PctestIpv4Udp(int p) { }; virtual ~PctestIpv4Udp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmpType, int icmpCode); protected: }; #endif /* PCTESTIPV4UDP_H */ pchar-1.5/PctestIpv4Raw.cc000644 002001 000024 00000033262 10203463722 015502 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4Raw.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4Raw.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Raw.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests using raw sockets to send UDP probes // #include #include #include #include #include #include #include #include #ifdef HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" #include "PctestIpv4Raw.h" #include "TestRecord.h" extern unsigned Mtu; // // PctestIpv4Raw::PctestIpv4Raw // PctestIpv4Raw::PctestIpv4Raw(int p) { extern bool PcapFlag; #ifdef HAVE_PCAP if (PcapFlag) { // Initialize packet filter // // XXX Note that we will see both inbound and outbound packets // with this filter rule. We *could* write up a new rule // to add a src host predicate. XXX if (pcap_compile(pc, &fp, "ip proto \\icmp", 1, maskp) < 0) { fprintf(stderr, "pcap_compile failed\n"); exit(1); } if (pcap_setfilter(pc, &fp) < 0) { fprintf(stderr, "pcap_setfilter failed\n"); exit(1); } } #endif /* HAVE_PCAP */ } // // GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, and store its FD in socketOut. // int PctestIpv4Raw::GetSocketOut() { int rc; socketOut = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (socketOut < 0) { perror("socket"); return socketOut; } int hdrinclOption; hdrinclOption = 1; rc = setsockopt(socketOut, IPPROTO_IP, IP_HDRINCL, (const char *) &hdrinclOption, sizeof(hdrinclOption)); if (rc < 0) { perror("setsockopt(IP_HDRINCL)"); return rc; } // Bind remote side of socket // (note that we need to have had PctestIpv4::SetTargetName() // called first! rc = connect(socketOut, (struct sockaddr *) &targetSocketAddress, sizeof(struct sockaddr_in)); if (rc < 0) { perror("connect"); return rc; } #ifdef linux // Linux needs SO_BSDCOMPAT enabled on our UDP socket, to avoid // getting ICMP errors when we send packets out. int bsdcompatOption; bsdcompatOption = 1; rc = setsockopt(socketOut, SOL_SOCKET, SO_BSDCOMPAT, (const char *) &bsdcompatOption, sizeof(bsdcompatOption)); if (rc < 0) { perror("setsockopt(SO_BSDCOMPAT)"); return rc; } #endif /* linux */ return socketOut; } // // PctestIpv4Raw::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv4Raw::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // generic loop counter // Parameters stored as globals extern bool PcapFlag; extern unsigned int Tos; extern int Timeout; // If the requested sending size is too small or too large, // then return an error. The caller should have figured out the // minimum sending size by calling Pctest::GetMinSize(). if ((tr.size < GetMinSize()) || (tr.size > IP_MAXPACKET)) { return -1; } // Make up a UDP packet to send out. Start with an IP header. // See Section 25.3 of UNIX Network Programming, Second Edition, // for why we need to twiddle the byte-orders of some fields but // not others, depending on what OS we run. struct ip ipHeader; memset(&ipHeader, 0, sizeof(ipHeader)); #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeader.ip_vhl = (sizeof(ip) >> 2) | (4 << 4); #else ipHeader.ip_hl = sizeof(ip) >> 2; ipHeader.ip_v = 4; #endif /* __osf__ */ ipHeader.ip_tos = Tos; #ifdef linux ipHeader.ip_len = htons(tr.size); #else ipHeader.ip_len = tr.size; #endif /* linux */ ipHeader.ip_id = htons(0); #ifdef linux ipHeader.ip_off = htons(IP_DF); #else ipHeader.ip_off = IP_DF; #endif /* linux */ ipHeader.ip_ttl = tr.hops; ipHeader.ip_p = IPPROTO_UDP; ipHeader.ip_sum = 0; memcpy(&(ipHeader.ip_src), &originAddress, sizeof(struct in_addr)); memcpy(&(ipHeader.ip_dst), &(targetSocketAddress.sin_addr), sizeof(struct in_addr)); // Make up UDP header; int udpPayloadSize = tr.size - sizeof(ip) - sizeof(udphdr); struct udphdr udpHeader; memset(&udpHeader, 0, sizeof(udpHeader)); udpHeader.uh_sport = htons(30003); //XXX udpHeader.uh_dport = htons(destPort++); udpHeader.uh_ulen = htons(udpPayloadSize + sizeof(udpHeader)); udpHeader.uh_sum = htons(0); // Let the UDP checksum be 0 // UDP payload char *udpPayload; udpPayload = GeneratePayload(udpPayloadSize); if (udpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } // Build the packet now. char *ipPacket; int ipPacketSize; ipPacketSize = sizeof(ip) + sizeof(udphdr) + udpPayloadSize; ipPacket = new char[ipPacketSize]; memcpy(ipPacket, &ipHeader, sizeof(ipHeader)); memcpy(ipPacket + sizeof(ipHeader), &udpHeader, sizeof(udpHeader)); memcpy(ipPacket + sizeof(ipHeader) + sizeof(udpHeader), udpPayload, udpPayloadSize); // Compute UDP checksum. We're going to build this up part by part, // starting with the different components of the pseudo-header, // and then doing the UDP header and payload as a single block. // The idea for this comes from the libnet code, basically we build the // checksum for the pseudo-header without actually having to // store it anywhere. Not real efficient but it should be OK for // our purposes. // // We note that the UDP checksum routine returns the 1s complement // of the 1s complement sum; we need to unroll this to do some // other manipulations before actually storing it. // We assemble some components to the checksum, and then re-do // the checksum carry and complement operations. u_int checksum; checksum = (u_short) ~InCksum((u_short *) &(ipHeader.ip_src), 2 * sizeof(struct in_addr)); checksum += (u_short) htons(IPPROTO_UDP) + (u_short) htons(sizeof(udpHeader) + udpPayloadSize); checksum += (u_short) ~InCksum((u_short *) (ipPacket + sizeof(ipHeader)), sizeof(udpHeader) + udpPayloadSize); while (checksum >> 16) { checksum = (checksum & 0xffff) + (checksum >> 16); } ((udphdr *)(ipPacket + sizeof(ipHeader)))->uh_sum = ~checksum; // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmpPacket; icmpPacket = (char *) malloc(IP_MAXPACKET); if (icmpPacket == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } #ifdef HAVE_PCAP if (!PcapFlag) { #endif /* HAVE_PCAP */ // Set timeout value and socket select parameters timeout.tv_sec = Timeout; timeout.tv_usec = 0; FD_ZERO(&readFds); FD_SET(socketIn, &readFds); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(socketOut, advancePacket, Mtu, 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send UDP packet rc = send(socketOut, ipPacket, ipPacketSize, 0); if (rc < 0) { perror("send"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { #ifdef HAVE_PCAP if (PcapFlag) { // Wait for a packet. Only take in one packet at a time. rc = pcap_dispatch(pc, 1, callback, (u_char *) this); if (rc < 0) { fprintf(stderr, "pcap_dispatch failed\n"); goto exittest; } // The callback will handle our after- timestamp if // we get a packet, but if the read timeout fired first, // we'll need to do a timestamp here to be sure that tvAfter // has a valid value in it. if (rc == 0) { gettimeofday(&tvAfter, NULL); } } else { #endif /* HAVE_PCAP */ // Select and wait for an ICMP response or a timeout rc = select(FD_SETSIZE, &readFds, NULL, NULL, &timeout); if (rc < 0) { perror("select"); goto exittest; } // Timestamp after and update test record timestamp fields gettimeofday(&tvAfter, NULL); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); #ifdef HAVE_PCAP if (PcapFlag) { memcpy(icmpPacket, packet, packetLength); tr.replsize = packetLength; } else { #endif /* HAVE_PCAP */ rc = read(socketIn, icmpPacket, IP_MAXPACKET); if (rc < 0) { perror("read"); goto exittest; } tr.replsize = rc; #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet.. ip *ipHeaderIn, *ipHeaderIn2; icmp *icmpHeaderIn; udphdr *udpHeaderIn; unsigned int ipHeaderLength, ipHeaderLength2; if (tr.replsize < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete IP packet of %d bytes\n", tr.replsize)); continue; } // Check protocol in IP header ipHeaderIn = (ip *) icmpPacket; if (ipHeaderIn->ip_p != proto) { IF_DEBUG(0, fprintf(stderr, "Received unknown protocol %d in (supposedly) ICMP packet\n", ipHeaderIn->ip_p)); rc = -1; goto exittest; } #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength = (ipHeaderIn->ip_vhl & 0x0f) << 2; #else ipHeaderLength = ipHeaderIn->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength) < ICMP_MINLEN) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMP packet of %d bytes\n", tr.replsize)); continue; } icmpHeaderIn = (icmp *) (((char *) ipHeaderIn) + ipHeaderLength); IF_DEBUG(3, fprintf(stderr, "ICMP type = %d, code = %d\n", icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code)); // Check ICMP type. Most types (such as echo request/reply, // router adverts, etc.) we ignore. if ((icmpHeaderIn->icmp_type != ICMP_TIMXCEED) && (icmpHeaderIn->icmp_type != ICMP_UNREACH)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet\n")); continue; } if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN) < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IP packet, %d bytes total\n", tr.replsize)); continue; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be 8 bytes past the ICMP header. ipHeaderIn2 = (ip *) ((char *) icmpHeaderIn + 8); // Additional checking here...must be UDP if (ipHeaderIn2->ip_p != IPPROTO_UDP) { IF_DEBUG(3, fprintf(stderr, "ignoring icmp packet for non-udp\n")); continue; } // Align UDP header template. #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength2 = (ipHeaderIn2->ip_vhl & 0x0f) << 2; #else ipHeaderLength2 = ipHeaderIn2->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN + ipHeaderLength2) < sizeof(udphdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner UDP packet, %d bytes total\n", tr.replsize)); continue; } udpHeaderIn = (udphdr *) (((char *) ipHeaderIn2) + ipHeaderLength2); // Check destination UDP port number (we don't know the // source) and UDP (header+payload) length if ((udpHeaderIn->uh_dport != udpHeader.uh_dport) || (ntohs(udpHeaderIn->uh_ulen) != udpPayloadSize + sizeof(udphdr))) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet for unknown UDP packet\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeaderIn->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = GetAction(icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code); done = 1; } else if (tr.tv.tv_sec >= Timeout) { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: if (advancePacket) { delete [] advancePacket; } delete [] udpPayload; delete [] ipPacket; free(icmpPacket); return rc; } pchar-1.5/PctestIpv4Raw.h000644 002001 000024 00000002511 10203463722 015335 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4Raw.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Raw.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv4 tests using raw sockets to send UDP probes. // #ifndef PCTESTIPV4RAW_H #define PCTESTIPV4RAW_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv4Udp.h" class PctestIpv4Raw : public PctestIpv4Udp { public: PctestIpv4Raw() { }; PctestIpv4Raw(int p); virtual ~PctestIpv4Raw() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); protected: }; #endif /* PCTESTIPV4RAW_H */ pchar-1.5/PctestIpv4Tcp.cc000644 002001 000024 00000032061 10203463722 015473 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4Tcp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4Tcp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Tcp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests using TCP // #include #include #include #include #include #include #include #include #ifdef HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" #include "PctestIpv4Tcp.h" #include "TestRecord.h" // // PctestIpv4Tcp::PctestIpv4Tcp // PctestIpv4Tcp::PctestIpv4Tcp(int p) { extern bool PcapFlag; #ifdef HAVE_PCAP if (PcapFlag) { // Initialize packet filter if (pcap_compile(pc, &fp, "(ip proto \\tcp) or (ip proto \\icmp)", 1, maskp) < 0) { fprintf(stderr, "pcap_compile failed\n"); exit(1); } if (pcap_setfilter(pc, &fp) < 0) { fprintf(stderr, "pcap_setfilter failed\n"); exit(1); } } else { #endif /* HAVE_PCAP */ fprintf(stderr, "ipv4tcp probes require libpcap functionality\n"); exit(1); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ } // // GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type and store its FD in socketOut. // int PctestIpv4Tcp::GetSocketOut() { int rc; socketOut = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); if (socketOut < 0) { perror("socket"); return socketOut; } int hdrinclOption; hdrinclOption = 1; rc = setsockopt(socketOut, IPPROTO_IP, IP_HDRINCL, (const char *) &hdrinclOption, sizeof(hdrinclOption)); if (rc < 0) { perror("setsockopt(IP_HDRINCL)"); return rc; } rc = connect(socketOut, (struct sockaddr *) &targetSocketAddress, sizeof(struct sockaddr_in)); if (rc < 0) { perror("connect"); return rc; } return socketOut; } // // PctestIpv4Tcp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv4Tcp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // loop counter for advance packets // Parameters stored as globals extern bool PcapFlag; extern unsigned int Tos; extern unsigned int Mtu; extern int Timeout; #ifdef HAVE_PCAP if (PcapFlag) { // If the requested sending size is too small or too large, // then return an error. The caller should have figured out the // minimum sending size by calling Pctest::GetMinSize(). if ((tr.size < GetMinSize()) || (tr.size > IP_MAXPACKET)) { return -1; } // Make up a TCP packet to send out. Start with an IP header. // See Section 25.3 of UNIX Network Programming, Second Edition, // for why we need to twiddle the byte-orders of some fields but // not others, depending on what OS we run. struct ip ipHeader; memset(&ipHeader, 0, sizeof(ipHeader)); #ifdef __osf__ // Tru64 does not declare ip_hl if __STDC__ == 1 ipHeader.ip_vhl = (sizeof(ip) >> 2) | (4 << 4); #else ipHeader.ip_hl = sizeof(ip) >> 2; ipHeader.ip_v = 4; #endif /* __osf__ */ ipHeader.ip_tos = Tos; #ifdef linux ipHeader.ip_len = htons(tr.size); #else ipHeader.ip_len = tr.size; #endif /* linux */ ipHeader.ip_id = htons(0); #ifdef linux ipHeader.ip_off = htons(IP_DF); #else ipHeader.ip_off = IP_DF; #endif /* linux */ ipHeader.ip_ttl = tr.hops; ipHeader.ip_p = IPPROTO_TCP; ipHeader.ip_sum = 0; memcpy(&(ipHeader.ip_src), &(originAddress), sizeof(struct in_addr)); memcpy(&(ipHeader.ip_dst), &(targetSocketAddress.sin_addr), sizeof(struct in_addr)); // Make up TCP header. int tcpPayloadSize = tr.size - sizeof(ip) - sizeof(tcphdr); struct tcphdr tcpHeader; memset(&tcpHeader, 0, sizeof(tcpHeader)); tcpHeader.th_sport = htons(30003); //XXX tcpHeader.th_dport = htons(destPort++); tcpHeader.th_seq = htons(0); // sequence number irrelevant tcpHeader.th_ack = htons(0); // acknowledgement irrelevant #ifdef __osf__ // Tru64 does not declare th_off if __STDC__ == 1 tcpHeader.th_xoff = (sizeof(tcphdr)/4)<<4; // header length words with no options // shifted by 4 bits to cover unused field #else tcpHeader.th_off = sizeof(tcphdr)/4; // header length words with no options #endif /* __osf__ */ tcpHeader.th_flags = TH_FIN | TH_ACK; // need to figure out right flags tcpHeader.th_win = htons(1); // window advert probably irrelevent tcpHeader.th_sum = 0; // XXX need to generate checksum tcpHeader.th_urp = htons(0); // no urgent pointer // TCP payload char *tcpPayload; tcpPayload = GeneratePayload(tcpPayloadSize); if (tcpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } // Build the packet now. char *ipPacket; int ipPacketSize; ipPacketSize = sizeof(ip) + sizeof(tcphdr) + tcpPayloadSize; ipPacket = new char[ipPacketSize]; memcpy(ipPacket, &ipHeader, sizeof(ipHeader)); memcpy(ipPacket + sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader)); memcpy(ipPacket + sizeof(ipHeader) + sizeof(tcpHeader), tcpPayload, tcpPayloadSize); // Compute TCP checksum. For comments, see PctestIpv4Raw::Test(). u_int checksum; checksum = (u_short) ~InCksum((u_short *) &(ipHeader.ip_src), 2 * sizeof(struct in_addr)); checksum += (u_short) htons(IPPROTO_TCP) + (u_short) htons(sizeof(tcpHeader) + tcpPayloadSize); checksum += (u_short) ~InCksum((u_short *) (ipPacket + sizeof(ipHeader)), sizeof(tcpHeader) + tcpPayloadSize); while (checksum >> 16) { checksum = (checksum & 0xffff) + (checksum >> 16); } ((tcphdr *)(ipPacket + sizeof(ipHeader)))->th_sum = ~checksum; // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmpPacket; icmpPacket = (char *) malloc(IP_MAXPACKET); if (icmpPacket == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(socketOut, advancePacket, Mtu, 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send TCP packet rc = send(socketOut, ipPacket, ipPacketSize, 0); if (rc < 0) { perror("sendto"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { // Wait for a packet. Only take in one packet at a time. rc = pcap_dispatch(pc, 1, callback, (u_char *) this); if (rc < 0) { fprintf(stderr, "pcap_dispatch failed\n"); goto exittest; } // The callback will handle our after- timestamp if // we get a packet, but if the read timeout fired first, // we'll need to do a timestamp here to be sure that tvAfter // has a valid value in it. if (rc == 0) { gettimeofday(&tvAfter, NULL); } tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "response packet received\n")); memcpy(icmpPacket, packet, packetLength); tr.replsize = packetLength; // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet.. ip *ipHeaderIn, *ipHeaderIn2; icmp *icmpHeaderIn; tcphdr *tcpHeaderIn; // Check protocol in IP header ipHeaderIn = (ip *) icmpPacket; if ((ipHeaderIn->ip_p != proto) && (ipHeaderIn->ip_p != IPPROTO_TCP)) { IF_DEBUG(0, fprintf(stderr, "Received unknown protocol %d in (supposedly) ICMP or TCP packet\n", ipHeaderIn->ip_p)); rc = -1; goto exittest; } if (ipHeaderIn->ip_p == proto) { #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 icmpHeaderIn = (icmp *) (((char *) ipHeaderIn) + ((ipHeaderIn->ip_vhl & 0x0f) << 2)); #else icmpHeaderIn = (icmp *) (((char *) ipHeaderIn) + (ipHeaderIn->ip_hl << 2)); #endif /* __osf__ */ IF_DEBUG(3, fprintf(stderr, "icmp type = %d, code = %d\n", icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code)); // Check ICMP type. Most types (such as echo request/reply, // router adverts, etc.) we ignore. if ((icmpHeaderIn->icmp_type != ICMP_TIMXCEED) && (icmpHeaderIn->icmp_type != ICMP_UNREACH)) { IF_DEBUG(3, fprintf(stderr, "ignoring icmp packet\n")); continue; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be 8 bytes past the ICMP header. ipHeaderIn2 = (ip *) ((char *) icmpHeaderIn + 8); // Check to be sure that we have enough of the packet to hold // a valid IP header? XXX // Additional checking here...must be TCP if (ipHeaderIn2->ip_p != IPPROTO_TCP) { IF_DEBUG(3, fprintf(stderr, "ignoring icmp packet for non-tcp\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeaderIn->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = GetAction(icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code); done = 1; } else if (ipHeaderIn->ip_p == IPPROTO_TCP) { // Align TCP header template, check port numbers and // payload length for us. XXX #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 tcpHeaderIn = (tcphdr *) (((char *) ipHeaderIn) + ((ipHeaderIn->ip_vhl & 0x0f) << 2)); #else tcpHeaderIn = (tcphdr *) (((char *) ipHeaderIn) + (ipHeaderIn->ip_hl << 2)); #endif /* __osf__ */ // Check destination TCP port number (we don't know the // source) and TCP (header+payload) length // fprintf(stderr, "%d %d %d %d\n", // ntohs(tcpHeaderIn->th_dport), ntohs(tcpHeaderIn->th_sport), // ntohs(tcpHeader.th_sport), ntohs(tcpHeader.th_dport)); if ((tcpHeaderIn->th_dport != tcpHeader.th_sport) || (tcpHeaderIn->th_sport != tcpHeader.th_dport)) { IF_DEBUG(3, fprintf(stderr, "ignoring tcp packet for unknown tcp packet\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeaderIn->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = PctestActionValidLasthop; done = 1; } } // If we didn't get a packet yet, see if we've waited too long else if (tr.tv.tv_sec >= Timeout) { IF_DEBUG(2, fprintf(stderr, "timeout\n")); tr.icmpSourceAddress = new char[sizeof(in_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: delete [] tcpPayload; delete [] ipPacket; free(icmpPacket); return rc; } else { #endif /* HAVE_PCAP */ fprintf(stderr, "ipv4tcp probes require libpcap functionality\n"); exit(1); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ } // // PctestIpv4Tcp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv4Tcp::GetMinSize() { return (sizeof(ip) + sizeof(tcphdr) + 4); } // // PctestIpv4Tcp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv4 type // and code values. // PctestActionType PctestIpv4Tcp::GetAction(int icmpType, int icmpCode) { if (icmpType == ICMP_TIMXCEED) { return PctestActionValid; } else if ((icmpType == ICMP_UNREACH) && (icmpCode == ICMP_UNREACH_PORT)) { return PctestActionValidLasthop; } else if ((icmpType == ICMP_UNREACH) && (icmpCode == ICMP_UNREACH_FILTER_PROHIB)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv4Tcp.h000644 002001 000024 00000002624 10203463722 015337 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4Tcp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Tcp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header for class of IPv4 tests using TCP // #ifndef PCTESTIPV4TCP_H #define PCTESTIPV4TCP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv4.h" class PctestIpv4Tcp : public PctestIpv4 { public: PctestIpv4Tcp() { }; PctestIpv4Tcp(int p); virtual ~PctestIpv4Tcp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmpType, int icmpCode); protected: }; #endif /* PCTESTIPV4TCP_H */ pchar-1.5/PctestIpv4Icmp.cc000644 002001 000024 00000034060 10203463722 015636 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv4Icmp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv4Icmp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Icmp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv4 tests using ICMP // #include #include #include #include #include #include #include #ifdef HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" #include "PctestIpv4Icmp.h" #include "TestRecord.h" extern unsigned int Mtu; // // PctestIpv4Icmp::PctestIpv4Icmp // PctestIpv4Icmp::PctestIpv4Icmp() { extern bool PcapFlag; #ifdef HAVE_PCAP if (PcapFlag) { // Initialize packet filter // // XXX Note that we will see both inbound and outbound packets // with this filter rule. We *could* write up a new rule // to add a src host predicate. XXX if (pcap_compile(pc, &fp, "ip proto \\icmp", 1, maskp) < 0) { fprintf(stderr, "pcap_compile failed\n"); exit(1); } if (pcap_setfilter(pc, &fp) < 0) { fprintf(stderr, "pcap_setfilter failed\n"); exit(1); } } #endif /* HAVE_PCAP */ } // // GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, store it in socketOut. // int PctestIpv4Icmp::GetSocketOut() { int rc; socketOut = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (socketOut < 0) { perror("socket"); return socketOut; } int hdrinclOption; hdrinclOption = 1; rc = setsockopt(socketOut, IPPROTO_IP, IP_HDRINCL, (const char *) &hdrinclOption, sizeof(hdrinclOption)); if (rc < 0) { perror("setsockopt(IP_HDRINCL)"); return rc; } // Bind remote side of socket // (note that we need to have had PctestIpv4::SetTargetName() // called first! rc = connect(socketOut, (struct sockaddr *) &targetSocketAddress, sizeof(struct sockaddr_in)); if (rc < 0) { perror("connect"); return rc; } return socketOut; } // // PctestIpv4Icmp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv4Icmp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // generic loop counter // Parameters stored as globals extern bool PcapFlag; extern unsigned int Tos; extern int Timeout; // If the requested sending size is too small or too large, // then return an error. The caller should have figured out the // minimum sending size by calling Pctest::GetMinSize(). if ((tr.size < GetMinSize()) || (tr.size > IP_MAXPACKET)) { return -1; } // Make up a ICMP packet to send out. Start with an IP header. // See Section 25.3 of UNIX Network Programming, Second Edition, // for why we need to twiddle the byte-orders of some fields but // not others, depending on what OS we run. struct ip ipHeader; memset(&ipHeader, 0, sizeof(ipHeader)); #ifdef __osf__ // Tru64 does not declare ip_hl if __STDC__ == 1 ipHeader.ip_vhl = (sizeof(ip) >> 2) | (4 << 4); #else ipHeader.ip_hl = sizeof(ip) >> 2; ipHeader.ip_v = 4; #endif /* __osf__ */ ipHeader.ip_tos = Tos; #ifdef linux ipHeader.ip_len = htons(tr.size); #else ipHeader.ip_len = tr.size; #endif /* linux */ ipHeader.ip_id = htons(0); #ifdef linux ipHeader.ip_off = htons(IP_DF); #else ipHeader.ip_off = IP_DF; #endif /* linux */ ipHeader.ip_ttl = tr.hops; ipHeader.ip_p = IPPROTO_ICMP; ipHeader.ip_sum = 0; memcpy(&(ipHeader.ip_src), &(originAddress), sizeof(struct in_addr)); memcpy(&(ipHeader.ip_dst), &(targetSocketAddress.sin_addr), sizeof(struct in_addr)); // Make up ICMP header. int icmpPayloadSize = tr.size - sizeof(ip) - ICMP_MINLEN; // need to hardcode size of headers for an ICMP // echo request packet, because the associated // structure is variable-sized. struct icmp icmpHeader; icmpHeader.icmp_type = ICMP_ECHO; icmpHeader.icmp_code = 0; icmpHeader.icmp_cksum = htons(0); // compute checksum icmpHeader.icmp_id = htons(icmpId); icmpHeader.icmp_seq = htons(icmpSequence++); IF_DEBUG(2, fprintf(stdout, "test size %d, payload size %d\n", tr.size, icmpPayloadSize)); // ICMP payload char *icmpPayload; icmpPayload = GeneratePayload(icmpPayloadSize); if (icmpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } // Build the packet now. char *ipPacket; int ipPacketSize; ipPacketSize = sizeof(ip) + ICMP_MINLEN + icmpPayloadSize; ipPacket = new char[ipPacketSize]; memcpy(ipPacket, &ipHeader, sizeof(ipHeader)); memcpy(ipPacket + sizeof(ipHeader), &icmpHeader, ICMP_MINLEN); memcpy(ipPacket + sizeof(ipHeader) + ICMP_MINLEN, icmpPayload, icmpPayloadSize); // Compute ICMP checksum. This is much simpler than the TCP or // UDP checksums, because there is no pseudo-header. u_int checksum; checksum = (u_short) InCksum((u_short *) (ipPacket + sizeof(ipHeader)), ICMP_MINLEN + icmpPayloadSize); ((icmp *)(ipPacket + sizeof(ipHeader)))->icmp_cksum = checksum; // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmpPacket; icmpPacket = (char *) malloc(IP_MAXPACKET); if (icmpPacket == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } #ifdef HAVE_PCAP if (!PcapFlag) { #endif /* HAVE_PCAP */ // Set timeout value and socket select parameters timeout.tv_sec = Timeout; timeout.tv_usec = 0; FD_ZERO(&readFds); FD_SET(socketIn, &readFds); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(socketOut, advancePacket, Mtu, 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send ICMP packet rc = send(socketOut, ipPacket, ipPacketSize, 0); if (rc < 0) { perror("send"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { #ifdef HAVE_PCAP if (PcapFlag) { // Wait for a packet. Only take in one packet at a time. rc = pcap_dispatch(pc, 1, callback, (u_char *) this); if (rc < 0) { fprintf(stderr, "pcap_dispatch failed\n"); goto exittest; } // The callback will handle our after- timestamp if // we get a packet, but if the read timeout fired first, // we'll need to do a timestamp here to be sure that tvAfter // has a valid value in it. if (rc == 0) { gettimeofday(&tvAfter, NULL); } } else { #endif /* HAVE_PCAP */ // Select and wait for an ICMP response or a timeout rc = select(FD_SETSIZE, &readFds, NULL, NULL, &timeout); if (rc < 0) { perror("select"); goto exittest; } // Timestamp after and update test record timestamp fields gettimeofday(&tvAfter, NULL); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); #ifdef HAVE_PCAP if (PcapFlag) { memcpy(icmpPacket, packet, packetLength); tr.replsize = packetLength; } else { #endif /* HAVE_PCAP */ rc = read(socketIn, icmpPacket, IP_MAXPACKET); if (rc < 0) { perror("read"); goto exittest; } tr.replsize = rc; #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet. ip *ipHeaderIn, *ipHeaderIn2; icmp *icmpHeaderIn, *icmpHeaderIn2; unsigned int ipHeaderLength, ipHeaderLength2; if (tr.replsize < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete IP packet of %d bytes\n", tr.replsize)); continue; } // Check protocol in IP header ipHeaderIn = (ip *) icmpPacket; if (ipHeaderIn->ip_p != proto) { IF_DEBUG(0, fprintf(stderr, "Received unknown protocol %d in (supposedly) icmp packet\n", ipHeaderIn->ip_p)); rc = -1; goto exittest; } #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength = (ipHeaderIn->ip_vhl & 0x0f) << 2; #else ipHeaderLength = ipHeaderIn->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength) < ICMP_MINLEN) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMP packet of %d bytes\n", tr.replsize)); continue; } icmpHeaderIn = (icmp *) (((char *) ipHeaderIn) + ipHeaderLength); IF_DEBUG(3, fprintf(stderr, "icmp type = %d, code = %d\n", icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code)); // Check ICMP type. Most types (such as echo request/reply, // router adverts, etc.) we ignore. if ((icmpHeaderIn->icmp_type != ICMP_TIMXCEED) && (icmpHeaderIn->icmp_type != ICMP_UNREACH) && (icmpHeaderIn->icmp_type != ICMP_ECHOREPLY)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet\n")); continue; } // Is it an echo reply? If so, see if it's a reply to // something we might have sent. if (icmpHeaderIn->icmp_type == ICMP_ECHOREPLY) { if ((icmpHeaderIn->icmp_id != icmpHeader.icmp_id) || (icmpHeaderIn->icmp_seq != icmpHeader.icmp_seq)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet with mismatched id/seq\n")); continue; } tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeaderIn->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = GetAction(icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code); done = 1; continue; } if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN) < sizeof(ip)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IP packet, %d bytes total\n", tr.replsize)); continue; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be right after the ICMP header. ipHeaderIn2 = (ip *) ((char *) icmpHeaderIn + ICMP_MINLEN); // Additional checking here...must be ICMP if (ipHeaderIn2->ip_p != IPPROTO_ICMP) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet for non-ICMP\n")); continue; } // Align ICMP header template. #ifdef __osf__ // Tru64 doesn't declar ip_hl if __STDC__ == 1 ipHeaderLength2 = (ipHeaderIn2->ip_vhl & 0x0f) << 2; #else ipHeaderLength2 = ipHeaderIn2->ip_hl << 2; #endif /* __osf__ */ if (tr.replsize - (0 + ipHeaderLength + ICMP_MINLEN + ipHeaderLength2) < ICMP_MINLEN) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner ICMP packet, %d bytes total\n", tr.replsize)); continue; } icmpHeaderIn2 = (icmp *) (((char *) ipHeaderIn2) + ipHeaderLength2); if ((icmpHeaderIn2->icmp_id != icmpHeader.icmp_id) || (icmpHeaderIn2->icmp_seq != icmpHeader.icmp_seq)) { IF_DEBUG(3, fprintf(stderr, "Ignoring inner ICMP packet with mismatched id/seq\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in_addr)]; memcpy(tr.icmpSourceAddress, &(ipHeaderIn->ip_src), sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = GetAction(icmpHeaderIn->icmp_type, icmpHeaderIn->icmp_code); done = 1; } // If we didn't get a packet yet, see if we've waited too long else if (tr.tv.tv_sec >= Timeout) { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in_addr)); tr.icmpSourceAddressLength = sizeof(in_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: if (advancePacket) { delete [] advancePacket; } delete [] icmpPayload; delete [] ipPacket; free(icmpPacket); return rc; } // // PctestIpv4Icmp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv4Icmp::GetMinSize() { return (sizeof(ip) + ICMP_MINLEN + 4); // need to hardcode size of an ICMP // echo request packet, because the associated // structure is variable-sized. } // // PctestIpv4Icmp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv4 type // and code values. // PctestActionType PctestIpv4Icmp::GetAction(int icmpType, int icmpCode) { if (icmpType == ICMP_TIMXCEED) { return PctestActionValid; } else if (icmpType == ICMP_ECHOREPLY) { return PctestActionValidLasthop; } else if ((icmpType == ICMP_UNREACH) && (icmpCode == ICMP_UNREACH_FILTER_PROHIB)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv4Icmp.h000644 002001 000024 00000002773 10203463722 015506 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv4Icmp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv4Icmp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header for class of IPv4 tests using ICMP echo request packets // #ifndef PCTESTIPV4ICMP_H #define PCTESTIPV4ICMP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv4.h" class PctestIpv4Icmp : public PctestIpv4 { public: PctestIpv4Icmp(); PctestIpv4Icmp(int p) { fprintf(stderr, "PctestIpv4Icmp can't take port numbers\n"); exit(1); }; virtual ~PctestIpv4Icmp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmpType, int icmpCode); protected: }; #endif /* PCTESTIPV4ICMP_H */ pchar-1.5/PctestIpv6.cc000644 002001 000024 00000035207 10203463722 015033 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv6.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv6.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv6 tests // #include #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef NEED_NRL_IPV6_HACK #include #include #else #include #include #endif /* NEED_NRL_IPV6_HACK */ #include #include #include "pc.h" #include "PctestIpv6.h" // // PctestIpv6::SetOriginName // // Input: origin hostname // // Output: success code (negative if error) // // Attempt to set the origin of probe packets emanating from this host, // for tests where it is applicable, using protocol family-dependent // resolution as necessary. If no origin hostname is given, // then use the target address to compute the correct outgoing interface. // originName and originAddress are set. // int PctestIpv6::SetOriginName(char *o) { // If nothing was passed in, then bind a dummy socket to try to // determine the output interface. if (o == NULL) { int dummySock; struct sockaddr_in6 dummyAddr, localAddr; #ifdef HAVE_SOCKLEN_T socklen_t localAddrLength; #else /* HAVE_SOCKLEN_T */ size_t localAddrLength; #endif /* HAVE_SOCKLEN_T */ // Create socket, then connect to it, and then read out // the local socket address with a getsockname call. dummySock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (dummySock < 0) { perror("socket"); return -1; } memset((void *) &dummyAddr, 0, sizeof(struct sockaddr_in6)); #ifdef HAVE_SOCKADDR_SA_LEN dummyAddr.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ dummyAddr.sin6_family = AF_INET6; dummyAddr.sin6_port = htons(32768); // port number irrelevant memcpy(&dummyAddr.sin6_addr, &targetAddress, sizeof(struct in6_addr)); if (connect(dummySock, (sockaddr *) &dummyAddr, sizeof(struct sockaddr_in6)) < 0) { perror("connect"); return -1; } localAddrLength = sizeof(sockaddr_in6); memset((void *) &localAddr, 0, sizeof(struct sockaddr_in6)); if (getsockname(dummySock, (struct sockaddr *) &localAddr, &localAddrLength) < 0) { perror("getsockname"); return -1; } // Got the local address, now do a reverse DNS looup memcpy(&originAddress, &localAddr.sin6_addr, sizeof(struct in6_addr)); originName = strdup(GetName((char *) &originAddress)); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for origin hostname.\n"); return -1; } close(dummySock); } else { // Attempt to resolve, if possible. Instead of using AI_DEFAULT, // we want to force the use of IPv6 addresses (no mapped or IPv4 // addresses, since the test code relies on knowing exactly what // protocol is being used on the wire). struct addrinfo *host = NULL; struct addrinfo hints; int ecode; // resolver error code memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET6; hints.ai_flags = AI_CANONNAME; ecode = getaddrinfo(o, NULL, &hints, &host); // Resolver failed if (host == NULL) { fprintf(stderr, "%s: %s\n", o, gai_strerror(ecode)); memset((void *) &originAddress, 0, sizeof(struct in6_addr)); originName = strdup(o); if (originName == NULL) { fprintf(stderr, "Couldn't allocate space for origin hostname.\n"); return -1; } return -1; } IF_DEBUG(3, fprintf(stderr, "h_name = %s\n", host->ai_canonname)); IF_DEBUG(3, fprintf(stderr, "h_length = %d\n", host->ai_addrlen)); // Get IP address memcpy(&originAddress, &((struct sockaddr_in6 *) host->ai_addr)->sin6_addr, sizeof(originAddress)); // Make a copy of the canonical hostname originName = strdup(host->ai_canonname); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for hostname.\n"); return -1; } freeaddrinfo(host); } return 0; } // // PctestIpv6::SetTargetName // // Input: target hostname (target) // // Output: success code (negative if error) // // Set target name and do protocol-dependent resolving to get a // network address. In case of an error, we're responsible for // printing some error message. // int PctestIpv6::SetTargetName(char *t) { int len; // temporary buffer length struct addrinfo *host = NULL; struct addrinfo hints; int ecode; // resolver error code extern int Tos; // Tos parameter (to be used for traffic class) // Attempt to resolve, if possible. Instead of using AI_DEFAULT, // we want to force the use of IPv6 addresses (no mapped or IPv4 // addresses, since the test code relies on knowing exactly what // protocol is being used on the wire). memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET6; hints.ai_flags = AI_CANONNAME; ecode = getaddrinfo(t, NULL, &hints, &host); // Resolver failed if (host == NULL) { fprintf(stderr, "%s: %s\n", t, gai_strerror(ecode)); memset((void *) &targetAddress, 0, sizeof(struct in6_addr)); targetName = strdup(t); if (targetName == NULL) { fprintf(stderr, "Couldn't allocate memory for target hostname.\n"); return -1; } return -1; } IF_DEBUG(3, fprintf(stderr, "h_name = %s\n", host->ai_canonname)); IF_DEBUG(3, fprintf(stderr, "h_length = %d\n", host->ai_addrlen)); // Get IP address memcpy(&targetAddress, &((struct sockaddr_in6 *) host->ai_addr)->sin6_addr, sizeof(targetAddress)); memset((void *) &targetSocketAddress, 0, sizeof(struct sockaddr_in6)); // Note: Only BSD4.3Reno and later have sin_len in struct // sockaddr_in, so we need to test for it. // // Really what we ought to have is a check in autoconf for // sockaddr_in6.sin6_len, rather than relying on the (already // existing) check for sockaddr.sin_len. There are two instances // in this file. (On the other hand, any system that has // sockaddr.sin_len for IPv4 is almost certainly going to have // sockaddr_in6.sin6_len for IPv6, since the socket code is going // to have to read both fields with the same semantics. #ifdef HAVE_SOCKADDR_SA_LEN targetSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ targetSocketAddress.sin6_family = AF_INET6; // Note: RFC 2553 doesn't define the semantics of sin6_flowinfo, // instead punting that that RFC 2460. We hardcode the fact // that flow labels are 20 bits long (note that RFC 1883 used to // have 24-bit flow labels). If we want to support setting a // flow label value, we can OR it with the value below. targetSocketAddress.sin6_flowinfo = htonl(Tos << 20); targetSocketAddress.sin6_port = htons(0); // set on each test memcpy(&targetSocketAddress.sin6_addr, &((struct sockaddr_in6 *) host->ai_addr)->sin6_addr, sizeof(struct in6_addr)); // Make a copy of the canonical hostname, if it exists. if (host->ai_canonname) { targetName = strdup(host->ai_canonname); } else { fprintf(stderr, "Warning: couldn't get canonical hostname.\n"); targetName = strdup(t); } freeaddrinfo(host); if (targetName == NULL) { fprintf(stderr, "Couldn't allocate memory for target hostname.\n"); return -1; } return 0; } // // GetSocketIn // // Input: None // // Output: In return value, returns socket number. // // Get input socket of an appropriate type. // int PctestIpv6::GetSocketIn() { struct protoent *icmpProto; struct icmp6_filter filt; int rc; // return code int on = 1; icmpProto = getprotobyname("ipv6-icmp"); // be really anal-retentive if (icmpProto == NULL) { fprintf(stderr, "Warning: Couldn't determine ICMPv6 protocol number, using 58\n"); proto = 58; // instance variable of PctestIpv6 } else { proto = icmpProto->p_proto; } socketIn = socket(PF_INET6, SOCK_RAW, proto); if (socketIn < 0) { perror("socket"); return socketIn; } // ICMPv6 message filtering. ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filt); ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filt); ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); rc = setsockopt(socketIn, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)); if (rc < 0) { perror("setsockopt(ICMP_FILTER)"); return rc; } // If the current system supports 2292bis (XXX to become RFC XXX) // we'll use its version of the advanced API. #ifdef IPV6_RECVPKTINFO rc = setsockopt(socketIn, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); if (rc < 0) { perror("setsockopt(IPV6_RECVPKTINFO)"); return rc; } #else rc = setsockopt(socketIn, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); if (rc < 0) { perror("setsockopt(IPV6_PKTINFO)"); return rc; } #endif /* IPV6_RECVPKTINFO */ return socketIn; } // // PctestIpv6::GetPrintableAddress // // Input: None // // Output: Pointer to ASCII representation of address (in return // value) // char *PctestIpv6::GetPrintableAddress() { return (GetPrintableAddress(&targetAddress)); } // // PctestIpv6::GetPrintableAddress // // Input: Pointer to address structure // // Output: Pointer to ASCII representation of address (in return // value) // static char PctestIpv6PrintableAddress[INET6_ADDRSTRLEN]; char *PctestIpv6::GetPrintableAddress(void *a) { return (char *)inet_ntop(AF_INET6, a, PctestIpv6PrintableAddress, INET6_ADDRSTRLEN); } // // PctestIpv6::GetName // // Input: Pointer to address structure // // Output: Pointer to ASCII representation of name (in return // value) // static char PctestIpv6GetName[NI_MAXHOST]; char *PctestIpv6::GetName(void *a) { int error_num; // return code from library lookup struct sockaddr_in6 sa; // need to build up a socket addr structure memset(&sa, 0, sizeof(sockaddr_in6)); #ifdef HAVE_SOCKADDR_SA_LEN sa.sin6_len = sizeof(sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ sa.sin6_family = AF_INET6; sa.sin6_port = htons(0); memcpy(&(sa.sin6_addr), a, sizeof(struct in6_addr)); error_num = getnameinfo((const struct sockaddr *) &sa, sizeof(struct sockaddr_in6), PctestIpv6GetName, NI_MAXHOST, NULL, 0, 0); return PctestIpv6GetName; } // // PctestIpv6::GetAdvanceSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket suitable for sending advance packets. // // NOTE: Advance sockets (and the implementation of -b) for IPv6 is // slightly different between IPv6 and IPv4. For IPv4, we use a // single raw socket (the same one that is used for the "real" probe // packets). This works because we can (need to) construct the // entire IP packet, starting from the IP header. // // With IPv6, we don't control the IP header directly; raw sockets // do not allow us to do this. So each socket is associated with // exactly one transport protocol (i.e. ICMPv6, UDP). In addition, // the ICMPv6 packets are treated specially by the stack, because // they have their pseudo-header calculated for them. For these // reasons, we use a separate socket to send the advance packets // for IPv6. This allows us to support -b independent of the actual // probe packet type. (The same is not true for IPv4, where -b is // supported for raw UDP probes but not for regular SOCK_DGRAM-type // UDP probes). // int PctestIpv6::GetAdvanceSocketOut() { int rc; advanceSocketOut = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (advanceSocketOut < 0) { perror("socket"); return advanceSocketOut; } // Make up a socket address structure for the source address // and attempt to bind the output socket to it. struct sockaddr_in6 originSocketAddress; memset((void *) &originSocketAddress, 0, sizeof(struct sockaddr_in6)); // See comments in PctestIpv6::SetTargetName() about the overloading // of HAVE_SOCKADDR_SA_LEN. #ifdef HAVE_SOCKADDR_SA_LEN originSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ originSocketAddress.sin6_family = AF_INET6; originSocketAddress.sin6_port = htons(0); memcpy(&(originSocketAddress.sin6_addr), &originAddress, sizeof(in6_addr)); rc = bind(advanceSocketOut, (struct sockaddr *) &originSocketAddress, sizeof(originSocketAddress)); if (rc < 0) { perror("bind()"); return rc; } rc = connect(advanceSocketOut, (struct sockaddr *) &targetSocketAddress, sizeof(targetSocketAddress)); if (rc < 0) { perror("connect"); return rc; } // Set TTL. unsigned int hops = IPV6_MAXHLIM; rc = setsockopt(advanceSocketOut, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &hops, sizeof(hops)); if (rc < 0) { perror("setsockopt(IPV6_UNICAST_HOPS)"); return rc; } return advanceSocketOut; } // // PctestIpv6::GenerateAdvancePacket // // Input: // // Output: // char *PctestIpv6::GenerateAdvancePacket(TestRecord &tr) { extern unsigned int Mtu; // Make up an ICMPv6 packet to send out. We only need the ICMPv6 // header and payload, and the kernel will take care of computng // the ICMPv6 checksum for us. int icmp6PayloadSize = Mtu - sizeof(ip6_hdr) - sizeof(icmp6_hdr); struct icmp6_hdr icmp6Header; icmp6Header.icmp6_type = ICMP6_ECHO_REPLY; icmp6Header.icmp6_code = 0; icmp6Header.icmp6_id = htons(icmp6Id); icmp6Header.icmp6_seq = htons(icmp6Sequence); IF_DEBUG(2, fprintf(stdout, "test size %d, payload size %d\n", tr.size, icmp6PayloadSize)); // ICMPv6 payload char *icmp6Payload; icmp6Payload = GeneratePayload(icmp6PayloadSize); if (icmp6Payload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return NULL; } // Build the packet (well, really just the ICMPv6 message) // Once again, we don't need to bother with the ICMPv6 checksum; // the kernel should deal with it for us. char *icmp6Packet; int icmp6PacketSize; icmp6PacketSize = sizeof(icmp6_hdr) + icmp6PayloadSize; icmp6Packet = new char[icmp6PacketSize]; memcpy(icmp6Packet, &icmp6Header, sizeof(icmp6Header)); memcpy(icmp6Packet + sizeof(icmp6Header), icmp6Payload, icmp6PayloadSize); return icmp6Packet; } pchar-1.5/PctestIpv6.h000644 002001 000024 00000005455 10203463722 014677 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv6.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv6 tests // #ifndef PCTESTIPV6_H #define PCTESTIPV6_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "Pctest.h" #include "TestRecord.h" class PctestIpv6 : public Pctest { public: PctestIpv6() { socketOut = 0; socketIn = 0; destPort = 32768; icmp6Id = (u_short) getpid(); // cache PID for ICMP ID field icmp6Sequence = 0; // init sequence number }; PctestIpv6(int p) { socketOut = 0; socketIn = 0; destPort = p; icmp6Id = (u_short) getpid(); // cache PID for ICMP ID field icmp6Sequence = 0; // init sequence number }; virtual ~PctestIpv6() { if (socketOut > 0) { close(socketOut); } if (socketIn > 0) { close(socketIn); } if (advanceSocketOut > 0) { close(advanceSocketOut); } }; virtual int SetOriginName(char *origin); virtual void *GetOriginAddress() {return &originAddress;}; virtual int SetTargetName(char *target); virtual int GetSocketIn(); virtual char *GetPrintableAddress(); virtual char *GetPrintableAddress(void *a); virtual char *GetName(void *a); virtual char *GetAddressFamilyString() { return "AF_INET6"; } virtual int GetAddressFamily() { return (AF_INET6); } protected: struct in6_addr originAddress; struct in6_addr targetAddress; struct sockaddr_in6 targetSocketAddress; struct sockaddr_in6 icmpDestSocketAddress; struct sockaddr_in6 icmpSourceSocketAddress; int socketOut; // output socket (RAW) int socketIn; // input socket (ICMP) int advanceSocketOut; // output socket (RAW for ICMP) int proto; // (hopefully) ICMP protocol number int destPort; // destination port number u_short icmp6Id; // ICMP ID u_short icmp6Sequence; // ICMP sequence number virtual int GetAdvanceSocketOut(); virtual char *GenerateAdvancePacket(TestRecord &tr); }; #endif /* PCTESTIPV6_H */ pchar-1.5/PctestIpv6File.cc000644 002001 000024 00000020061 10203463722 015623 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv6File.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv6File.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6File.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv6 tests reading test data from previously-saved results // #include #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef NEED_NRL_IPV6_HACK #include #include #else #include #include #endif /* NEED_NRL_IPV6_HACK */ #include #include #include "pc.h" #include "PctestIpv6File.h" #include "TestRecord.h" extern unsigned int Mtu; // // PctestIpv6File::GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, but for us it's a no-op. // int PctestIpv6File::GetSocketOut() { return 0; } // // PctestIpv6File::GetSocketIn // // Input: None // // Output: In return value, returns socket number. // // Override the superclass behavior...we don't use sockets. // int PctestIpv6File::GetSocketIn() { return 0; } // // PctestIpv6File::SetOriginName // // Input: ignored // // Output: success code (negative if an error) // // This method exists primarily to override PctestIpv6::SetOriginName // to prevent it from overwriting the originAddress and originName // members, which were set when the trace file was read using // PctestIpv6File::SetTargetName. All we need to do here is a // name lookup. // // Note: This code comes from PctestIpv4File::SetOriginName. // If we can ever do a multiple inheritance on the file-reading // test methods, this is a candidate for inclusion in the base // file-reading class. // int PctestIpv6File::SetOriginName(char *t) { struct hostent *host; // resolver hostname entry originName = strdup(GetName((char *) &originAddress)); if (originName == NULL) { fprintf(stderr, "Couldn't allocate memory for origin hostname.\n"); return -1; } } // // PctestIpv6File::SetTargetName // // Input: none // // Output: success code (negative if error) // // For protocols that actually send packets on the network, // do name resolution on the target host. For this case, however, // we read in the savefile, for later use by PctestIpv6File::Test. // As with the other, similar routine(s), we're responsible for // printing any error messages that come up, since they're likely // to be domain-specific. // int PctestIpv6File::SetTargetName(char *t) { extern unsigned int Burst; // maximum burst size extern unsigned int Hops; // number of hops extern unsigned int Increment; // packet size increment extern unsigned int Mtu; // transfer MTU extern char *ReadFilename; // user-supplied filename extern unsigned int Repetitions; // number of repetitions per packet size extern unsigned int StartHop; // starting hop number extern int VerboseFlag; // -v from command-line bool done = false; // done reading? int linenum = 1; // line number const unsigned int buflen = 1024; // maximum line length char buf[buflen]; // line buffer char *s; // return value from fgets TestRecord *tr; // test record read from file TestRecord *trstail = NULL; // If the user didn't supply us with a command-line filename, // it's an error. if (!ReadFilename) { fprintf(stderr, "No filename specified for -r\n"); return -1; } // Try to open the file f = fopen(ReadFilename, "r"); if (!f) { perror("fopen"); return -1; } // Loop until finished while (!done) { s = fgets(buf, buflen, f); // See if we're done... if (!s) { if (ferror(f)) { // error condition perror("fgets"); } done = true; goto doneline; } // Process a line. We're going to make a very simple parser // here and in TestRecord::atoh(). // char *cur; // First, throw out all blank (or almost blank) lines... for (cur = s; *cur != '\0'; cur++) { if (!isspace(*cur)) { break; } } if (*cur == '\0') { goto doneline; } // Then, look for comment lines if (*s == '#') { goto doneline; } if (strncasecmp(s, "probe ", 6) == 0) { tr = TestRecord::atoh(s, this); if (tr == NULL) { return -1; } tr->used = false; // Try to keep the SLL in the same order that we read stuff. // To do this efficiently means we need to (temporarily) // keep a tail pointer. if (trstail) { trstail->next = tr; trstail = tr; tr->next = NULL; } else { trs = tr; trstail = tr; tr->next = NULL; } } else if (strncasecmp(s, "src ", 4) == 0) { char t[128]; sscanf(s, "src %127s", t); inet_pton(AF_INET6, t, (void *) &originAddress); } else if (strncasecmp(s, "dest ", 5) == 0) { char t[128]; sscanf(s, "dest %127s", t); inet_pton(AF_INET6, t, (void *) &targetAddress); } else if (strncasecmp(s, "burst ", 6) == 0) { sscanf(s, "burst %d", &Burst); } else if (strncasecmp(s, "minsize ", 8) == 0) { sscanf(s, "minsize %d", &minsize); } // hops: else if (strncasecmp(s, "hops ", 5) == 0) { sscanf(s, "hops %d", &Hops); } else if (strncasecmp(s, "increment ", 10) == 0) { sscanf(s, "increment %d", &Increment); } else if (strncasecmp(s, "mtu ", 4) == 0) { sscanf(s, "mtu %d", &Mtu); } else if (strncasecmp(s, "repetitions ", 12) == 0) { sscanf(s, "repetitions %d", &Repetitions); } else if (strncasecmp(s, "starthop ", 9) == 0) { sscanf(s, "starthop %d", &StartHop); } else if (strncasecmp(s, "targethost ", 11) == 0) { char t[128]; sscanf(s, "targethost %127s", t); PctestIpv6::SetTargetName(t); } else if (strncasecmp(s, "addresses ", 10) == 0) { // Ignore lines that look like this; we already parsed // them to select this object. } // We can semi-quietly ignore everything else from this point. // If we're in verbose mode, we can yell about it. else if (VerboseFlag) { fprintf(stderr, "warning: ignoring line %s", s); } doneline: linenum++; } // Done with file fclose(f); f = NULL; return 0; } // // PctestIpv6File::Test // // Input: // // Output: // // A negative icmpCode indicates a timeout. // int PctestIpv6File::Test(TestRecord &tr) { TestRecord *cur; // Loop through our set of TestRecords that we've already read // in, find the first one that matches both the hops and size, // and isn't used yet. for (cur = trs; cur; cur = cur->next) { if ((!cur->used) && (cur->size == tr.size + ((tr.burst - 1) * Mtu)) && (cur->hops == tr.hops)) { // Found one! Now copy everything over from our TestRecord // into the object provided by the caller. tr.tvstart.tv_sec = cur->tvstart.tv_sec; tr.tvstart.tv_usec = cur->tvstart.tv_usec; tr.tv.tv_sec = cur->tv.tv_sec; tr.tv.tv_usec = cur->tv.tv_usec; tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memcpy(tr.icmpSourceAddress, cur->icmpSourceAddress, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.size = cur->size; tr.replsize = cur->replsize; tr.result = cur->result; cur->used = true; return 0; } } // Error exit fprintf(stderr, "Couldn't find enough records\n"); return -1; } // // PctestIpv6File::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv6File::GetMinSize() { return (minsize); } pchar-1.5/PctestIpv6File.h000644 002001 000024 00000003401 10203463722 015464 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv6File.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6File.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv6 tests reading previously saved data from a file. // #ifndef PCTESTIPV6FILE_H #define PCTESTIPV6FILE_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv6.h" class PctestIpv6File : public PctestIpv6 { public: PctestIpv6File() { PctestIpv6File(0); }; PctestIpv6File(int p) { f = NULL; trs = NULL; }; virtual ~PctestIpv6File() { if (f) { fclose(f); } }; virtual int SetOriginName(char *t); virtual int SetTargetName(char *t); virtual int GetSocketOut(); virtual int GetSocketIn(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); protected: FILE *f; TestRecord *trs; // SLL of records read from the file u_int minsize; // minimum packet size }; #endif /* PCTESTIPV6FILE_H */ pchar-1.5/PctestIpv6Icmp.cc000644 002001 000024 00000037334 10203463722 015647 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv6Icmp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv6Icmp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Udp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv6 tests using ICMP // // // Solaris needs some "extra stuff" to get msg_control in recvmsg(2) // according to Erik Nordmark . His quick // fix to do this is: #ifdef NEED_XOPEN #define _XOPEN_SOURCE 500 #define __EXTENSIONS__ #endif /* NEED_XOPEN */ #include #include #include #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef NEED_NRL_IPV6_HACK #include #include #else #include #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" #include "PctestIpv6Icmp.h" #include "TestRecord.h" // // PctestIpv6Icmp::PctestIpv6Icmp // PctestIpv6Icmp::PctestIpv6Icmp() { extern bool PcapFlag; #ifdef HAVE_PCAP if (PcapFlag) { // Initialize packet filter if (pcap_compile(pc, &fp, "icmp6", 1, maskp) < 0) { fprintf(stderr, "pcap_compile failed\n"); exit(1); } if (pcap_setfilter(pc, &fp) < 0) { fprintf(stderr, "pcap_setfilter failed\n"); exit(1); } } #endif /* HAVE_PCAP */ }; // // PctestIpv6Icmp::GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, store it in socketOut. // int PctestIpv6Icmp::GetSocketOut() { int rc; socketOut = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (socketOut < 0) { perror("socket"); return socketOut; } // Make up a socket address structure for the source address // and attempt to bind the output socket to it. struct sockaddr_in6 originSocketAddress; memset((void *) &originSocketAddress, 0, sizeof(struct sockaddr_in6)); // See comments in PctestIpv6::SetTargetName() about the overloading // of HAVE_SOCKADDR_SA_LEN. #ifdef HAVE_SOCKADDR_SA_LEN originSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ originSocketAddress.sin6_family = AF_INET6; originSocketAddress.sin6_port = htons(0); memcpy(&(originSocketAddress.sin6_addr), &originAddress, sizeof(in6_addr)); rc = bind(socketOut, (struct sockaddr *) &originSocketAddress, sizeof(originSocketAddress)); if (rc < 0) { perror("bind()"); return rc; } // Bind remote side of socket rc = connect(socketOut, (struct sockaddr *) &targetSocketAddress, sizeof(targetSocketAddress)); if (rc < 0) { perror("connect"); return rc; } // Set up sockets for advance packets if (GetAdvanceSocketOut() < 0) { return -1; } return socketOut; } // // PctestIpv6Icmp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv6Icmp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // generic loop counter // Parameters stored as globals extern unsigned int Mtu; extern bool PcapFlag; extern int Timeout; // If the requested sending size is too small, then return an // error. The caller should have figured out the minimum sending // size by calling Pctest::GetMinSize(). if (tr.size < GetMinSize()) { return -1; } // Make up an ICMPv6 packet to send out. We only need the ICMPv6 // header and payload, and the kernel will take care of computng // the ICMPv6 checksum for us. int icmp6PayloadSize = tr.size - sizeof(ip6_hdr) - sizeof(icmp6_hdr); struct icmp6_hdr icmp6Header; icmp6Header.icmp6_type = ICMP6_ECHO_REQUEST; icmp6Header.icmp6_code = 0; icmp6Header.icmp6_id = htons(icmp6Id); icmp6Header.icmp6_seq = htons(icmp6Sequence); IF_DEBUG(2, fprintf(stdout, "test size %d, payload size %d\n", tr.size, icmp6PayloadSize)); // ICMPv6 payload char *icmp6Payload; icmp6Payload = GeneratePayload(icmp6PayloadSize); if (icmp6Payload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } // Build the packet (well, really just the ICMPv6 message) // Once again, we don't need to bother with the ICMPv6 checksum; // the kernel should deal with it for us. char *icmp6Packet; int icmp6PacketSize; icmp6PacketSize = sizeof(icmp6_hdr) + icmp6PayloadSize; icmp6Packet = new char[icmp6PacketSize]; memcpy(icmp6Packet, &icmp6Header, sizeof(icmp6Header)); memcpy(icmp6Packet + sizeof(icmp6Header), icmp6Payload, icmp6PayloadSize); // Set TTL. rc = setsockopt(socketOut, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &tr.hops, sizeof(tr.hops)); if (rc < 0) { perror("setsockopt(IPV6_UNICAST_HOPS)"); return rc; } // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmp6PacketIn; icmp6PacketIn = (char *) malloc(IPV6_MAXPACKET); if (icmp6PacketIn == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } #ifdef HAVE_PCAP if (!PcapFlag) { #endif /* HAVE_PCAP */ // Set timeout value and socket select parameters timeout.tv_sec = Timeout; timeout.tv_usec = 0; FD_ZERO(&readFds); FD_SET(socketIn, &readFds); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(advanceSocketOut, advancePacket, Mtu - sizeof(ip6_hdr), 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send packet rc = send(socketOut, icmp6Packet, icmp6PacketSize, 0); if (rc < 0) { perror("sendto"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { #ifdef HAVE_PCAP if (PcapFlag) { // Wait for a packet. Only take in one packet at a time. rc = pcap_dispatch(pc, 1, callback, (u_char *) this); if (rc < 0) { fprintf(stderr, "pcap_dispatch failed\n"); goto exittest; } // The callback will handle our after- timestamp if // we get a packet, but if the read timeout fired first, // we'll need to do a timestamp here to be sure that tvAfter // has a valid value in it. if (rc == 0) { gettimeofday(&tvAfter, NULL); } } else { #endif /* HAVE_PCAP */ // Select and wait for an ICMP response or a timeout rc = select(FD_SETSIZE, &readFds, NULL, NULL, &timeout); if (rc < 0) { perror("select"); goto exittest; } // Timestamp after and update test record timestamp fields gettimeofday(&tvAfter, NULL); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { struct msghdr msg; // msghdr is for recvmsg struct iovec iov[1]; int controlsize; IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); memset(&msg, 0, sizeof(struct msghdr)); #ifdef HAVE_PCAP if (PcapFlag) { struct ip6_hdr *ipv6Header; ipv6Header = (struct ip6_hdr *) packet; // Chase down the headers to get to the ICMPv6 header // Make tr.replsize and icmp6PacketIn only cover // the ICMPv6 header. // XXX This isn't the right way to do it, because there might // be some extension headers between the IPv6 header // and the ICMPv6 header. if (ipv6Header->ip6_nxt != IPPROTO_ICMPV6) { IF_DEBUG(2, fprintf(stderr, "Ignoring packet\n")); goto donepacket; } memcpy(icmp6PacketIn, packet + sizeof(ip6_hdr), packetLength - sizeof(ip6_hdr)); tr.replsize = packetLength - sizeof(ip6_hdr); // Fill in icmpSourceSocketAddress from the IPv6 // header. memcpy(&icmpSourceSocketAddress.sin6_addr, &(ipv6Header->ip6_src), sizeof(in6_addr)); icmpSourceSocketAddress.sin6_family = AF_INET6; #ifdef HAVE_SOCKADDR_SA_LEN icmpSourceSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ } else { #endif /* HAVE_PCAP */ // Fill in the message header so we can read all the // metadata from the ICMP packet. A lot harder than // with ICMPv4 since we had the IP header to work with. msg.msg_name = (char *) &icmpSourceSocketAddress; msg.msg_namelen = sizeof(icmpSourceSocketAddress); iov[0].iov_base = icmp6PacketIn; iov[0].iov_len = IPV6_MAXPACKET; msg.msg_iov = iov; msg.msg_iovlen = 1; // Solaris 8 (which has native IPv6) doesn't define // CMSG_SPACE for now. According to Erik Nordmark // it'll be added once // draft-ietf-ipngwg-2292bis becomes an RFC. Until // then, he has a small hack to fix this, slightly // modified by bmah. #if (defined(__sun__) || (defined(__sun))) #ifndef CMSG_SPACE #define CMSG_SPACE(length) \ (_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)) + _CMSG_HDR_ALIGN(length)) #endif /* CMSG_SPACE */ #endif /* __sun__ */ controlsize = CMSG_SPACE(sizeof(in6_pktinfo)); msg.msg_control = new char[controlsize]; msg.msg_controllen = controlsize; msg.msg_flags = 0; rc = recvmsg(socketIn, &msg, 0); if (rc < 0) { perror("read"); goto exittest; } tr.replsize = rc; #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet.. ip6_hdr *ip6Header; icmp6_hdr *icmp6HeaderIn, *icmp6HeaderIn2; if (tr.replsize - (0) < sizeof(icmp6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMPv6 packet of %d bytes\n", tr.replsize)); continue; } // Find the ICMPv6 header icmp6HeaderIn = (icmp6_hdr *) icmp6PacketIn; IF_DEBUG(3, fprintf(stderr, "ICMPv6 type = %d, code = %d\n", icmp6HeaderIn->icmp6_type, icmp6HeaderIn->icmp6_code)); // Check ICMPv6 type. See this code in // PctestIpv6Udp::Test for some commentary on a more graceful // way to deal with this whole issue of what type/codes we // want to take. if ((icmp6HeaderIn->icmp6_type != ICMP6_TIME_EXCEEDED) && (icmp6HeaderIn->icmp6_type != ICMP6_DST_UNREACH) && (icmp6HeaderIn->icmp6_type != ICMP6_ECHO_REPLY)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet\n")); goto donepacket; } // Is it an echo reply? If so, check to see if it's // ours. Note no ntoh() conversions needed here because // we're just comparing fields in two "on-the-wire" packets. if (icmp6HeaderIn->icmp6_type == ICMP6_ECHO_REPLY) { if ((icmp6HeaderIn->icmp6_id != icmp6Header.icmp6_id) || (icmp6HeaderIn->icmp6_seq != icmp6Header.icmp6_seq)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet with mismatched id/seq\n")); goto donepacket; } // It's ours; fill in return fields. goto acceptpacket; } if (tr.replsize - (0 + sizeof(icmp6_hdr)) < sizeof(ip6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IPv6 packet, %d bytes total\n", tr.replsize)); goto donepacket; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be just past the ICMPv6 header. ip6Header = (ip6_hdr *) ((char *) icmp6HeaderIn + sizeof(icmp6_hdr)); // Note: We can look for an ICMPv6 header immediately following // the inner IPv6 header because we know (or at least we // think we know) that the original packet went out with no // extension headers. If that's not true, this test will fail. // If we happen to be a situation where we need to do this, // then we have to insert a parser to skip over the extension // headers right here. if (ip6Header->ip6_nxt != IPPROTO_ICMP) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet for non-ICMPv6\n")); goto donepacket; } // Check to see if we got enough for a complete ICMP header. // RFC 2463 says that we should get back as much of the // packet that will fit in an MTU. if (tr.replsize - (0 + sizeof(icmp6_hdr) + sizeof(ip6_hdr)) < sizeof(icmp6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner ICMPv6 packet, %d bytes total\n", tr.replsize)); goto donepacket; } // Align ICMP header template. icmp6HeaderIn2 = (icmp6_hdr *) (((char *) ip6Header) + sizeof(ip6_hdr)); // Check ID and sequence number of the inner packet to be sure // it matches the one we sent out. if ((icmp6HeaderIn2->icmp6_id != icmp6Header.icmp6_id) || (icmp6HeaderIn2->icmp6_id != icmp6Header.icmp6_id)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet for unknown ICMPv6 packet\n")); goto donepacket; } acceptpacket: // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memcpy(tr.icmpSourceAddress, &icmpSourceSocketAddress.sin6_addr, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = GetAction(icmp6HeaderIn->icmp6_type, icmp6HeaderIn->icmp6_code); done = 1; donepacket: if (msg.msg_control) { delete [] (char *) msg.msg_control; msg.msg_control = NULL; } } else if (tr.tv.tv_sec >= Timeout) { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: delete [] icmp6Payload; delete [] icmp6Packet; free(icmp6PacketIn); return rc; } // // PctestIpv6Icmp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv6Icmp::GetMinSize() { return (sizeof(ip6_hdr) + sizeof(icmp6_hdr) + 4); } // // PctestIpv6Icmp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv6 type // and code values. // PctestActionType PctestIpv6Icmp::GetAction(int icmp6_type, int icmp6_code) { if (icmp6_type == ICMP6_TIME_EXCEEDED) { return PctestActionValid; } else if (icmp6_type == ICMP6_ECHO_REPLY) { return PctestActionValidLasthop; } else if ((icmp6_type == ICMP6_DST_UNREACH) && (icmp6_code == ICMP6_DST_UNREACH_ADMIN)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv6Icmp.h000644 002001 000024 00000003073 10203463722 015502 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv6Icmp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Icmp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv6 tests using ICMP // #ifndef PCTESTIPV6ICMP_H #define PCTESTIPV6ICMP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv6.h" class PctestIpv6Icmp : public PctestIpv6 { public: PctestIpv6Icmp(); PctestIpv6Icmp(int p) { fprintf(stderr, "PctestIpv6Icmp can't take port numbers\n"); exit(1); }; virtual ~PctestIpv6Icmp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmp6_type, int icmp6_code); protected: }; #endif /* PCTESTIPV6ICMP_H */ pchar-1.5/PctestIpv6Tcp.cc000644 002001 000024 00000034566 10203463722 015511 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv6Tcp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv6Tcp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Tcp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv6 tests using TCP // // // Solaris needs some "extra stuff" to get msg_control in recvmsg(2) // according to Erik Nordmark . His quick // fix to do this is: #ifdef NEED_XOPEN #define _XOPEN_SOURCE 500 #define __EXTENSIONS__ #endif /* NEED_XOPEN */ #include #include #include #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef NEED_NRL_IPV6_HACK #include #include #else #include #include #endif /* NEED_NRL_IPV6_HACK */ #include #include #ifdef HAVE_PCAP #include #endif /* HAVE_PCAP */ #include "pc.h" #include "PctestIpv6Tcp.h" #include "TestRecord.h" // // PctestIpv6Tcp::PctestIpv6Tcp // PctestIpv6Tcp::PctestIpv6Tcp(int p) { extern bool PcapFlag; #ifdef HAVE_PCAP if (PcapFlag) { // Initialize packet filter if (pcap_compile(pc, &fp, "(ip6 and tcp) or (ip6 and icmp6)", 1, maskp) < 0) { fprintf(stderr, "pcap_compile failed\n"); exit(1); } if (pcap_setfilter(pc, &fp) < 0) { fprintf(stderr, "pcap_setfilter failed\n"); exit(1); } } else { #endif /* HAVE_PCAP */ fprintf(stderr, "ipv6tcp probes require libpcap functionality\n"); exit(1); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ }; // // PctestIpv6Tcp::GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, store it in socketOut. // int PctestIpv6Tcp::GetSocketOut() { int rc; socketOut = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP); if (socketOut < 0) { perror("socket"); return socketOut; } // Turn on checksum computation int checksumOffset; checksumOffset = 16; // voodoo constant: how far into the // packet does the TCP checksum live? rc = setsockopt(socketOut, IPPROTO_IPV6, IPV6_CHECKSUM, &checksumOffset, sizeof(checksumOffset)); if (rc < 0) { perror("setsockopt(IPV6_CHECKSUM)"); return rc; } // Make up a socket address structure for the source address // and attempt to bind the output socket to it. struct sockaddr_in6 originSocketAddress; memset((void *) &originSocketAddress, 0, sizeof(struct sockaddr_in6)); // See comments in PctestIpv6::SetTargetName() about the overloading // of HAVE_SOCKADDR_SA_LEN. #ifdef HAVE_SOCKADDR_SA_LEN originSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ originSocketAddress.sin6_family = AF_INET6; originSocketAddress.sin6_port = htons(0); memcpy(&(originSocketAddress.sin6_addr), &originAddress, sizeof(in6_addr)); rc = bind(socketOut, (struct sockaddr *) &originSocketAddress, sizeof(originSocketAddress)); if (rc < 0) { perror("bind()"); return rc; } // Bind remote side of socket rc = connect(socketOut, (struct sockaddr *) &targetSocketAddress, sizeof(targetSocketAddress)); if (rc < 0) { perror("connect"); return rc; } // Set up sockets for advance packets if (GetAdvanceSocketOut() < 0) { return -1; } return socketOut; } // // PctestIpv6Tcp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv6Tcp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // generic loop counter // Parameters stored as globals extern unsigned int Mtu; extern bool PcapFlag; extern int Timeout; #ifdef HAVE_PCAP if (PcapFlag) { // If the requested sending size is too small, then return an // error. The caller should have figured out the minimum sending // size by calling Pctest::GetMinSize(). if (tr.size < GetMinSize()) { return -1; } // Make up a TCP segment to send out. int tcpPayloadSize = tr.size - sizeof(ip6_hdr) - sizeof(icmp6_hdr); struct tcphdr tcpHeader; // Fill in TCP header fields, see PctestIpv4Tcp::Test() for // commentary. memset(&tcpHeader, 0, sizeof(tcpHeader)); tcpHeader.th_sport = htons(30003); tcpHeader.th_dport = htons(destPort++); tcpHeader.th_seq = htons(0); tcpHeader.th_ack = htons(0); #ifdef __osf__ // Tru64 does not declare th_off if __STDC__ == 1 tcpHeader.th_xoff = (sizeof(tcphdr)/4)<<4; // header length words with no options // shifted by 4 bits to cover unused field #else tcpHeader.th_off = sizeof(tcphdr)/4; // header length words with no options #endif /* __osf__ */ tcpHeader.th_flags = TH_FIN | TH_ACK; tcpHeader.th_win = htons(1); tcpHeader.th_sum = 0; tcpHeader.th_urp = htons(0); IF_DEBUG(2, fprintf(stdout, "test size %d, payload size %d\n", tr.size, tcpPayloadSize)); // TCP payload char *tcpPayload; tcpPayload = GeneratePayload(tcpPayloadSize); if (tcpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } // Build the packet (well, really just the TCP segment) char *tcpPacket; int tcpPacketSize; tcpPacketSize = sizeof(tcphdr) + tcpPayloadSize; tcpPacket = new char[tcpPacketSize]; memcpy(tcpPacket, &tcpHeader, sizeof(tcpHeader)); memcpy(tcpPacket + sizeof(tcpHeader), tcpPayload, tcpPayloadSize); // Set TTL. rc = setsockopt(socketOut, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &tr.hops, sizeof(tr.hops)); if (rc < 0) { perror("setsockopt(IPV6_UNICAST_HOPS)"); return rc; } // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmp6PacketIn; icmp6PacketIn = (char *) malloc(IPV6_MAXPACKET); if (icmp6PacketIn == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(advanceSocketOut, advancePacket, Mtu - sizeof(ip6_hdr), 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send packet rc = send(socketOut, tcpPacket, tcpPacketSize, 0); if (rc < 0) { perror("sendto"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { // Wait for a packet. Only take in one packet at a time. rc = pcap_dispatch(pc, 1, callback, (u_char *) this); if (rc < 0) { fprintf(stderr, "pcap_dispatch failed\n"); goto exittest; } // The callback will handle our after- timestamp if // we get a packet, but if the read timeout fired first, // we'll need to do a timestamp here to be sure that tvAfter // has a valid value in it. if (rc == 0) { gettimeofday(&tvAfter, NULL); } tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); struct ip6_hdr *ipv6HeaderIn; ipv6HeaderIn = (struct ip6_hdr *) packet; if ((ipv6HeaderIn->ip6_nxt != IPPROTO_ICMPV6) && (ipv6HeaderIn->ip6_nxt != IPPROTO_TCP)) { IF_DEBUG(2, fprintf(stderr, "Ignoring non-ICMPv6, non-TCP packet\n")); continue; } memcpy(icmp6PacketIn, packet + sizeof(ip6_hdr), packetLength - sizeof(ip6_hdr)); tr.replsize = packetLength - sizeof(ip6_hdr); // Fill in icmpSourceSocketAddress from the IPv6 // header. memcpy(&icmpSourceSocketAddress.sin6_addr, &(ipv6HeaderIn->ip6_src), sizeof(in6_addr)); icmpSourceSocketAddress.sin6_family = AF_INET6; #ifdef HAVE_SOCKADDR_SA_LEN icmpSourceSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ // Parse the packet and error-check icmp6_hdr *icmp6HeaderIn, *icmp6HeaderIn2; // Check protocol if ((ipv6HeaderIn->ip6_nxt != proto) && (ipv6HeaderIn->ip6_nxt != IPPROTO_TCP)) { IF_DEBUG(0, fprintf(stderr, "Received unknown protocol %d in (supposedly) ICMPv6 or TCP packet\n", ipv6HeaderIn->ip6_nxt)); rc = -1; goto exittest; } // See if it was an ICMPv6 message if (ipv6HeaderIn->ip6_nxt == proto) { if (tr.replsize - (0) < sizeof(icmp6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMPv6 packet of %d bytes\n", tr.replsize)); continue; } // Find the ICMPv6 header icmp6HeaderIn = (icmp6_hdr *) icmp6PacketIn; IF_DEBUG(3, fprintf(stderr, "ICMPv6 type = %d, code = %d\n", icmp6HeaderIn->icmp6_type, icmp6HeaderIn->icmp6_code)); // Check ICMPv6 type. See this code in // PctestIpv6Udp::Test for some commentary on a more graceful // way to deal with this whole issue of what type/codes we // want to take. if ((icmp6HeaderIn->icmp6_type != ICMP6_TIME_EXCEEDED) && (icmp6HeaderIn->icmp6_type != ICMP6_DST_UNREACH)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet\n")); continue; } // Check the inner packet contained within the ICMP payload if (tr.replsize - (0 + sizeof(icmp6_hdr)) < sizeof(ip6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IPv6 packet, %d bytes total\n", tr.replsize)); continue; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be just past the ICMPv6 header. ipv6HeaderIn = (ip6_hdr *) ((char *) icmp6HeaderIn + sizeof(icmp6_hdr)); // Look for TCP header immediately following the inner // IPv6 header. See PctestIpv6Icmp::Test for commentary // on the lack of extension headers. if (ipv6HeaderIn->ip6_nxt != IPPROTO_TCP) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet for non-TCP\n")); continue; } // Check to see if we got enough for a complete TCP header. if (tr.replsize - (0 + sizeof(icmp6_hdr) + sizeof(ip6_hdr)) < sizeof(tcphdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner TCP header, %d bytes total\n", tr.replsize)); continue; } // Align ICMP header template. tcphdr *tcpHeaderIn; tcpHeaderIn = (tcphdr *) (((char *) ipv6HeaderIn) + sizeof(ip6_hdr)); // XXX Check IPv6 addresses and port numbers to match what we // sent out. if ((memcmp(&(ipv6HeaderIn->ip6_src), &(originAddress), sizeof(struct in6_addr))) || (memcmp(&(ipv6HeaderIn->ip6_dst), &(targetAddress), sizeof(struct in6_addr))) || (tcpHeaderIn->th_dport != tcpHeader.th_dport) || (tcpHeaderIn->th_sport != tcpHeader.th_sport)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet referring to unknown TCP connection\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memcpy(tr.icmpSourceAddress, &icmpSourceSocketAddress.sin6_addr, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = GetAction(icmp6HeaderIn->icmp6_type, icmp6HeaderIn->icmp6_code); done = 1; } // See if we got back a TCP packet else if (ipv6HeaderIn->ip6_nxt == IPPROTO_TCP) { tcphdr *tcpHeaderIn; tcpHeaderIn = (tcphdr *) (((char *) ipv6HeaderIn) + sizeof(ip6_hdr)); if ((memcmp(&(ipv6HeaderIn->ip6_src), &(targetAddress), sizeof(struct in6_addr))) || (memcmp(&(ipv6HeaderIn->ip6_dst), &(originAddress), sizeof(struct in6_addr))) || (tcpHeaderIn->th_dport != tcpHeader.th_sport) || (tcpHeaderIn->th_sport != tcpHeader.th_dport)) { IF_DEBUG(3, fprintf(stderr, "Ignoring TCP packet for unknown connection\n")); continue; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memcpy(tr.icmpSourceAddress, &(ipv6HeaderIn->ip6_src), sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = PctestActionValidLasthop; done = 1; } } else if (tr.tv.tv_sec >= Timeout) { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: delete [] tcpPayload; delete [] tcpPacket; free(icmp6PacketIn); return rc; } else { #endif /* HAVE_PCAP */ fprintf(stderr, "ipv6tcp probes require libpcap functionality"); exit(1); #ifdef HAVE_PCAP } #endif /* HAVE_PCAP */ } // // PctestIpv6Tcp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv6Tcp::GetMinSize() { return (sizeof(ip6_hdr) + sizeof(tcphdr) + 4); } // // PctestIpv6Tcp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv6 type // and code values. // PctestActionType PctestIpv6Tcp::GetAction(int icmp6_type, int icmp6_code) { if (icmp6_type == ICMP6_TIME_EXCEEDED) { return PctestActionValid; } else if (icmp6_type == ICMP6_ECHO_REPLY) { return PctestActionValidLasthop; } else if ((icmp6_type == ICMP6_DST_UNREACH) && (icmp6_code == ICMP6_DST_UNREACH_ADMIN)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv6Tcp.h000644 002001 000024 00000002751 10203463722 015342 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv6Tcp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Tcp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header for class of IPv6 tests using TCP // #ifndef PCTESTIPV6TCP_H #define PCTESTIPV6TCP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv6.h" class PctestIpv6Tcp : public PctestIpv6 { public: PctestIpv6Tcp() { }; PctestIpv6Tcp(int p); virtual ~PctestIpv6Tcp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmpType, int icmpCode); protected: }; #endif /* PCTESTIPV6TCP_H */ pchar-1.5/PctestIpv6Udp.cc000644 002001 000024 00000030570 10203463722 015502 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: PctestIpv6Udp.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: PctestIpv6Udp.cc 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Udp.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Class of IPv6 tests using UDP // // // Solaris needs some "extra stuff" to get msg_control in recvmsg(2) // according to Erik Nordmark . His quick // fix to do this is: #ifdef NEED_XOPEN #define _XOPEN_SOURCE 500 #define __EXTENSIONS__ #endif /* NEED_XOPEN */ #include #include #include #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #include #ifdef NEED_NRL_IPV6_HACK #include #include #else #include #include #endif /* NEED_NRL_IPV6_HACK */ #include #include #include "pc.h" #include "PctestIpv6Udp.h" #include "TestRecord.h" // // GetSocketOut // // Input: None // // Output: In return value, returns socket number. // // Get output socket of an appropriate type, store in socketOut. // int PctestIpv6Udp::GetSocketOut() { int rc; socketOut = socket(AF_INET6, SOCK_DGRAM, 0); if (socketOut < 0) { perror("socket"); return socketOut; } #ifdef linux // Linux needs SO_BSDCOMPAT enabled on our UDP socket, to avoid // getting ICMP errors when we send packets out. int bsdcompatOption; bsdcompatOption = 1; rc = setsockopt(socketOut, SOL_SOCKET, SO_BSDCOMPAT, &bsdcompatOption, sizeof(bsdcompatOption)); if (rc < 0) { perror("setsockopt(SO_BSDCOMPAT)"); return rc; } #endif /* linux */ // Make up a socket address structure for the source address // and attempt to bind the output socket to it. struct sockaddr_in6 originSocketAddress; memset((void *) &originSocketAddress, 0, sizeof(struct sockaddr_in6)); // See comments in PctestIpv6::SetTargetName() about the overloading // of HAVE_SOCKADDR_SA_LEN. #ifdef HAVE_SOCKADDR_SA_LEN originSocketAddress.sin6_len = sizeof(struct sockaddr_in6); #endif /* HAVE_SOCKADDR_SA_LEN */ originSocketAddress.sin6_family = AF_INET6; originSocketAddress.sin6_port = htons(0); memcpy(&(originSocketAddress.sin6_addr), &originAddress, sizeof(in6_addr)); rc = bind(socketOut, (struct sockaddr *) &originSocketAddress, sizeof(originSocketAddress)); if (rc < 0) { perror("bind()"); return rc; } // Set up sockets for advance packets if (GetAdvanceSocketOut() < 0) { return -1; } return socketOut; } // // PctestIpv6Udp::Test // // Input: // // Output: // // A negative icmpCode indicates an error. // int PctestIpv6Udp::Test(TestRecord &tr) { struct timeval timeout; int rc; // syscall return code fd_set readFds; // reading file descriptors int done = 0; int i; // generic loop counter // Parameters stored as globals extern unsigned int Mtu; extern int Timeout; // If the requested sending size is too small, then return an // error. The caller should have figured out the minimum sending // size by calling Pctest::GetMinSize(). if (tr.size < GetMinSize()) { return -1; } // Make up a UDP packet to send out. int udpPayloadSize = tr.size - sizeof(ip6_hdr) - sizeof(udphdr); char *udpPayload; udpPayload = GeneratePayload(udpPayloadSize); if (udpPayload == NULL) { fprintf(stderr, "Couldn't allocate space for payload\n"); return -1; } targetSocketAddress.sin6_port = htons(destPort++); // Set TTL. rc = setsockopt(socketOut, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &tr.hops, sizeof(tr.hops)); if (rc < 0) { perror("setsockopt(IPV6_UNICAST_HOPS)"); return rc; } // If we need to construct some advance packets, generate // an image of said packet. char *advancePacket; if (tr.burst - 1 == 0) { advancePacket = NULL; } else { advancePacket = GenerateAdvancePacket(tr); if (advancePacket == NULL) { return -1; } } // Use malloc(3) to allocate (memory-aligned) space for the inbound // packet. char *icmp6PacketIn; icmp6PacketIn = (char *) malloc(IPV6_MAXPACKET); if (icmp6PacketIn == NULL) { fprintf(stderr, "Couldn't allocate space for inbound packet\n"); return -1; } // Set timeout value and socket select parameters timeout.tv_sec = Timeout; timeout.tv_usec = 0; FD_ZERO(&readFds); FD_SET(socketIn, &readFds); // Timestamp before gettimeofday(&tvBefore, NULL); // Send advance packets if necessary for (i = 1; i < tr.burst; i++) { rc = send(advanceSocketOut, advancePacket, Mtu - sizeof(ip6_hdr), 0); if (rc < 0) { perror("send"); goto exittest; } } tr.size += (tr.burst - 1) * Mtu; // Send UDP packet rc = sendto(socketOut, udpPayload, udpPayloadSize, 0, (struct sockaddr *) &targetSocketAddress, sizeof(struct sockaddr_in6)); if (rc < 0) { perror("sendto"); goto exittest; } // We need to check the socket until we get a valid packet. // So we might end up doing this select/read several times. do { // Select and wait for an ICMP response or a timeout rc = select(FD_SETSIZE, &readFds, NULL, NULL, &timeout); if (rc < 0) { perror("select"); goto exittest; } // Timestamp after and update test record timestamp fields gettimeofday(&tvAfter, NULL); tr.tv.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec - syscallTime.tv_sec; tr.tv.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec - syscallTime.tv_usec; while (tr.tv.tv_usec < 0) { tr.tv.tv_usec += 1000000; tr.tv.tv_sec--; } // Read response from socket if (rc == 1) { IF_DEBUG(2, fprintf(stderr, "Response packet received\n")); struct msghdr msg; // msghdr is for recvmsg struct iovec iov[1]; int controlsize; // Fill in the message header so we can read all the // metadata from the ICMP packet. A lot harder than // with ICMPv4 since we had the IP header to work with. msg.msg_name = (char *) &icmpSourceSocketAddress; msg.msg_namelen = sizeof(icmpSourceSocketAddress); iov[0].iov_base = icmp6PacketIn; iov[0].iov_len = IPV6_MAXPACKET; msg.msg_iov = iov; msg.msg_iovlen = 1; // Solaris 8 (which has native IPv6) doesn't define // CMSG_SPACE for now. According to Erik Nordmark // it'll be added once // draft-ietf-ipngwg-2292bis becomes an RFC. Until // then, he has a small hack to fix this, slightly // modified by bmah. #if (defined(__sun__) || (defined(__sun))) #ifndef CMSG_SPACE #define CMSG_SPACE(length) \ (_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)) + _CMSG_HDR_ALIGN(length)) #endif /* CMSG_SPACE */ #endif /* __sun__ */ controlsize = CMSG_SPACE(sizeof(in6_pktinfo)); msg.msg_control = new char[controlsize]; msg.msg_controllen = controlsize; msg.msg_flags = 0; rc = recvmsg(socketIn, &msg, 0); if (rc < 0) { perror("read"); goto exittest; } tr.replsize = rc; // Now parse the packet, doing a little error checking along // the way. By the end, we'll have ipHeader and icmpHeader // pointing to valid structures within the packet, and // ipHeader2 pointing to the IP header of the generating // IP packet.. ip6_hdr *ipHeader2; icmp6_hdr *icmpHeader; udphdr *udpHeader; if (tr.replsize - (0) < sizeof(icmp6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete ICMPv6 packet of %d bytes\n", tr.replsize)); continue; } // Find the ICMPv6 header icmpHeader = (icmp6_hdr *) icmp6PacketIn; IF_DEBUG(3, fprintf(stderr, "ICMPv6 type = %d, code = %d\n", icmpHeader->icmp6_type, icmpHeader->icmp6_code)); // Check ICMPv6 type. Note that we already set up ICMPv6 // message filtering in PctestIpv6::GetSocketIn(), which // should catch most messages we don't want. This check // handles the case of messages that pchar in general is // interested in, but this particular test is not. We may // want to rethink this in the future, perhaps by making // ICMPv6 filtering dependent on the test protocol in use.. if ((icmpHeader->icmp6_type != ICMP6_TIME_EXCEEDED) && (icmpHeader->icmp6_type != ICMP6_DST_UNREACH)) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet\n")); goto donepacket; } if (tr.replsize - (0 + sizeof(icmp6_hdr)) < sizeof(ip6_hdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner IPv6 packet, %d bytes total\n", tr.replsize)); goto donepacket; } // Check for a valid (to us) IP header within the packet. // For "time exceeded" or "destination unreachable", this // header will be just past the ICMPv6 header. ipHeader2 = (ip6_hdr *) ((char *) icmpHeader + sizeof(icmp6_hdr)); // Note: We can look for a UDP header immediately following // the inner IPv6 header because we know (or at least we // think we know) that the original packet went out with no // extension headers. If that's not true, this test will fail. // If we happen to be a situation where we need to do this, // then we have to insert a parser to skip over the extension // headers right here. if (ipHeader2->ip6_nxt != IPPROTO_UDP) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMPv6 packet for non-UDP\n")); goto donepacket; } // Check to see if we got enough for a complete UDP header. // RFC 2463 says that we should get back as much of the // packet that will fit in an MTU. if (tr.replsize - (0 + sizeof(icmp6_hdr) + sizeof(ip6_hdr)) < sizeof(udphdr)) { IF_DEBUG(3, fprintf(stderr, "Received incomplete inner UDP packet, %d bytes total\n", tr.replsize)); goto donepacket; } // Align UDP header template. udpHeader = (udphdr *) (((char *) ipHeader2) + sizeof(ip6_hdr)); // Check destination UDP port number (we don't know the // source) and UDP (header+payload) length if ((udpHeader->uh_dport != targetSocketAddress.sin6_port) || (ntohs(udpHeader->uh_ulen) != udpPayloadSize + sizeof(udphdr))) { IF_DEBUG(3, fprintf(stderr, "Ignoring ICMP packet for unknown UDP packet\n")); goto donepacket; } // Fill in return fields tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memcpy(tr.icmpSourceAddress, &icmpSourceSocketAddress.sin6_addr, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = GetAction(icmpHeader->icmp6_type, icmpHeader->icmp6_code); done = 1; donepacket: if (msg.msg_control) { delete [] (char *) msg.msg_control; msg.msg_control = NULL; } } else { IF_DEBUG(2, fprintf(stderr, "Timeout\n")); tr.icmpSourceAddress = new char[sizeof(in6_addr)]; memset(tr.icmpSourceAddress, 0, sizeof(in6_addr)); tr.icmpSourceAddressLength = sizeof(in6_addr); tr.result = PctestActionTimeout; done = 1; } } while (!done); rc = 0; exittest: delete [] udpPayload; free(icmp6PacketIn); return rc; } // // PctestIpv6Udp::GetMinSize // // Input: None // // Output: Minimum packet size possible for this protocol (in return // value). // unsigned int PctestIpv6Udp::GetMinSize() { return (sizeof(ip6_hdr) + sizeof(udphdr) + 4); } // // PctestIpv6Udp::GetAction // // Input: a test record // // Output: action code // // Figure out the meaning of a particular combination of ICMPv6 type // and code values. // PctestActionType PctestIpv6Udp::GetAction(int icmpType, int icmpCode) { if (icmpType == ICMP6_TIME_EXCEEDED) { return PctestActionValid; } else if ((icmpType == ICMP6_DST_UNREACH) && (icmpCode == ICMP6_DST_UNREACH_NOPORT)) { return PctestActionValidLasthop; } else if ((icmpType == ICMP6_DST_UNREACH) && (icmpCode == ICMP6_DST_UNREACH_ADMIN)) { return PctestActionFiltered; } else { return PctestActionAbort; } } pchar-1.5/PctestIpv6Udp.h000644 002001 000024 00000002757 10203463722 015352 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: PctestIpv6Udp.h 1082 2005-02-12 19:40:04Z bmah $ // // PctestIpv6Udp.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Header class for IPv6 tests using UDP // #ifndef PCTESTIPV6UDP_H #define PCTESTIPV6UDP_H #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #if STDC_HEADERS #include #endif /* STDC_HEADERS */ #include #include #include #ifdef NEED_NRL_IPV6_HACK #include #endif /* NEED_NRL_IPV6_HACK */ #if HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ #include "pc.h" #include "PctestIpv6.h" class PctestIpv6Udp : public PctestIpv6 { public: PctestIpv6Udp() { }; PctestIpv6Udp(int p) { }; virtual ~PctestIpv6Udp() { }; virtual int GetSocketOut(); virtual int Test(TestRecord &tr); virtual unsigned int GetMinSize(); virtual PctestActionType GetAction(int icmpType, int icmpCode); protected: }; #endif /* PCTESTIPV6UDP_H */ pchar-1.5/ResultTable.cc000644 002001 000024 00000062774 10203463722 015263 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: ResultTable.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: ResultTable.cc 1082 2005-02-12 19:40:04Z bmah $ // // ResultTable.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // #include #include #include #include "pc.h" #include "ResultTable.h" #include "Kendall.h" // // Constructor // // Input: Table parameters (i, m, b, r) // // Output: None // ResultTable::ResultTable(unsigned int inc, unsigned int m, unsigned int b, unsigned int r) : increment(inc), mtu(m), repetitions(r), burst(b), columns((burst+1)*mtu+1) // Note the initialization of the columns member; we want to be // able to hold the largest possible response packet. (burst+1)*MTU should // work unless the user sets MTU to something small (then add one because // packet sizes begin with 1, not 0). { int i; // Stupid typedef hack for SparcWorks C++ compilier, which apparently // can't handle "new (footype *)[bar]". We're trying to do: // data = new (double *) [columns]; typedef double *DoublePtr; data = new (double *[columns]); if (data == NULL) { fprintf(stderr, "Couldn't allocate data array for a ResultTable\n"); exit(1); } used = new int[columns]; if (used == NULL) { fprintf(stderr, "Couldn't allocate used array for a ResultTable\n"); exit(1); } for (i = 0; i < columns; i++) { data[i] = NULL; used[i] = 0; } // Invalidate result caches cacheSlrValid = false; cacheTauValid = false; cacheLmsValid = false; cacheQueueingValid = false; } // // ResultTable::~ResultTable // // Input: None // // Output None // ResultTable::~ResultTable() { int i; for (i = 0; i < columns; i++) { if (data[i]) { delete [] data[i]; data[i] = NULL; } } delete data; delete used; } // // ResultTable::put // // Input: size, time pair // // Output: Success code in return value (negative if an error) // // Insert a new result into the table. // int ResultTable::put(int size, double time) { int offset; // Is the offset within the proper range for the table? offset = size2column(size); if ((offset < 0) || (offset >= columns)) { fprintf(stderr, "Size %d out of bounds [0,%d)\n", offset, columns); return -1; } // Any room left for more results in this column? if (used[offset] == repetitions) { fprintf(stderr, "Too many repetitions for this size (%d >= %d)\n", used[offset], repetitions); return -1; } // Need to allocate more memory to hold this column? if (data[offset] == NULL) { data[offset] = new double[repetitions]; if (data[offset] == NULL) { fprintf(stderr, "Couldn't allocate memory for new column\n"); return -1; } } // Store data data[offset][used[offset]] = time; (used[offset])++; return 0; // Invalidate result caches cacheSlrValid = false; cacheTauValid = false; cacheQueueingValid = false; } // // ResultTable::getMin // // Input: none // // Output: Pointer to a new ResultTable (NULL if an error) // // Return a new ResultTable, which contains the minimum values // of each packet size test. // ResultTable *ResultTable::getMin() { // Get new ResultTable, but we only need room for one // "repetition". ResultTable *t2 = new ResultTable(increment, mtu, burst, 1); if (t2 == NULL) { return NULL; } // Iterate over columns (packet sizes) int i; for (i = 0; i < columns; i++) { // If any values, then find the minimum and store it. if (used[i]) { int j; double min = data[i][0]; for (j = 1; j < used[i]; j++) { if (data[i][j] < min) { min = data[i][j]; } } if (t2->put(column2size(i), min) < 0) { return NULL; } } } return t2; } // // ResultTable::queueing // // Input: None // // Output: Average queueing delay for this dataset (in return // value). If there are no data points in this table, the result // is 0.0. // // Compute average (?) queueing delay for this dataset. // Found by computing, for each column, the difference from the column // minimum. // // XXX we might want some better statistics too, such as getting // a confidence interval. // double ResultTable::queueing() { // If we've cached a queueing figure, then just return it. if (cacheQueueingValid) { return cacheQueueing; IF_DEBUG(1, fprintf(stderr, "ResultTable::queueing(): cache hit\n")); } // Results not valid, need to compute them. else { int i, j; double sigmaY = 0.0; int n = 0; // Loop over columns for (i = 0; i < columns; i++) { // Only the ones with data points if (used[i] > 0) { double min; double y; // Find the minimum data point for this column min = data[i][0]; for (j = 1; j < used[i]; j++) { if (data[i][j] < min) { min = data[i][j]; } } // Now compute the difference between each data // point and the minimum and add it to the sum. // // NB: There are faster ways to get this result, // but we do it this way so that we can get access // to the individual data points, for example to // compute some other statistics on them. for (j = 0; j < used[i]; j++) { y = data[i][j] - min; sigmaY += y; n++; } } } if (n > 0) { cacheQueueing = sigmaY / n; } else { cacheQueueing = 0.0; } cacheQueueingValid = true; return cacheQueueing; } } // // ResultTable::slr // // Input: None // // Output: SLR parameters (a and b, where a is the linear constant // and b is the X coeffecient), coefficient of determination R2, // standard deviation of parameters sb and sb. // // Compute simple linear regression for all data points, based on // a least-squares algorithm as described by // text in Chapter 14 of "The Art of Computer Systems Performance // Analysis", R. Jain, 1991. // void ResultTable::slr(double &a, double &b, double &R2, double &sa, double &sb) { // If cached results valid, use them if (cacheSlrValid) { a = cacheSlrA; b = cacheSlrB; R2 = cacheSlrR2; sa = cacheSlrSA; sb = cacheSlrSB; IF_DEBUG(1, fprintf(stderr, "ResultTable::slr(): cache hit\n")); return; } // Compute results else { double sigmaX = 0.0, sigmaY = 0.0, sigmaXY = 0.0, sigmaX2 = 0.0, sigmaY2 = 0.0; double Xbar, Ybar; double b0, b1; double SSY, SS0, SST, SSE, SSR; double se; int n = 0; int i, j; // Iterate over columns for (i = 0; i < columns; i++) { // Iterate over points within a column for (j = 0; j < used[i]; j++) { double X = (double) column2size(i); double Y = data[i][j]; sigmaX += X; sigmaY += Y; sigmaXY += (X*Y); sigmaX2 += (X*X); sigmaY2 += (Y*Y); n++; } } // We need at least three datapoints. If we don't have that // many, return something that, while bogus, at least makes a // little sense, to avoid getting divide-by-zero situations. if (n == 0) { a = 0.0; b = 0.0; R2 = 0.0; sa = 0.0; sb = 0.0; return; } Xbar = sigmaX / n; Ybar = sigmaY / n; // b1 = b, b0 = a b1 = (sigmaXY - (n * Xbar * Ybar)) / (sigmaX2 - (n * Xbar * Xbar)); b0 = Ybar - b1 * Xbar; // Compute variation SSY = sigmaY2; SS0 = n * (Ybar * Ybar); SST = SSY - SS0; SSE = sigmaY2 - (b0 * sigmaY) - (b1 * sigmaXY); SSR = SST - SSE; // Compute regression parameters a = b0; b = b1; // Compute coefficient of determination R2 = SSR/SST; // Compute standard deviation of errors se = sqrt(SSE/(n-2)); // Compute Standard deviation of parameters sa = se * sqrt( (1/n) + ((Xbar * Xbar) / (sigmaX2 - (n * Xbar * Xbar)))); sb = se / sqrt( sigmaX2 - (n * Xbar * Xbar)); // Cache results for later cacheSlrA = a; cacheSlrB = b; cacheSlrR2 = R2; cacheSlrSA = sa; cacheSlrSB = sb; cacheSlrValid = true; } } // // ResultTable::tau // // Input: None // // Output: Linear regression parameters (a and b, where a is the // linear constant and b is the X coeffecient), width of XXX% confidence // interval for b. // // Compute linear fit based on Kendall's tau statistic, as described // in "Practical Nonparametric Statistics", Third Edition, W. J. Conover, // 1999, p. 335. // void ResultTable::tau(double &a, double &b, double &blower, double &bupper) { // Check for valid, cached results if (cacheTauValid) { } else { unsigned int maxSlopes; // maximum number of slopes to compute unsigned int numSlopes; // actual number of slopes found unsigned int maxValues; // max values in the table? unsigned int numValues; // how many values in the table? int i; // universal loop counter unsigned int xcol, xitem, ycol, yitem; // Compute number of slopes we might need to work with maxSlopes = 0; maxValues = 0; for (i = 0; i < columns; i++) { maxValues += used[i]; } // If less than two values we can't compute a regression, // so give up. if (maxValues < 2) { a = 0.0; b = 0.0; blower = 0.0; bupper = 0.0; return; } maxSlopes = maxValues * (maxValues - 1) / 2; double *slopes; slopes = new double[maxSlopes]; if (slopes == NULL) { fprintf(stderr, "Couldn't allocate slopes array for a ResultTable\n"); exit(1); } double *xvalues, *yvalues; xvalues = new double[maxValues]; if (xvalues == NULL) { fprintf(stderr, "Couldn't allocate xvalues array for a ResultTable\n"); exit(1); } yvalues = new double[maxValues]; if (yvalues == NULL) { fprintf(stderr, "Couldn't allocate yvalues array for a ResultTable\n"); exit(1); } // Compute all the slopes. Basically, we try to treat the // maxSlopes datapoints as being in a single, 1-D array, // rather than being in a set of 1-D arrays of variable // sizes. We refer to the two values being "pointed to" // as x and y. numSlopes = 0; numValues = 0; xcol = 0; xitem = 0; // Iterate through the items to find X values while (xcol < columns) { while (xitem < used[xcol]) { // Record this X and Y value xvalues[numValues] = (double)column2size(xcol); yvalues[numValues] = data[xcol][xitem]; numValues++; // Start looking for Y values, given a single X // value. Start with the "next" item in sequence // after the one we chose for X. Note that after // the next two lines, ycol/yitem might point out // of bounds. That's OK, because we check them // immediately afterwards (incrementing if necessary). ycol = xcol; yitem = xitem + 1; while (ycol < columns) { while (yitem < used[ycol]) { double xx, xy, yx, yy; xx = column2size(xcol); xy = data[xcol][xitem]; yx = column2size(ycol); yy = data[ycol][yitem]; // Try to avoid divide-by-zero errors if (yx != xx) { double slope = (yy-xy) / (yx-xx); slopes[numSlopes++] = slope; } else { fprintf(stderr, "Warning: Duplicate x values (%f,%f) = (%f,%f)\n", xx, xy, yx, yy); } yitem++; } ycol++; yitem = 0; } xitem++; } xcol++; xitem = 0; } // If we had to throw away points because of duplicate X // values, this could throw our confidence intervals off. if (numSlopes != maxSlopes) { fprintf(stderr, "Warning: duplicate X values forced discarding of data points\n"); } // Compute slope b = median(slopes, numSlopes); // Compute intercept double xmedian, ymedian; xmedian = median(xvalues, numValues); ymedian = median(yvalues, numValues); a = ymedian - b * xmedian; // Compute confidence interval on slope unsigned int T, r, s; T = Kendall::T(numValues, KendallP950); // 90% confidence for now r = (numSlopes - T) / 2 - 1; s = ((numSlopes + T + 1)) / 2; bupper = slopes[r]; blower = slopes[s]; delete [] slopes; delete [] xvalues; delete [] yvalues; } } // // ResultTable::lms // // Input: None // // Output: Linear regression parameters (a and b, where a is the // linear constant and b is the X coeffecient), coeffecient of // determination R2. // // Compute linear fit based on a Least Median of Squares fit, as // described in Peter J. Rousseeuw and Annick M. Leroy's // "Robust Regression and Outlier Detection", John Wiley & Sons, Inc., // New York, NY, 1987. // void ResultTable::lms(double &a, double &b, double &r2) { // Check for valid, cached results if (cacheLmsValid) { } else { unsigned int maxSlopes; // maximum number of slopes to compute unsigned int numSlopes; // actual number of slopes found unsigned int maxValues; // max values in the table? int i; // universal loop counter unsigned int xcol, xitem, ycol, yitem, zcol, zitem; bool estimatorFound; // flag to see if we've actually computed // a residuals quantity yet double minLMS, minLMSa, minLMSb; // LMS estimator and associated regression parameters // Compute number of slopes we might need to work with maxSlopes = 0; maxValues = 0; for (i = 0; i < columns; i++) { maxValues += used[i]; } // If less than two values we can't compute a regression, // so give up. if (maxValues < 2) { a = 0.0; b = 0.0; r2 = 0.0; return; } maxSlopes = maxValues * (maxValues - 1) / 2; double *residuals; double *ys; residuals = new double[maxValues]; if (residuals == NULL) { fprintf(stderr, "Couldn't allocate residuals array for a ResultTable\n"); exit(1); } ys = new double[maxValues]; if (ys == NULL) { fprintf(stderr, "Couldn't allocate ys array for a ResultTable\n"); exit(1); } estimatorFound = false; // Find all pairs of points, and use them to find a trial // set of regression parameters. We then compute the LMS // estimator given these regression parameters, and save // the parameters that give us the minimum value of the // estimator. // // Implementation note: As with ResultTable::tau (from which // this code is derived), we try to treat the // maxSlopes datapoints as being in a single, 1-D array, // rather than being in a set of 1-D arrays of variable // sizes. We refer to the two values being "pointed to" // as x and y. numSlopes = 0; xcol = 0; xitem = 0; // Iterate through the items to find X values while (xcol < columns) { while (xitem < used[xcol]) { // Start looking for Y values, given a single X // value. Start with the "next" item in sequence // after the one we chose for X. Note that after // the next two lines, ycol/yitem might point out // of bounds. That's OK, because we check them // immediately afterwards (incrementing if necessary). ycol = xcol; yitem = xitem + 1; while (ycol < columns) { while (yitem < used[ycol]) { double xx, xy, yx, yy; xx = column2size(xcol); xy = data[xcol][xitem]; yx = column2size(ycol); yy = data[ycol][yitem]; // Try to avoid divide-by-zero errors if (yx != xx) { double slope = (yy-xy) / (yx-xx); double intercept = xy - (slope * xx); unsigned int numResiduals = 0; double estimator; // Compute residuals (well, actually // we're computing the squares of the residuals) zcol = 0; zitem = 0; while (zcol < columns) { while (zitem < used[zcol]) { residuals[numResiduals] = pow(data[zcol][zitem] - (column2size(zcol) * slope + intercept), 2); numResiduals++; zitem++; } zcol++; zitem = 0; } // Compute estimator. If it's less than our // minimum, then save the current regression // parameters. estimator = median(residuals, numResiduals); if ((!estimatorFound) || (estimator < minLMS)) { minLMS = estimator; minLMSa = intercept; minLMSb = slope; estimatorFound = true; } numSlopes++; } else { fprintf(stderr, "Warning: Duplicate x values (%f,%f) = (%f,%f)\n", xx, xy, yx, yy); } yitem++; } ycol++; yitem = 0; } xitem++; } xcol++; xitem = 0; } // If we had to throw away points because of duplicate X // values, note this. It shouldn't really affect results much. if (numSlopes != maxSlopes) { fprintf(stderr, "Warning: duplicate X values forced discarding of data points\n"); } if (estimatorFound) { a = minLMSa; b = minLMSb; // Coefficient of Determination computation unsigned int numResiduals; unsigned int numYs; double medianRabs; // median of all absolute residuals double medianY; // median of all Y values double madY; // median absolute deviation // We need to make two passes over the data. The first pass // gathers the absolute values of the residuals, as well as // all of the data values. The former will go to compute // med|r sub i|, while the latter gives us med(y sub i). xcol = 0; xitem = 0; numResiduals = 0; numYs = 0; while (xcol < columns) { while (xitem < used[xcol]) { residuals[numResiduals] = fabs(data[xcol][xitem] - (column2size(xcol) * minLMSb + minLMSa)); numResiduals++; ys[numYs] = data[xcol][xitem]; numYs++; xitem++; } xcol++; xitem = 0; } medianRabs = median(residuals, numResiduals); medianY = median(ys, numYs); // In the second pass over the data, we use the median Y // value we computed earlier to determine // med|y sub i - med(y sub j)|. xcol = 0; xitem = 0; numYs = 0; while (xcol < columns) { while (xitem < used[xcol]) { ys[numYs] = fabs(data[xcol][xitem] - medianY); numYs++; xitem++; } xcol++; xitem = 0; } madY = median(ys, numYs); r2 = 1.0 - pow((medianRabs / madY), 2); } else { fprintf(stderr, "Warning: residual computation failed\n"); a = 0.0; b = 0.0; r2 = 0.0; } delete [] residuals; delete [] ys; } } // // ResultTable::lmsint // // Input: None // // Output: Linear regression parameters (a and b, where a is the // linear constant and b is the X coeffecient), coeffecient of // determination R2. // // Compute linear fit based on a Least Median of Squares fit. // The algorithm used is the same as ResultTable::lms, except that // we do all computations using only int32 variables. This is a // check of an IOS implementation of this algorithm. // void ResultTable::lmsint(double &a, double &b, double &r2) { unsigned int *partialmins; // We assume we've got minfiltered points unsigned int *residuals; // Residuals unsigned int *ys; // Copy of y values int i, j, k, l; // loop counters int currentslope; int currentintercept; unsigned int r2int; // coefficient of determination const unsigned int timeoutresult = 0; const unsigned int slopescale = 1000; // scaling factor for slope computations const unsigned int codscale = 1000; // sqrt of scaling factor for coefficient of determination ys = new unsigned int[columns]; if (ys == NULL) { fprintf(stderr, "Couldn't allocate ys array for a ResultTable\n"); exit(1); } partialmins = new unsigned int[columns]; if (partialmins == NULL) { fprintf(stderr, "Couldn't allocate partialmins array for a ResultTable\n"); exit(1); } for (i = 0; i < columns; i++) { // Convert dataset to integers representing microseconds. partialmins[i] = (unsigned int) (data[i][0] * 1000000.0); } residuals = new unsigned int[columns*columns]; if (residuals == NULL) { fprintf(stderr, "Couldn't allocate residuals array for a ResultTable\n"); exit(1); } // Following code comes from the IOS version of pchar, hence // the C-style comments. /* * Linear regression happens on the minfiltered datapoints. */ { /* * Use the least median of squares regression. Slopes are in * microseconds per byte but this may change. * * We need to do something here for the case that we didn't * get any data points at all for one or more packet sizes. */ unsigned long testslope, testintercept; unsigned long estimator; unsigned long minestimator; bool estimatorvalid; minestimator = 0; estimatorvalid = false; testslope = 0; testintercept = 0; for (i = 0; i < columns; i++) { for (j = i+1; j < columns; j++) { if ((partialmins[i] != timeoutresult) && (partialmins[j] != timeoutresult)) { /* Compute test slope and estimator */ testslope = (((partialmins[j] - partialmins[i])) * slopescale) / (column2size(j - i)); testintercept = partialmins[j] - ((partialmins[j] - partialmins[i]) * (column2size(j)) / (column2size(j - i))); /* Compute squares of residuals */ for (k = 0, l = 0; k < columns; k++) { if (partialmins[k] != timeoutresult) { residuals[l] = partialmins[k] - ((testslope * column2size(k) / slopescale) + testintercept); residuals[l] *= residuals[l]; l++; } } if (l > 0) { /* Estimator is median of squared residuals */ estimator = median(residuals, l); if ((estimator < minestimator) || (!estimatorvalid)) { minestimator = estimator; currentslope = testslope; currentintercept = testintercept; estimatorvalid = true; } } } } } } /* * Coeffecient of determination calculation...how good was * the fit? */ r2int = 0; if ((currentslope != 0) || (currentintercept != 0)) { unsigned int medianr; /* median of all absolute residuals */ unsigned int mediany; /* median of all Y values */ unsigned int mady; /* median absolute deviation */ /* * Make two passes over the data. The first pass gather * the absolute values of the residuals, as well as all * of the dependent variable values. The former goes to * compute med|r|, while the latter gives med(y). */ l = 0; for (i = 0; i < columns; i++) { if (partialmins[i] != timeoutresult) { residuals[l] = abs(partialmins[i] - ((currentslope * column2size(i) / slopescale) + currentintercept)); ys[l] = partialmins[i]; l++; } } medianr = median(residuals, l); mediany = median(ys, l); /* * In the second pass over the data, we use the median Y * value computed by the first pass to determine * med|y sub i - med(y)| */ l = 0; for (i = 0; i < columns; i++) { if (partialmins[i] != timeoutresult) { ys[l] = abs(partialmins[i] - mediany); l++; } } mady = median(ys, l); /* r2 = 1.0 - pow((medianr / mady), 2); */ r2int = (codscale * codscale) - ((codscale * codscale * medianr * medianr) / (mady * mady)); } a = ((double) currentintercept) / 1000000.0; b = ((double) currentslope / 1000000.0 / (double) slopescale); r2 = ((double) r2int) / ((double) codscale * (double) codscale); delete [] partialmins; delete [] residuals; delete [] ys; } // // ResultTable::median // // Input: // // Output: Median value // // Compute the median of an array of doubles. // As a side effect, the input array is sorted // double ResultTable::median(double *values, unsigned int numValues) { double medianValue; // Sort the using qsort(3). extern int doublecomp(const void *a, const void *b); qsort((void *) values, numValues, sizeof(double), doublecomp); // Find median value. if (numValues & 1) { // Odd number of samples medianValue = values[(numValues-1)/2]; } else { // Even number of samples medianValue = (values[(numValues/2)] + values[(numValues/2)-1]) / 2.0; } return medianValue; } // Function for qsort(3) to determine the relative ordering of two // doubles. Used in the call to qsort above. int doublecomp(const void *a, const void *b) { double adouble = *(const double *) a; double bdouble = *(const double *) b; if (adouble == bdouble) { return 0; } else { if (adouble < bdouble) { return -1; } else { return 1; } } } // // ResultTable::median // // Input: // // Output: Median value // // Compute the median of an array of unsigned ints. // As a side effect, the input array is sorted // unsigned int ResultTable::median(unsigned int *values, unsigned int numValues) { unsigned int medianValue; // Sort the using qsort(3). extern int uintcomp(const void *a, const void *b); qsort((void *) values, numValues, sizeof(unsigned int), uintcomp); // Find median value. if (numValues & 1) { // Odd number of samples medianValue = values[(numValues-1)/2]; } else { // Even number of samples medianValue = (values[(numValues/2)] + values[(numValues/2)-1]) / 2; } return medianValue; } // Function for qsort(3) to determine the relative ordering of two // doubles. Used in the call to qsort above. int uintcomp(const void *a, const void *b) { unsigned int auint = *(const unsigned int *) a; unsigned int buint = *(const unsigned int *) b; if (auint == buint) { return 0; } else { if (auint < buint) { return -1; } else { return 1; } } } // // ResultTable::Print // // Input: file pointer to print to, tag string, hop number // // Output: Success code // // Print the contents of the table to the file pointer fp. // int ResultTable::Print(FILE *fp, char *tag, int hop) { int i, j; for (i = 0; i < columns; i++) { for (j = 0; j < used[i]; j++) { fprintf(fp, "%s %d %d %f\n", tag, hop, column2size(i), data[i][j]); } } return 0; } pchar-1.5/ResultTable.h000644 002001 000024 00000003670 10203463722 015113 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: ResultTable.h 1082 2005-02-12 19:40:04Z bmah $ // // ResultTable.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Table of pc results. // #ifndef RESULTTABLE_H #define RESULTTABLE_H #include class ResultTable { public: const unsigned int increment, mtu, burst, repetitions; const unsigned int columns; ResultTable(unsigned int i, unsigned int m, unsigned int b, unsigned int r); virtual ~ResultTable(); int put(int size, double time); ResultTable *getMin(); double queueing(); void slr(double &a, double &b, double &r2, double &sa, double &sb); void tau(double &a, double &b, double &blower, double &bupper); void lms(double &a, double &b, double &r2); void lmsint(double &a, double &b, double &r2); double median(double *values, unsigned int numValues); unsigned int median(unsigned int *values, unsigned int numValues); int Print(FILE *fp, char *tag, int hop); protected: double **data; int *used; bool cacheSlrValid; // Cached SLR results valid? double cacheSlrA, cacheSlrB, cacheSlrR2; double cacheSlrSA, cacheSlrSB; bool cacheTauValid; // Cached tau results valid? bool cacheLmsValid; // Cached tau results valid? bool cacheQueueingValid; // Cached queueing results valid? double cacheQueueing; int size2column(int s) { return (s); } int column2size(int c) { return (c); } }; #endif /* RESULTTABLE_H */ pchar-1.5/TestRecord.cc000644 002001 000024 00000007545 10203463722 015106 0ustar00bmahstaff000000 000000 static char rcsid[] = "$Id: TestRecord.cc 1082 2005-02-12 19:40:04Z bmah $"; // // $Id: TestRecord.cc 1082 2005-02-12 19:40:04Z bmah $ // // TestRecord.cc // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // #include #include #include #include #include #include #include "pc.h" #include "TestRecord.h" static const int buflen=1024; static char buffer[buflen]; static char buffer2[buflen]; // // TestRecord::htoa // // Input: Pctest structure, needed for figuring out the right // representations of IP addresses. // // Output: Pointer to a statically-allocated buffer with an ASCII // representation of the TestRecord. // // Make an ASCII representation of a TestRecord structure. // char *TestRecord::htoa(Pctest *pct) { // The way we build up the output is an artifact of various // method calls (i.e. Pctest::GetPrintableAddress) that used fixed, // statically-allocated buffers for returning their output. buffer[0] = '\0'; #ifdef HAVE_SNPRINTF snprintf(buffer2, buflen, #else sprintf(buffer2, #endif /* HAVE_SNPRINTF */ "probe t %ld.%06ld ", tvstart.tv_sec, tvstart.tv_usec); strncat(buffer, buffer2, buflen); #ifdef HAVE_SNPRINTF snprintf(buffer2, buflen, #else sprintf(buffer2, #endif /* HAVE_SNPRINTF */ "h %d b %d addr %s res %d rtt %ld.%06ld rb %d", hops, size, pct->GetPrintableAddress(icmpSourceAddress), result, tv.tv_sec, tv.tv_usec, replsize); strncat(buffer, buffer2, buflen); return buffer; } // // TestRecord::atoh // // Input: input string, Pctest record // // Output: pointer to a new TestRecord, NULL if an error // // Parse the ASCII representation described above and make up a new // TestRecord with demarshalled parameters. The caller "owns" // this object and is responsible for deallocating it. // // The Pctest record is necessary to determine the address family // that needs to be used when parsing addresses on this line. // TestRecord *TestRecord::atoh(char *s, Pctest *pct) { TestRecord *tr; char icmpsrcChars[256]; float tvstartFloat, tvFloat; int hops, size, replsize; int result; if (sscanf(s, "probe t %f h %d b %d addr %s res %d rtt %f rb %d", &tvstartFloat, &hops, &size, icmpsrcChars, &result, &tvFloat, &replsize) == 7) { tr = new TestRecord; tr->size = size; tr->hops = hops; tr->tvstart.tv_sec = (long) tvstartFloat; tr->tvstart.tv_usec = (long) ((tvstartFloat - ((long) tvstartFloat)) * 1000000.0); tr->tv.tv_sec = (long) tvFloat; tr->tv.tv_usec = (long) ((tvFloat - ((long) tvFloat)) * 1000000.0); // Parse the gateway address in an address-family dependant // way. int af = pct->GetAddressFamily(); if (af == AF_INET) { tr->icmpSourceAddress = new char[sizeof(in_addr)]; ((in_addr *) tr->icmpSourceAddress)->s_addr = inet_addr(icmpsrcChars); tr->icmpSourceAddressLength= sizeof(in_addr); } #ifdef HAVE_IPV6 else if (af == AF_INET6) { tr->icmpSourceAddress = new char[sizeof(in6_addr)]; inet_pton(AF_INET6, icmpsrcChars, (void *) tr->icmpSourceAddress); tr->icmpSourceAddressLength= sizeof(in6_addr); } #endif // HAVE_IPV6 else { fprintf(stderr, "Unknown address family: %s\n", s); return NULL; } tr->result = (PctestActionType) result; tr->replsize = replsize; return tr; } else { fprintf(stderr, "Syntax error: %s\n", s); return NULL; } } pchar-1.5/TestRecord.h000644 002001 000024 00000003251 10203463722 014736 0ustar00bmahstaff000000 000000 // -*- c++ -*- // // $Id: TestRecord.h 1082 2005-02-12 19:40:04Z bmah $ // // TestRecord.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Encapsulation of test data structure // #ifndef TESTRECORD_H #define TESTRECORD_H #include #if STDC_HEADERS #include #include #endif /* STDC_HEADERS */ #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include "pc.h" #include "Pctest.h" class TestRecord { public: bool used; // has this TestRecord been used yet? TestRecord *next; // for supporting a SLL of these things unsigned int size; // bytes in the packet in this test unsigned int hops; // TTL used for this packet unsigned int burst; // burst size for multi-packet tests struct timeval tvstart; // starting timestamp struct timeval tv; // RTT recorded void *icmpSourceAddress; // source address of ICMP packet int icmpSourceAddressLength; // length of source address PctestActionType result; // test result unsigned int replsize; // bytes in the response packet char *htoa(Pctest *pct); static TestRecord *atoh(char *, Pctest *); }; #endif /* TESTRECORD_H */ pchar-1.5/pc.h000644 002001 000024 00000011004 10203463722 013255 0ustar00bmahstaff000000 000000 // -*- c++ -*- // $Id: pc.h 1082 2005-02-12 19:40:04Z bmah $ // // pc.h // Bruce A. Mah // // This work was first produced by an employee of Sandia National // Laboratories under a contract with the U.S. Department of Energy. // Sandia National Laboratories dedicates whatever right, title or // interest it may have in this software to the public. Although no // license from Sandia is needed to copy and use this software, // copying and using the software might infringe the rights of // others. This software is provided as-is. SANDIA DISCLAIMS ANY // WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. // // Global definitions, macros, and so forth // #ifndef PC_H #define PC_H // Debugging macros extern int DebugLevel; #define IF_DEBUG(level, action) if (DebugLevel >= level) { action; } // bool type might not be available everywhere #if (SIZEOF_BOOL == 0) typedef enum {false, true} bool; #endif /* SIZEOF_BOOL */ // Mode types typedef enum { ModeNone, ModePchar, ModeTrout } ModeType; // Network protocol types typedef enum { NetworkProtocolNone, NetworkProtocolIpv4Udp, NetworkProtocolIpv4Raw, NetworkProtocolIpv4Tcp, NetworkProtocolIpv4Icmp, NetworkProtocolIpv4File #ifdef HAVE_IPV6 , NetworkProtocolIpv6Icmp, NetworkProtocolIpv6Udp, NetworkProtocolIpv6File, NetworkProtocolIpv6Tcp #endif /* HAVE_IPV6 */ } NetworkProtocolType; // Analysis types typedef enum { AnalysisNone, AnalysisLeastSquares, AnalysisKendall, AnalysisLeastMedianSquares, AnalysisLeastMedianSquaresIntegers } AnalysisType; // Gap types typedef enum { GapNone, GapFixed, GapExponential } GapType; // Linux networking compatability macros. For some unfathomable // reason, Linux systems seem to have named many of their networking // constants differently than those used by virtually every other // sockets API implementation. We try to bring it in line with // the more widely-used sockets API standards here. #ifdef linux // UDP #define uh_sport source #define uh_dport dest #define uh_ulen len #define uh_sum check #endif /* linux */ // Make sure we have a definition for the maximum IP packet size. // Apparently some Linux systems don't have this defined. #ifndef IP_MAXPACKET #define IP_MAXPACKET 65535 #endif /* IP_MAXPACKET */ // Ditto for IPv6 maximum packet size. #ifndef IPV6_MAXPACKET #define IPV6_MAXPACKET 65535 #endif /* IPV6_MAXPACKET */ // Some systems might not have MAXTTL #ifndef MAXTTL #define MAXTTL 255 #endif /* MAXTTL */ // Some systems might not have IPV6_MAXHLIM. This is intended for Linux // systems (observed on RH 7.1), but might be applicable elsewhere. // NRL-derived IPv6 systems have this constant defined below. #ifndef IPV6_MAXHLIM #ifndef NEED_NRL_IPV6_HACK #define IPV6_MAXHLIM 255 #endif /* NEED_NRL_IPV6_HACK */ #endif /* IPV6_MAXHLIM */ // Define ICMP unreachable codes that might not be otherwise // available. (Solaris 2.5.1 and 2.6 have this problem.) #define ICMP_UNREACH_FILTER_PROHIB 13 // Solaris 2.5.1 (and earlier?) for some reason is lacking the // prototype for random(3). We give them one. // // It turns out that Linux glibc2 needs this too, since a mutually // incompatible set of preprocessor defines is necessary to get // the headers to define both BSD-style network structures // and the random(3) prototype. So we punt on this and roll our // own. #ifdef NEED_RANDOM_PROTO extern "C" { long random(void); void srandom(unsigned int); } #endif /* NEED_RANDOM_PROTO */ // NRL IPv6 stack hacks. Basically, they define data structures, // constants, etc. with different names than KAME (and, apparently, // the API RFCs). Some of these we can take care of with some // preprocessor definitions; others require some different headers. #ifdef NEED_NRL_IPV6_HACK #define ip6_hdr ipv6hdr #define ip6_nxt ipv6_nextheader #define IPV6_MAXHLIM IPV6_HOPLIMIT #define icmp6_hdr icmpv6hdr #define icmp6_type icmpv6_type #define icmp6_code icmpv6_code #define icmp6_id icmpv6_id #define icmp6_seq icmpv6_seq #define ICMP6_ECHO_REQUEST ICMPV6_ECHO_REQUEST #define ICMP6_ECHO_REPLY ICMPV6_ECHO_REPLY #define ICMP6_TIME_EXCEEDED ICMPV6_TIME_EXCEEDED #define ICMP6_DST_UNREACH ICMPV6_DST_UNREACH #define ICMP6_DST_UNREACH_ADMIN ICMPV6_UNREACH_ADMIN #define ICMP6_DST_UNREACH_NOPORT ICMPV6_UNREACH_PORT #define icmp6_filter icmpv6_filter #define ICMP6_FILTER ICMPV6_FILTER #define ICMP6_FILTER_SETBLOCKALL ICMPV6_FILTER_SETBLOCKALL #define ICMP6_FILTER_SETPASS ICMPV6_FILTER_SETPASS #endif /* NEED_NRL_IPV6_HACK */ #endif /* PC_H */ pchar-1.5/README000644 002001 000024 00000016765 10203463722 013405 0ustar00bmahstaff000000 000000 PCHAR: A TOOL FOR MEASURING NETWORK PATH CHARACTERISTICS Bruce A. Mah $Id: README 1085 2005-02-12 20:25:51Z bmah $ --------------------------------------------------------- INTRODUCTION ------------ pchar is a reimplementation of the pathchar utility, written by Van Jacobson. Both programs attempt to characterize the bandwidth, latency, and loss of links along an end-to-end path through the Internet. pchar works in both IPv4 and IPv6 networks. As of pchar-1.5, this program is no longer under active development, and no further releases are planned. Please see the disclaimer notice at the end of this file for legal information. PLATFORMS --------- The main development platforms for pchar are FreeBSD and Solaris. There have been reports of success with pchar on: FreeBSD 2.2.7, 3.X, 4.X, 5.X (x86, Alpha) NetBSD 1.4.1, 1.5 (various architectures) OpenBSD 2.5-2.8 (various architectures) IRIX 6.2, 6.5 (MIPS) IRIX64 6.5 (MIPS) Linux (RedHat 9 / x86, various Debian versions / x86) Solaris 2.4-2.6, 7, 8 (Sparc) Tru64/OSF/Digital Unix 4.0 (Alpha) MacOS 10.3.7 (Macintosh) pchar is written in C++. During various stages of development, the gcc-2.7.2.1, gcc-2.8.1, egcs-1.1.2, gcc-2.95, and gcc-3.4.2 compilers were used for building pchar. Some testing has also taken place with the Sun SparcWorks and IRIX MIPSpro C++ compilers. pchar's IPv6 support was originally written for the KAME 19991018 snapshot for FreeBSD 3.3-RELEASE. The KAME team has since tested it with FreeBSD, NetBSD, and OpenBSD, for more recent versions of the KAME IPv6 stack and the integrated IPv6 stacks in FreeBSD, NetBSD, and OpenBSD. pchar has also been run successfully on the native IPv6 stack in Solaris 8. OBTAINING PCHAR --------------- The current version of pchar is 1.5. Clearly, anyone reading this file has very likely already obtained a copy of pchar, but it's worth noting that the current source code distribution can be found at: http://www.kitchenlab.org/~bmah/Software/pchar/ pchar can also be found as part of the FreeBSD Ports Collection and the NetBSD Packages Collection, the OpenBSD Ports Collection, and as part of the ports/pkgsrc collections for the KAME distributions for FreeBSD, NetBSD, and OpenBSD. pchar is available as a Debian package as well. Beginning with pchar-1.3, source distributions are signed with the following PGP public key, available from the author's Web page or from most PGP keyservers: pub 1024R/23EC263D 1997-03-12 Bruce A. Mah Key fingerprint = C6 12 04 94 49 D5 B1 79 24 E9 D2 D7 0E 4F 5E 40 Beginning with pchar-1.5, source distributions are signed with the following PGP public key, available from the author's Web page or from most PGP keyservers: pub 1024D/5BA052C3 1997-12-08 Key fingerprint = F829 B805 207D 14C7 7197 7832 D8CA 3171 5BA0 52C3 uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah uid Bruce A. Mah sub 2048g/B4E60EA1 1997-12-08 INSTALLATION ------------ pchar uses GNU autoconf, so compiling it may be as simple as extracting the source code from the tar file and doing: % ./configure % make To enable IPv6 support, give the --with-ipv6 option to configure. If there is a directory for IPv6-specific libraries, it can be specified via an argument to the --with-ipv6 option, for example: % ./configure --with-ipv6=/usr/local/v6 % make To enable SNMP support, give the --with-snmp option to configure. Any argument to this option, if given, is taken as a directory in which to find the UCD SNMP support files (usually /usr/local). To enable pcap support (this enables kernel-level timestamps and TCP probes), give the --with-pcap option to configure. Any argument to this option, if given, is taken as a directory in which to find the pcap library/include files. Note that the -C option must be given at runtime to actually use the pcap support. A FEW NOTES ON PCHAR'S OPERATION -------------------------------- pchar sends probe packets into the network of varying sizes and analyzes ICMP messages produced by intermediate routers, or by the target host. By measuring the response time for packets of different sizes, pchar can estimate the bandwidth and fixed round-trip delay along the path. pchar varies the TTL of the outgoing packets to get responses from different intermediate routers. It can use UDP or ICMP packets as probes; either or both might be useful in different situations. At each hop, pchar sends a number of packets (controlled by the -R flag) of varying sizes (controlled by the -i and -m flags). pchar determines the minimum response times for each packet size, in an attempt to isolate jitter caused by network queueing. It performs a simple linear regression fit to the resulting minimum response times. This fit yields the partial path bandwidth and round-trip time estimates. To yield the per-hop estimates, pchar computes the differences in the linear regression parameter estimates for two adjacent partial-path datasets. (Earlier versions of pchar differenced the minima for the datasets, then computed a linear regressions.) The -a flag selects between one of (currently) two different algorithms for performing the linear regression, either a least squares fit or a nonparametric method based on Kendall's test statistic. Using the -b option causes pchar to send small packet bursts, consisting of a string of back-to-back ICMP ECHO_REPLY packets followed by the actual probe. This can be useful in probing switched networks. CAVEATS ------- Router implementations may very well forward a packet faster than they can return an ICMP error message in response to a packet. Because of this fact, it's possible to see faster response times from longer partial paths; the result is a seemingly non-sensical, negative estimate of per-hop round-trip time. Transient fluctuations in the network may also cause some odd results. If all else fails, writing statistics to a file will give all of the raw data that pchar used for its analysis. Some types of networks are intrinsically difficult for pchar to measure. Two notable examples are switched networks (with multiple queues at Layer 2) or striped networks. We are currently investigating methods for trying to measure these networks. pchar needs superuser access due to its use of raw sockets. OSF/1 (a.k.a. Digital UNIX or Tru64) users should see item 5 in the FAQ file regarding timing. CONTACT INFO ------------ I can be reached by email at . Although pchar is no longer under active development, I still welcome comments and suggestions on how to improve it. DISCLAIMER ---------- This work was first produced by an employee of Sandia National Laboratories under a contract with the U.S. Department of Energy. Sandia National Laboratories dedicates whatever right, title or interest it may have in this software to the public. Although no license from Sandia is needed to copy and use this software, copying and using the software might infringe the rights of others. This software is provided as-is. SANDIA DISCLAIMS ANY WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Contains software developed at Lawrence Berkeley Laboratory, and which is "Copyright (c) 1995, 1996, 1997, 1998 The Regents of the University of California." pchar-1.5/CHANGES000644 002001 000024 00000033071 10203463722 013505 0ustar00bmahstaff000000 000000 PCHAR: A TOOL FOR MEASURING NETWORK PATH CHARACTERISTICS Bruce A. Mah $Id: CHANGES 1086 2005-02-12 20:31:40Z bmah $ --------------------------------------------------------- This file lists changes to pchar, in reverse chronological order (i.e. most recent entries at the top of the file). pchar-1.5: Compile fixes, minor bug fixes. Last planned release of pchar. (12 February 2005) Source code moved from CVS to Subversion. Although generally not user-visible, the version control strings now use Subversion's format. Builds on recent (RH 9.0-vintage) Linux systems seem to work now. Some off-by-one errors have been fixed, based on patches submitted by Anil Madhavapeddy . pchar with SNMP enabled now has at least a chance of working correctly. pchar no longer incorrectly aborts after a hop with 100% packet loss. pchar now does a better job of linking libraries using --with-snmp on machines where libsnmp depends on libcrypto, thanks to Matt Zimmerman . Some problems using --with-pcap on RedHat 7.0/7.1 (possibly other Linux distributions as well) were found thanks to a debugging session with Fran Boon . pchar-1.4: Multi-packet probes, TCP probes, kernel-level timestamps. (13 June 2001) pchar now has some limited compatability with the NRL IPv6 implementation in BSDI 4.1, thanks to some patches originally submitted by Antonio Querubin . pchar now supports TCP over IPv4 and TCP over IPv6 probes. pchar now will use the pcap packet capture library if given the --with-pcap flag at configure time (the motivation for this is to enable TCP probes, as well as to give potentially more accurate timestamps). It is enabled at run-time with the new -C flag. The selection of which network interface to snoop is now controlled by the -i flag (in the same way as tcpdump(1)). The packet-size increment is now controlled by the -I flag (it used to be controlled by -i). Add -b burst parameter for measuring store-and-forward switched subnets, inspired by LBL's pipechar. It works for most, but not all, protocol types (so far, it is supported by everything except UDP over IPv4; note that raw UDP over IPv4 supports -b just fine). Add a time_t cast to fix building on OpenBSD, submitted by "Angelos D. Keromytis" . pchar-1.3.2: Solaris and IRIX compatability, a few bugfixes, SUID root installation as an option. (9 April 2001) Compatability with IRIX has been improved, thanks to Ayamura KIKUCHI . A related compatability fix was provided by Jeffrey Mogul . pchar should now use less memory to hold its results, due to a change in the way memory is allocated and managed. Henk Langeveld discovered some alignment bugs that were breaking on the Sun compiler. These have been fixed. pchar now prints the start and end times at the end of each run (in local time). When reading from tracefiles, the origin address in printed output used to be taken from the local machine. This was a bug. The origin address is now properly taken from the tracefile. Handle route changes more gracefully, and keep track of up to ten alternative routes for a hop. Asked for by many folks. Providing an invalid argument to the -m argument no longer produces a core dump. Submitted by Pete Wyckoff . pchar now has a compile-time option to build and install as SUID root (--with-suid). It's off by default, and needs to be explicitly enabled. pchar-1.3.1: Compatability release, as noted below. (29 January 2001) Fixed a typo that broke SNMP support. Reported by "Soren S. Jorvang" and Karl Auerbach . Version 5.0 of the Sun C++ compiler defines some slightly different preprocessor variables; account for this. Pointed out by Erik Nordmark . The Sun compiler doesn't like arrays whose sizes are determined at runtime; this has been fixed. Pointed out by Henk Langeveld . Added a prototype for srandom(3) to support Linux compilation on more recent gcc versions. This requirement pointed out by Jaiwant Mulik and Karl Auerbach . pchar-1.3 ("Year of the Snake" release): New analysis types, support for ICMP and ICMPv6 probe packets, "tiny traceroute" mode, outgoing interface selection, bugfixes. (24 January 2001) Added -M option for operational mode. This controls whether pchar retains its original behavior or collects "trouts" (tiny traceroutes). Added ICMPv6 over IPv6 probes. pchar will no longer try output negative RTT or BW estimates. They don't have any physical meaning, and they generate the most frequent FAQ. There were a few more cosmetic changes made to the output. pchar's analysis methods now take into account the size of the response packet when computing bandwidth and delay estimates. This makes it possible for to use probes which may return non-constant-sized responses (such as the ICMP probes below). As a consequence of considering response packet sizes, the UDP over IPv6 probes will now return more sane values on the last hop (they were too low by about 50%). Added ICMP over IPv4 and TCP over IPv4 probes. (TCP over IPv4 is not completely functional as of this writing.) As a consequence of supporting multiple probe types, tracefiles for pchar-1.3 and later are not compatible with pchar-1.2 and earlier. The new tracefiles are smaller than the old tracefiles due to less redundant information being included. Added -l flag to set the source address of outgoing probe packets. If this flag is not specified, attempt to use the target address to figure out what the correct source address should be. This is a change in behavior from prior versions, but it should behave the same on most sanely-configured hosts. "Angelos D. Keromytis" gave some useful suggestions for implementing this, over a prior, less reliable, implementation. Added lmsint analysis type, which is the same algorithm as LMS, but implemented using integers only. Multiple build directories are supported properly, thanks to a patch from Paul Southworth . Add least median of squares (LMS) analysis. This is work completed at Sandia/CA, but not committed until now. pchar-1.2: Miscellaneous bugfixes, some SNMP support, better use of IPv6. (5 June 2000) SNMP query feature (-S flag) from Karl Auerbach . This feature requires the UCD SNMP library, and is enabled with --with-snmp at configure time. This feature works only with IPv4, and has not been extensively tested in its current integration. Better portability with glibc2 and gcc-2.95. Originally found on Linux by Lutz Sammer and "Aaron Seelye" . Handle more gracefully the case where we read in a tracefile with a target host who can't be resolved. (We don't care in this case because we're not going to use the resolved addresses for anything but printing.) Fix a problem with CMSG_* macros on FreeBSD 4.0-STABLE and 5.0-CURRENT. If no protocol is specified with -p, pchar automatically selects between IPv4/UDP and IPv6/UDP by doing a DNS query and using the address family of the first returned response. Enhancement suggested by Erik Nordmark . Fix off-by-one handling of filenames which could have caused tracefiles to break again. Use to determine IPv6 status at configure time, and let --with-ipv6 and --without-ipv6 override the test. Suggested by "Angelos D. Keromytis" and Erik Nordmark . Also cache the results of the IPv6 test between configure runs. Changes for better compatability with Solaris 8 native IPv6, from Erik Nordmark . pchar 1.1.1: Fixed a bug which caused reading back of tracefiles to be broken. (24 January 2000) Tracefiles were temporarily broken. pchar 1.1: Better compatability with more OSs (in particular, IRIX and OSF). Better IPv6 compatability (on BSDs and glibc systems with integrated IPv6). Numerous small bugfixes and usability enhancements. (24 January 2000) Remove a KAME assumption as to where IPv6 support lives. Note that KAME users will now need to explicitly configure --with-ipv6=/usr/local/v6 on systems that don't have KAME integrated into the base OS. Patch from . Incorporate patches from "Angelos D. Keromytis" for compilation under the IPv6 support included in OpenBSD-current. As a side effect, all getipnodename(3), et al. calls were changed to getaddrinfo(3), et al. Incorporate patches from "Jeffrey R. Hay (CIC-5)" for SGI IRIX and the SGI vendor compiler. Incorporate patches from Jeffrey Mogul for Tru64/Digital Unix/OSF compatability. These patches also attempt to alleviate problems caused by the fact that the default clock resolution is 1024 Hz under Tru64 (which is too coarse to measure nearby or fast links). Try three probes before running the entire measurement algorithm to find out if the destination host is really alive. Inspired by a comment by Jeffrey Mogul . Move manual page to section 8 from section 1. Minor fixes for IPv6 from . bcopy, et al. changed to memcpy, et al. Handle more gracefully the case where all packets on a link are dropped, based on a patch from Pete Wyckoff . Fixed calculation of total queueing along the path. Fixed buglet in install of manpage, patch from SUMIKAWA Munechika . Fixed FAQ Q1 to handle configure-time shared library problems on Solaris. "make pristine" really does now. Omissions pointed out by Pete Wyckoff . pchar 1.0: First externally announced version. Lots of changes, including IPv6 support, better Linux compatability, more useful tracefiles, bugfixes, etc. (3 November 1999) Limited IPv6 functionality (./configure --with-ipv6 to enable). Portability mods for the Sun SparcWorks compiler. Repetitions flag is now -R, to free up -r for... -r flag to read in a previously collected set of measurements. Inspired by clink, a very similar pathchar reimplementation, written by Allen Downey . Measurements written to -w data files are now written immediately after each probe measurement, rather than at the completion of each hop. The data file format has changed somewhat as well to provide more information, although it is still line-oriented. More Linux compatability from Pete Wyckoff . Also, try to detect firewalls that might be blocking our packets and quit if we find one. Add -G gaptype flag to select between fixed inter-probe gaps and exponentially-distributed inter-probe gaps. Change parameter estimation to perform linear regressions of min-filtered datapoints, then a subtraction of parameters. Previous behavior was to difference the min-filtered datapoints, then perform a simple linear regression. Add functionality (and -a command-line option) to select a linear regression based on Kendall's test statistic T. Fix a problem with -q disabling the bottleneck bandwidth computation. Add aclocal.m4 to distribution (omitted by mistake). Support for multiple/separate build directories contributed by Assar Westerlund . pchar 0.3: Bugfixes, some internal code rearrangement, and raw IPv4 support (13 August 1999). Minor documentation cleanups suggested by Rose Tsang . "make install" now works, reported and fixed by Pete Wyckoff , along with sundry other embarassing bugs. -c option now works, problem reported by Linda Winkler . Multi-protocol support...pchar now supports both normal UDP/IPv4 and raw IPv4 (constructing UDP packets internally). -p option is now enabled. Cleanup Makefile.in so that installs use more of the autoconf variables and now correctly install the manpage. Default install directory moved from ${prefix}/bin to ${prefix}/sbin. pchar 0.2: First externally-available release (23 February 1999). Fix Makefile typos which broke non-GNU make builds. Portability for IRIX 6.X builds. Use tcpdump tests in aclocal.m4 for sa_len and network library checks at configure time. Add some sanity checking of command-line options, motivated by BUGTRAQ posting regarding the use of traceroute as a packet flooder. pchar 0.2pre1: Software release for Sandia review and approval (4 February 1999). New name: pc has been renamed pchar. Import fresh versions of autoconf files from autoconf-2.13. Add -T option to set IPv4 TOS bits, based on discussions with Joe Burrescia , Mike Collins , and Rebecca Nitzan . pc 0.1: Semi-release, internal to SNL/CA (15 January 1999). Add -P flag to set an initial UDP port number. Corrected interpretation of partial path SLR slope results (was formerly being misinterpreted as partial path bandwidth). Fixed computation of path pipe. Improved Linux compatability, thanks to a patch by Pete Wyckoff . Fix divide-by-zero problems when no packets come back from the far end of a hop. Noted by Pete Wyckoff . pc 0.0: Semi-release, internal to SNL/CA (12 January 1999). pchar-1.5/FAQ000644 002001 000024 00000006755 10203463722 013055 0ustar00bmahstaff000000 000000 PCHAR: A TOOL FOR MEASURING NETWORK PATH CHARACTERISTICS Bruce A. Mah $Id: FAQ 1083 2005-02-12 20:10:28Z bmah $ --------------------------------------------------------- A compilation of questions, experiences, and suggestions from users of pchar. ----- Q1. I compiled pchar using GCC on Solaris. When I try to run pchar, I get an error message that looks like this: ld.so.1: ./pchar: fatal: libstdc++.so.2.10.0: open failed: No such file or directory Killed A1. When trying to link shared libraries for processes running as root, Solaris will only look for shared libraries in directories explicitly named at compile-time or in a few hardcoded directories such as /usr/lib. The libraries provided with GCC are usually located somewhere else. To work around this problem, first determine where the library in question resides (the example cited above is a C++ support library from GCC, which installs by default into /usr/local/lib). Then, before configuring the build of pchar, set the LDFLAGS environment variable, for example: % setenv LDFLAGS "-R /usr/local/lib" % ./configure (Adjust appropriately for non-csh-like shells.) Compile and install as normal. ----- Q2. pchar dies as soon as it detects a routing change. How can I make it not do this? A2. Pass the -c option to pchar, to get something similar to pathchar's default behavior. ----- Q3. I see really high packet losses when tracing a path through a Solaris machine. Why? A3. Solaris and Cisco IOS implement rate control on some ICMP packets they generate, typically limiting the rate to at most 2 packets per second per destination. This prevents ICMP generation from being used in a possible (D)DOS attack. Increase the gap between packets to slightly over 0.5s, using the -g option. This will make pchar slightly slower for intermediate hops, but will speed up the last hop significantly. ----- Q4. Sometimes I get negative values for round-trip-time and bandwidth estimates. What gives? A4. pchar relies on being able to infer the characteristics of network links. Essentially this involves sending packets into the network and measuring their response times, and then analyzing the results. Any or all of the following conditions can cause negative round-trip-times or bandwidths: 1. Excessive packet loss along a link, leading to a lack of useful data from which to estimate link parameters. 2. Variations in the amount of time taken for routers to process packets (for example, the forwarding codepath taking less time than the ICMP packet generation codepath). 3. Transient changes in network conditions for links that have been previously measured. pchar-1.3 and later will actually replace negative values here by hyphens, to indicate that the estimates are most likely not valid. ----- Q5. Many of the measurement times recorded by my OSF/1 (a.k.a. Digital UNIX or Tru64) machine are zero, and I see the message "Warning: No non-zero timestamps measured, bumping up to 0.0000001". What can I do about this? A5. According to Jeffrey Mogul , the default kernel clock resolution on an OSF/1 machine is 1024Hz (which gives millisecond resolution, rather than microsecond resolution, as is the case for many other UNIX systems). He writes that: ...for Tru64, you [could] recommend enabling the MICRO_TIME kernel option, to get sufficient timing resolution. To enable this option, add the following line to the kernel configuration file options MICRO_TIME and rebuild the kernel. ----- pchar-1.5/pchar.8000644 002001 000024 00000032472 10203463722 013704 0ustar00bmahstaff000000 000000 .\" Copyright and comments .TH pchar 8 "15 January 2001" .SH NAME pchar \- Perform network measurements along an Internet path .SH SYNOPSIS .B pchar .RB [ " \-cChnqSvV " ] .RB [ " \-a\ \fIanalysis\fP " ] .RB [ " \-b\ \fIburst\fP " ] .RB [ " \-d\ \fIdebug\fP " ] .RB [ " \-g\ \fIgap\fP " ] .RB [ " \-H\ \fIhops\fP " ] .RB [ " \-i\ \fIinterface\fP " ] .RB [ " \-I\ \fIincrement\fP " ] .RB [ " \-l\ \fIorigin\fP " ] .RB [ " \-m\ \fImtu\fP " ] .RB [ " \-M\ \fImode\fP " ] .RB [ " \-p\ \fIprotocol\fP " ] .RB [ " \-P\ \fIport\fP " ] .RB [ " \-R\ \fIreps\fP " ] .RB [ " \-s\ \fIhop\fP " ] .RB [ " \-t\ \fItimeout\fP " ] .RB [ " \-w\ \fIfile\fP " ] .BR " \-r\ \fIfile\fP " | .I "host" .SH DESCRIPTION .I Pchar measures the characteristics of the network path between two Internet hosts, on either IPv4 or IPv6 networks. It is an independently-written reimplementation of the .I pathchar utility, using similar algorithms. Both programs measure network throughput and round-trip time by sending varying-sized UDP packets into the network and waiting for ICMP messages in response. Like .IR traceroute , they modulate the IPv4 time-to-live (TTL) field or the IPv6 hop limit field to get measurements at different distances along a path. .LP In its default mode, a run of .I pchar over a short path might produce an output that looks like this: \fC .nf pchar to dancer.ca.sandia.gov (146.246.246.1) using UDP/IPv4 Packet size increments by 32 to 1500 46 test(s) per repetition 32 repetition(s) per hop 0: Partial loss: 0 / 1472 (0%) Partial char: rtt = 0.657235 ms, (b = 0.000358 ms/B), r2 = 0.989713 stddev rtt = 0.004140, stddev b = 0.000006 Hop char: rtt = 0.657235 ms, bw = 22333.268771 Kbps Partial queueing: avg = 0.000150 ms (418 bytes) 1: 146.246.243.254 (con243.ca.sandia.gov) Partial loss: 0 / 1472 (0%) Partial char: rtt = 0.811278 ms, (b = 0.000454 ms/B), r2 = 0.995401 stddev rtt = 0.003499, stddev b = 0.000005 Hop char: rtt = 0.154043 ms, bw = 83454.764777 Kbps Partial queueing: avg = 0.000153 ms (336 bytes) 2: 146.246.250.251 (slcon1.ca.sandia.gov) Partial loss: 0 / 1472 (0%) Partial char: rtt = 1.044412 ms, (b = 0.002161 ms/B), r2 = 0.999658 stddev rtt = 0.004533, stddev b = 0.000006 Hop char: rtt = 0.233133 ms, bw = 4686.320952 Kbps Partial queueing: avg = 0.000100 ms (46 bytes) 3: 146.246.246.1 (dancer.ca.sandia.gov) Path length: 3 hops Path char: rtt = 1.044412 ms, r2 = 0.999658 Path bottleneck: 4686.320952 Kbps Path pipe: 611 bytes Path queueing: average = 0.000100 ms (46 bytes) .fi \fP .LP The path here passes through three hops. Each hop consists of four lines of output: .B Partial loss documents the number and percentage of probe packets that were lost during the probes for that hop. The .B partial char line shows the estimated round-trip time from the probing host through the current hop. The .B hop char line shows estimates of the round-trip time and bandwidth for the current hop. Finally, the .B partial queueing shows an estimate of the average queueing along the path, up to and including the current hop. .LP Between each hop, .I pchar prints the IP address and (if known) name of the host/router at the end of the link. .LP After the last hop (usually the target host), .I pchar prints statistics on the entire path, including the .B path length and .B path pipe (the latter is an estimate of the delay-bandwidth product of the path). .LP .I Pchar has another mode of operation, called \fItrout\fP (short for \*(lqtiny traceroute\*(rq). In this mode, packets of random sizes (one packet per hop diameter) are sent along the path to a destination. No attempt at estimating link properties is made; however, this mode is extremely fast. It is intended for use as a part of a larger measurement infrastructure. The output from this mode might look like: \fC .nf trout to bmah-freebsd-1.cisco.com (171.70.84.44) using ICMP/IPv4 (raw sockets) Packet size increments from 28 to 1500 by 32 0: 171.70.84.42 (bmah-freebsd-0.cisco.com) 1: 171.70.84.44 (bmah-freebsd-1.cisco.com) 352 -> 352 bytes: 0.318 ms .fi \fP .SH OPTIONS .TP .B \-a \fIanalysis\fP Set analysis type. Current choices are \fBlsq\fP (the default), which uses a minimum filter followed by a least sum-of-squares fit to estimate link bandwidths, \fBkendall\fP, which uses the same minimum filter followed by a linear fit based on Kendall's test statistic, \fBlms\fP, which does a minimum filter followed by a least median of squares fit, and \fBlmsint\fP, which is an implementation of the \fBlms\fP computations using only integer arithmetic. .TP .B \-b \fIburst\fP Set the size of packet bursts. A burst parameter > 1 will result in some number of ICMP_ECHOREPLY packets sent before the probe packet to induce queueing. These packets are useful for measuring store-and-forward switched subnets, but make measurements of fast links behind bottlenecks inaccurate. .TP .B \-c Ignore routing changes detected during running. Normally, .I pchar will exit if it receives responses from more than one host for a given hop, assuming that this condition is caused by a routing transient. However, certain load-balancing schemes can also cause this condition. In such situations, using the .B \-c option may be useful. .TP .B \-C Use .IR pcap (3) packet capture library (this must have been enabled at configure time). Note that this option must be specified to enable TCP-based probes. .TP .B \-d \fIdebug\fP Sets debugging output level. Generally not useful except to the developer. .TP .B \-g \fIgap\fP Set the mean inter-probe gap in seconds. The default is 0.25, which results in approximately four probes per second being run. Care should be taken not to decrease this gap by too much, in order to avoid flooding the network. The default value here is deliberately conservative; users with the need or desire to probe more quickly are presumed to have at least perused the documentation for the relevant command-line options. .TP .B \-G \fIgaptype\fP Set distribution used to select interprobe gap times. Current alternatives are \fBfixed\fP (the default) and \fBexp\fP, which picks gap times from an exponential distribution. The latter option is an attempt to simulate a Poisson process of probe packets (a lot of aliteration), however due to the fact that each probe experiment takes a non-zero amount of time, this is only an approximation. .TP .B \-H \fIhops\fP Set the maximum number of hops that .I pchar will probe into the network. The default maximum is 30 hops, the same as with .I pathchar and .IR traceroute. .TP .B \-h Print usage information. .TP .B \-i \fIinterface\fP Set the interface to listen on for the .B -C option. .TP .B \-I \fIincrement\fP Set the probe packet size increment. .I Pchar will send IP packets with sizes that are integer multiples of .IR increment , up to the maximum specified by the .B \-m option. The default is a 32-byte increment. Small increments should produce more accurate results, but will result in more probes (thus taking longer to run). .TP .B \-l \fIorigin\fP Set the local source of probe packets. This option is mostly useful on multi-homed hosts. If not specified, it defaults to the value of .IR hostname (3). Note that this option \fImust\fP be used if the local hostname cannot be resolved to an IPv4 or IPv6 address. .TP .B \-m \fImtu\fP Set the maximum probe packet size. This value should be no larger than the path MTU between the two hosts. The default is 1500 bytes, the Ethernet MTU. .TP .B \-M \fImode\fP Set operational mode. The normal operational mode is \fIpchar\fP, which uses active probes to characterize the bandwidth, latency, loss, and queueing of the links comprising a path. Another mode is \fItrout\fP, a \*(lqtiny traceroute\*(rq that is intended to be used as a portion of a larger network management infrastructure. .TP .B \-n Don't attempt to resolve host addresses to names. .TP .B \-p \fIprotocol\fP Select protocol to use. Current options are: .B ipv4udp (UDP over IPv4), .B ipv4raw (UDP over IPv4, using raw IP packets), .B ipv4icmp (ICMP over IPv4, using raw IP packets), .B ipv4tcp (TCP over IPv4, using raw IP packets), .B ipv6icmp (ICMPv6 over IPv6, using raw IP packets), and .B ipv6udp (UDP over IPv6). The default protocol is either \fBipv4udp\fP or \fBipv6udp\fP, as appropriate to the network-layer address associated with the \fIhostname\fP provided. Compared with .BR ipv4udp , the implementation of .B ipv4raw offers finer control over the contents of packet fields, but is otherwise identical. Note that the .B ipv6icmp and .B ipv6udp options are only available if IPv6 support was compiled into .IR pchar , which can be selected at configure time. Finally, the .B ipv4tcp option requires that .IR pcap (3) support be specified at configure time and enabled with the .B \-C option. .TP .B \-P \fIport\fP Select starting UDP port number (the default is 32768). .I Pchar uses consecutive port numbers starting from this value, counting up. Care should be taken not to use port numbers that are actually in use by network services. .TP .B \-q Quiet mode, suppressing all output. Useful if writing statistics to standard out (see the .B \-w option). .TP .B \-r \fIfile\fP Read measurements in from a file named .IR file , as written by the .B -w option. This option is useful for experimenting with different analysis algorithms over a fixed data set. .TP .B \-R \fIreps\fP Set the number of repetitions of each probe packet size to be sent. The default is 32 packets of each size. Smaller values speed up testing, at the expense of accuracy. .TP .B \-s \fIhop\fP Set the starting hop at which to begin probing. The default is 1, so network probing will begin at the host adjacent to the host where .I pchar is being run. Larger values allow probing to begin farther out from the testing host; this can be helpful when attempting to probe outside a local internetwork whose characterisics are well-known. .TP .B \-S Do SNMP queries at each hop to determine each router's idea of what it thinks its next-hop interface characteristics are. Use of this features requires the UCD SNMP library, as well as enabling at configure-time using \fB--with-snmp\fP. .TP .B \-t \fItimeout\fP Set the amount of time (in seconds) that .I pchar will wait for an ICMP error message before declaring a packet loss. The default is 3 seconds. .TP .B \-T \fItos\fP Set the IP Type Of Service bits for outgoing UDP packets. This option isn't terribly useful for a lot of people, but it can be used, for example, to force a particular DiffServ codepoint within networks that support this functionality. For values of .B \-p that use IPv6 as a network-layer protocol, this option sets the traffic class field in the IPv6 header according to RFC 2460. .TP .B \-v Verbose mode. While each probe is in progress, print a synopsis of the hop number, repetition, and probe packet size on standard out. Verbose mode mimicks the output of .IR pathchar . .TP .B \-V Print version and copyright information and exit. .TP .B \-w \fIfile\fP Write statistics to a datafile named .IR file . This file can be read back in by specifying the .B \-r option in a subsequent run of .I pchar for off-line analysis, or parsed by other programs for plotting, etc. .IP If .I file is given as .BR \- , then the statistics are written to standard out. In this case, the quiet flag .B \-q may be useful, to avoid cluttering the standard output stream. .SH SEE ALSO .IR pcap (3), .IR ping (8), .IR traceroute (8), .IR pathchar (8) .SH NOTES Because .I pchar relies on measurements to drive its estimates of network characteristics, it may occasionally produce some seemingly odd results. Care should be taken when interpreting the output of .IR pchar . For example, the coeffecients of determination for the least squares fit can be useful in seeing how \*(lqgood\*(rq of a fit the bandwidth and round-trip time parameters describe the performance seen by the probe packets. The coefficient of determination takes values from 0 to 1, where a value of 1 indicates that the estimated parameters perfectly fit the data. .LP .I Pchar was originally named .IR pc , which was either an abbreviation for \*(lqpath characteristics\*(rq or \*(lqpathchar clone\*(rq. .SH BUGS .I Pathchar automatically determines an appropriate maximum packet size to use, based on a Path MTU discovery algorithm. .I Pchar relies on the user specifying the maximum packet size manually. .LP Some versions of Solaris rate-limit the generation of ICMP error messages. Any run of .I pchar through, or to, a Solaris machine may show abnormally high packet loss rates. This feature of Solaris affects .I traceroute and .I pathchar as well, but not .IR ping . Some versions of Linux appear to have similar rate-limiting. In situations such as this, the use of ICMP-based probes (selected by the \fB-p\fP option) may yield more satisfactory (or at least faster) results. .LP Timestamps printed after each run are printed relative to the local time zone. Timestamps saved in trace files are expressed as seconds past the epoch. .LP There are way too many command-line options. .SH AUTHOR Bruce A. Mah . The author of the original .I pathchar utility is Van Jacobson . The algorithms used by .I pchar were coded from Van Jacobson's viewgraphs describing the operation of .IR pathchar . pchar-1.5/Makefile.in000644 002001 000024 00000017210 10203463722 014554 0ustar00bmahstaff000000 000000 # -*- makefile -*- # # $Id: Makefile.in 1084 2005-02-12 20:17:04Z bmah $ # based on: # $ID: Makefile.in,v 1.20 1996/11/19 18:56:38 bmah Exp $ # # Intergalactic Makefile # Bruce A. Mah # # This work was first produced by an employee of Sandia National # Laboratories under a contract with the U.S. Department of Energy. # Sandia National Laboratories dedicates whatever right, title or # interest it may have in this software to the public. Although no # license from Sandia is needed to copy and use this software, # copying and using the software might infringe the rights of # others. This software is provided as-is. SANDIA DISCLAIMS ANY # WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. # # # Locations of things # srcdir=@srcdir@ VPATH=@srcdir@ INCLUDE_DIR=@srcdir@ prefix=@prefix@ exec_prefix=@exec_prefix@ sbindir=@sbindir@ mandir=@mandir@ # Locations of dependency files. No reason to change these. MAKEDEP_TMP=.makedep MAKEFILE_DEPEND=Makefile.depend # # Configuration and stuff # host=@host@ host_alias=@host_alias@ host_cpu=@host_cpu@ host_vendor=@host_vendor@ host_os=@host_os@ # # Compile-time options # DFLAGS= @DEFS@ # # Compilation flags # LDFLAGS=@LDFLAGS@ LIBS=@LIBS@ IFLAGS=@CPPFLAGS@ -I$(srcdir) # # Other cc options get defined here. # CXXFLAGS=@CXXFLAGS@ $(IFLAGS) $(DFLAGS) # # Specification of programs. # # Notes: CC affects the generation of dependencies (at many sites, # gcc has its own set of include files). # # SHELL is absolutely necessary for dependencies to work on Silicon # Graphics Irix (at least version 3.3, not sure about 4.0 or later). # AWK=@AWK@ CXX=@CXX@ ECHO=echo ECHOQNL=@echoqnl@ GZIP=gzip -9v INSTALL=@INSTALL@ INSTALL_DATA=@INSTALL_DATA@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ LD=@CXX@ LN_S=@LN_S@ MKDIR=mkdir MKINSTALLDIRS=${srcdir}/mkinstalldirs PGP=gpg RM=rm SHELL=/bin/sh TAR=tar TOUCH=touch A.OUT=pchar VERSION=@PC_VERSION@ TARDIR=$(A.OUT)-$(VERSION) TARFILE=$(TARDIR).tar TARGZFILE=$(TARFILE).gz SIGFILE=$(TARGZFILE).asc # # Various files # # OBJ lists the pathnames of the object files in the build tree as # defined by $(srcdir). # # Other file lists are used in generation distribution tarballs. # OBJ =@obj_subsets@ OBJ_BASE= \ main.o \ Kendall.o \ Pctest.o PctestIpv4.o PctestIpv4File.o PctestIpv4Udp.o PctestIpv4Raw.o\ PctestIpv4Tcp.o PctestIpv4Icmp.o \ ResultTable.o \ TestRecord.o \ version.o OBJ_IPV6= \ PctestIpv6.o PctestIpv6File.o PctestIpv6Icmp.o PctestIpv6Tcp.o \ PctestIpv6Udp.o OBJ_SNMP= \ GetIfInfo.o GENSRC= \ version.cc SRCFILES= \ main.cc \ GetIfInfo.cc GetIfInfo.h \ Kendall.cc Kendall.h \ Pctest.cc Pctest.h \ PctestIpv4.cc PctestIpv4.h \ PctestIpv4File.cc PctestIpv4File.h \ PctestIpv4Udp.cc PctestIpv4Udp.h \ PctestIpv4Raw.cc PctestIpv4Raw.h \ PctestIpv4Tcp.cc PctestIpv4Tcp.h \ PctestIpv4Icmp.cc PctestIpv4Icmp.h \ PctestIpv6.cc PctestIpv6.h \ PctestIpv6File.cc PctestIpv6File.h \ PctestIpv6Icmp.cc PctestIpv6Icmp.h \ PctestIpv6Tcp.cc PctestIpv6Tcp.h \ PctestIpv6Udp.cc PctestIpv6Udp.h \ ResultTable.cc ResultTable.h \ TestRecord.cc TestRecord.h \ pc.h OTHERFILES= \ README CHANGES FAQ pchar.8 \ Makefile.in Makefile.depend.in \ VERSION \ aclocal.m4 \ config.guess config.sub configure configure.in install-sh mkinstalldirs CONFIGFILES= \ Makefile $(MAKEFILE_DEPEND) $(MAKEDEP_TMP)\ config.cache config.log config.status # # Main target dependencies # all: $(A.OUT) $(A.OUT): $(OBJ) $(LD) $(OBJ) $(LDFLAGS) $(LIBS) -o $(A.OUT) version.o: version.cc version.cc: VERSION @$(RM) -f $@ @$(TOUCH) $@ @echo "# Generating $@ for this build..." @echo "static char version[] = \"$(A.OUT) `cat $(srcdir)/VERSION`\";" >> $@ @echo "static char copyright[] = " >> $@ @echo '"This work was first produced by an employee of Sandia National"' >> $@ @${ECHOQNL} >> $@ @echo '"Laboratories under a contract with the U.S. Department of Energy."' >> $@ @${ECHOQNL} >> $@ @echo '"Sandia National Laboratories dedicates whatever right, title or"' >> $@ @${ECHOQNL} >> $@ @echo '"interest it may have in this software to the public. Although no"' >> $@ @${ECHOQNL} >> $@ @echo '"license from Sandia is needed to copy and use this software,"' >> $@ @${ECHOQNL} >> $@ @echo '"copying and using the software might infringe the rights of"' >> $@ @${ECHOQNL} >> $@ @echo '"others. This software is provided as-is. SANDIA DISCLAIMS ANY"' >> $@ @${ECHOQNL} >> $@ @echo '"WARRANTY OF ANY KIND, EXPRESS OR IMPLIED."' >> $@ @${ECHOQNL} >> $@ @echo ';' >> $@ @echo "static char build[] = \"Built for $(host) by `hostname` on `date`\";" >> $@ @echo "static char dflags[] = \"$(DFLAGS)\";" >> $@ @echo "char *Version = version;" >> $@ @echo "char *Copyright = copyright;" >> $@ @echo "char *Build = build;" >> $@ @echo "char *DFlags = dflags;" >> $@ FORCE: # # install # TRANSFORM=@program_transform_name@ install: install-program install-man install-program: all $(MKINSTALLDIRS) ${sbindir} $(INSTALL_PROGRAM) $(A.OUT) $(sbindir)/`echo $(A.OUT) | sed '$(TRANSFORM)'` install-man: $(MKINSTALLDIRS) ${mandir}/man8 $(INSTALL_DATA) ${srcdir}/pchar.8 ${mandir}/man8/pchar.8 # # clean # # Remove all object and executable files. # clean: $(RM) -f $(OBJ) $(A.OUT) $(GENSRC) # # pristine # # Like clean target, but also removes "meta-files" and distribution # tarballs that we might have lying around # pristine: clean $(RM) -f $(CONFIGFILES) $(RM) -f $(TARDIR) $(TARFILE) $(TARGZFILE) $(SIGFILE) $(RM) -f core $(A.OUT).core distclean: pristine # # dist # # Create a tarball in the current directory # dist: $(TARGZFILE) $(TARGZFILE): $(RM) -rf $(TARDIR) $(TARFILE) $(TARGZFILE) $(MKDIR) $(TARDIR) for f in `echo $(SRCFILES) $(OTHERFILES)`; do \ (cd $(TARDIR); $(LN_S) ../$(srcdir)/$$f $$f); \ done; (export POSIXLY_CORRECT=yes; $(TAR) -cvhlf $(TARFILE) $(TARDIR)) $(GZIP) $(GZIPFLAGS) $(TARFILE) $(RM) -rf $(TARDIR) # # sign # # PGP-sign a distribution # sign: $(SIGFILE) $(SIGFILE): $(TARGZFILE) @$(PGP) -sba $(TARGZFILE) # # depend # # Create source file dependency rules at the end of this file. # depend: @$(RM) -f $(MAKEDEP_TMP) @echo "# make depend started on" `hostname` "on" `date` > $(MAKEDEP_TMP) @echo "Building dependencies ..."; \ for src in `echo $(OBJ) $(SRC) " " | sed -e 's/\.o[ \t\n]/.cc /g'`; do \ echo -n " " $$src ": "; \ if [ -r $(srcdir)/$$src ]; then \ $(CXX) -M $(CXXFLAGS) $(srcdir)/$$src >> $(MAKEDEP_TMP); \ echo "done"; \ else \ echo "nonexistent"; \ fi; \ done; @echo "# make depend completed on" `hostname` "on" `date` >> $(MAKEDEP_TMP) @echo "Commiting dependencies to" $(MAKEFILE_DEPEND) "..." @$(RM) -f $(MAKEFILE_DEPEND) @mv $(MAKEDEP_TMP) $(MAKEFILE_DEPEND) @echo "Done." # # Modified default rules. They are roughly the same as the defaults, # but compilation commands are modified to put the compiler output at # the location specified by the makefile target instead of the current # directory. # # .cc C++ source file # .tcl Tcl source file # .cdf Cumulative distribution function file # .pdf Probability density function file # .SUFFIXES: .cc .tcl .cdf .pdf .cc.o: $(CXX) $(CXXFLAGS) -c $< -o $@ .tcl.cc: @$(RM) -f $@ @$(TOUCH) $@ @echo "# Generating $@ from $<..." @echo "// $@ generated from $<" > $@ @echo "// on `date` by $$USER" >> $@ @echo "" >> $@ @echo 'static char foo[] = {' >> $@ @sed -e '/^$$/d' \ -e 's/ / /g' \ -e 's/^ *//g' \ -e "s/\\(.\\)/'\\1',/g" \ -e 's/\\/\\\\/g' \ -e 's/$$/0x0a,/' \ $< >> $@ @echo '0x0 };' >> $@ @echo "" >> $@ @echo "// Indirection is needed to fool damaged linker" >> $@ @echo "" >> $@ @echo 'char *$(*F) = foo;' >> $@ # # Grab dependencies. Note that the file $(MAKEFILE_DEPEND) *must* # exist, even if empty. # include $(MAKEFILE_DEPEND) pchar-1.5/Makefile.depend.in000644 002001 000024 00000001436 10203463722 016015 0ustar00bmahstaff000000 000000 # -*- makefile -*- # # $Id: Makefile.depend.in 1082 2005-02-12 19:40:04Z bmah $ # # Makefile.depend.in # Bruce A. Mah # # This work was first produced by an employee of Sandia National # Laboratories under a contract with the U.S. Department of Energy. # Sandia National Laboratories dedicates whatever right, title or # interest it may have in this software to the public. Although no # license from Sandia is needed to copy and use this software, # copying and using the software might infringe the rights of # others. This software is provided as-is. SANDIA DISCLAIMS ANY # WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. # # This is a placeholder for Makefile dependencies. # After a "make depend", all of the lines in this file will # be replaced by automatically-generated lines. # pchar-1.5/VERSION000644 002001 000024 00000000005 10203463722 013551 0ustar00bmahstaff000000 000000 1.5 pchar-1.5/aclocal.m4000644 002001 000024 00000044662 10203463722 014362 0ustar00bmahstaff000000 000000 dnl @(#) $Header$ (LBL) dnl dnl Copyright (c) 1995, 1996, 1997, 1998 dnl The Regents of the University of California. All rights reserved. dnl dnl Redistribution and use in source and binary forms, with or without dnl modification, are permitted provided that: (1) source code distributions dnl retain the above copyright notice and this paragraph in its entirety, (2) dnl distributions including binary code include the above copyright notice and dnl this paragraph in its entirety in the documentation or other materials dnl provided with the distribution, and (3) all advertising materials mentioning dnl features or use of this software display the following acknowledgement: dnl ``This product includes software developed by the University of California, dnl Lawrence Berkeley Laboratory and its contributors.'' Neither the name of dnl the University nor the names of its contributors may be used to endorse dnl or promote products derived from this software without specific prior dnl written permission. dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED dnl WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. dnl dnl LBL autoconf macros dnl dnl dnl Determine which compiler we're using (cc or gcc) dnl If using gcc, determine the version number dnl If using cc, require that it support ansi prototypes dnl If using gcc, use -O2 (otherwise use -O) dnl If using cc, explicitly specify /usr/local/include dnl dnl usage: dnl dnl AC_LBL_C_INIT(copt, incls) dnl dnl results: dnl dnl $1 (copt set) dnl $2 (incls set) dnl CC dnl LDFLAGS dnl ac_cv_lbl_gcc_vers dnl LBL_CFLAGS dnl AC_DEFUN(AC_LBL_C_INIT, [AC_PREREQ(2.12) AC_BEFORE([$0], [AC_PROG_CC]) AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) AC_BEFORE([$0], [AC_LBL_DEVEL]) AC_ARG_WITH(gcc, [ --without-gcc don't use gcc]) $1="-O" $2="" if test "${srcdir}" != "." ; then $2="-I\$\(srcdir\)" fi if test "${CFLAGS+set}" = set; then LBL_CFLAGS="$CFLAGS" fi if test -z "$CC" ; then case "$target_os" in bsdi*) AC_CHECK_PROG(SHLICC2, shlicc2, yes, no) if test $SHLICC2 = yes ; then CC=shlicc2 export CC fi ;; esac fi if test -z "$CC" -a "$with_gcc" = no ; then CC=cc export CC fi AC_PROG_CC if test "$GCC" = yes ; then if test "$SHLICC2" = yes ; then ac_cv_lbl_gcc_vers=2 $1="-O2" else AC_MSG_CHECKING(gcc version) AC_CACHE_VAL(ac_cv_lbl_gcc_vers, ac_cv_lbl_gcc_vers=`$CC -v 2>&1 | \ sed -e '/^gcc version /!d' \ -e 's/^gcc version //' \ -e 's/ .*//' -e 's/^[[[^0-9]]]*//' \ -e 's/\..*//'`) AC_MSG_RESULT($ac_cv_lbl_gcc_vers) if test $ac_cv_lbl_gcc_vers -gt 1 ; then $1="-O2" fi fi else AC_MSG_CHECKING(that $CC handles ansi prototypes) AC_CACHE_VAL(ac_cv_lbl_cc_ansi_prototypes, AC_TRY_COMPILE( [#include ], [int frob(int, char *)], ac_cv_lbl_cc_ansi_prototypes=yes, ac_cv_lbl_cc_ansi_prototypes=no)) AC_MSG_RESULT($ac_cv_lbl_cc_ansi_prototypes) if test $ac_cv_lbl_cc_ansi_prototypes = no ; then case "$target_os" in hpux*) AC_MSG_CHECKING(for HP-UX ansi compiler ($CC -Aa -D_HPUX_SOURCE)) savedcflags="$CFLAGS" CFLAGS="-Aa -D_HPUX_SOURCE $CFLAGS" AC_CACHE_VAL(ac_cv_lbl_cc_hpux_cc_aa, AC_TRY_COMPILE( [#include ], [int frob(int, char *)], ac_cv_lbl_cc_hpux_cc_aa=yes, ac_cv_lbl_cc_hpux_cc_aa=no)) AC_MSG_RESULT($ac_cv_lbl_cc_hpux_cc_aa) if test $ac_cv_lbl_cc_hpux_cc_aa = no ; then AC_MSG_ERROR(see the INSTALL doc for more info) fi CFLAGS="$savedcflags" V_CCOPT="-Aa $V_CCOPT" AC_DEFINE(_HPUX_SOURCE) ;; *) AC_MSG_ERROR(see the INSTALL doc for more info) ;; esac fi $2="$$2 -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" case "$target_os" in irix*) V_CCOPT="$V_CCOPT -xansi -signed -g3" ;; osf*) V_CCOPT="$V_CCOPT -std1 -g3" ;; ultrix*) AC_MSG_CHECKING(that Ultrix $CC hacks const in prototypes) AC_CACHE_VAL(ac_cv_lbl_cc_const_proto, AC_TRY_COMPILE( [#include ], [struct a { int b; }; void c(const struct a *)], ac_cv_lbl_cc_const_proto=yes, ac_cv_lbl_cc_const_proto=no)) AC_MSG_RESULT($ac_cv_lbl_cc_const_proto) if test $ac_cv_lbl_cc_const_proto = no ; then AC_DEFINE(const,) fi ;; esac fi ]) dnl dnl Use pfopen.c if available and pfopen() not in standard libraries dnl Require libpcap dnl Look for libpcap in .. dnl Use the installed libpcap if there is no local version dnl dnl usage: dnl dnl AC_LBL_LIBPCAP(pcapdep, incls) dnl dnl results: dnl dnl $1 (pcapdep set) dnl $2 (incls appended) dnl LIBS dnl LBL_LIBS dnl AC_DEFUN(AC_LBL_LIBPCAP, [AC_REQUIRE([AC_LBL_LIBRARY_NET]) dnl dnl save a copy before locating libpcap.a dnl LBL_LIBS="$LIBS" pfopen=/usr/examples/packetfilter/pfopen.c if test -f $pfopen ; then AC_CHECK_FUNCS(pfopen) if test $ac_cv_func_pfopen = "no" ; then AC_MSG_RESULT(Using $pfopen) LIBS="$LIBS $pfopen" fi fi AC_MSG_CHECKING(for local pcap library) libpcap=FAIL lastdir=FAIL places=`ls .. | sed -e 's,/$,,' -e 's,^,../,' | \ egrep '/libpcap-[[0-9]]*\.[[0-9]]*(\.[[0-9]]*)?([[ab]][[0-9]]*)?$'` for dir in $places ../libpcap libpcap ; do basedir=`echo $dir | sed -e 's/[[ab]][[0-9]]*$//'` if test $lastdir = $basedir ; then dnl skip alphas when an actual release is present continue; fi lastdir=$dir if test -r $dir/pcap.c ; then libpcap=$dir/libpcap.a d=$dir dnl continue and select the last one that exists fi done if test $libpcap = FAIL ; then AC_MSG_RESULT(not found) AC_CHECK_LIB(pcap, main, libpcap="-lpcap") if test $libpcap = FAIL ; then AC_MSG_ERROR(see the INSTALL doc for more info) fi else $1=$libpcap $2="-I$d $$2" AC_MSG_RESULT($libpcap) fi LIBS="$libpcap $LIBS" case "$target_os" in aix*) pseexe="/lib/pse.exp" AC_MSG_CHECKING(for $pseexe) if test -f $pseexe ; then AC_MSG_RESULT(yes) LIBS="$LIBS -I:$pseexe" fi ;; esac]) dnl dnl Define RETSIGTYPE and RETSIGVAL dnl dnl usage: dnl dnl AC_LBL_TYPE_SIGNAL dnl dnl results: dnl dnl RETSIGTYPE (defined) dnl RETSIGVAL (defined) dnl AC_DEFUN(AC_LBL_TYPE_SIGNAL, [AC_BEFORE([$0], [AC_LBL_LIBPCAP]) AC_TYPE_SIGNAL if test "$ac_cv_type_signal" = void ; then AC_DEFINE(RETSIGVAL,) else AC_DEFINE(RETSIGVAL,(0)) fi case "$target_os" in irix*) AC_DEFINE(_BSD_SIGNALS) ;; *) dnl prefer sigset() to sigaction() AC_CHECK_FUNCS(sigset) if test $ac_cv_func_sigset = no ; then AC_CHECK_FUNCS(sigaction) fi ;; esac]) dnl dnl If using gcc, make sure we have ANSI ioctl definitions dnl dnl usage: dnl dnl AC_LBL_FIXINCLUDES dnl AC_DEFUN(AC_LBL_FIXINCLUDES, [if test "$GCC" = yes ; then AC_MSG_CHECKING(for ANSI ioctl definitions) AC_CACHE_VAL(ac_cv_lbl_gcc_fixincludes, AC_TRY_COMPILE( [/* * This generates a "duplicate case value" when fixincludes * has not be run. */ # include # include # include # ifdef HAVE_SYS_IOCCOM_H # include # endif], [switch (0) { case _IO('A', 1):; case _IO('B', 1):; }], ac_cv_lbl_gcc_fixincludes=yes, ac_cv_lbl_gcc_fixincludes=no)) AC_MSG_RESULT($ac_cv_lbl_gcc_fixincludes) if test $ac_cv_lbl_gcc_fixincludes = no ; then # Don't cache failure unset ac_cv_lbl_gcc_fixincludes AC_MSG_ERROR(see the INSTALL for more info) fi fi]) dnl dnl Check for flex, default to lex dnl Require flex 2.4 or higher dnl Check for bison, default to yacc dnl Default to lex/yacc if both flex and bison are not available dnl Define the yy prefix string if using flex and bison dnl dnl usage: dnl dnl AC_LBL_LEX_AND_YACC(lex, yacc, yyprefix) dnl dnl results: dnl dnl $1 (lex set) dnl $2 (yacc appended) dnl $3 (optional flex and bison -P prefix) dnl AC_DEFUN(AC_LBL_LEX_AND_YACC, [AC_ARG_WITH(flex, [ --without-flex don't use flex]) AC_ARG_WITH(bison, [ --without-bison don't use bison]) if test "$with_flex" = no ; then $1=lex else AC_CHECK_PROGS($1, flex, lex) fi if test "$$1" = flex ; then # The -V flag was added in 2.4 AC_MSG_CHECKING(for flex 2.4 or higher) AC_CACHE_VAL(ac_cv_lbl_flex_v24, if flex -V >/dev/null 2>&1; then ac_cv_lbl_flex_v24=yes else ac_cv_lbl_flex_v24=no fi) AC_MSG_RESULT($ac_cv_lbl_flex_v24) if test $ac_cv_lbl_flex_v24 = no ; then s="2.4 or higher required" AC_MSG_WARN(ignoring obsolete flex executable ($s)) $1=lex fi fi if test "$with_bison" = no ; then $2=yacc else AC_CHECK_PROGS($2, bison, yacc) fi if test "$$2" = bison ; then $2="$$2 -y" fi if test "$$1" != lex -a "$$2" = yacc -o "$$1" = lex -a "$$2" != yacc ; then AC_MSG_WARN(don't have both flex and bison; reverting to lex/yacc) $1=lex $2=yacc fi if test "$$1" = flex -a -n "$3" ; then $1="$$1 -P$3" $2="$$2 -p $3" fi]) dnl dnl Checks to see if union wait is used with WEXITSTATUS() dnl dnl usage: dnl dnl AC_LBL_UNION_WAIT dnl dnl results: dnl dnl DECLWAITSTATUS (defined) dnl AC_DEFUN(AC_LBL_UNION_WAIT, [AC_MSG_CHECKING(if union wait is used) AC_CACHE_VAL(ac_cv_lbl_union_wait, AC_TRY_COMPILE([ # include # include ], [int status; u_int i = WEXITSTATUS(status); u_int j = waitpid(0, &status, 0);], ac_cv_lbl_union_wait=no, ac_cv_lbl_union_wait=yes)) AC_MSG_RESULT($ac_cv_lbl_union_wait) if test $ac_cv_lbl_union_wait = yes ; then AC_DEFINE(DECLWAITSTATUS,union wait) else AC_DEFINE(DECLWAITSTATUS,int) fi]) dnl dnl Checks to see if the sockaddr struct has the 4.4 BSD sa_len member dnl dnl usage: dnl dnl AC_LBL_SOCKADDR_SA_LEN dnl dnl results: dnl dnl HAVE_SOCKADDR_SA_LEN (defined) dnl AC_DEFUN(AC_LBL_SOCKADDR_SA_LEN, [AC_MSG_CHECKING(if sockaddr struct has sa_len member) AC_CACHE_VAL(ac_cv_lbl_sockaddr_has_sa_len, AC_TRY_COMPILE([ # include # include ], [u_int i = sizeof(((struct sockaddr *)0)->sa_len)], ac_cv_lbl_sockaddr_has_sa_len=yes, ac_cv_lbl_sockaddr_has_sa_len=no)) AC_MSG_RESULT($ac_cv_lbl_sockaddr_has_sa_len) if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then AC_DEFINE(HAVE_SOCKADDR_SA_LEN) fi]) dnl dnl Checks to see if -R is used dnl dnl usage: dnl dnl AC_LBL_HAVE_RUN_PATH dnl dnl results: dnl dnl ac_cv_lbl_have_run_path (yes or no) dnl AC_DEFUN(AC_LBL_HAVE_RUN_PATH, [AC_MSG_CHECKING(for ${CC-cc} -R) AC_CACHE_VAL(ac_cv_lbl_have_run_path, [echo 'main(){}' > conftest.c ${CC-cc} -o conftest conftest.c -R/a1/b2/c3 >conftest.out 2>&1 if test ! -s conftest.out ; then ac_cv_lbl_have_run_path=yes else ac_cv_lbl_have_run_path=no fi rm -f conftest*]) AC_MSG_RESULT($ac_cv_lbl_have_run_path) ]) dnl dnl Due to the stupid way it's implemented, AC_CHECK_TYPE is nearly useless. dnl dnl usage: dnl dnl AC_LBL_CHECK_TYPE dnl dnl results: dnl dnl int32_t (defined) dnl u_int32_t (defined) dnl AC_DEFUN(AC_LBL_CHECK_TYPE, [AC_MSG_CHECKING(for $1 using $CC) AC_CACHE_VAL(ac_cv_lbl_have_$1, AC_TRY_COMPILE([ # include "confdefs.h" # include # if STDC_HEADERS # include # include # endif], [$1 i], ac_cv_lbl_have_$1=yes, ac_cv_lbl_have_$1=no)) AC_MSG_RESULT($ac_cv_lbl_have_$1) if test $ac_cv_lbl_have_$1 = no ; then AC_DEFINE($1, $2) fi]) dnl dnl Checks to see if unaligned memory accesses fail dnl dnl usage: dnl dnl AC_LBL_UNALIGNED_ACCESS dnl dnl results: dnl dnl LBL_ALIGN (DEFINED) dnl AC_DEFUN(AC_LBL_UNALIGNED_ACCESS, [AC_MSG_CHECKING(if unaligned accesses fail) AC_CACHE_VAL(ac_cv_lbl_unaligned_fail, [case "$target_cpu" in alpha|hp*|mips|sparc) ac_cv_lbl_unaligned_fail=yes ;; *) cat >conftest.c < # include # include unsigned char a[[5]] = { 1, 2, 3, 4, 5 }; main() { unsigned int i; pid_t pid; int status; /* avoid "core dumped" message */ pid = fork(); if (pid < 0) exit(2); if (pid > 0) { /* parent */ pid = waitpid(pid, &status, 0); if (pid < 0) exit(3); exit(!WIFEXITED(status)); } /* child */ i = *(unsigned int *)&a[[1]]; printf("%d\n", i); exit(0); } EOF ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \ conftest.c $LIBS >/dev/null 2>&1 if test ! -x conftest ; then dnl failed to compile for some reason ac_cv_lbl_unaligned_fail=yes else ./conftest >conftest.out if test ! -s conftest.out ; then ac_cv_lbl_unaligned_fail=yes else ac_cv_lbl_unaligned_fail=no fi fi rm -f conftest* core core.conftest ;; esac]) AC_MSG_RESULT($ac_cv_lbl_unaligned_fail) if test $ac_cv_lbl_unaligned_fail = yes ; then AC_DEFINE(LBL_ALIGN) fi]) dnl dnl If using gcc and the file .devel exists: dnl Compile with -g (if supported) and -Wall dnl If using gcc 2, do extra prototype checking dnl If an os prototype include exists, symlink os-proto.h to it dnl dnl usage: dnl dnl AC_LBL_DEVEL(copt) dnl dnl results: dnl dnl $1 (copt appended) dnl HAVE_OS_PROTO_H (defined) dnl os-proto.h (symlinked) dnl AC_DEFUN(AC_LBL_DEVEL, [rm -f os-proto.h if test "${LBL_CFLAGS+set}" = set; then $1="$$1 ${LBL_CFLAGS}" fi if test -f .devel ; then if test "$GCC" = yes ; then if test "${LBL_CFLAGS+set}" != set; then if test "$ac_cv_prog_cc_g" = yes ; then $1="-g $$1" fi $1="$$1 -Wall" if test $ac_cv_lbl_gcc_vers -gt 1 ; then $1="$$1 -Wmissing-prototypes -Wstrict-prototypes" fi fi else case "$target_os" in irix6*) V_CCOPT="$V_CCOPT -n32" ;; *) ;; esac fi os=`echo $target_os | sed -e 's/\([[0-9]][[0-9]]*\)[[^0-9]].*$/\1/'` name="lbl/os-$os.h" if test -f $name ; then ln -s $name os-proto.h AC_DEFINE(HAVE_OS_PROTO_H) else AC_MSG_WARN(can't find $name) fi fi]) dnl dnl Improved version of AC_CHECK_LIB dnl dnl Thanks to John Hawkinson (jhawk@mit.edu) dnl dnl usage: dnl dnl AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) dnl dnl results: dnl dnl LIBS dnl define(AC_LBL_CHECK_LIB, [AC_MSG_CHECKING([for $2 in -l$1]) dnl Use a cache variable name containing both the library and function name, dnl because the test really is for library $1 defining function $2, not dnl just for library $1. Separate tests with the same $1 and different $2's dnl may have different results. ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'` AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var, [ac_save_LIBS="$LIBS" LIBS="-l$1 $5 $LIBS" AC_TRY_LINK(dnl ifelse([$2], [main], , dnl Avoid conflicting decl of main. [/* Override any gcc2 internal prototype to avoid an error. */ ]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus extern "C" #endif ])dnl [/* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $2(); ]), [$2()], eval "ac_cv_lbl_lib_$ac_lib_var=yes", eval "ac_cv_lbl_lib_$ac_lib_var=no") LIBS="$ac_save_LIBS" ])dnl if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then AC_MSG_RESULT(yes) ifelse([$3], , [changequote(, )dnl ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` changequote([, ])dnl AC_DEFINE_UNQUOTED($ac_tr_lib) LIBS="-l$1 $LIBS" ], [$3]) else AC_MSG_RESULT(no) ifelse([$4], , , [$4 ])dnl fi ]) dnl dnl AC_LBL_LIBRARY_NET dnl dnl This test is for network applications that need socket() and dnl gethostbyname() -ish functions. Under Solaris, those applications dnl need to link with "-lsocket -lnsl". Under IRIX, they need to link dnl with "-lnsl" but should *not* link with "-lsocket" because dnl libsocket.a breaks a number of things (for instance: dnl gethostbyname() under IRIX 5.2, and snoop sockets under most dnl versions of IRIX). dnl dnl Unfortunately, many application developers are not aware of this, dnl and mistakenly write tests that cause -lsocket to be used under dnl IRIX. It is also easy to write tests that cause -lnsl to be used dnl under operating systems where neither are necessary (or useful), dnl such as SunOS 4.1.4, which uses -lnsl for TLI. dnl dnl This test exists so that every application developer does not test dnl this in a different, and subtly broken fashion. dnl It has been argued that this test should be broken up into two dnl seperate tests, one for the resolver libraries, and one for the dnl libraries necessary for using Sockets API. Unfortunately, the two dnl are carefully intertwined and allowing the autoconf user to use dnl them independantly potentially results in unfortunate ordering dnl dependancies -- as such, such component macros would have to dnl carefully use indirection and be aware if the other components were dnl executed. Since other autoconf macros do not go to this trouble, dnl and almost no applications use sockets without the resolver, this dnl complexity has not been implemented. dnl dnl The check for libresolv is in case you are attempting to link dnl statically and happen to have a libresolv.a lying around (and no dnl libnsl.a). dnl AC_DEFUN(AC_LBL_LIBRARY_NET, [ # Most operating systems have gethostbyname() in the default searched # libraries (i.e. libc): AC_CHECK_FUNC(gethostbyname, , # Some OSes (eg. Solaris) place it in libnsl: AC_LBL_CHECK_LIB(nsl, gethostbyname, , # Some strange OSes (SINIX) have it in libsocket: AC_LBL_CHECK_LIB(socket, gethostbyname, , # Unfortunately libsocket sometimes depends on libnsl. # AC_CHECK_LIB's API is essentially broken so the # following ugliness is necessary: AC_LBL_CHECK_LIB(socket, gethostbyname, LIBS="-lsocket -lnsl $LIBS", AC_CHECK_LIB(resolv, gethostbyname), -lnsl)))) AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, , AC_LBL_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl))) # DLPI needs putmsg under HPUX so test for -lstr while we're at it AC_CHECK_LIB(str, putmsg) ]) pchar-1.5/config.guess000755 002001 000024 00000115230 10203463722 015030 0ustar00bmahstaff000000 000000 #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-01-17' # This file 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Written by Per Bothner . # Please send patches to . # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. # # Only a few systems have been added to this list; please add others # (but try to keep the structure clean). # me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi dummy=dummy-$$ trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int dummy(){}" > $dummy.c for c in cc gcc c89 ; do ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 if test $? = 0 ; then CC_FOR_BUILD="$c"; break fi done rm -f $dummy.c $dummy.o $dummy.rel if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 8/24/94.) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # Netbsd (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # Determine the machine/vendor (is the vendor relevant). case "${UNAME_MACHINE}" in amiga) machine=m68k-unknown ;; arm32) machine=arm-unknown ;; atari*) machine=m68k-atari ;; sun3*) machine=m68k-sun ;; mac68k) machine=m68k-apple ;; macppc) machine=powerpc-apple ;; hp3[0-9][05]) machine=m68k-hp ;; ibmrt|romp-ibm) machine=romp-ibm ;; *) machine=${UNAME_MACHINE}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE}" in i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; esac fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; arc64:OpenBSD:*:*) echo mips64el-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hkmips:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; atari*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; sun3*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i?86:AIX:*:*) echo i386-ibm-aix exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:4) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=4.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:5) case "`lsattr -El proc0 -a type -F value`" in PowerPC*) IBM_ARCH=powerpc IBM_MANUF=ibm ;; Itanium) IBM_ARCH=ia64 IBM_MANUF=unknown ;; POWER*) IBM_ARCH=power IBM_MANUF=ibm ;; *) IBM_ARCH=powerpc IBM_MANUF=ibm ;; esac echo ${IBM_ARCH}-${IBM_MANUF}-aix${UNAME_VERSION}.${UNAME_RELEASE} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) case "${HPUX_REV}" in 11.[0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; esac ;; esac fi ;; esac if [ "${HP_ARCH}" = "" ]; then sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i?86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; hppa*:OpenBSD:*:*) echo hppa-unknown-openbsd exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*X-MP:*:*:*) echo xmp-cray-unicos exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY-2:*:*:*) echo cray2-cray-unicos exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; *:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. ld_supported_emulations=`cd /; ld --help 2>&1 \ | sed -ne '/supported emulations:/!d s/[ ][ ]*/ /g s/.*supported emulations: *// s/ .*// p'` case "$ld_supported_emulations" in *ia64) echo "${UNAME_MACHINE}-unknown-linux" exit 0 ;; i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; elf_i?86) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; elf32_sparc) echo "${UNAME_MACHINE}-unknown-linux-gnu" exit 0 ;; armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; elf32arm*) echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" exit 0 ;; armelf_linux*) echo "${UNAME_MACHINE}-unknown-linux-gnu" exit 0 ;; m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; elf32ppc | elf32ppclinux) # Determine Lib Version cat >$dummy.c < #if defined(__GLIBC__) extern char __libc_version[]; extern char __libc_release[]; #endif main(argc, argv) int argc; char *argv[]; { #if defined(__GLIBC__) printf("%s %s\n", __libc_version, __libc_release); #else printf("unkown\n"); #endif return 0; } EOF LIBC="" $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null if test "$?" = 0 ; then ./$dummy | grep 1\.99 > /dev/null if test "$?" = 0 ; then LIBC="libc1" fi fi rm -f $dummy.c $dummy echo powerpc-unknown-linux-gnu${LIBC} exit 0 ;; shelf_linux) echo "${UNAME_MACHINE}-unknown-linux-gnu" exit 0 ;; esac if test "${UNAME_MACHINE}" = "alpha" ; then cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF LIBC="" $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; esac objdump --private-headers $dummy | \ grep ld.so.1 > /dev/null if test "$?" = 0 ; then LIBC="libc1" fi fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 elif test "${UNAME_MACHINE}" = "mips" ; then cat >$dummy.c < /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __MIPSEB__ printf ("%s-unknown-linux-gnu\n", argv[1]); #endif #ifdef __MIPSEL__ printf ("%sel-unknown-linux-gnu\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy elif test "${UNAME_MACHINE}" = "s390"; then echo s390-ibm-linux && exit 0 elif test "${UNAME_MACHINE}" = "x86_64"; then echo x86_64-unknown-linux-gnu && exit 0 elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 else # Either a pre-BFD a.out linker (linux-gnuoldld) # or one that does not give us useful --help. # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. # If ld does not provide *any* "supported emulations:" # that means it is gnuoldld. test -z "$ld_supported_emulations" \ && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 case "${UNAME_MACHINE}" in i?86) VENDOR=pc; ;; *) VENDOR=unknown; ;; esac # Determine whether the default compiler is a.out or elf cat >$dummy.c < #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif #else printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 fi ;; # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions # are messed up and put the nodename in both sysname and nodename. i?86:DYNIX/ptx:4*:*) echo i386-sequent-sysv4 exit 0 ;; i?86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i?86:*:5:7*) # Fixed at (any) Pentium or better UNAME_MACHINE=i586 if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} fi exit 0 ;; i?86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i?86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) if test "${UNAME_MACHINE}" = "x86pc"; then UNAME_MACHINE=pc fi echo `uname -p`-${UNAME_MACHINE}-nto-qnx exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[KW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i?86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) printf ("vax-dec-bsd\n"); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pchar-1.5/config.sub000755 002001 000024 00000065434 10203463722 014505 0ustar00bmahstaff000000 000000 #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-01-12' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \ | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \ | pyramid | mn10200 | mn10300 | tron | a29k \ | 580 | i960 | h8300 \ | x86 | ppcbe | mipsbe | mipsle | shbe | shle \ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ | hppa64 \ | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ | alphaev6[78] \ | we32k | ns16k | clipper | i370 | sh | sh[34] \ | powerpc | powerpcle \ | 1750a | dsp16xx | pdp10 | pdp11 \ | mips16 | mips64 | mipsel | mips64el \ | mips64orion | mips64orionel | mipstx39 | mipstx39el \ | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ | mips64vr5000 | miprs64vr5000el | mcore \ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ | thumb | d10v | d30v | fr30 | avr | openrisc) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i[234567]86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. # FIXME: clean up the formatting here. vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \ | arm-* | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ | xmp-* | ymp-* \ | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \ | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ | hppa2.0n-* | hppa64-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ | alphaev6[78]-* \ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | clipper-* | orion-* \ | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ | mipstx39-* | mipstx39el-* | mcore-* \ | f30[01]-* | f700-* | s390-* | sv1-* | t3e-* \ | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ | bs2000-* | tic54x-* | c54x-* | x86_64-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [ctj]90-cray) basic_machine=c90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i[34567]86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i[34567]86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i[34567]86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i[34567]86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4) basic_machine=sh-unknown ;; sparc | sparcv9) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i[34567]86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pchar-1.5/configure000755 002001 000024 00000223777 10203463722 014437 0ustar00bmahstaff000000 000000 #! /bin/sh # From configure.in Revision: 1.35 # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --with-ipv6 always enable IPv6 support" ac_help="$ac_help --with-pcap use pcap library" ac_help="$ac_help --with-snmp use UCD SNMP library" ac_help="$ac_help --with-suid install SUID root" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= sitefile= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --site-file=FILE use FILE as the site file --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -site-file | --site-file | --site-fil | --site-fi | --site-f) ac_prev=sitefile ;; -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*) sitefile="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=pc.h # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$sitefile"; then if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi else CONFIG_SITE="$sitefile" fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross if test "$program_transform_name" = s,x,x,; then program_transform_name= else # Double any \ or $. echo might interpret backslashes. cat <<\EOF_SED > conftestsed s,\\,\\\\,g; s,\$,$$,g EOF_SED program_transform_name="`echo $program_transform_name|sed -f conftestsed`" rm -f conftestsed fi test "$program_prefix" != NONE && program_transform_name="s,^,${program_prefix},; $program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" # sed with no file args requires a program. test "$program_transform_name" = "" && program_transform_name="s,x,x," ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Make sure we can run config.sub. if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 echo "configure:625: checking host system type" >&5 host_alias=$host case "$host_alias" in NONE) case $nonopt in NONE) if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } fi ;; *) host_alias=$nonopt ;; esac ;; esac host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 # Check whether --with-ipv6 or --without-ipv6 was given. if test "${with_ipv6+set}" = set; then withval="$with_ipv6" : fi # Check whether --with-pcap or --without-pcap was given. if test "${with_pcap+set}" = set; then withval="$with_pcap" : fi # Check whether --with-snmp or --without-snmp was given. if test "${with_snmp+set}" = set; then withval="$with_snmp" : fi # Check whether --with-suid or --without-suid was given. if test "${with_suid+set}" = set; then withval="$with_suid" : fi for ac_prog in mawk gawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:676: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_AWK="$ac_prog" break fi done IFS="$ac_save_ifs" fi fi AWK="$ac_cv_prog_AWK" if test -n "$AWK"; then echo "$ac_t""$AWK" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$AWK" && break done for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:710: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CXX="$ac_prog" break fi done IFS="$ac_save_ifs" fi fi CXX="$ac_cv_prog_CXX" if test -n "$CXX"; then echo "$ac_t""$CXX" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$CXX" && break done test -n "$CXX" || CXX="gcc" echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:742: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross cat > conftest.$ac_ext << EOF #line 753 "configure" #include "confdefs.h" int main(){return(0);} EOF if { (eval echo configure:758: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cxx_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cxx_cross=no else ac_cv_prog_cxx_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cxx_works=no fi rm -fr conftest* ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 if test $ac_cv_prog_cxx_works = no; then { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:784: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 cross_compiling=$ac_cv_prog_cxx_cross echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 echo "configure:789: checking whether we are using GNU C++" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gxx=yes else ac_cv_prog_gxx=no fi fi echo "$ac_t""$ac_cv_prog_gxx" 1>&6 if test $ac_cv_prog_gxx = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS="${CXXFLAGS+set}" ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS= echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 echo "configure:817: checking whether ${CXX-g++} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.cc if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then ac_cv_prog_cxx_g=yes else ac_cv_prog_cxx_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS="$ac_save_CXXFLAGS" elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 echo "configure:860: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_IFS" fi if test "${ac_cv_path_install+set}" = set; then INSTALL="$ac_cv_path_install" else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL="$ac_install_sh" fi fi echo "$ac_t""$INSTALL" 1>&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 echo "configure:913: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftestdata if ln -s X conftestdata 2>/dev/null then rm -f conftestdata ac_cv_prog_LN_S="ln -s" else ac_cv_prog_LN_S=ln fi fi LN_S="$ac_cv_prog_LN_S" if test "$ac_cv_prog_LN_S" = "ln -s"; then echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for pchar version number""... $ac_c" 1>&6 echo "configure:935: checking for pchar version number" >&5 PC_VERSION=`cat ${srcdir}/VERSION` echo "$ac_t"""$PC_VERSION"" 1>&6 echo $ac_n "checking echo functionality""... $ac_c" 1>&6 echo "configure:941: checking echo functionality" >&5 if test "`echo "\\n"`" = '\n'; then echoqnl='echo "\"\\n\""' echo "$ac_t""" 1>&6 "BSD-style" else echoqnl='echo "\"\\\n\""' echo "$ac_t""" 1>&6 "SysV-style" fi echo $ac_n "checking size of bool""... $ac_c" 1>&6 echo "configure:952: checking size of bool" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_bool'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() { FILE *f=fopen("conftestval", "w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(bool)); exit(0); } EOF if { (eval echo configure:974: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_bool=`cat conftestval` else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_sizeof_bool=0 fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_sizeof_bool" 1>&6 cat >> confdefs.h <&6 echo "configure:995: checking for socklen_t" >&5 if eval "test \"`echo '$''{'pchar_cv_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { { socklen_t foo; } ; return 0; } EOF if { (eval echo configure:1008: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* pchar_cv_socklen_t=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* pchar_cv_socklen_t=no fi rm -f conftest* fi echo "$ac_t""$pchar_cv_socklen_t" 1>&6 if test "$pchar_cv_socklen_t" = "yes"; then cat >> confdefs.h <<\EOF #define HAVE_SOCKLEN_T 1 EOF fi echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6 echo "configure:1031: checking how to run the C++ preprocessor" >&5 if test -z "$CXXCPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross CXXCPP="${CXX-g++} -E" cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1049: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CXXCPP=/lib/cpp fi rm -f conftest* ac_cv_prog_CXXCPP="$CXXCPP" ac_ext=C # CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cxx_cross fi fi CXXCPP="$ac_cv_prog_CXXCPP" echo "$ac_t""$CXXCPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo "configure:1074: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1087: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF if { (eval echo configure:1157: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_header_stdc=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi for ac_hdr in unistd.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1184: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1194: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in strings.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1224: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1234: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking if sockaddr struct has sa_len member""... $ac_c" 1>&6 echo "configure:1262: checking if sockaddr struct has sa_len member" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_sockaddr_has_sa_len'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < # include int main() { u_int i = sizeof(((struct sockaddr *)0)->sa_len) ; return 0; } EOF if { (eval echo configure:1276: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_sockaddr_has_sa_len=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_lbl_sockaddr_has_sa_len=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_lbl_sockaddr_has_sa_len" 1>&6 if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then cat >> confdefs.h <<\EOF #define HAVE_SOCKADDR_SA_LEN 1 EOF fi # Most operating systems have gethostbyname() in the default searched # libraries (i.e. libc): echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 echo "configure:1299: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyname(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) choke me #else gethostbyname(); #endif ; return 0; } EOF if { (eval echo configure:1330: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_gethostbyname=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 # Some OSes (eg. Solaris) place it in libnsl: echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 echo "configure:1349: checking for gethostbyname in -lnsl" >&5 ac_lib_var=`echo nsl'_'gethostbyname'_' | sed 'y%./+- %__p__%'` if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 # Some strange OSes (SINIX) have it in libsocket: echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6 echo "configure:1398: checking for gethostbyname in -lsocket" >&5 ac_lib_var=`echo socket'_'gethostbyname'_' | sed 'y%./+- %__p__%'` if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 # Unfortunately libsocket sometimes depends on libnsl. # AC_CHECK_LIB's API is essentially broken so the # following ugliness is necessary: echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6 echo "configure:1449: checking for gethostbyname in -lsocket" >&5 ac_lib_var=`echo socket'_'gethostbyname'_'-lnsl | sed 'y%./+- %__p__%'` if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket -lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="-lsocket -lnsl $LIBS" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6 echo "configure:1490: checking for gethostbyname in -lresolv" >&5 ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lresolv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/^a-zA-Z0-9_/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi fi fi fi fi echo $ac_n "checking for socket""... $ac_c" 1>&6 echo "configure:1548: checking for socket" >&5 if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char socket(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_socket) || defined (__stub___socket) choke me #else socket(); #endif ; return 0; } EOF if { (eval echo configure:1579: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_socket=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_socket=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 echo "configure:1597: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 echo "configure:1645: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket'_'-lnsl | sed 'y%./+- %__p__%'` if eval "test \"`echo '$''{'ac_cv_lbl_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket -lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lbl_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="-lsocket -lnsl $LIBS" else echo "$ac_t""no" 1>&6 fi fi fi # DLPI needs putmsg under HPUX so test for -lstr while we're at it echo $ac_n "checking for putmsg in -lstr""... $ac_c" 1>&6 echo "configure:1693: checking for putmsg in -lstr" >&5 ac_lib_var=`echo str'_'putmsg | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lstr $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo str | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi for ac_func in herror do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1747: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done for ac_func in snprintf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1805: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for log in -lm""... $ac_c" 1>&6 echo "configure:1861: checking for log in -lm" >&5 ac_lib_var=`echo m'_'log | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi obj_subsets='${OBJ_BASE}' echo $ac_n "checking for IPv6 support""... $ac_c" 1>&6 echo "configure:1915: checking for IPv6 support" >&5 if eval "test \"`echo '$''{'pchar_cv_sys_ipv6'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$with_ipv6" ; then if test "$with_ipv6" != "no" ; then pchar_cv_sys_ipv6=yes else pchar_cv_sys_ipv6=no fi else cat > conftest.$ac_ext < #include #include int main() { { struct in6_addr foo; } ; return 0; } EOF if { (eval echo configure:1936: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* pchar_cv_sys_ipv6=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* pchar_cv_sys_ipv6=no fi rm -f conftest* fi fi echo "$ac_t""$pchar_cv_sys_ipv6" 1>&6 if test "$pchar_cv_sys_ipv6" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_IPV6 1 EOF obj_subsets="$obj_subsets \${OBJ_IPV6}" if test "$with_ipv6" -a "$with_ipv6" != "yes" ; then LDFLAGS="-L$with_ipv6/lib $LDFLAGS" fi echo $ac_n "checking for inet_pton in -linet6""... $ac_c" 1>&6 echo "configure:1961: checking for inet_pton in -linet6" >&5 ac_lib_var=`echo inet6'_'inet_pton | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-linet6 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo inet6 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi fi echo $ac_n "checking for UCD SNMP support""... $ac_c" 1>&6 echo "configure:2014: checking for UCD SNMP support" >&5 if eval "test \"`echo '$''{'pchar_cv_sys_snmp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else pchar_cv_sys_snmp=no if test "$with_snmp" ; then if test "$with_snmp" != "no" ; then pchar_cv_sys_snmp=yes else pchar_cv_sys_snmp=no fi fi fi echo "$ac_t""$pchar_cv_sys_snmp" 1>&6 if test "$pchar_cv_sys_snmp" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_SNMP 1 EOF obj_subsets="$obj_subsets \${OBJ_SNMP}" if test "$with_snmp" -a "$with_snmp" != "yes" ; then LDFLAGS="-L$with_snmp/lib $LDFLAGS" CPPFLAGS="-I$with_snmp/include $CPPFLAGS" fi echo $ac_n "checking for des_cbc_encrypt in -lcrypto""... $ac_c" 1>&6 echo "configure:2041: checking for des_cbc_encrypt in -lcrypto" >&5 ac_lib_var=`echo crypto'_'des_cbc_encrypt | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo crypto | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi echo $ac_n "checking for snmp_sess_init in -lsnmp""... $ac_c" 1>&6 echo "configure:2091: checking for snmp_sess_init in -lsnmp" >&5 ac_lib_var=`echo snmp'_'snmp_sess_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsnmp -lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo snmp | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi fi echo $ac_n "checking for LBL pcap support""... $ac_c" 1>&6 echo "configure:2144: checking for LBL pcap support" >&5 if eval "test \"`echo '$''{'pchar_cv_sys_pcap'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else pchar_cv_sys_pcap=no if test "$with_pcap" ; then if test "$with_pcap" != "no" ; then pchar_cv_sys_pcap=yes else pchar_cv_sys_pcap=no fi fi fi echo "$ac_t""$pchar_cv_sys_pcap" 1>&6 if test "$pchar_cv_sys_pcap" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_PCAP 1 EOF obj_subsets="$obj_subsets" if test "$with_pcap" -a "$with_pcap" != "yes" ; then LDFLAGS="-L$with_pcap/lib $LDFLAGS" CPPFLAGS="-I$with_pcap/include $CPPFLAGS" fi echo $ac_n "checking for pcap_open_live in -lpcap""... $ac_c" 1>&6 echo "configure:2171: checking for pcap_open_live in -lpcap" >&5 ac_lib_var=`echo pcap'_'pcap_open_live | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lpcap $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_lib=HAVE_LIB`echo pcap | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&6 fi fi if test "$pchar_cv_sys_pcap" = "yes" ; then echo $ac_n "checking for BPF support""... $ac_c" 1>&6 echo "configure:2224: checking for BPF support" >&5 if eval "test \"`echo '$''{'pchar_cv_sys_bpf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else pchar_cvs_sys_bpf=no if test -r /dev/bpf0 ; then pchar_cv_sys_bpf=yes else if test -c /dev/bpf0 ; then pchar_cv_sys_bpf=yes else pchar_cv_sys_bpf=no fi fi fi echo "$ac_t""$pchar_cv_sys_bpf" 1>&6 if test "$pchar_cv_sys_bpf" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_BPF 1 EOF fi fi echo $ac_n "checking for SUID root build""... $ac_c" 1>&6 echo "configure:2253: checking for SUID root build" >&5 if test "$with_suid" ; then if test "$with_suid" = "yes" ; then cat >> confdefs.h <<\EOF #define WITH_SUID 1 EOF INSTALL_PROGRAM='${INSTALL} -m 4755 -s' echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for OS-specific requirements""... $ac_c" 1>&6 echo "configure:2270: checking for OS-specific requirements" >&5 case $host in *-solaris2*) cat >> confdefs.h <<\EOF #define NEED_XOPEN 1 EOF case $host in *-solaris2.5.1) cat >> confdefs.h <<\EOF #define NEED_RANDOM_PROTO 1 EOF echo "$ac_t""Solaris X/Open flags and random prototype" 1>&6 ;; *) echo "$ac_t""Solaris X/Open flags" 1>&6 ;; esac ;; *-irix* | *-osf*) cat >> confdefs.h <<\EOF #define NEED_GETSOCKNAME_HACK 1 EOF echo "$ac_t""getsockname(3) takes (int *)" 1>&6 ;; *-bsdi4.1) cat >> confdefs.h <<\EOF #define NEED_NRL_IPV6_HACK 1 EOF echo "$ac_t""BSDI 4.1 uses NRL IPv6 stack" 1>&6 ;; *) echo "$ac_t""none" 1>&6; esac trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile Makefile.depend" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@host@%$host%g s%@host_alias@%$host_alias%g s%@host_cpu@%$host_cpu%g s%@host_vendor@%$host_vendor%g s%@host_os@%$host_os%g s%@AWK@%$AWK%g s%@CXX@%$CXX%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@LN_S@%$LN_S%g s%@PC_VERSION@%$PC_VERSION%g s%@echoqnl@%$echoqnl%g s%@CXXCPP@%$CXXCPP%g s%@obj_subsets@%$obj_subsets%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 pchar-1.5/configure.in000644 002001 000024 00000014254 10203463722 015025 0ustar00bmahstaff000000 000000 dnl Process this file with autoconf to produce a configure script. dnl $Id: configure.in 1082 2005-02-12 19:40:04Z bmah $ dnl based on: dnl $ID: configure.in,v 1.10 1996/10/27 01:35:36 bmah Exp $ AC_REVISION($Revision: 1082 $) AC_INIT(pc.h) AC_LANG_CPLUSPLUS AC_ARG_PROGRAM AC_CANONICAL_HOST AC_ARG_WITH(ipv6, [ --with-ipv6 always enable IPv6 support]) AC_ARG_WITH(pcap, [ --with-pcap use pcap library]) AC_ARG_WITH(snmp, [ --with-snmp use UCD SNMP library]) AC_ARG_WITH(suid, [ --with-suid install SUID root]) dnl Checks for programs. AC_PROG_AWK AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LN_S AC_MSG_CHECKING(for pchar version number) PC_VERSION=`cat ${srcdir}/VERSION` AC_SUBST(PC_VERSION) AC_MSG_RESULT("$PC_VERSION") dnl Check echo functionality AC_MSG_CHECKING(echo functionality) if test "`echo "\\n"`" = '\n'; then echoqnl='echo "\"\\n\""' AC_MSG_RESULT "BSD-style" else echoqnl='echo "\"\\\n\""' AC_MSG_RESULT "SysV-style" fi AC_SUBST(echoqnl) dnl Check for a bool type. AC_CHECK_SIZEOF(bool) dnl Check for a socklen_t type. AC_CACHE_CHECK(for socklen_t, pchar_cv_socklen_t, AC_TRY_COMPILE( [#include #include ], [{ socklen_t foo; }], [pchar_cv_socklen_t=yes], [pchar_cv_socklen_t=no]) ) if test "$pchar_cv_socklen_t" = "yes"; then AC_DEFINE(HAVE_SOCKLEN_T) fi dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(unistd.h) AC_CHECK_HEADERS(strings.h) AC_LBL_SOCKADDR_SA_LEN AC_LBL_LIBRARY_NET dnl Checks for library functions. AC_CHECK_FUNCS(herror) AC_CHECK_FUNCS(snprintf) AC_CHECK_LIB(m, log) dnl Subsets of object files that we need to link together. dnl These are defined in the Makefile. We always need ${OBJ_BASE}. obj_subsets='${OBJ_BASE}' dnl IPv6 support if desired. If the user enabled --with-ipv6, dnl then force IPv6 support on. If the user set --without-ipv6, dnl then force IPv6 support off. Otherwise, test for a definition dnl of struct in6_addr and use that to figure out if we have IPv6 on dnl this system. An argument to --with-ipv6 dnl is taken as the base directory to where any IPv6 support libraries dnl live (e.g. with libraries in /usr/local/v6/lib, pchar should dnl be configured --with-ipv6=/usr/local/v6 to find its libraries). dnl Specification of a library is not needed with systems that have dnl IPv6 support built-in, for example, in libc. AC_CACHE_CHECK(for IPv6 support, pchar_cv_sys_ipv6, if test "$with_ipv6" ; then if test "$with_ipv6" != "no" ; then pchar_cv_sys_ipv6=yes else pchar_cv_sys_ipv6=no fi else AC_TRY_COMPILE( [#include #include #include ], [{ struct in6_addr foo; }], [pchar_cv_sys_ipv6=yes], [pchar_cv_sys_ipv6=no]) fi) if test "$pchar_cv_sys_ipv6" = "yes" ; then AC_DEFINE(HAVE_IPV6) obj_subsets="$obj_subsets \${OBJ_IPV6}" if test "$with_ipv6" -a "$with_ipv6" != "yes" ; then LDFLAGS="-L$with_ipv6/lib $LDFLAGS" fi AC_CHECK_LIB(inet6, inet_pton) fi dnl UCD SNMP support if desired. If the user enabled --with-snmp, dnl then modify the include path and library definitions as needed. dnl If the user gave an argument to --with-snmp, use that as the dnl base directory for support libraries and header files. AC_CACHE_CHECK(for UCD SNMP support, pchar_cv_sys_snmp, pchar_cv_sys_snmp=no if test "$with_snmp" ; then if test "$with_snmp" != "no" ; then pchar_cv_sys_snmp=yes else pchar_cv_sys_snmp=no fi fi) if test "$pchar_cv_sys_snmp" = "yes" ; then AC_DEFINE(HAVE_SNMP) obj_subsets="$obj_subsets \${OBJ_SNMP}" if test "$with_snmp" -a "$with_snmp" != "yes" ; then LDFLAGS="-L$with_snmp/lib $LDFLAGS" CPPFLAGS="-I$with_snmp/include $CPPFLAGS" fi AC_CHECK_LIB(crypto, des_cbc_encrypt) AC_CHECK_LIB(snmp, snmp_sess_init,,,-lcrypto) fi dnl pcap support if desired. If the user enabled --with-pcap, dnl the modify the include path and library definitions as needed. dnl (Basically, do what we do for UCD SNMP support.) AC_CACHE_CHECK(for LBL pcap support, pchar_cv_sys_pcap, pchar_cv_sys_pcap=no if test "$with_pcap" ; then if test "$with_pcap" != "no" ; then pchar_cv_sys_pcap=yes else pchar_cv_sys_pcap=no fi fi) if test "$pchar_cv_sys_pcap" = "yes" ; then AC_DEFINE(HAVE_PCAP) obj_subsets="$obj_subsets" if test "$with_pcap" -a "$with_pcap" != "yes" ; then LDFLAGS="-L$with_pcap/lib $LDFLAGS" CPPFLAGS="-I$with_pcap/include $CPPFLAGS" fi AC_CHECK_LIB(pcap, pcap_open_live) fi dnl If we are using pcap, check if we're running it over BPF dnl The check using "test -r" followed by "test -c" comes from dnl the pcap configure script. if test "$pchar_cv_sys_pcap" = "yes" ; then AC_CACHE_CHECK(for BPF support, pchar_cv_sys_bpf, pchar_cvs_sys_bpf=no if test -r /dev/bpf0 ; then pchar_cv_sys_bpf=yes else if test -c /dev/bpf0 ; then pchar_cv_sys_bpf=yes else pchar_cv_sys_bpf=no fi fi) if test "$pchar_cv_sys_bpf" = "yes" ; then AC_DEFINE(HAVE_BPF) fi fi dnl Set object file list substitution AC_SUBST(obj_subsets) dnl Check for setuid root. If user specified this as an argument dnl to configure, then turn on that part of the code and tweak our dnl install program variable. Doing this is bad for the general case dnl since anything installed with ${INSTALL_PROGRAM} will get dnl installed SUID. Also make sure to strip the binary. AC_MSG_CHECKING(for SUID root build) if test "$with_suid" ; then if test "$with_suid" = "yes" ; then AC_DEFINE(WITH_SUID) INSTALL_PROGRAM='${INSTALL} -m 4755 -s' AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi else AC_MSG_RESULT(no) fi dnl OS-specific kludges AC_MSG_CHECKING(for OS-specific requirements) case $host in *-solaris2*) AC_DEFINE(NEED_XOPEN) case $host in *-solaris2.5.1) AC_DEFINE(NEED_RANDOM_PROTO) AC_MSG_RESULT(Solaris X/Open flags and random prototype) ;; *) AC_MSG_RESULT(Solaris X/Open flags) ;; esac ;; *-irix* | *-osf*) AC_DEFINE(NEED_GETSOCKNAME_HACK) AC_MSG_RESULT(getsockname(3) takes (int *)) ;; *-bsdi4.1) AC_DEFINE(NEED_NRL_IPV6_HACK) AC_MSG_RESULT(BSDI 4.1 uses NRL IPv6 stack) ;; *) AC_MSG_RESULT(none); esac AC_OUTPUT(Makefile Makefile.depend) pchar-1.5/install-sh000755 002001 000024 00000012736 10203463722 014523 0ustar00bmahstaff000000 000000 #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 pchar-1.5/mkinstalldirs000755 002001 000024 00000001316 10203463722 015315 0ustar00bmahstaff000000 000000 #! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs 1082 2005-02-12 19:40:04Z bmah $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here