1 /*
2 * Libmetrics Native Windows Metrics (through mingw32)
3 *
4 * Copyright (c) 2008 Carlo Marcelo Arenas Belon <carenas@sajinet.com.pe>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction,
9 * including without limitation the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #define _WIN32_WINNT 0x0500
34 #include <windows.h>
35 #include <iphlpapi.h>
36 #include <sys/types.h>
37 #include <sys/timeb.h>
38 #include <psapi.h>
39
40 /* From old ganglia 2.5.x... */
41 #include "libmetrics.h"
42 /* End old ganglia 2.5.x headers */
43 #undef min
44 #undef max
45 #include "interface.h"
46
47 const char *sys_osname = "Windows";
48 char sys_osrelease[MAX_G_STRING_SIZE];
49
50 static time_t
get_netbw(double * in_bytes,double * out_bytes,double * in_pkts,double * out_pkts)51 get_netbw(double *in_bytes, double *out_bytes,
52 double *in_pkts, double *out_pkts)
53 {
54 PMIB_IFTABLE iftable;
55 double bytes_in = 0, bytes_out = 0, pkts_in = 0, pkts_out = 0;
56 static DWORD dwSize;
57 DWORD ret, dwInterface;
58 struct timeb timebuffer;
59 PMIB_IFROW ifrow;
60
61 dwSize = sizeof(MIB_IFTABLE);
62
63 iftable = (PMIB_IFTABLE) malloc (dwSize);
64 while ((ret = GetIfTable(iftable, &dwSize, 1)) == ERROR_INSUFFICIENT_BUFFER) {
65 iftable = (PMIB_IFTABLE) realloc (iftable, dwSize);
66 }
67
68 if (ret == NO_ERROR) {
69
70 ftime ( &timebuffer );
71
72 /* scan the interface table */
73 for (dwInterface = 0; dwInterface < (iftable -> dwNumEntries); dwInterface++) {
74 ifrow = &(iftable -> table[dwInterface]);
75
76 /* exclude loopback */
77 if ( (ifrow -> dwType != MIB_IF_TYPE_LOOPBACK ) && (ifrow -> dwOperStatus ==MIB_IF_OPER_STATUS_OPERATIONAL ) ) {
78 bytes_in += ifrow -> dwInOctets;
79 bytes_out += ifrow -> dwOutOctets;
80
81 /* does not include multicast traffic (dw{In,Out}NUcastPkts) */
82 pkts_in += ifrow -> dwInUcastPkts;
83 pkts_out += ifrow -> dwOutUcastPkts;
84 }
85 }
86 free (iftable);
87 }
88
89 if (in_bytes) *in_bytes = bytes_in;
90 if (out_bytes) *out_bytes = bytes_out;
91 if (in_pkts) *in_pkts = pkts_in;
92 if (out_pkts) *out_pkts = pkts_out;
93
94 return timebuffer.time;
95 }
96
97 /*
98 * This function is called only once by the gmond. Use to
99 * initialize data structures, etc or just return SYNAPSE_SUCCESS;
100 */
101 g_val_t
metric_init(void)102 metric_init(void)
103 {
104 g_val_t rval;
105 OSVERSIONINFO osvi;
106
107 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
108 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
109
110 if (GetVersionEx(&osvi)) {
111 snprintf(sys_osrelease, MAX_G_STRING_SIZE, "%d.%d",
112 osvi.dwMajorVersion, osvi.dwMinorVersion);
113 } else {
114 strncpy(sys_osrelease, "unknown", MAX_G_STRING_SIZE);
115 }
116 sys_osrelease[MAX_G_STRING_SIZE - 1] = '\0';
117 rval.int32 = SYNAPSE_SUCCESS;
118 return rval;
119 }
120
121 g_val_t
pkts_in_func(void)122 pkts_in_func ( void )
123 {
124 double in_pkts=0, t=0;
125 time_t stamp;
126 static time_t last_stamp;
127 static double last_pkts_in;
128 g_val_t val;
129 unsigned long diff;
130
131 stamp = get_netbw(NULL, NULL, &in_pkts, NULL);
132 diff = (unsigned long)(in_pkts - last_pkts_in);
133 if ( diff && last_stamp ) {
134 t = stamp - last_stamp;
135 t = diff / t;
136 debug_msg("Returning value: %f\n", t);
137 } else t = 0;
138
139 val.f = t;
140 last_pkts_in = in_pkts;
141 last_stamp = stamp;
142
143 return val;
144 }
145
146 g_val_t
pkts_out_func(void)147 pkts_out_func ( void )
148 {
149 double out_pkts=0, t=0;
150 time_t stamp;
151 static time_t last_stamp;
152 static double last_pkts_out;
153 g_val_t val;
154 unsigned long diff;
155
156 stamp = get_netbw(NULL, NULL, NULL, &out_pkts);
157 diff = (unsigned long)(out_pkts - last_pkts_out);
158 if ( diff && last_stamp ) {
159 t = stamp - last_stamp;
160 t = diff / t;
161 debug_msg("Returning value: %f\n", t);
162 } else t = 0;
163
164 val.f = t;
165 last_pkts_out = out_pkts;
166 last_stamp = stamp;
167
168 return val;
169 }
170
171 g_val_t
bytes_out_func(void)172 bytes_out_func ( void )
173 {
174 double out_bytes=0, t=0;
175 time_t stamp;
176 static time_t last_stamp;
177 static double last_bytes_out;
178 g_val_t val;
179 unsigned long diff;
180
181 stamp = get_netbw(NULL, &out_bytes, NULL, NULL);
182 diff = (unsigned long)(out_bytes - last_bytes_out);
183 if ( diff && last_stamp ) {
184 t = stamp - last_stamp;
185 t = diff / t;
186 debug_msg("Returning value: %f\n", t);
187 } else t = 0;
188
189 val.f = t;
190 last_bytes_out = out_bytes;
191 last_stamp = stamp;
192
193 return val;
194 }
195
196 g_val_t
bytes_in_func(void)197 bytes_in_func ( void )
198 {
199 double in_bytes=0, t=0;
200 time_t stamp;
201 static time_t last_stamp;
202 static double last_bytes_in;
203 g_val_t val;
204 unsigned long diff;
205
206 stamp = get_netbw(&in_bytes, NULL, NULL, NULL);
207 diff = (unsigned long)(in_bytes - last_bytes_in);
208 if ( diff && last_stamp ) {
209 t = stamp - last_stamp;
210 t = diff / t;
211 debug_msg("Returning value: %f\n", t);
212 } else t = 0;
213
214 val.f = t;
215 last_bytes_in = in_bytes;
216 last_stamp = stamp;
217
218 return val;
219 }
220
221 g_val_t
cpu_num_func(void)222 cpu_num_func ( void )
223 {
224 static DWORD cpu_num = 0;
225 SYSTEM_INFO siSysInfo;
226 g_val_t val;
227
228 /* Only need to do this once */
229 if (!cpu_num) {
230 GetSystemInfo(&siSysInfo);
231 cpu_num = siSysInfo.dwNumberOfProcessors;
232 }
233
234 val.uint16 = cpu_num;
235 return val;
236 }
237
238 g_val_t
cpu_speed_func(void)239 cpu_speed_func ( void )
240 {
241 g_val_t val;
242
243 val.uint32 = 0;
244
245 return val;
246 }
247
248 g_val_t
mem_total_func(void)249 mem_total_func ( void )
250 {
251 MEMORYSTATUSEX stat;
252 DWORDLONG size;
253 g_val_t val;
254
255 stat.dwLength = sizeof(stat);
256
257 if ( GlobalMemoryStatusEx (&stat)) {
258 size = stat.ullTotalPhys;
259 /* get the value in kB */
260 val.f = size / 1024;
261 } else {
262 val.f = 0;
263 }
264
265 return val;
266 }
267
268 /* FIXME?: should be using PERFORMANCE_INFORMATION.CommitLimit */
269 g_val_t
swap_total_func(void)270 swap_total_func ( void )
271 {
272 MEMORYSTATUSEX stat;
273 DWORDLONG size;
274 g_val_t val;
275
276 stat.dwLength = sizeof(stat);
277
278 if ( GlobalMemoryStatusEx (&stat)) {
279 size = stat.ullTotalPageFile;
280 /* get the value in kB */
281 val.f = size / 1024;
282 } else {
283 val.f = 0;
284 }
285
286 return val;
287 }
288
289 g_val_t
boottime_func(void)290 boottime_func ( void )
291 {
292 g_val_t val;
293
294 val.uint32 = 0;
295
296 return val;
297 }
298
299 g_val_t
sys_clock_func(void)300 sys_clock_func ( void )
301 {
302 g_val_t val;
303
304 val.uint32 = time(NULL);
305 return val;
306 }
307
308 g_val_t
machine_type_func(void)309 machine_type_func ( void )
310 {
311 SYSTEM_INFO siSysInfo;
312 g_val_t val;
313
314 GetSystemInfo(&siSysInfo);
315
316 switch (siSysInfo.wProcessorArchitecture) {
317 case PROCESSOR_ARCHITECTURE_AMD64:
318 snprintf(val.str, MAX_G_STRING_SIZE, "x86_64");
319 break;
320 case PROCESSOR_ARCHITECTURE_IA64:
321 snprintf(val.str, MAX_G_STRING_SIZE, "ia64");
322 break;
323 case PROCESSOR_ARCHITECTURE_INTEL:
324 snprintf(val.str, MAX_G_STRING_SIZE, "x86");
325 break;
326 case PROCESSOR_ARCHITECTURE_ALPHA:
327 case PROCESSOR_ARCHITECTURE_ALPHA64:
328 snprintf(val.str, MAX_G_STRING_SIZE, "alpha");
329 break;
330 case PROCESSOR_ARCHITECTURE_PPC:
331 snprintf(val.str, MAX_G_STRING_SIZE, "powerpc");
332 break;
333 case PROCESSOR_ARCHITECTURE_MIPS:
334 snprintf(val.str, MAX_G_STRING_SIZE, "mips");
335 break;
336 case PROCESSOR_ARCHITECTURE_ARM:
337 snprintf(val.str, MAX_G_STRING_SIZE, "arm");
338 break;
339 default:
340 snprintf(val.str, MAX_G_STRING_SIZE, "unknown");
341 }
342
343 return val;
344 }
345
346 g_val_t
os_name_func(void)347 os_name_func ( void )
348 {
349 g_val_t val;
350
351 snprintf(val.str, MAX_G_STRING_SIZE, "%s", sys_osname);
352
353 return val;
354 }
355
356 g_val_t
os_release_func(void)357 os_release_func ( void )
358 {
359 g_val_t val;
360
361 snprintf(val.str, MAX_G_STRING_SIZE, "%s", sys_osrelease);
362
363 return val;
364 }
365
366 g_val_t
cpu_user_func(void)367 cpu_user_func ( void )
368 {
369 g_val_t val;
370
371 val.f = 0.0;
372
373 return val;
374 }
375
376 g_val_t
cpu_nice_func(void)377 cpu_nice_func ( void )
378 {
379 g_val_t val;
380
381 val.f = 0.0;
382
383 return val;
384 }
385
386 g_val_t
cpu_system_func(void)387 cpu_system_func ( void )
388 {
389 g_val_t val;
390
391 val.f = 0.0;
392
393 return val;
394 }
395
396 g_val_t
cpu_idle_func(void)397 cpu_idle_func ( void )
398 {
399 g_val_t val;
400
401 val.f = 0.0;
402
403 return val;
404 }
405
406 /* FIXME? */
407 g_val_t
cpu_aidle_func(void)408 cpu_aidle_func ( void )
409 {
410 g_val_t val;
411
412 val.f = 0.0;
413
414 return val;
415 }
416
417 /* FIXME? */
418 g_val_t
cpu_wio_func(void)419 cpu_wio_func ( void )
420 {
421 g_val_t val;
422
423 val.f = 0.0;
424
425 return val;
426 }
427
428 /* FIXME? */
429 g_val_t
cpu_intr_func(void)430 cpu_intr_func ( void )
431 {
432 g_val_t val;
433
434 val.f = 0.0;
435
436 return val;
437 }
438
439 /* FIXME? */
440 g_val_t
cpu_sintr_func(void)441 cpu_sintr_func ( void )
442 {
443 g_val_t val;
444
445 val.f = 0.0;
446
447 return val;
448 }
449
450 /* FIXME? */
451 g_val_t
load_one_func(void)452 load_one_func ( void )
453 {
454 g_val_t val;
455
456 val.f = 0.0;
457
458 return val;
459 }
460
461 /* FIXME? */
462 g_val_t
load_five_func(void)463 load_five_func ( void )
464 {
465 g_val_t val;
466
467 val.f = 0.0;
468
469 return val;
470 }
471
472 /* FIXME? */
473 g_val_t
load_fifteen_func(void)474 load_fifteen_func ( void )
475 {
476 g_val_t val;
477
478 val.f = 0.0;
479
480 return val;
481 }
482
483 #define MAXPROCESSES 1024
484
485 /* FIXME */
486 g_val_t
proc_run_func(void)487 proc_run_func( void )
488 {
489 DWORD aProcesses[MAXPROCESSES], cbNeeded, cProcesses;
490 unsigned int i, running = 0;
491 HANDLE hProcess;
492 BOOL bResult;
493 g_val_t val;
494
495 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
496 cProcesses = 0;
497 } else {
498 cProcesses = cbNeeded / sizeof(DWORD);
499 }
500 #if (_WIN32_WINNT >= 0x0501)
501 /* Only for XP or newer */
502 for (i = 0; i < cProcesses; i++)
503 if (aProcesses[i] != 0) {
504 hProcess = OpenProcess (PROCESS_QUERY_INFORMATION,
505 FALSE, aProcesses[i]);
506 if (hProcess != NULL) {
507 if (IsProcessInJob(hProcess, NULL, &bResult)) {
508 if (bResult)
509 running++;
510 }
511 CloseHandle(hProcess);
512 }
513 }
514 #endif
515
516 val.uint32 = running;
517
518 return val;
519 }
520
521 /* FIXME */
522 g_val_t
proc_total_func(void)523 proc_total_func ( void )
524 {
525 DWORD aProcesses[MAXPROCESSES], cbNeeded, cProcesses;
526 g_val_t val;
527
528 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
529 cProcesses = 0;
530 } else {
531 cProcesses = cbNeeded / sizeof(DWORD);
532 }
533 val.uint32 = cProcesses;
534
535 return val;
536 }
537
538 g_val_t
mem_free_func(void)539 mem_free_func ( void )
540 {
541 MEMORYSTATUSEX stat;
542 DWORDLONG size;
543 g_val_t val;
544
545 stat.dwLength = sizeof(stat);
546
547 if ( GlobalMemoryStatusEx (&stat)) {
548 size = stat.ullAvailPhys;
549 /* get the value in kB */
550 val.f = size / 1024;
551 } else {
552 val.f = 0;
553 }
554
555 return val;
556 }
557
558 /* FIXME */
559 g_val_t
mem_shared_func(void)560 mem_shared_func ( void )
561 {
562 g_val_t val;
563
564 val.f = 0;
565
566 return val;
567 }
568
569 /* FIXME */
570 g_val_t
mem_buffers_func(void)571 mem_buffers_func ( void )
572 {
573 g_val_t val;
574
575 val.f = 0;
576
577 return val;
578 }
579
580 /* FIXME */
581 g_val_t
mem_cached_func(void)582 mem_cached_func ( void )
583 {
584 g_val_t val;
585
586 val.f = 0;
587
588 return val;
589 }
590
591 /* FIXME: should be using PERFORMANCE_INFORMATION.CommitTotal */
592 g_val_t
swap_free_func(void)593 swap_free_func ( void )
594 {
595 MEMORYSTATUSEX stat;
596 DWORDLONG size;
597 g_val_t val;
598
599 stat.dwLength = sizeof(stat);
600
601 if ( GlobalMemoryStatusEx (&stat)) {
602 size = stat.ullAvailPageFile;
603 /* get the value in kB */
604 val.f = size / 1024;
605 } else {
606 val.f = 0;
607 }
608
609 return val;
610 }
611
612 /* --------------------------------------------------------------------------- */
613 g_val_t
mtu_func(void)614 mtu_func ( void )
615 {
616 /* We want to find the minimum MTU (Max packet size) over all UP interfaces. */
617 g_val_t val;
618
619 val.uint32 = get_min_mtu();
620
621 /* A val of 0 means there are no UP interfaces. Shouldn't happen. */
622 return val;
623 }
624
625 /* FIXME: hardcoded max number of disks */
626 #define MAXDRIVES 4
627
628 typedef struct {
629 double total;
630 double avail;
631 } disk_t;
632
633 static float
find_disk_space(double * total,double * avail)634 find_disk_space(double *total, double *avail)
635 {
636 float most_full = 0.0;
637
638 *total = 0.0;
639 *avail = 0.0;
640
641 return most_full;
642 }
643
644 g_val_t
disk_free_func(void)645 disk_free_func( void )
646 {
647 double total_free = 0.0;
648 double total_size = 0.0;
649 g_val_t val;
650
651 find_disk_space(&total_size, &total_free);
652
653 val.d = total_free;
654 return val;
655 }
656
657 g_val_t
disk_total_func(void)658 disk_total_func( void )
659 {
660 double total_free = 0.0;
661 double total_size = 0.0;
662 g_val_t val;
663
664 find_disk_space(&total_size, &total_free);
665
666 val.d = total_size;
667 return val;
668 }
669
670 g_val_t
part_max_used_func(void)671 part_max_used_func( void )
672 {
673 double total_free = 0.0;
674 double total_size = 0.0;
675 float most_full;
676 g_val_t val;
677
678 most_full = find_disk_space(&total_size, &total_free);
679
680 val.f = most_full;
681 return val;
682 }
683