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