#include "mgen.h" #include "mgenMsg.h" #include "mgenPattern.h" #include #include #include // for gmtime() #include // for toupper() MgenPattern::MgenPattern() : interval_remainder(0.0), burst_pattern(NULL) { } MgenPattern::~MgenPattern() { if (burst_pattern) { delete burst_pattern; burst_pattern = NULL; } } const StringMapper MgenPattern::TYPE_LIST[] = { {"PERIODIC", PERIODIC}, {"POISSON", POISSON}, {"BURST", BURST}, {"JITTER", JITTER}, {"XXXX", INVALID_TYPE} }; MgenPattern::Type MgenPattern::GetTypeFromString(const char* string) { // Make comparison case-insensitive char upperString[16]; unsigned int len = strlen(string); len = len < 15 ? len : 15; unsigned int i; for (i =0 ; i < len; i++) upperString[i] = toupper(string[i]); upperString[i] = '\0'; unsigned int matchCount = 0; Type patternType = INVALID_TYPE; const StringMapper* m = TYPE_LIST; while (INVALID_TYPE != (*m).key) { if (!strncmp(upperString, (*m).string, len)) { patternType = ((Type)((*m).key)); matchCount++; } m++; } if (matchCount > 1) { DMSG(0, "MgenPattern::GetTypeFromString() error: ambiguous pattern type\n"); return INVALID_TYPE; } else { return patternType; } } // end MgenPattern::GetTypeFromString() const StringMapper MgenPattern::BURST_LIST[] = { {"REGULAR", REGULAR}, {"RANDOM", RANDOM}, {"XXXX", INVALID_BURST} }; MgenPattern::Burst MgenPattern::GetBurstTypeFromString(const char* string) { // Make comparison case-insensitive char upperString[16]; unsigned int len = strlen(string); len = len < 15 ? len : 15; unsigned int i; for (i =0 ; i < len; i++) upperString[i] = toupper(string[i]); upperString[i] = '\0'; unsigned int matchCount = 0; Burst burstType = INVALID_BURST; const StringMapper* m = BURST_LIST; while (INVALID_BURST != (*m).key) { if (!strncmp(upperString, (*m).string, len)) { burstType = ((Burst)((*m).key)); matchCount++; } m++; } if (matchCount > 1) { DMSG(0, "MgenPattern::GetBurstTypeFromString() Error: ambiguous burst type\n"); return INVALID_BURST; } else { return burstType; } } // end MgenPattern::GetBurstTypeFromString() const StringMapper MgenPattern::DURATION_LIST[] = { {"FIXED", FIXED}, {"EXPONENTIAL", EXPONENTIAL}, {"XXXX", INVALID_DURATION} }; MgenPattern::Duration MgenPattern::GetDurationTypeFromString(const char* string) { // Make comparison case-insensitive char upperString[16]; unsigned int len = strlen(string); len = len < 15 ? len : 15; unsigned int i; for (i =0 ; i < len; i++) upperString[i] = toupper(string[i]); upperString[i] = '\0'; unsigned int matchCount = 0; Duration durationType = INVALID_DURATION; const StringMapper* m = DURATION_LIST; while (INVALID_DURATION != (*m).key) { if (!strncmp(upperString, (*m).string, len)) { durationType = ((Duration)((*m).key)); matchCount++; } m++; } if (matchCount > 1) { DMSG(0, "MgenPattern::GetDurationTypeFromString() Error: ambiguous duration type\n"); return INVALID_DURATION; } else { return durationType; } } // end MgenPattern::GetDurationTypeFromString() bool MgenPattern::InitFromString(MgenPattern::Type theType, const char* string) { type = theType; switch (type) { case PERIODIC: // form " " case POISSON: { double aveRate; if (2 != sscanf(string, "%lf %hu\n", &aveRate, &pkt_size)) { DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid parameters.\n"); return false; } if (aveRate < 0.0) { if (-1.0 != aveRate) { DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid packet rate.\n"); return false; } else { interval_ave = 0.0; } } else if (aveRate > 0.0) { interval_ave = 1.0 / aveRate; } else { interval_ave = -1.0; } if ((pkt_size > MgenMsg::MAX_SIZE) || (pkt_size < MgenMsg::MIN_SIZE)) { DMSG(0, "MgenPattern::InitFromString(PERIODIC/POISSON) error: invalid message size.\n"); return false; } break; } case JITTER: { double aveRate, jitterFraction; interval_remainder = 0.0; if (3 != sscanf(string, "%lf %hu %lf\n", &aveRate, &pkt_size, &jitterFraction)) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid parameters.\n"); return false; } if ((jitterFraction < 0.0) || (jitterFraction > 0.5)) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid jitter fraction.\n"); return false; } if (aveRate < 0.0) { if (-1.0 != aveRate) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid packet rate.\n"); return false; } else { interval_ave = 0.0; } } else if (aveRate > 0.0) { interval_ave = 1.0 / aveRate; } else { interval_ave = -1.0; } if (interval_ave > 0.0) { jitter_min = interval_ave * (1.0 - jitterFraction); jitter_max = interval_ave * (1.0 + jitterFraction); } else { jitter_min = jitter_max = interval_ave; } if ((pkt_size > MgenMsg::MAX_SIZE) || (pkt_size < MgenMsg::MIN_SIZE)) { DMSG(0, "MgenPattern::InitFromString(JITTER) error: invalid message size.\n"); return false; } break; } case BURST: // form " [] // " { char fieldBuffer[Mgen::SCRIPT_LINE_MAX+1]; const char* ptr = string; // Strip leading white space while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; if (1 != sscanf(ptr, "%s", fieldBuffer)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: missing burst type.\n"); return false; } burst_type = GetBurstTypeFromString(fieldBuffer); if (INVALID_BURST == burst_type) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst type.\n"); return false; } ptr += strlen(fieldBuffer); // Strip leading white space while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; if (1 != sscanf(ptr, "%s", fieldBuffer)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: missing burst interval.\n"); return false; } if (1 != sscanf(fieldBuffer, "%lf", &interval_ave)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst interval.\n"); return false; } if (interval_ave < 0.0) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst interval.\n"); return false; } ptr += strlen(fieldBuffer); // Strip leading white space while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; if (1 != sscanf(ptr, "%s", fieldBuffer)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: missing burst pattern.\n"); return false; } Type patternType = GetTypeFromString(fieldBuffer); ptr += strlen(fieldBuffer); while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; // Point to beginning of pattern parameters const char* pptr = ptr; // Find end of pattern parameter set unsigned int nested = 1; while (nested) { ptr++; if ('[' == *ptr) nested++; else if (']' == *ptr) nested--; if ('\0' == *ptr) { DMSG(0, "MgenPattern::InitFromString(BURST) Error: non-terminated \n"); return false; } } ptr = strchr(ptr, ']'); if ((*pptr != '[') || !ptr) { DMSG(0, "MgenPattern::InitFromString(BURST) Error: missing \n"); return false; } if (!burst_pattern) { if (!(burst_pattern = new MgenPattern())) { DMSG(0, "MgenPattern::InitFromString(BURST) Error: pattern allocation: %s\n", GetErrorString()); return false; } } strncpy(fieldBuffer, pptr+1, ptr - pptr - 1); fieldBuffer[ptr - pptr - 1] = '\0'; if (!burst_pattern->InitFromString(patternType, fieldBuffer)) { DMSG(0, "MgenPattern::InitFromString(BURST) Error: invalid \n"); return false; } // Set ptr to next field, skipping any white space ptr++; while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; if (1 != sscanf(ptr, "%s", fieldBuffer)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: missing burst duration type.\n"); return false; } burst_duration_type = GetDurationTypeFromString(fieldBuffer); if (INVALID_DURATION == burst_duration_type) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst duration type.\n"); return false; } ptr += strlen(fieldBuffer); while ((' ' == *ptr) || ('\t' == *ptr)) ptr++; if (1 != sscanf(ptr, "%lf", &burst_duration_ave)) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst duration.\n"); return false; } if (burst_duration_ave < 0.0) { DMSG(0, "MgenPattern::InitFromString(BURST) error: invalid burst duration.\n"); return false; } switch (burst_duration_type) { case FIXED: burst_duration = burst_duration_ave; break; case EXPONENTIAL: burst_duration = ExponentialRand(burst_duration_ave); break; case INVALID_DURATION: ASSERT(0); // can't get here break; } interval_remainder = burst_duration; last_time.tv_sec = last_time.tv_usec = 0; break; } case INVALID_TYPE: DMSG(0, "MgenPattern::InitFromString() unsupported pattern type\n"); ASSERT(0); return false; } // end switch(type) return true; } // end MgenPattern::InitFromString() double MgenPattern::GetPktInterval() { switch (type) { case PERIODIC: return interval_ave; case POISSON: return (interval_ave > 0.0) ? ExponentialRand(interval_ave) : interval_ave; case JITTER: { double pktInterval = UniformRand(jitter_min, jitter_max); double result = pktInterval + interval_remainder; interval_remainder = (interval_ave - pktInterval); return result; } case BURST: { // double pktInterval = burst_pattern->GetPktInterval(); if (pktInterval <= 0.0) { struct timeval currentTime; ProtoSystemTime(currentTime); if ((0 == last_time.tv_sec) && (0 == last_time.tv_usec)) last_time = currentTime; double deltaTime = (double)(currentTime.tv_sec - last_time.tv_sec); if (currentTime.tv_usec > last_time.tv_usec) deltaTime += 1.0e-06*(double)(currentTime.tv_usec - last_time.tv_usec); else deltaTime -= 1.0e-06*(double)(last_time.tv_usec - currentTime.tv_usec); if (interval_remainder > deltaTime) { last_time = currentTime; interval_remainder -= deltaTime; return pktInterval; } last_time.tv_sec = last_time.tv_usec = 0; } else if (interval_remainder > pktInterval) { interval_remainder -= pktInterval; return pktInterval; } // Prev burst has finished, schedule next burst double burstInterval = -1.0; switch (burst_type) { case REGULAR: burstInterval = interval_ave; break; case RANDOM: burstInterval = ExponentialRand(interval_ave); break; case INVALID_BURST: ASSERT(0); return burstInterval; } if (burstInterval > burst_duration) burstInterval = burstInterval - burst_duration + interval_remainder; else burstInterval = interval_remainder; if (burstInterval > pktInterval) pktInterval = burstInterval; // Now pick next burst duration. switch(burst_duration_type) { case FIXED: burst_duration = burst_duration_ave; break; case EXPONENTIAL: burst_duration = ExponentialRand(burst_duration_ave); break; case INVALID_DURATION: ASSERT(0); return -1.0; } interval_remainder = burst_duration; return pktInterval; } case INVALID_TYPE: ASSERT(0); break; } // end switch(type) return -1.0; } // end MgenPattern::GetPktInterval() unsigned short MgenPattern::GetPktSize() { switch (type) { case PERIODIC: case POISSON: case JITTER: return pkt_size; case BURST: return burst_pattern->GetPktSize(); case INVALID_TYPE: ASSERT(0); break; } return 0; } // end MgenPattern::GetPktSize()