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