/* Copyright (c) 2001 RIPE NCC All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, 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 the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* ------------------------------------------------------------------------------- Module Header Filename : TTMOptions.C Author : Rene Wilhelm Date : 31-OCT-2001 Description : TTMOptions class implemenation Language Version : C++ OSs Tested : Solaris 2.6, Solaris 8, Debian Linux 2.2 TODO : Implement destructor (nice to clean up) Implement dynamic help function $Id: TTMOptions.C,v 1.4 2003/05/16 13:57:41 ttraffic Exp $ ------------------------------------------------------------------------------- */ #include #include #include #include #include #include #include "TTMOptions.h" #include "utils.h" static char const rcsid[] = "$Id: TTMOptions.C,v 1.4 2003/05/16 13:57:41 ttraffic Exp $"; static char const *rcsid_p = rcsid; // Prevent g++ from optimizing out rcsid /* ------------------------------------------------------------------------------- Subroutine Header Purpose : Initializing constructor Input : argument vector, option string (getopt(3) syntax) Comments : This constructor assigns default values to all parameters, and then parses the argument vector, setting optional parameters to the provided values ------------------------------------------------------------------------------- */ TTMOptions::TTMOptions(int argc, char** argv, char* optstring) { extern char *optarg; char buffer[50]; char ch; sourceId = 0; targetId = 0; endTime = 0; timePeriod = 0; ipVersion = 4; inputPath = "/ncc/ttpro/data/root"; outputPath = "/ncc/ttpro/data/plots"; minDelay = 0; maxDelay = 250; allPackets = 0; logScale = 0; storageType = 'H'; // hierarchical sumPeriod = day; optionString = optstring; plotFormat = gif; verbose = 0; progName = argv[0]; putenv("TZ=GMT+0"); // ensure GMT/UTC for time operations short fflag=0; short cflag=0; short mflag=0; short oflag=0; short pflag=0; short sflag=0; short tflag=0; short zflag=0; char *endpointer; while ((ch = getopt(argc, argv, optstring)) != -1) switch(ch) { case '6': ipVersion = 6; break; case 'a': allPackets = 1; break; case 'f': if (fflag) { usage(); /* only one -f allowed */ } if (strcmp(optarg, "csv") == 0) { plotFormat = csv; } else if (strcmp(optarg, "gif") == 0) { plotFormat = gif; } else if (strcmp(optarg, "ps") == 0) { plotFormat = ps; } else if (strcmp(optarg, "eps") == 0) { plotFormat = eps; } else if (strcmp(optarg, "pdf") == 0) { plotFormat = pdf; } else { usage(); } fflag = 1; break; case 's': if (!sflag) { sflag = 1; if (sscanf(optarg, "%[0-9]", buffer) != 1) { usage(); } sourceId = atoi(buffer); } else { /* only one -s allowed */ usage(); } break; case 't': if (!tflag) { tflag = 1; if (sscanf(optarg, "%[0-9]", buffer) != 1) { usage(); } targetId = atoi(buffer); } else { /* only one -t allowed */ usage(); } break; case 'p': if (!pflag) { pflag = 1; decodePeriod(optarg, endTime, timePeriod); } else { /* only one -p allowed */ usage(); } break; case 'o': if (!oflag) { outputPath = new char[strlen(optarg)+1]; strcpy(outputPath, optarg); } else { /* only one -o allowed */ usage(); } break; case 'v': verbose = 1; break; case 'm': if (!mflag) { mflag = 1; maxDelay = strtod(optarg, &endpointer); if (*endpointer != '\0') { usage(); } if (maxDelay <0) { fprintf (stderr, "error: %s: -m positive value expected\n", progName); exit(1); } else if ((maxDelay == HUGE) || (maxDelay == HUGE_VAL)) { fprintf (stderr, "error: %s: -m value out of range\n", progName); exit(1); } } else { /* only one -m allowed */ usage(); } break; case 'w': sumPeriod = week; break; case 'z': if (!zflag) { zflag = 1; minDelay = strtod(optarg, &endpointer); if (*endpointer != '\0') { usage(); } if (minDelay <0) { fprintf (stderr, "error: %s: -z positive value expected\n", progName); exit(1); } else if ((minDelay == HUGE) || (minDelay == HUGE_VAL)) { fprintf (stderr, "error: %s: -z value out of range\n", progName); exit(1); } } else { /* only one -z allowed */ usage(); } break; default: usage(); } if ( !pflag || (tflag && !sflag)) { /* time period is only required argument */ /* specific target requires source to be specified as well */ usage(); } if ( !cflag ) { // construct default config command: // "TTCONFIG_COMMAND -d TTCONFIG_COMMAND_ARGS" int len = strlen(TTCONFIG_COMMAND) + strlen(TTCONFIG_COMMAND_ARGS) + 33; configCmd = new char[len]; strcpy(configCmd, TTCONFIG_COMMAND); char *cp = strchr(configCmd, '\0'); strcpy(cp, " -d "); cp = cp + 4; if (strftime(cp,26,"'%Y-%m-%d %H:%M:%S'",localtime(&endTime)) == 0) { fprintf(stderr, "%s: strftime(): ERROR converting time %d\n", progName, (int) endTime); } strcat(configCmd, " "); if (ipVersion == 6) { strcat(configCmd, TTCONFIG_COMMAND_ARGS6); } else { strcat(configCmd, TTCONFIG_COMMAND_ARGS); } } } /* ------------------------------------------------------------------------------- Subroutine Header Purpose : TTMOptions destructor Comments : ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- Subroutine header Purpose : Error handler Input : none Output : error message Side effects : terminates program ------------------------------------------------------------------------------- */ void TTMOptions::invaliddate() { fprintf (stderr, "%s: invalid date/time specification\n", progName); exit(1); } /* ------------------------------------------------------------------------------- Subroutine header Purpose : decode ascii ISO8601 time period string into an ending time in time_t format (seconds since 1970) and a duration Input : char *datestring string to be decoded Output : time_t& endtime system timestamp of end time time_t& duration duration in seconds ------------------------------------------------------------------------------- */ void TTMOptions::decodePeriod (char* datestring, time_t& endtime, time_t& duration) { char *part1, *part2; char flag1, flag2; time_t time1, time2; /* datestring = ISO8601 time period string */ /* two parts seperated by / */ part1 = datestring; if ((part2 = strchr(part1, '/')) == NULL) { invaliddate(); } *part2 = '\0'; part2++; parseISO8601 (part1, time1, flag1); parseISO8601 (part2, time2, flag2); if ((flag1 == 'T') && (flag2 == 'D')) { /* format: starttime/duration */ duration = time2; endtime = time1 + duration; } else if ((flag1 == 'D') && (flag2 == 'T')) { /* format: duration/endtime */ duration = time1; endtime = time2; } else if ((flag1 == 'T') && (flag2 == 'T')) { /* format: starttime/endtime */ if (time1 >= time2) { /* negative or zero time interval */ invaliddate(); } else { endtime = time2; duration = time2 - time1; } } else { invaliddate(); } } /* ------------------------------------------------------------------------------- Subroutine header Purpose : decode ascii time string into duration of time or fixed point in time; the string should be in the formats described by ISO8601 standard NOTE : to not complicate the routine too much, points in time MUST be complete representations of either a date (CCYYMMDD) or a date+time (CCYYMMDDTHHMMSS). - and : are allowed as separators. similarly, durations are only supported when specified in days, hours, minutes and seconds. Length of months and years are content dependant. Input : char* text string to be decoded Output : time_t& time system timestamp or duration (seconds) char& flag indicates if returned time is timestamp or duration ------------------------------------------------------------------------------- */ #define DAYFLAG 0x001000 #define DHMSFLAG 0x001111 #define HOURFLAG 0x000100 #define HMSFLAG 0x000111 #define MINFLAG 0x000010 #define MSFLAG 0x000011 #define SECFLAG 0x000001 void TTMOptions::parseISO8601 (char *text, time_t& isotime, char& flag) { char *c; int num; struct tm tmstruct; int year = 0; int month = 0; int seconds = 0; int minutes = 0; int hours = 0; int days = 0; int dateflags = 0; /* flag which date component we've seen */ c = text; isotime = 0; if (*c++ == 'P') { /* duration */ flag = 'D'; while (*c != '\0') { num = 0; while (*c >= '0' && *c <= '9') { /* assumes ASCII sequence! */ num = 10 * num + *c++ - '0'; } switch (*c++) { case 'D': if (dateflags & DHMSFLAG) { /* day, hour, min or sec already set */ invaliddate(); } else { dateflags |= DAYFLAG; days = num; } break; case 'H': if (dateflags & HMSFLAG) { /* hour, min or sec already set */ invaliddate(); } else { dateflags |= DAYFLAG; hours = num; } break; case 'M': if (dateflags & MSFLAG) { /* min or sec already set */ invaliddate(); } else { dateflags |= MINFLAG; minutes = num; } break; case 'S': if (dateflags & SECFLAG) { /* sec already set */ invaliddate(); } else { dateflags |= SECFLAG; seconds = num; } break; default: invaliddate(); } } isotime = seconds + 60 * minutes + 3600 * hours + SECONDSPERDAY * days; } else { /* point in time, must be one of CCYYMMDD CCYY-MM-DD CCYYMMDDTHHMM CCYY-MM-DDTHH:MM CCYYMMDDTHHMMSS CCYY-MM-DDTHH:MM:SS */ c = text; flag = 'T'; /* NOTE: we have to check for the extended format first, because otherwise the separting '-' will be interpreted by sscanf as signs of a 1 digit integer .... :-( */ if (sscanf(text, "%4u-%2u-%2u", &year, &month, &days) == 3) { c += 10; } else if (sscanf(text, "%4u%2u%2u", &year, &month, &days) == 3) { c += 8; } else { invaliddate(); } tmstruct.tm_year = year - 1900; tmstruct.tm_mon = month - 1; tmstruct.tm_mday = days; if (*c == '\0') { tmstruct.tm_hour = 0; tmstruct.tm_sec = 0; tmstruct.tm_min = 0; isotime = mktime (&tmstruct); } else if (*c == 'T') { /* time of day part */ c++; if (sscanf(c, "%2d%2d", &hours, &minutes) == 2) { c += 4; } else if (sscanf(c, "%2d:%2d", &hours, &minutes) == 2) { c += 5; } else { invaliddate(); } if (*c == ':') { c++; } if (*c != '\0') { if (sscanf(c, "%2d", &seconds) == 1) { c += 2; } else { invaliddate(); } if (*c != '\0') { /* something left? */ invaliddate(); } } tmstruct.tm_hour = hours; tmstruct.tm_min = minutes; tmstruct.tm_sec = seconds; isotime = mktime (&tmstruct); } else { invaliddate(); } } } TTMOptions::~TTMOptions() { } void TTMOptions::usage() { char *cp = optionString; fprintf (stderr, "usage: %s", progName); while (*cp != '\0') { switch (*cp) { case 'v': // verbose, optional fprintf(stderr, " [-v]"); break; case 'w': // week summaries, optional fprintf(stderr, " [-w]"); break; case 'f': // plot format, optional cp++; fprintf(stderr, " [-f fmt]"); break; case 's': // source id, optional cp++; fprintf(stderr, " [-s src]"); break; case 't': // target id, optional cp++; fprintf(stderr, " [-t tgt]"); break; case 'm': // max delay, optional cp++; fprintf(stderr, " [-m max]"); break; case 'z': // target id, optional cp++; fprintf(stderr, " [-z min]"); break; case '6': // IPv6 instead of IPv4 data, optional cp++; fprintf(stderr, " [-6]"); break; case 'p': // time period, required cp++; fprintf(stderr, " -p period"); break; case 'o': // output dir, optional cp++; fprintf(stderr, " [-o outdir]"); break; default: fprintf(stderr, " %c", *cp); } cp++; } fprintf(stderr, "\n"); exit(1); }