00001
00002
00003 #include "PingTarget.h"
00004 #include <iomanip>
00005 #include <math.h>
00006 #include <float.h>
00007 #include <sstream>
00008 #include "format_system_time.h"
00009 #include "fit_text.h"
00010 #include "safe_assign.h"
00011 #include "trim_spaces.h"
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sys/stat.h>
00015
00016
00017 PingTarget::PingTarget(PingTargets& targets, const char* name, in_addr inetAddr, long id)
00018 : m_targets(targets)
00019 {
00020 safe_assign(m_sName, name);
00021 m_inetAddr = inetAddr;
00022 m_lId = id;
00023 m_bResponseAdded = false;
00024
00025 m_dCurrent = -1.0;
00026 m_lReceived = 0;
00027 m_lSkipped = 0;
00028 m_dMin = DBL_MAX;
00029 m_dMax = 0.0;
00030 m_dSum = 0.0;
00031 m_dSumSquares = 0.0;
00032 }
00033
00034 const char* PingTarget::GetIpAddr() const
00035 {
00036 return inet_ntoa(m_inetAddr);
00037 }
00038
00039 USHORT PingTarget::MakeSequence(long sequence) const
00040 {
00041 return m_targets.MakeSequence(m_lId, sequence);
00042 }
00043
00044 void PingTarget::AddResponseTime(double ms)
00045 {
00046 m_bResponseAdded = true;
00047 m_dCurrent = ms;
00048 if (ms > -1)
00049 {
00050 if (ms < m_dMin)
00051 m_dMin = ms;
00052 if (ms > m_dMax)
00053 m_dMax = ms;
00054 m_dSum += ms;
00055 m_dSumSquares += ms*ms;
00056 m_lReceived++;
00057 }
00058 else
00059 {
00060 m_lSkipped++;
00061 }
00062 }
00063
00064 void PingTarget::ClearResponseFlag()
00065 {
00066 m_bResponseAdded = false;
00067 }
00068
00069 double PingTarget::GetMin() const
00070 {
00071 if (m_lReceived > 0)
00072 return m_dMin;
00073 else
00074 return 0.0;
00075 }
00076
00077 double PingTarget::GetMax() const
00078 {
00079 if (m_lReceived > 0)
00080 return m_dMax;
00081 else
00082 return 0.0;
00083 }
00084
00085 double PingTarget::GetAvg() const
00086 {
00087 if (m_lReceived > 0)
00088 {
00089 double rec = m_lReceived;
00090 return m_dSum/rec;
00091 }
00092 else
00093 return 0.0;
00094 }
00095 double PingTarget::GetStdDev() const
00096 {
00097 if (m_lReceived > 0)
00098 {
00099 double avg = GetAvg();
00100 double rec = m_lReceived;
00101 double stddev = sqrt(m_dSumSquares / rec - avg*avg);
00102 return stddev;
00103 }
00104 else
00105 return 0.0;
00106 }
00107
00108 double PingTarget::GetSkippedPercent() const
00109 {
00110 double total = m_lReceived+m_lSkipped;
00111 if (total > 0.0)
00112 {
00113 double skipped = m_lSkipped;
00114 return 100.0*skipped/total;
00115 }
00116 else
00117 return 0.0;
00118 }
00119
00120 std::ostream& operator<<(std::ostream& os, const PingTarget& t)
00121 {
00122 os.precision(6);
00123 os.unsetf(std::ios::showpoint | std::ios::fixed);
00124 os << t.GetName() << " (" << t.GetIpAddr() << ") id=" << t.GetId() << std::endl;
00125 os << " responses=" << t.GetResponseCount();
00126 os << " skipped=" << t.GetSkipped();
00127 os << " (" << t.GetSkippedPercent() << "%)";
00128 os << std::endl;
00129 os << " current=";
00130 if (t.GetCurrent() == -1.0)
00131 os << "(*)";
00132 else
00133 os << t.GetCurrent();
00134 os << " min=" << t.GetMin();
00135 os << " avg=" << t.GetAvg() << " max=" << t.GetMax();
00136 os << " stddev=" << t.GetStdDev();
00137 return os;
00138 }
00139
00140
00141 PingTargets::PingTargets()
00142 {
00143 m_lIdBits = 6;
00144 m_lIdMax = (1 << m_lIdBits) -1;
00145 m_lSequenceBits = sizeof(USHORT)*8 - m_lIdBits;
00146 m_uIdMask = (USHORT)(m_lIdMax << m_lSequenceBits);
00147 m_uSeqMask = m_uIdMask ^ (USHORT)0xffff;
00148 m_lSequenceMax = m_uSeqMask;
00149 m_lMaxNameWidth = 0;
00150 }
00151
00152 PingTargets::~PingTargets()
00153 {
00154 for (const_iterator i = begin(); i != end(); ++i)
00155 delete *i;
00156 m_targets.clear();
00157 }
00158
00159 PingTarget* PingTargets::AddTarget(const char* name)
00160 {
00161 in_addr inetAddr;
00162 inetAddr.S_un.S_addr = inet_addr(name);
00163 if (inetAddr.S_un.S_addr == INADDR_NONE)
00164 {
00165 hostent* pHost = gethostbyname(name);
00166 if (pHost && pHost->h_addrtype == AF_INET)
00167 memcpy(&inetAddr, pHost->h_addr_list[0], pHost->h_length);
00168 }
00169 if (inetAddr.S_un.S_addr == INADDR_NONE)
00170 {
00171 std::cerr << "Unable to add target. Target " << name << " cannot be resolved." << std::endl;
00172 return NULL;
00173 }
00174 if ((long)m_targets.size() < m_lIdMax)
00175 {
00176 PingTarget* pTarget = new PingTarget(*this, name, inetAddr, (long)m_targets.size()+1);
00177 m_targets.push_back(pTarget);
00178 m_lMaxNameWidth = max(m_lMaxNameWidth, (long)pTarget->m_sName.size());
00179 return pTarget;
00180 }
00181 else
00182 {
00183 std::cerr << "Unable to add target: " << name << std::endl;
00184 std::cerr << "Maximum target count " << GetMaxTargets() << " would be exceeded." << std::endl;
00185 }
00186 return NULL;
00187 }
00188
00189 bool PingTargets::AddTargets(std::istream& is)
00190 {
00191 bool resolved = true;
00192 while (is && resolved)
00193 {
00194 std::string s;
00195 std::getline(is, s);
00196 s = trim_spaces(s.c_str());
00197 if (!s.empty())
00198 {
00199 if (!AddTarget(s.c_str()))
00200 resolved = false;
00201 }
00202 }
00203 return resolved;
00204 }
00205
00206 bool PingTargets::AddTargets(const char* pszFilename)
00207 {
00208 std::ifstream is(pszFilename);
00209 if (is.is_open())
00210 {
00211 return AddTargets(is);
00212 }
00213 else
00214 {
00215 std::cerr << "Unable to open file " << pszFilename << " for reading." << std::endl;
00216 return false;
00217 }
00218 }
00219
00220 long PingTargets::GetMaxTargets() const
00221 {
00222 return m_lIdMax;
00223 }
00224
00225 PingTarget* PingTargets::Get(long id) const
00226 {
00227 if (id > 0 && id <= (long)size())
00228 return m_targets[id-1];
00229 else
00230 return NULL;
00231 }
00232
00233 bool PingTargets::AddResponse(long id, double ms)
00234 {
00235 PingTarget* pTarget = Get(id);
00236 if (pTarget)
00237 {
00238 pTarget->AddResponseTime(ms);
00239 return true;
00240 }
00241 return false;
00242 }
00243
00244 void PingTargets::ClearResponseFlags()
00245 {
00246 for (iterator i = m_targets.begin(); i != m_targets.end(); ++i)
00247 (*i)->m_bResponseAdded = false;
00248 }
00249
00250 void PingTargets::AddUnreachableResponses()
00251 {
00252 for (iterator i = m_targets.begin(); i != m_targets.end(); ++i)
00253 {
00254 PingTarget& t = **i;
00255 if (!t.IsResponseAdded())
00256 t.AddResponseTime();
00257 }
00258 }
00259
00260 long PingTargets::GetTargetId(USHORT sequence) const
00261 {
00262 return sequence >> m_lSequenceBits;
00263 }
00264
00265 long PingTargets::GetSequence(USHORT sequence) const
00266 {
00267 return sequence & m_uSeqMask;
00268 }
00269
00270 USHORT PingTargets::MakeSequence(long lId, long lSequence) const
00271 {
00272 return (USHORT)((lId << m_lSequenceBits) + lSequence);
00273 }
00274
00275 void PingTargets::PrintStatisticsHeader(std::ostream& os, long lConsoleWidth) const
00276 {
00277 os << std::setfill(' ') << std::left;
00278 long lNameWidth = GetMaxNameWidth();
00279 if (lNameWidth > lConsoleWidth-7*8-1)
00280 lNameWidth = lConsoleWidth-7*8-1;
00281 os << std::right;
00282 os << std::setw(lNameWidth) << " ";
00283 os << std::setw(8) << "now";
00284 os << std::setw(8) << "minimum";
00285 os << std::setw(8) << "average";
00286 os << std::setw(8) << "maximum";
00287 os << std::setw(8) << "std.dev";
00288 os << std::setw(8) << "skipped";
00289 os << std::setw(8) << "skip%";
00290 }
00291
00292 void PingTargets::PrintStatistics(std::ostream& os, long lConsoleWidth) const
00293 {
00294 long lNameWidth = GetMaxNameWidth();
00295 if (lNameWidth > lConsoleWidth-7*8-1)
00296 lNameWidth = lConsoleWidth-7*8-1;
00297 os.fill(' ');
00298 for (PingTargets::const_iterator i = begin(); i != end(); ++i)
00299 {
00300 if (i != begin())
00301 os << std::endl;
00302 const PingTarget& t = **i;
00303 os << std::left << std::setw(lNameWidth) << fit_text(t.GetName()) << std::right;
00304 os.precision(1);
00305 os.setf(std::ios::showpoint | std::ios::fixed);
00306 if (t.GetCurrent() == -1.0)
00307 os << std::setw(8) << "(*)";
00308 else
00309 os << std::setw(8) << t.GetCurrent();
00310 os << std::setw(8) << t.GetMin();
00311 os << std::setw(8) << t.GetAvg();
00312 os << std::setw(8) << t.GetMax();
00313 os << std::setw(8) << t.GetStdDev();
00314 os << std::setw(8) << t.GetSkipped();
00315 os << std::setw(8) << t.GetSkippedPercent();
00316 }
00317 }
00318
00319 void PingTargets::PrintLogHeader(std::ostream& os) const
00320 {
00321 os << std::left;
00322 os << "Time/Target";
00323 for (PingTargets::const_iterator i = begin(); i != end(); ++i)
00324 {
00325 const PingTarget& t = **i;
00326 os << "\t" << t.GetName();
00327 }
00328 }
00329
00330 void PingTargets::PrintLogCurrent(std::ostream& os, const SYSTEMTIME& systemtime) const
00331 {
00332 os << std::left;
00333 os << format_system_time(systemtime, format_system_time::show_seconds);
00334 os.precision(1);
00335 os.setf(std::ios::showpoint | std::ios::fixed);
00336 for (PingTargets::const_iterator i = begin(); i != end(); ++i)
00337 {
00338 const PingTarget& t = **i;
00339 os << "\t" << t.GetCurrent();
00340 }
00341 }
00342
00343 bool PingTargets::PrintLogCurrent(const char* pszFilename, const SYSTEMTIME& systemtime,
00344 LOG_FILENAME_TYPE FilenameType, bool bNewFile) const
00345 {
00346 std::ostringstream osName;
00347 char path_buffer[_MAX_PATH];
00348 char drive[_MAX_DRIVE];
00349 char dir[_MAX_DIR];
00350 char fname[_MAX_FNAME];
00351 char ext[_MAX_EXT];
00352 _splitpath(pszFilename, drive, dir, fname, ext);
00353 switch(FilenameType)
00354 {
00355 case LOG_FILENAME_PLAIN:
00356 default:
00357 osName << fname;
00358 break;
00359 case LOG_FILENAME_DAILY:
00360 osName << fname;
00361 osName << std::setw(4) << std::setfill('0') << systemtime.wYear;
00362 osName << std::setw(2) << std::setfill('0') << systemtime.wMonth;
00363 osName << std::setw(2) << std::setfill('0') << systemtime.wDay;
00364 break;
00365 case LOG_FILENAME_HOURLY:
00366 osName << fname;
00367 osName << std::setw(4) << std::setfill('0') << systemtime.wYear;
00368 osName << std::setw(2) << std::setfill('0') << systemtime.wMonth;
00369 osName << std::setw(2) << std::setfill('0') << systemtime.wDay;
00370 osName << "_";
00371 osName << std::setw(2) << std::setfill('0') << systemtime.wHour;
00372 break;
00373 }
00374 _makepath(path_buffer, drive, dir, osName.str().c_str(), ext);
00375 bool bFileExists = false;
00376 struct _stat st;
00377 if (_stat(path_buffer, &st) == 0 && st.st_size > 0)
00378 bFileExists = true;
00379 std::ofstream os;
00380 os.imbue(std::locale(""));
00381 if (bNewFile)
00382 os.open(path_buffer);
00383 else
00384 os.open(path_buffer, std::ios::app);
00385 if (!os.is_open())
00386 {
00387 std::cerr << "Unable to create or open log file " << path_buffer<< std::endl;
00388 return false;
00389 }
00390 if (bNewFile || !bFileExists)
00391 {
00392 PrintLogHeader(os);
00393 os << std::endl;
00394 }
00395 PrintLogCurrent(os, systemtime);
00396 os << std::endl;
00397 return true;
00398 }
00399
00400 std::ostream& operator<<(std::ostream& os, const PingTargets& targets)
00401 {
00402 for (PingTargets::const_iterator i = targets.begin(); i != targets.end(); ++i)
00403 os << **i << std::endl;
00404 return os;
00405 }