1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #define WIN32_LEAN_AND_MEAN
22 #include "plugins/thresholds.hpp"
23 #include <boost/program_options.hpp>
24 #include <boost/algorithm/string/replace.hpp>
37 namespace po = boost::program_options;
42 LONG BytesInSec, BytesOutSec;
43 nInterface(std::wstring p)
48 struct printInfoStruct
55 static bool l_NoISATAP;
57 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
59 WCHAR namePath[MAX_PATH];
60 GetModuleFileName(NULL, namePath, MAX_PATH);
61 WCHAR *progName = PathFindFileName(namePath);
63 po::options_description desc("Options");
66 ("help,h", "print usage and exit")
67 ("version,V", "print version and exit")
68 ("debug,d", "Verbose/Debug output")
69 ("noisatap,n", "Don't show ISATAP interfaces in output")
70 ("warning,w", po::wvalue<std::wstring>(), "warning value")
71 ("critical,c", po::wvalue<std::wstring>(), "critical value")
74 po::wcommand_line_parser parser(ac, av);
81 po::command_line_style::unix_style |
82 po::command_line_style::allow_long_disguise)
86 } catch (const std::exception& e) {
87 std::cout << e.what() << '\n' << desc << '\n';
91 if (vm.count("help")) {
92 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
94 L"%s is a simple program to check a machines network performance.\n"
95 L"You can use the following options to define its behaviour:\n\n", progName);
98 L"\nIt will then output a string looking something like this:\n\n"
99 L"\tNETWORK WARNING 1131B/s | network=1131B;1000;7000;0\n\n"
100 L"\"NETWORK\" being the type of the check, \"WARNING\" the returned status\n"
101 L"and \"1131B/s\" is the returned value.\n"
102 L"The performance data is found behind the \"|\", in order:\n"
103 L"returned value, warning threshold, critical threshold, minimal value and,\n"
104 L"if applicable, the maximal value. Performance data will only be displayed when\n"
105 L"you set at least one threshold\n\n"
106 L"This program will also print out additional performance data interface\n"
108 L"%s' exit codes denote the following:\n"
109 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
110 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
111 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
112 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
113 L"Threshold syntax:\n\n"
115 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
116 L"(unless stated differently)\n\n"
118 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
120 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
122 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
124 L"if the plugin accepts percentage based thresholds those will be used.\n"
125 L"Does nothing if the plugin does not accept percentages, or only uses\n"
126 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
127 L"to end with a percentage sign.\n\n"
128 L"All of these options work with the critical threshold \"-c\" too."
134 if (vm.count("version"))
135 std::cout << "Version: " << VERSION << '\n';
137 if (vm.count("warning")) {
139 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
140 } catch (const std::invalid_argument& e) {
141 std::cout << e.what() << '\n';
145 if (vm.count("critical")) {
147 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
148 } catch (const std::invalid_argument& e) {
149 std::cout << e.what() << '\n';
154 l_Debug = vm.count("debug") > 0;
155 l_NoISATAP = vm.count("noisatap") > 0;
160 static int printOutput(printInfoStruct& printInfo, const std::vector<nInterface>& vInterfaces, const std::map<std::wstring, std::wstring>& mapNames)
163 std::wcout << L"Constructing output string" << '\n';
165 long tIn = 0, tOut = 0;
166 std::wstringstream tss;
169 std::map<std::wstring, std::wstring>::const_iterator mapIt;
170 std::wstring wsFriendlyName;
172 for (std::vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
173 tIn += it->BytesInSec;
174 tOut += it->BytesOutSec;
176 std::wcout << "Getting friendly name of " << it->name << '\n';
177 mapIt = mapNames.find(it->name);
178 if (mapIt != mapNames.end()) {
180 std::wcout << "\tIs " << mapIt->second << '\n';
181 wsFriendlyName = mapIt->second;
184 std::wcout << "\tNo friendly name found, using adapter name\n";
185 wsFriendlyName = it->name;
187 if (wsFriendlyName.find(L"isatap") != std::wstring::npos && l_NoISATAP) {
189 std::wcout << "\tSkipping isatap interface " << wsFriendlyName << "\n";
192 boost::algorithm::replace_all(wsFriendlyName, "'", "''");
193 tss << L"\'" << wsFriendlyName << L"_in\'=" << it->BytesInSec << L"B \'" << wsFriendlyName << L"_out\'=" << it->BytesOutSec << L"B ";
197 if (printInfo.warn.rend(tIn + tOut))
199 if (printInfo.crit.rend(tIn + tOut))
202 std::wcout << "NETWORK ";
209 std::wcout << L"WARNING";
212 std::wcout << L"CRITICAL";
216 std::wcout << " " << tIn + tOut << L"B/s | "
217 << L"network=" << tIn + tOut << L"B;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; "
218 << tss.str() << '\n';
223 static int check_network(std::vector<nInterface>& vInterfaces)
227 std::wcout << L"Creating Query and adding counters" << '\n';
229 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
232 PDH_STATUS err = PdhOpenQuery(NULL, NULL, &phQuery);
236 const WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
237 PDH_HCOUNTER phCounterIn;
238 err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn);
242 const WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
243 PDH_HCOUNTER phCounterOut;
244 err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut);
249 std::wcout << L"Collecting first batch of query data" << '\n';
251 err = PdhCollectQueryData(phQuery);
256 std::wcout << L"Sleep for one second" << '\n';
261 std::wcout << L"Collecting second batch of query data" << '\n';
263 err = PdhCollectQueryData(phQuery);
268 std::wcout << L"Creating formatted counter arrays" << '\n';
271 DWORD dwBufferSizeIn = 0;
272 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
273 if (err == PDH_MORE_DATA || SUCCEEDED(err))
274 pDisplayValuesIn = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
278 DWORD dwBufferSizeOut = 0;
279 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
280 if (err == PDH_MORE_DATA || SUCCEEDED(err))
281 pDisplayValuesOut = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
285 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
289 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
294 std::wcout << L"Going over counter array" << '\n';
296 for (DWORD i = 0; i < dwItemCount; i++) {
297 nInterface iface{pDisplayValuesIn[i].szName};
298 iface.BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
299 iface.BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
300 vInterfaces.push_back(iface);
303 std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n';
307 std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
310 PdhCloseQuery(phQuery);
312 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
313 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
319 PdhCloseQuery(phQuery);
321 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
322 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
327 static bool mapSystemNamesToFamiliarNames(std::map<std::wstring, std::wstring>& mapNames)
330 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
331 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
332 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
333 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL;
334 PIP_ADAPTER_PREFIX pPrefix = NULL;
336 ULONG outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses
339 std::wcout << "Mapping adapter system names to friendly names\n";
341 PIP_ADAPTER_ADDRESSES pAddresses;
343 unsigned int Iterations = 0;
347 pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(new BYTE[outBufLen]);
349 dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
351 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
356 } while (++Iterations < 3);
358 if (dwRetVal != NO_ERROR) {
359 std::wcout << "Failed to collect friendly adapter names\n";
364 for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) {
366 std::wcout << "Got: " << pCurrAddresses->Description << " -- " << pCurrAddresses->FriendlyName << '\n';
368 mapNames[pCurrAddresses->Description] = pCurrAddresses->FriendlyName;
375 int wmain(int argc, WCHAR **argv)
377 std::vector<nInterface> vInterfaces;
378 std::map<std::wstring, std::wstring> mapNames;
379 printInfoStruct printInfo;
380 po::variables_map vm;
382 int ret = parseArguments(argc, argv, vm, printInfo);
387 if (!mapSystemNamesToFamiliarNames(mapNames))
390 ret = check_network(vInterfaces);
394 return printOutput(printInfo, vInterfaces, mapNames);