#include "mgen.h"
#include "mgenMsg.h"
#include "mgenPattern.h"
#include <string.h>
#include <stdio.h>
#include <time.h> // for gmtime()
#include <ctype.h> // 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 "<aveRate> <pktSize>"
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 "<burstType> <aveInterval> <pattern> [<params>]
// <durationDistribution> <aveDuration>"
{
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 <patternParams>\n");
return false;
}
}
ptr = strchr(ptr, ']');
if ((*pptr != '[') || !ptr)
{
DMSG(0, "MgenPattern::InitFromString(BURST) Error: missing <patternParams>\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 <patternParams>\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()
syntax highlighted by Code2HTML, v. 0.9.1