1 /******************************************************************************
3 * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
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
32 #include "check_network.h"
36 namespace po = boost::program_options;
38 static BOOL debug = FALSE;
40 INT wmain(INT argc, WCHAR **argv)
42 std::vector<nInterface> vInterfaces;
43 std::map<std::wstring, std::wstring> mapNames;
44 printInfoStruct printInfo{};
47 INT ret = parseArguments(argc, argv, vm, printInfo);
52 if (!mapSystemNamesToFamiliarNames(mapNames))
55 ret = check_network(vInterfaces);
59 return printOutput(printInfo, vInterfaces, mapNames);
62 INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
64 WCHAR namePath[MAX_PATH];
65 GetModuleFileName(NULL, namePath, MAX_PATH);
66 WCHAR *progName = PathFindFileName(namePath);
68 po::options_description desc("Options");
71 ("help,h", "print usage and exit")
72 ("version,V", "print version and exit")
73 ("debug,d", "Verbose/Debug output")
74 ("warning,w", po::wvalue<std::wstring>(), "warning value")
75 ("critical,c", po::wvalue<std::wstring>(), "critical value")
78 po::basic_command_line_parser<WCHAR> parser(ac, av);
85 po::command_line_style::unix_style |
86 po::command_line_style::allow_long_disguise)
90 } catch (std::exception& e) {
91 std::cout << e.what() << '\n' << desc << '\n';
95 if (vm.count("help")) {
96 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
98 L"%s is a simple program to check a machines network performance.\n"
99 L"You can use the following options to define its behaviour:\n\n", progName);
102 L"\nIt will then output a string looking something like this:\n\n"
103 L"\tNETWORK WARNING 1131B/s | network=1131B/s;1000;7000;0\n\n"
104 L"\"NETWORK\" being the type of the check, \"WARNING\" the returned status\n"
105 L"and \"1131B/s\" is the returned value.\n"
106 L"The performance data is found behind the \"|\", in order:\n"
107 L"returned value, warning threshold, critical threshold, minimal value and,\n"
108 L"if applicable, the maximal value. Performance data will only be displayed when\n"
109 L"you set at least one threshold\n\n"
110 L"This program will also print out additional performance data interface\n"
112 L"%s' exit codes denote the following:\n"
113 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
114 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
115 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
116 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
117 L"Threshold syntax:\n\n"
119 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
120 L"(unless stated differently)\n\n"
122 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
124 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
126 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
128 L"if the plugin accepts percentage based thresholds those will be used.\n"
129 L"Does nothing if the plugin does not accept percentages, or only uses\n"
130 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
131 L"to end with a percentage sign.\n\n"
132 L"All of these options work with the critical threshold \"-c\" too."
138 if (vm.count("version"))
139 std::cout << "Version: " << VERSION << '\n';
141 if (vm.count("warning")) {
143 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
144 } catch (std::invalid_argument& e) {
145 std::cout << e.what() << '\n';
149 if (vm.count("critical")) {
151 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
152 } catch (std::invalid_argument& e) {
153 std::cout << e.what() << '\n';
158 if (vm.count("debug"))
164 INT printOutput(printInfoStruct& printInfo, CONST std::vector<nInterface>& vInterfaces, CONST std::map<std::wstring, std::wstring>& mapNames)
167 std::wcout << L"Constructing output string" << '\n';
169 long tIn = 0, tOut = 0;
170 std::wstringstream tss, perfDataFirst;
173 std::map<std::wstring, std::wstring>::const_iterator mapIt;
174 std::wstring wsFriendlyName;
176 for (std::vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
177 tIn += it->BytesInSec;
178 tOut += it->BytesOutSec;
180 std::wcout << "Getting friendly name of " << it->name << '\n';
181 mapIt = mapNames.find(it->name);
182 if (mapIt != mapNames.end()) {
184 std::wcout << "\tIs " << mapIt->second << '\n';
185 wsFriendlyName = mapIt->second;
188 std::wcout << "\tNo friendly name found, using adapter name\n";
189 wsFriendlyName = it->name;
191 tss << L"netI=\"" << wsFriendlyName << L"\";in=" << it->BytesInSec << "B/s;out=" << it->BytesOutSec << L"B/s ";
194 if (printInfo.warn.rend(tIn + tOut))
196 if (printInfo.crit.rend(tIn + tOut))
199 perfDataFirst << L"network=" << tIn + tOut << L"B/s;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; ";
203 std::wcout << L"NETWORK OK " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
206 std::wcout << L"NETWORK WARNING " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
209 std::wcout << L"NETWORK CRITICAL " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
216 INT check_network(std::vector <nInterface>& vInterfaces)
218 CONST WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
219 CONST WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
221 PDH_HQUERY phQuery = NULL;
222 PDH_HCOUNTER phCounterIn, phCounterOut;
223 DWORD dwBufferSizeIn = 0, dwBufferSizeOut = 0, dwItemCount = 0;
224 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
228 std::wcout << L"Creating Query and adding counters" << '\n';
230 err = PdhOpenQuery(NULL, NULL, &phQuery);
234 err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn);
238 err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut);
243 std::wcout << L"Collecting first batch of query data" << '\n';
245 err = PdhCollectQueryData(phQuery);
250 std::wcout << L"Sleep for one second" << '\n';
255 std::wcout << L"Collecting second batch of query data" << '\n';
257 err = PdhCollectQueryData(phQuery);
262 std::wcout << L"Creating formatted counter arrays" << '\n';
264 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
265 if (err == PDH_MORE_DATA || SUCCEEDED(err))
266 pDisplayValuesIn = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
270 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
271 if (err == PDH_MORE_DATA || SUCCEEDED(err))
272 pDisplayValuesOut = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
276 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
280 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
285 std::wcout << L"Going over counter array" << '\n';
287 for (DWORD i = 0; i < dwItemCount; i++) {
288 nInterface *iface = new nInterface(std::wstring(pDisplayValuesIn[i].szName));
289 iface->BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
290 iface->BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
291 vInterfaces.push_back(*iface);
293 std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n';
296 std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
299 PdhCloseQuery(phQuery);
300 if (pDisplayValuesIn)
301 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesIn);
302 if (pDisplayValuesOut)
303 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesOut);
308 PdhCloseQuery(phQuery);
309 if (pDisplayValuesIn)
310 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesIn);
311 if (pDisplayValuesOut)
312 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesOut);
316 BOOL mapSystemNamesToFamiliarNames(std::map<std::wstring, std::wstring>& mapNames)
318 DWORD dwSize = 0, dwRetVal = 0;
320 ULONG family = AF_UNSPEC, flags = GAA_FLAG_INCLUDE_PREFIX,
321 outBufLen = 0, Iterations = 0;
322 LPVOID lpMsgBuf = NULL;
324 PIP_ADAPTER_ADDRESSES pAddresses = NULL;
325 PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
327 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
328 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
329 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
330 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL;
331 PIP_ADAPTER_PREFIX pPrefix = NULL;
333 outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses
336 std::wcout << "Mapping adapter system names to friendly names\n";
339 pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(new BYTE[outBufLen]);
341 dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
343 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
348 } while (++Iterations < 3);
350 if (dwRetVal != NO_ERROR) {
351 std::wcout << "Failed to collect friendly adapter names\n";
356 pCurrAddresses = pAddresses;
357 std::wstringstream wssAdapterName;
358 std::wstringstream wssFriendlyName;
359 for (pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) {
360 wssAdapterName.str(std::wstring());
361 wssFriendlyName.str(std::wstring());
362 wssAdapterName << pCurrAddresses->Description;
363 wssFriendlyName << pCurrAddresses->FriendlyName;
365 std::wcout << "Got: " << wssAdapterName.str() << " -- " << wssFriendlyName.str() << '\n';
367 mapNames.insert(std::pair<std::wstring, std::wstring>(wssAdapterName.str(), wssFriendlyName.str()));