1 /*
2  * Copyright (c) 2004-2009 Hyperic, Inc.
3  * Copyright (c) 2009 SpringSource, Inc.
4  * Copyright (c) 2009-2010 VMware, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "sigar.h"
20 #include "sigar_private.h"
21 #include "sigar_pdh.h"
22 #include "sigar_os.h"
23 #include "sigar_util.h"
24 #include "sigar_format.h"
25 #include <shellapi.h>
26 #include <assert.h>
27 
28 #define USING_WIDE_S(s) (s)->using_wide
29 #define USING_WIDE()    USING_WIDE_S(sigar)
30 
31 #define PERFBUF_SIZE 8192
32 
33 #define PERF_TITLE_PROC       230
34 #define PERF_TITLE_SYS_KEY   "2"
35 #define PERF_TITLE_MEM_KEY   "4"
36 #define PERF_TITLE_PROC_KEY  "230"
37 #define PERF_TITLE_CPU_KEY   "238"
38 #define PERF_TITLE_DISK_KEY  "236"
39 
40 #define PERF_TITLE_CPU_USER    142
41 #define PERF_TITLE_CPU_IDLE    1746
42 #define PERF_TITLE_CPU_SYS     144
43 #define PERF_TITLE_CPU_IRQ     698
44 
45 typedef enum {
46     PERF_IX_CPU_USER,
47     PERF_IX_CPU_IDLE,
48     PERF_IX_CPU_SYS,
49     PERF_IX_CPU_IRQ,
50     PERF_IX_CPU_MAX
51 } perf_cpu_offsets_t;
52 
53 #define PERF_TITLE_CPUTIME    6
54 #define PERF_TITLE_PAGE_FAULTS 28
55 #define PERF_TITLE_MEM_VSIZE  174
56 #define PERF_TITLE_MEM_SIZE   180
57 #define PERF_TITLE_THREAD_CNT 680
58 #define PERF_TITLE_HANDLE_CNT 952
59 #define PERF_TITLE_PID        784
60 #define PERF_TITLE_PPID       1410
61 #define PERF_TITLE_PRIORITY   682
62 #define PERF_TITLE_START_TIME 684
63 
64 typedef enum {
65     PERF_IX_CPUTIME,
66     PERF_IX_PAGE_FAULTS,
67     PERF_IX_MEM_VSIZE,
68     PERF_IX_MEM_SIZE,
69     PERF_IX_THREAD_CNT,
70     PERF_IX_HANDLE_CNT,
71     PERF_IX_PID,
72     PERF_IX_PPID,
73     PERF_IX_PRIORITY,
74     PERF_IX_START_TIME,
75     PERF_IX_MAX
76 } perf_proc_offsets_t;
77 
78 typedef enum {
79     PERF_IX_DISK_TIME,
80     PERF_IX_DISK_READ_TIME,
81     PERF_IX_DISK_WRITE_TIME,
82     PERF_IX_DISK_READ,
83     PERF_IX_DISK_WRITE,
84     PERF_IX_DISK_READ_BYTES,
85     PERF_IX_DISK_WRITE_BYTES,
86     PERF_IX_DISK_QUEUE,
87     PERF_IX_DISK_MAX
88 } perf_disk_offsets_t;
89 
90 #define PERF_TITLE_DISK_TIME 200 /* % Disk Time */
91 #define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */
92 #define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */
93 #define PERF_TITLE_DISK_READ  214 /* Disk Reads/sec */
94 #define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */
95 #define PERF_TITLE_DISK_READ_BYTES  220 /* Disk Read Bytes/sec */
96 #define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */
97 #define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */
98 
99 /*
100  * diff is:
101  *   ExW      -> ExA
102  *   wcounter -> counter
103  */
104 #define MyRegQueryValue() \
105     (USING_WIDE() ? \
106         RegQueryValueExW(sigar->handle, \
107                          wcounter_key, NULL, &type, \
108                          sigar->perfbuf, \
109                          &bytes) : \
110         RegQueryValueExA(sigar->handle, \
111                          counter_key, NULL, &type, \
112                          sigar->perfbuf, \
113                          &bytes))
114 
115 #define PERF_VAL(ix) \
116     perf_offsets[ix] ? \
117         *((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
118 
119 #define PERF_VAL64(ix) \
120     perf_offsets[ix] ? \
121         *((sigar_uint64_t *)((BYTE *)counter_block + perf_offsets[ix])) : 0
122 
123 /* 1/100ns units to milliseconds */
124 #define NS100_2MSEC(t) ((t) / 10000)
125 
126 #define PERF_VAL_CPU(ix) \
127     NS100_2MSEC(PERF_VAL(ix))
128 
129 #define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter"
130 #define NETIF_LA "la"
131 
sigar_FileTimeToTime(FILETIME *ft)132 sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft)
133 {
134     sigar_uint64_t time;
135     time = ft->dwHighDateTime;
136     time = time << 32;
137     time |= ft->dwLowDateTime;
138     time /= 10;
139     time -= EPOCH_DELTA;
140     return time;
141 }
142 
perfbuf_init(sigar_t *sigar)143 static DWORD perfbuf_init(sigar_t *sigar)
144 {
145     if (!sigar->perfbuf) {
146         sigar->perfbuf = malloc(PERFBUF_SIZE);
147         sigar->perfbuf_size = PERFBUF_SIZE;
148     }
149 
150     return sigar->perfbuf_size;
151 }
152 
perfbuf_grow(sigar_t *sigar)153 static DWORD perfbuf_grow(sigar_t *sigar)
154 {
155     sigar->perfbuf_size += PERFBUF_SIZE;
156 
157     sigar->perfbuf =
158         realloc(sigar->perfbuf, sigar->perfbuf_size);
159 
160     return sigar->perfbuf_size;
161 }
162 
get_counter_name(char *key)163 static char *get_counter_name(char *key)
164 {
165     if (strEQ(key, PERF_TITLE_MEM_KEY)) {
166         return "Memory";
167     }
168     else if (strEQ(key, PERF_TITLE_PROC_KEY)) {
169         return "Process";
170     }
171     else if (strEQ(key, PERF_TITLE_CPU_KEY)) {
172         return "Processor";
173     }
174     else if (strEQ(key, PERF_TITLE_DISK_KEY)) {
175         return "LogicalDisk";
176     }
177     else {
178         return key;
179     }
180 }
181 
get_perf_object_inst(sigar_t *sigar, char *counter_key, DWORD inst, DWORD *err)182 static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar,
183                                               char *counter_key,
184                                               DWORD inst, DWORD *err)
185 {
186     DWORD retval, type, bytes;
187     WCHAR wcounter_key[MAX_PATH+1];
188     PERF_DATA_BLOCK *block;
189     PERF_OBJECT_TYPE *object;
190 
191     *err = SIGAR_OK;
192 
193     if (USING_WIDE()) {
194         SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
195     }
196 
197     bytes = perfbuf_init(sigar);
198 
199     while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
200         if (retval == ERROR_MORE_DATA) {
201             bytes = perfbuf_grow(sigar);
202         }
203         else {
204             *err = retval;
205             return NULL;
206         }
207     }
208 
209     block = (PERF_DATA_BLOCK *)sigar->perfbuf;
210     if (block->NumObjectTypes == 0) {
211         counter_key = get_counter_name(counter_key);
212         sigar_strerror_printf(sigar, "No %s counters defined (disabled?)",
213                               counter_key);
214         *err = -1;
215         return NULL;
216     }
217     object = PdhFirstObject(block);
218 
219     /*
220      * only seen on windows 2003 server when pdh.dll
221      * functions are in use by the same process.
222      * confucius say what the fuck.
223      */
224     if (inst && (object->NumInstances == PERF_NO_INSTANCES)) {
225         int i;
226 
227         for (i=0; i<block->NumObjectTypes; i++) {
228             if (object->NumInstances != PERF_NO_INSTANCES) {
229                 return object;
230             }
231             object = PdhNextObject(object);
232         }
233         return NULL;
234     }
235     else {
236         return object;
237     }
238 }
239 
240 #define get_perf_object(sigar, counter_key, err) \
241     get_perf_object_inst(sigar, counter_key, 1, err)
242 
get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem)243 static int get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem)
244 {
245     DWORD status;
246     PERF_OBJECT_TYPE *object =
247         get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status);
248     PERF_COUNTER_DEFINITION *counter;
249     BYTE *data;
250     DWORD i;
251 
252     if (!object) {
253         return status;
254     }
255 
256     data = (BYTE *)((BYTE *)object + object->DefinitionLength);
257 
258     for (i=0, counter = PdhFirstCounter(object);
259          i<object->NumCounters;
260          i++, counter = PdhNextCounter(counter))
261     {
262         DWORD offset = counter->CounterOffset;
263 
264         switch (counter->CounterNameTitleIndex) {
265           case 48: /* "Pages Output/sec" */
266             if (swap) swap->page_out = *((DWORD *)(data + offset));
267             break;
268           case 76: /* "System Cache Resident Bytes" aka file cache */
269             if (mem) {
270                 sigar_uint64_t kern = *((DWORD *)(data + offset));
271                 mem->actual_free = mem->free + kern;
272                 mem->actual_used = mem->used - kern;
273                 return SIGAR_OK;
274             }
275           case 822: /* "Pages Input/sec" */
276             if (swap) swap->page_in = *((DWORD *)(data + offset));
277             break;
278           default:
279             continue;
280         }
281     }
282 
283     return SIGAR_OK;
284 }
285 
get_sysinfo(sigar_t *sigar)286 static void get_sysinfo(sigar_t *sigar)
287 {
288     SYSTEM_INFO sysinfo;
289 
290     GetSystemInfo(&sysinfo);
291 
292     sigar->ncpu = sysinfo.dwNumberOfProcessors;
293     sigar->pagesize = sysinfo.dwPageSize;
294 }
295 
296 /* for C# bindings */
sigar_new(void)297 SIGAR_DECLARE(sigar_t *) sigar_new(void)
298 {
299     sigar_t *sigar;
300     if (sigar_open(&sigar) != SIGAR_OK) {
301         return NULL;
302     }
303     return sigar;
304 }
305 
306 static sigar_wtsapi_t sigar_wtsapi = {
307     "wtsapi32.dll",
308     NULL,
309     { "WTSEnumerateSessionsA", NULL },
310     { "WTSFreeMemory", NULL },
311     { "WTSQuerySessionInformationA", NULL },
312     { NULL, NULL }
313 };
314 
315 static sigar_iphlpapi_t sigar_iphlpapi = {
316     "iphlpapi.dll",
317     NULL,
318     { "GetIpForwardTable", NULL },
319     { "GetIpAddrTable", NULL },
320     { "GetIfTable", NULL },
321     { "GetIfEntry", NULL },
322     { "GetNumberOfInterfaces", NULL },
323     { "GetTcpTable", NULL },
324     { "GetUdpTable", NULL },
325     { "AllocateAndGetTcpExTableFromStack", NULL },
326     { "AllocateAndGetUdpExTableFromStack", NULL },
327     { "GetTcpStatistics", NULL },
328     { "GetNetworkParams", NULL },
329     { "GetAdaptersInfo", NULL },
330     { "GetAdaptersAddresses", NULL },
331     { "GetIpNetTable", NULL },
332     { NULL, NULL }
333 };
334 
335 static sigar_advapi_t sigar_advapi = {
336     "advapi32.dll",
337     NULL,
338     { "ConvertStringSidToSidA", NULL },
339     { "QueryServiceStatusEx", NULL },
340     { NULL, NULL }
341 };
342 
343 static sigar_ntdll_t sigar_ntdll = {
344     "ntdll.dll",
345     NULL,
346     { "NtQuerySystemInformation", NULL },
347     { "NtQueryInformationProcess", NULL },
348     { NULL, NULL }
349 };
350 
351 static sigar_psapi_t sigar_psapi = {
352     "psapi.dll",
353     NULL,
354     { "EnumProcessModules", NULL },
355     { "EnumProcesses", NULL },
356     { "GetModuleFileNameExA", NULL },
357     { NULL, NULL }
358 };
359 
360 static sigar_psapi_t sigar_winsta = {
361     "winsta.dll",
362     NULL,
363     { "WinStationQueryInformationW", NULL },
364     { NULL, NULL }
365 };
366 
367 static sigar_psapi_t sigar_kernel = {
368     "kernel32.dll",
369     NULL,
370     { "GlobalMemoryStatusEx", NULL },
371     { NULL, NULL }
372 };
373 
374 static sigar_mpr_t sigar_mpr = {
375     "mpr.dll",
376     NULL,
377     { "WNetGetConnectionA", NULL },
378     { NULL, NULL }
379 };
380 
381 #define DLLMOD_COPY(name) \
382     memcpy(&(sigar->name), &sigar_##name, sizeof(sigar_##name))
383 
384 #define DLLMOD_INIT(name, all) \
385     sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->name), all)
386 
387 #define DLLMOD_FREE(name) \
388     sigar_dllmod_free((sigar_dll_module_t *)&(sigar->name))
389 
sigar_dllmod_free(sigar_dll_module_t *module)390 static void sigar_dllmod_free(sigar_dll_module_t *module)
391 {
392     if (module->handle) {
393         FreeLibrary(module->handle);
394         module->handle = NULL;
395     }
396 }
397 
sigar_dllmod_init(sigar_t *sigar, sigar_dll_module_t *module, int all)398 static int sigar_dllmod_init(sigar_t *sigar,
399                              sigar_dll_module_t *module,
400                              int all)
401 {
402     sigar_dll_func_t *funcs = &module->funcs[0];
403     int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
404     int rc, success;
405 
406     if (module->handle == INVALID_HANDLE_VALUE) {
407         return ENOENT; /* XXX better rc */
408     }
409 
410     if (module->handle) {
411         return SIGAR_OK;
412     }
413 
414     module->handle = LoadLibrary(module->name);
415     if (!(success = (module->handle ? TRUE : FALSE))) {
416         rc = GetLastError();
417         /* dont try again */
418         module->handle = INVALID_HANDLE_VALUE;
419     }
420 
421     if (is_debug) {
422         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
423                          "LoadLibrary(%s): %s",
424                          module->name,
425                          success ?
426                          "OK" :
427                          sigar_strerror(sigar, rc));
428     }
429 
430     if (!success) {
431         return rc;
432     }
433 
434     while (funcs->name) {
435         funcs->func = GetProcAddress(module->handle, funcs->name);
436 
437         if (!(success = (funcs->func ? TRUE : FALSE))) {
438             rc = GetLastError();
439         }
440 
441         if (is_debug) {
442             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
443                              "GetProcAddress(%s:%s): %s",
444                              module->name, funcs->name,
445                              success ?
446                              "OK" :
447                              sigar_strerror(sigar, rc));
448         }
449 
450         if (all && !success) {
451             return rc;
452         }
453 
454         funcs++;
455     }
456 
457     return SIGAR_OK;
458 }
459 
sigar_wsa_init(sigar_t *sigar)460 int sigar_wsa_init(sigar_t *sigar)
461 {
462     if (sigar->ws_version == 0) {
463         WSADATA data;
464 
465         if (WSAStartup(MAKEWORD(2, 0), &data)) {
466             sigar->ws_error = WSAGetLastError();
467             WSACleanup();
468             return sigar->ws_error;
469         }
470 
471         sigar->ws_version = data.wVersion;
472     }
473 
474     return SIGAR_OK;
475 }
476 
sigar_enable_privilege(char *name)477 static int sigar_enable_privilege(char *name)
478 {
479     int status;
480     HANDLE handle;
481     TOKEN_PRIVILEGES tok;
482 
483     SIGAR_ZERO(&tok);
484 
485     if (!OpenProcessToken(GetCurrentProcess(),
486                           TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
487                           &handle))
488     {
489         return GetLastError();
490     }
491 
492     if (LookupPrivilegeValue(NULL, name,
493                              &tok.Privileges[0].Luid))
494     {
495         tok.PrivilegeCount = 1;
496         tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
497 
498         if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) {
499             status = SIGAR_OK;
500         }
501         else {
502             status = GetLastError();
503         }
504     }
505     else {
506         status = GetLastError();
507     }
508 
509     CloseHandle(handle);
510 
511     return status;
512 }
513 
sigar_os_open(sigar_t **sigar_ptr)514 int sigar_os_open(sigar_t **sigar_ptr)
515 {
516     LONG result;
517     OSVERSIONINFO version;
518     sigar_t *sigar;
519 
520     *sigar_ptr = sigar = malloc(sizeof(*sigar));
521     sigar->machine = ""; /* local machine */
522     sigar->using_wide = 0; /*XXX*/
523 
524     sigar->perfbuf = NULL;
525     sigar->perfbuf_size = 0;
526 
527     version.dwOSVersionInfoSize = sizeof(version);
528     GetVersionEx(&version);
529 
530     /*
531      * 4 == NT 4.0
532      * 5 == 2000, XP, 2003 Server
533      */
534     sigar->winnt = (version.dwMajorVersion == 4);
535 
536     if (USING_WIDE_S(sigar)) {
537         WCHAR wmachine[MAX_PATH+1];
538 
539         SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine));
540 
541         result = RegConnectRegistryW(wmachine,
542                                      HKEY_PERFORMANCE_DATA,
543                                      &sigar->handle);
544     }
545     else {
546         result = RegConnectRegistryA(sigar->machine,
547                                      HKEY_PERFORMANCE_DATA,
548                                      &sigar->handle);
549     }
550 
551     get_sysinfo(sigar);
552 
553     DLLMOD_COPY(wtsapi);
554     DLLMOD_COPY(iphlpapi);
555     DLLMOD_COPY(advapi);
556     DLLMOD_COPY(ntdll);
557     DLLMOD_COPY(psapi);
558     DLLMOD_COPY(winsta);
559     DLLMOD_COPY(kernel);
560     DLLMOD_COPY(mpr);
561 
562     sigar->log_level = -1; /* else below segfaults */
563     /* XXX init early for use by javasigar.c */
564     sigar_dllmod_init(sigar,
565                       (sigar_dll_module_t *)&sigar->advapi,
566                       FALSE);
567 
568     sigar->netif_mib_rows = NULL;
569     sigar->netif_addr_rows = NULL;
570     sigar->netif_adapters = NULL;
571     sigar->netif_names = NULL;
572     sigar->pinfo.pid = -1;
573     sigar->ws_version = 0;
574     sigar->lcpu = -1;
575 
576     /* increase process visibility */
577     sigar_enable_privilege(SE_DEBUG_NAME);
578 
579     return result;
580 }
581 
dllmod_init_ntdll(sigar_t *sigar)582 void dllmod_init_ntdll(sigar_t *sigar)
583 {
584     DLLMOD_INIT(ntdll, FALSE);
585 }
586 
sigar_os_close(sigar_t *sigar)587 int sigar_os_close(sigar_t *sigar)
588 {
589     int retval;
590 
591     DLLMOD_FREE(wtsapi);
592     DLLMOD_FREE(iphlpapi);
593     DLLMOD_FREE(advapi);
594     DLLMOD_FREE(ntdll);
595     DLLMOD_FREE(psapi);
596     DLLMOD_FREE(winsta);
597     DLLMOD_FREE(kernel);
598     DLLMOD_FREE(mpr);
599 
600     if (sigar->perfbuf) {
601         free(sigar->perfbuf);
602     }
603 
604     retval = RegCloseKey(sigar->handle);
605 
606     if (sigar->ws_version != 0) {
607         WSACleanup();
608     }
609 
610     if (sigar->netif_mib_rows) {
611         sigar_cache_destroy(sigar->netif_mib_rows);
612     }
613 
614     if (sigar->netif_addr_rows) {
615         sigar_cache_destroy(sigar->netif_addr_rows);
616     }
617 
618     if (sigar->netif_adapters) {
619         sigar_cache_destroy(sigar->netif_adapters);
620     }
621 
622     if (sigar->netif_names) {
623         sigar_cache_destroy(sigar->netif_names);
624     }
625 
626     free(sigar);
627 
628     return retval;
629 }
630 
sigar_os_error_string(sigar_t *sigar, int err)631 char *sigar_os_error_string(sigar_t *sigar, int err)
632 {
633     switch (err) {
634       case SIGAR_NO_SUCH_PROCESS:
635         return "No such process";
636         break;
637     }
638     return NULL;
639 }
640 
641 #define sigar_GlobalMemoryStatusEx \
642     sigar->kernel.memory_status.func
643 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)644 SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
645 {
646     DLLMOD_INIT(kernel, TRUE);
647 
648     if (sigar_GlobalMemoryStatusEx) {
649         MEMORYSTATUSEX memstat;
650 
651         memstat.dwLength = sizeof(memstat);
652 
653         if (!sigar_GlobalMemoryStatusEx(&memstat)) {
654             return GetLastError();
655         }
656 
657         mem->total = memstat.ullTotalPhys;
658         mem->free  = memstat.ullAvailPhys;
659     }
660     else {
661         MEMORYSTATUS memstat;
662         GlobalMemoryStatus(&memstat);
663         mem->total = memstat.dwTotalPhys;
664         mem->free  = memstat.dwAvailPhys;
665     }
666 
667     mem->used = mem->total - mem->free;
668 
669     mem->actual_free = mem->free;
670     mem->actual_used = mem->used;
671     /* set actual_{free,used} */
672     get_mem_counters(sigar, NULL, mem);
673 
674     sigar_mem_calc_ram(sigar, mem);
675 
676     return SIGAR_OK;
677 }
678 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)679 SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
680 {
681     DLLMOD_INIT(kernel, TRUE);
682 
683     if (sigar_GlobalMemoryStatusEx) {
684         MEMORYSTATUSEX memstat;
685 
686         memstat.dwLength = sizeof(memstat);
687 
688         if (!sigar_GlobalMemoryStatusEx(&memstat)) {
689             return GetLastError();
690         }
691 
692         swap->total = memstat.ullTotalPageFile;
693         swap->free  = memstat.ullAvailPageFile;
694     }
695     else {
696         MEMORYSTATUS memstat;
697         GlobalMemoryStatus(&memstat);
698         swap->total = memstat.dwTotalPageFile;
699         swap->free  = memstat.dwAvailPageFile;
700     }
701 
702     swap->used = swap->total - swap->free;
703 
704     if (get_mem_counters(sigar, swap, NULL) != SIGAR_OK) {
705         swap->page_in = SIGAR_FIELD_NOTIMPL;
706         swap->page_out = SIGAR_FIELD_NOTIMPL;
707     }
708 
709     return SIGAR_OK;
710 }
711 
get_cpu_instance(sigar_t *sigar, DWORD *perf_offsets, DWORD *num, DWORD *err)712 static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
713                                                   DWORD *perf_offsets,
714                                                   DWORD *num, DWORD *err)
715 {
716     PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, err);
717     PERF_COUNTER_DEFINITION *counter;
718     DWORD i;
719 
720     if (!object) {
721         return NULL;
722     }
723 
724     for (i=0, counter = PdhFirstCounter(object);
725          i<object->NumCounters;
726          i++, counter = PdhNextCounter(counter))
727     {
728         DWORD offset = counter->CounterOffset;
729 
730         switch (counter->CounterNameTitleIndex) {
731           case PERF_TITLE_CPU_SYS:
732             perf_offsets[PERF_IX_CPU_SYS] = offset;
733             break;
734           case PERF_TITLE_CPU_USER:
735             perf_offsets[PERF_IX_CPU_USER] = offset;
736             break;
737           case PERF_TITLE_CPU_IDLE:
738             perf_offsets[PERF_IX_CPU_IDLE] = offset;
739             break;
740           case PERF_TITLE_CPU_IRQ:
741             perf_offsets[PERF_IX_CPU_IRQ] = offset;
742             break;
743         }
744     }
745 
746     if (num) {
747         *num = object->NumInstances;
748     }
749 
750     return PdhFirstInstance(object);
751 }
752 
753 #define SPPI_MAX 128 /* XXX unhardcode; should move off this api anyhow */
754 
755 #define sigar_NtQuerySystemInformation \
756    sigar->ntdll.query_sys_info.func
757 
get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu, DWORD idx, PERF_COUNTER_BLOCK *counter_block, DWORD *perf_offsets)758 static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
759                         DWORD idx,
760                         PERF_COUNTER_BLOCK *counter_block,
761                         DWORD *perf_offsets)
762 {
763     cpu->idle = 0;
764 
765     if (perf_offsets[PERF_IX_CPU_IDLE]) {
766         cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE);
767     }
768     else {
769         /* windows NT and 2000 do not have an Idle counter */
770         DLLMOD_INIT(ntdll, FALSE);
771         if (sigar_NtQuerySystemInformation) {
772             DWORD retval, num;
773             SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
774             /* into the lungs of hell */
775             sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
776                                            &info, sizeof(info), &retval);
777 
778             if (!retval) {
779                 return GetLastError();
780             }
781             num = retval/sizeof(info[0]);
782 
783             if (idx == -1) {
784                 int i;
785                 for (i=0; i<num; i++) {
786                     cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
787                 }
788             }
789             else if (idx < num) {
790                 cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart);
791             }
792             else {
793                 return ERROR_INVALID_DATA;
794             }
795         }
796         else {
797             return ERROR_INVALID_FUNCTION;
798         }
799     }
800 
801     return SIGAR_OK;
802 }
803 
sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)804 static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
805 {
806     int status;
807     PERF_INSTANCE_DEFINITION *inst;
808     PERF_COUNTER_BLOCK *counter_block;
809     DWORD perf_offsets[PERF_IX_CPU_MAX], err;
810 
811     SIGAR_ZERO(cpu);
812     memset(&perf_offsets, 0, sizeof(perf_offsets));
813 
814     inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
815 
816     if (!inst) {
817         return err;
818     }
819 
820     /* first instance is total, rest are per-cpu */
821     counter_block = PdhGetCounterBlock(inst);
822 
823     cpu->sys  = PERF_VAL_CPU(PERF_IX_CPU_SYS);
824     cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER);
825     status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
826     cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ);
827     cpu->nice = 0; /* no nice here */
828     cpu->wait = 0; /*N/A?*/
829     cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq;
830 
831     if (status != SIGAR_OK) {
832         sigar_log_printf(sigar, SIGAR_LOG_WARN,
833                          "unable to determine idle cpu time: %s",
834                          sigar_strerror(sigar, status));
835     }
836 
837     return SIGAR_OK;
838 }
839 
sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)840 static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)
841 {
842     DWORD retval, num;
843     int i;
844     SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
845     /* into the lungs of hell */
846     sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
847                                    &info, sizeof(info), &retval);
848 
849     if (!retval) {
850         return GetLastError();
851     }
852     num = retval/sizeof(info[0]);
853     SIGAR_ZERO(cpu);
854 
855     for (i=0; i<num; i++) {
856         cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
857         cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart);
858         cpu->sys  += NS100_2MSEC(info[i].KernelTime.QuadPart -
859                                  info[i].IdleTime.QuadPart);
860         cpu->irq  += NS100_2MSEC(info[i].InterruptTime.QuadPart);
861     }
862     cpu->total = cpu->idle + cpu->user + cpu->sys;
863 
864     return SIGAR_OK;
865 }
866 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)867 SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
868 {
869     DLLMOD_INIT(ntdll, FALSE);
870     if (sigar_NtQuerySystemInformation) {
871         return sigar_cpu_ntsys_get(sigar, cpu);
872     }
873     else {
874         return sigar_cpu_perflib_get(sigar, cpu);
875     }
876 }
877 
878 
879 #define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */
880 
881 
882 #define get_process_object(sigar, err) \
883     get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
884 
sigar_proc_list_get_perf(sigar_t *sigar, sigar_proc_list_t *proclist)885 static int sigar_proc_list_get_perf(sigar_t *sigar,
886                                     sigar_proc_list_t *proclist)
887 {
888 
889     PERF_OBJECT_TYPE *object;
890     PERF_INSTANCE_DEFINITION *inst;
891     PERF_COUNTER_DEFINITION *counter;
892     DWORD i, err;
893     DWORD perf_offsets[PERF_IX_MAX];
894 
895     perf_offsets[PERF_IX_PID] = 0;
896 
897     object = get_process_object(sigar, &err);
898 
899     if (!object) {
900         return err;
901     }
902 
903     /*
904      * note we assume here:
905      *  block->NumObjectTypes == 1
906      *  object->ObjectNameTitleIndex == PERF_TITLE_PROC
907      *
908      * which should always be the case.
909      */
910 
911     for (i=0, counter = PdhFirstCounter(object);
912          i<object->NumCounters;
913          i++, counter = PdhNextCounter(counter))
914     {
915         DWORD offset = counter->CounterOffset;
916 
917         switch (counter->CounterNameTitleIndex) {
918           case PERF_TITLE_PID:
919             perf_offsets[PERF_IX_PID] = offset;
920             break;
921         }
922     }
923 
924     for (i=0, inst = PdhFirstInstance(object);
925          i<object->NumInstances;
926          i++, inst = PdhNextInstance(inst))
927     {
928         PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
929         DWORD pid = PERF_VAL(PERF_IX_PID);
930 
931         if (pid == 0) {
932             continue; /* dont include the system Idle process */
933         }
934 
935         SIGAR_PROC_LIST_GROW(proclist);
936 
937         proclist->data[proclist->number++] = pid;
938     }
939 
940     return SIGAR_OK;
941 }
942 
943 #define sigar_EnumProcesses \
944     sigar->psapi.enum_processes.func
945 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)946 int sigar_os_proc_list_get(sigar_t *sigar,
947                            sigar_proc_list_t *proclist)
948 {
949     DLLMOD_INIT(psapi, FALSE);
950 
951     if (sigar_EnumProcesses) {
952         DWORD retval, *pids;
953         DWORD size = 0, i;
954 
955         do {
956             /* re-use the perfbuf */
957             if (size == 0) {
958                 size = perfbuf_init(sigar);
959             }
960             else {
961                 size = perfbuf_grow(sigar);
962             }
963 
964             if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf,
965                                      sigar->perfbuf_size,
966                                      &retval))
967             {
968                 return GetLastError();
969             }
970         } while (retval == sigar->perfbuf_size); //unlikely
971 
972         pids = (DWORD *)sigar->perfbuf;
973 
974         size = retval / sizeof(DWORD);
975 
976         for (i=0; i<size; i++) {
977             DWORD pid = pids[i];
978             if (pid == 0) {
979                 continue; /* dont include the system Idle process */
980             }
981             SIGAR_PROC_LIST_GROW(proclist);
982             proclist->data[proclist->number++] = pid;
983         }
984 
985         return SIGAR_OK;
986     }
987     else {
988         return sigar_proc_list_get_perf(sigar, proclist);
989     }
990 }
991 
992 #define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
993 
open_process(sigar_pid_t pid)994 static HANDLE open_process(sigar_pid_t pid)
995 {
996     return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
997 }
998 
999 /*
1000  * Pretty good explanation of counters:
1001  * http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory
1002  */
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)1003 SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
1004                                       sigar_proc_mem_t *procmem)
1005 {
1006     int status = get_proc_info(sigar, pid);
1007     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1008 
1009     if (status != SIGAR_OK) {
1010         return status;
1011     }
1012 
1013     procmem->size     = pinfo->size;     /* "Virtual Bytes" */
1014     procmem->resident = pinfo->resident; /* "Working Set" */
1015     procmem->share    = SIGAR_FIELD_NOTIMPL;
1016     procmem->page_faults  = pinfo->page_faults;
1017     procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1018     procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1019 
1020     return SIGAR_OK;
1021 }
1022 
1023 #define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
1024 
1025 #define FILETIME2MSEC(ft) \
1026         NS100_2MSEC((((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime))
1027 
sigar_time_now_millis(void)1028 sigar_int64_t sigar_time_now_millis(void)
1029 {
1030     SYSTEMTIME st;
1031     FILETIME time;
1032 
1033     GetSystemTime(&st);
1034     SystemTimeToFileTime(&st, &time);
1035 
1036     return sigar_FileTimeToTime(&time) / 1000;
1037 }
1038 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)1039 int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
1040                         sigar_proc_time_t *proctime)
1041 {
1042     HANDLE proc = open_process(pid);
1043     FILETIME start_time, exit_time, system_time, user_time;
1044     int status = ERROR_SUCCESS;
1045 
1046     if (!proc) {
1047         return GetLastError();
1048     }
1049 
1050     if (!GetProcessTimes(proc,
1051                          &start_time, &exit_time,
1052                          &system_time, &user_time))
1053     {
1054         status = GetLastError();
1055     }
1056 
1057     CloseHandle(proc);
1058 
1059     if (status != ERROR_SUCCESS) {
1060         return status;
1061     }
1062 
1063     if (start_time.dwHighDateTime) {
1064         proctime->start_time =
1065             sigar_FileTimeToTime(&start_time) / 1000;
1066     }
1067     else {
1068         proctime->start_time = 0;
1069     }
1070 
1071     proctime->user = FILETIME2MSEC(user_time);
1072     proctime->sys  = FILETIME2MSEC(system_time);
1073     proctime->total = proctime->user + proctime->sys;
1074 
1075     return SIGAR_OK;
1076 }
1077 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1078 SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
1079                                         sigar_proc_state_t *procstate)
1080 {
1081     int status = get_proc_info(sigar, pid);
1082     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1083 
1084     if (status != SIGAR_OK) {
1085         return status;
1086     }
1087 
1088     memcpy(procstate->name, pinfo->name, sizeof(procstate->name));
1089     procstate->state = pinfo->state;
1090     procstate->ppid = pinfo->ppid;
1091     procstate->priority = pinfo->priority;
1092     procstate->nice = SIGAR_FIELD_NOTIMPL;
1093     procstate->tty =  SIGAR_FIELD_NOTIMPL;
1094     procstate->threads = pinfo->threads;
1095     procstate->processor = SIGAR_FIELD_NOTIMPL;
1096 
1097     return SIGAR_OK;
1098 }
1099 
get_proc_info(sigar_t *sigar, sigar_pid_t pid)1100 int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
1101 {
1102     PERF_OBJECT_TYPE *object;
1103     PERF_INSTANCE_DEFINITION *inst;
1104     PERF_COUNTER_DEFINITION *counter;
1105     DWORD i, err;
1106     DWORD perf_offsets[PERF_IX_MAX];
1107     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1108     time_t timenow = time(NULL);
1109 
1110     if (pinfo->pid == pid) {
1111         if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) {
1112             return SIGAR_OK;
1113         }
1114     }
1115 
1116     memset(&perf_offsets, 0, sizeof(perf_offsets));
1117 
1118     object = get_process_object(sigar, &err);
1119 
1120     if (object == NULL) {
1121         return err;
1122     }
1123 
1124     pinfo->pid = pid;
1125     pinfo->mtime = timenow;
1126 
1127     /*
1128      * note we assume here:
1129      *  block->NumObjectTypes == 1
1130      *  object->ObjectNameTitleIndex == PERF_TITLE_PROC
1131      *
1132      * which should always be the case.
1133      */
1134 
1135     for (i=0, counter = PdhFirstCounter(object);
1136          i<object->NumCounters;
1137          i++, counter = PdhNextCounter(counter))
1138     {
1139         DWORD offset = counter->CounterOffset;
1140 
1141         switch (counter->CounterNameTitleIndex) {
1142           case PERF_TITLE_CPUTIME:
1143             perf_offsets[PERF_IX_CPUTIME] = offset;
1144             break;
1145           case PERF_TITLE_PAGE_FAULTS:
1146             perf_offsets[PERF_IX_PAGE_FAULTS] = offset;
1147             break;
1148           case PERF_TITLE_MEM_VSIZE:
1149             assert(counter->CounterSize >= 8);
1150             perf_offsets[PERF_IX_MEM_VSIZE] = offset;
1151             break;
1152           case PERF_TITLE_MEM_SIZE:
1153             assert(counter->CounterSize >= 8);
1154             perf_offsets[PERF_IX_MEM_SIZE] = offset;
1155             break;
1156           case PERF_TITLE_THREAD_CNT:
1157             perf_offsets[PERF_IX_THREAD_CNT] = offset;
1158             break;
1159           case PERF_TITLE_HANDLE_CNT:
1160             perf_offsets[PERF_IX_HANDLE_CNT] = offset;
1161             break;
1162           case PERF_TITLE_PID:
1163             perf_offsets[PERF_IX_PID] = offset;
1164             break;
1165           case PERF_TITLE_PPID:
1166             perf_offsets[PERF_IX_PPID] = offset;
1167             break;
1168           case PERF_TITLE_PRIORITY:
1169             perf_offsets[PERF_IX_PRIORITY] = offset;
1170             break;
1171           case PERF_TITLE_START_TIME:
1172             perf_offsets[PERF_IX_START_TIME] = offset;
1173             break;
1174         }
1175     }
1176 
1177     for (i=0, inst = PdhFirstInstance(object);
1178          i<object->NumInstances;
1179          i++, inst = PdhNextInstance(inst))
1180     {
1181         PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
1182         sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID);
1183 
1184         if (this_pid != pid) {
1185             continue;
1186         }
1187 
1188         pinfo->state = 'R'; /* XXX? */
1189         SIGAR_W2A(PdhInstanceName(inst),
1190                   pinfo->name, sizeof(pinfo->name));
1191 
1192         pinfo->size     = PERF_VAL64(PERF_IX_MEM_VSIZE);
1193         pinfo->resident = PERF_VAL64(PERF_IX_MEM_SIZE);
1194         pinfo->ppid     = PERF_VAL(PERF_IX_PPID);
1195         pinfo->priority = PERF_VAL(PERF_IX_PRIORITY);
1196         pinfo->handles  = PERF_VAL(PERF_IX_HANDLE_CNT);
1197         pinfo->threads  = PERF_VAL(PERF_IX_THREAD_CNT);
1198         pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
1199 
1200         return SIGAR_OK;
1201     }
1202 
1203     return SIGAR_NO_SUCH_PROCESS;
1204 }
1205 
sigar_os_fs_type_get(sigar_file_system_t *fsp)1206 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1207 {
1208     return fsp->type;
1209 }
1210 
1211 #ifndef FILE_READ_ONLY_VOLUME
1212 #define FILE_READ_ONLY_VOLUME 0x00080000
1213 #endif
1214 #ifndef FILE_NAMED_STREAMS
1215 #define FILE_NAMED_STREAMS 0x00040000
1216 #endif
1217 #ifndef FILE_SEQUENTIAL_WRITE_ONCE
1218 #define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
1219 #endif
1220 #ifndef FILE_SUPPORTS_TRANSACTIONS
1221 #define FILE_SUPPORTS_TRANSACTIONS 0x00200000
1222 #endif
1223 
get_fs_options(char *opts, int osize, long flags)1224 static void get_fs_options(char *opts, int osize, long flags)
1225 {
1226     *opts = '\0';
1227     if (flags & FILE_READ_ONLY_VOLUME)        strncat(opts, "ro", osize);
1228     else                                      strncat(opts, "rw", osize);
1229 #if 0 /*XXX*/
1230     if (flags & FILE_CASE_PRESERVED_NAMES)    strncat(opts, ",casepn", osize);
1231     if (flags & FILE_CASE_SENSITIVE_SEARCH)   strncat(opts, ",casess", osize);
1232     if (flags & FILE_FILE_COMPRESSION)        strncat(opts, ",fcomp", osize);
1233     if (flags & FILE_NAMED_STREAMS)           strncat(opts, ",streams", osize);
1234     if (flags & FILE_PERSISTENT_ACLS)         strncat(opts, ",acls", osize);
1235     if (flags & FILE_SEQUENTIAL_WRITE_ONCE)   strncat(opts, ",wronce", osize);
1236     if (flags & FILE_SUPPORTS_ENCRYPTION)     strncat(opts, ",efs", osize);
1237     if (flags & FILE_SUPPORTS_OBJECT_IDS)     strncat(opts, ",oids", osize);
1238     if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize);
1239     if (flags & FILE_SUPPORTS_SPARSE_FILES)   strncat(opts, ",sparse", osize);
1240     if (flags & FILE_SUPPORTS_TRANSACTIONS)   strncat(opts, ",trans", osize);
1241     if (flags & FILE_UNICODE_ON_DISK)         strncat(opts, ",unicode", osize);
1242     if (flags & FILE_VOLUME_IS_COMPRESSED)    strncat(opts, ",vcomp", osize);
1243     if (flags & FILE_VOLUME_QUOTAS)           strncat(opts, ",quota", osize);
1244 #endif
1245 }
1246 
1247 #define sigar_WNetGetConnection \
1248     sigar->mpr.get_net_connection.func
1249 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)1250 SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
1251                                               sigar_file_system_list_t *fslist)
1252 {
1253     char name[256];
1254     char *ptr = name;
1255     /* XXX: hmm, Find{First,Next}Volume not available in my sdk */
1256     DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
1257 
1258     DLLMOD_INIT(mpr, TRUE);
1259 
1260     if (len == 0) {
1261         return GetLastError();
1262     }
1263 
1264     sigar_file_system_list_create(fslist);
1265 
1266     while (*ptr) {
1267         sigar_file_system_t *fsp;
1268         DWORD flags, serialnum=0;
1269         char fsname[1024];
1270         UINT drive_type = GetDriveType(ptr);
1271         int type;
1272 
1273         switch (drive_type) {
1274           case DRIVE_FIXED:
1275             type = SIGAR_FSTYPE_LOCAL_DISK;
1276             break;
1277           case DRIVE_REMOTE:
1278             type = SIGAR_FSTYPE_NETWORK;
1279             break;
1280           case DRIVE_CDROM:
1281             type = SIGAR_FSTYPE_CDROM;
1282             break;
1283           case DRIVE_RAMDISK:
1284             type = SIGAR_FSTYPE_RAM_DISK;
1285             break;
1286           case DRIVE_REMOVABLE:
1287             /* skip floppy, usb, etc. drives */
1288             ptr += strlen(ptr)+1;
1289             continue;
1290           default:
1291             type = SIGAR_FSTYPE_NONE;
1292             break;
1293         }
1294 
1295         fsname[0] = '\0';
1296 
1297         GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
1298                              &flags, fsname, sizeof(fsname));
1299 
1300         if (!serialnum && (drive_type == DRIVE_FIXED)) {
1301             ptr += strlen(ptr)+1;
1302             continue; /* ignore unformatted partitions */
1303         }
1304 
1305         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1306 
1307         fsp = &fslist->data[fslist->number++];
1308 
1309         fsp->type = type;
1310         SIGAR_SSTRCPY(fsp->dir_name, ptr);
1311         SIGAR_SSTRCPY(fsp->dev_name, ptr);
1312 
1313         if ((drive_type == DRIVE_REMOTE) && sigar_WNetGetConnection) {
1314             DWORD len = sizeof(fsp->dev_name);
1315             char drive[3] = {'\0', ':', '\0'}; /* e.g. "X:" w/o trailing "\" */
1316             drive[0] = fsp->dir_name[0];
1317             sigar_WNetGetConnection(drive, fsp->dev_name, &len);
1318             /* ignoring failure, leaving dev_name as dir_name */
1319         }
1320 
1321         /* we set fsp->type, just looking up sigar.c:fstype_names[type] */
1322         sigar_fs_type_get(fsp);
1323 
1324         if (*fsname == '\0') {
1325             SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name);
1326         }
1327         else {
1328             SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */
1329         }
1330 
1331         get_fs_options(fsp->options, sizeof(fsp->options)-1, flags);
1332 
1333         ptr += strlen(ptr)+1;
1334     }
1335 
1336     return SIGAR_OK;
1337 }
1338 
1339 
1340 
1341 #define sigar_GetNetworkParams \
1342     sigar->iphlpapi.get_net_params.func
1343 
1344 #define sigar_GetAdaptersInfo \
1345     sigar->iphlpapi.get_adapters_info.func
1346 
1347 #define sigar_GetAdaptersAddresses \
1348     sigar->iphlpapi.get_adapters_addrs.func
1349 
1350 #define sigar_GetNumberOfInterfaces \
1351     sigar->iphlpapi.get_num_if.func
1352 
sigar_netif_cache_new(sigar_t *sigar)1353 static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar)
1354 {
1355     DWORD num = 0;
1356 
1357     DLLMOD_INIT(iphlpapi, FALSE);
1358 
1359     if (sigar_GetNumberOfInterfaces) {
1360         DWORD rc = sigar_GetNumberOfInterfaces(&num);
1361 
1362         if (rc == NO_ERROR) {
1363             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1364                              "GetNumberOfInterfaces=%d",
1365                              num);
1366         }
1367         else {
1368             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1369                              "GetNumberOfInterfaces failed: %s",
1370                              sigar_strerror(sigar, rc));
1371         }
1372     }
1373 
1374     if (num == 0) {
1375         num = 10; /* reasonable default */
1376     }
1377 
1378     return sigar_cache_new(num);
1379 }
1380 
sigar_get_adapters_info(sigar_t *sigar, PIP_ADAPTER_INFO *adapter)1381 static int sigar_get_adapters_info(sigar_t *sigar,
1382                                    PIP_ADAPTER_INFO *adapter)
1383 {
1384     ULONG size = sigar->ifconf_len;
1385     DWORD rc;
1386 
1387     DLLMOD_INIT(iphlpapi, FALSE);
1388 
1389     if (!sigar_GetAdaptersInfo) {
1390         return SIGAR_ENOTIMPL;
1391     }
1392 
1393     *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
1394     rc = sigar_GetAdaptersInfo(*adapter, &size);
1395 
1396     if (rc == ERROR_BUFFER_OVERFLOW) {
1397         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1398                          "GetAdaptersInfo "
1399                          "realloc ifconf_buf old=%d, new=%d",
1400                          sigar->ifconf_len, size);
1401         sigar->ifconf_len = size;
1402         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
1403                                     sigar->ifconf_len);
1404 
1405         *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
1406         rc = sigar_GetAdaptersInfo(*adapter, &size);
1407     }
1408 
1409     if (rc != NO_ERROR) {
1410         return rc;
1411     }
1412     else {
1413         return SIGAR_OK;
1414     }
1415 }
1416 
1417 
sigar_get_adapters_addresses(sigar_t *sigar, ULONG family, ULONG flags, PIP_ADAPTER_ADDRESSES *addrs)1418 static int sigar_get_adapters_addresses(sigar_t *sigar,
1419                                         ULONG family, ULONG flags,
1420                                         PIP_ADAPTER_ADDRESSES *addrs)
1421 {
1422     ULONG size = sigar->ifconf_len;
1423     ULONG rc;
1424 
1425     DLLMOD_INIT(iphlpapi, FALSE);
1426 
1427     if (!sigar_GetAdaptersAddresses) {
1428         return SIGAR_ENOTIMPL;
1429     }
1430 
1431     *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
1432     rc = sigar_GetAdaptersAddresses(family,
1433                                     flags,
1434                                     NULL,
1435                                     *addrs,
1436                                     &size);
1437 
1438     if (rc == ERROR_BUFFER_OVERFLOW) {
1439         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1440                          "GetAdaptersAddresses "
1441                          "realloc ifconf_buf old=%d, new=%d",
1442                          sigar->ifconf_len, size);
1443         sigar->ifconf_len = size;
1444         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
1445                                     sigar->ifconf_len);
1446 
1447         *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
1448         rc = sigar_GetAdaptersAddresses(family,
1449                                         flags,
1450                                         NULL,
1451                                         *addrs,
1452                                         &size);
1453     }
1454 
1455     if (rc != ERROR_SUCCESS) {
1456         return rc;
1457     }
1458     else {
1459         return SIGAR_OK;
1460     }
1461 }
1462 
1463 #define sigar_GetIpAddrTable \
1464     sigar->iphlpapi.get_ipaddr_table.func
1465 
sigar_get_ipaddr_table(sigar_t *sigar, PMIB_IPADDRTABLE *ipaddr)1466 static int sigar_get_ipaddr_table(sigar_t *sigar,
1467                                   PMIB_IPADDRTABLE *ipaddr)
1468 {
1469     ULONG size = sigar->ifconf_len;
1470     DWORD rc;
1471 
1472     DLLMOD_INIT(iphlpapi, FALSE);
1473 
1474     if (!sigar_GetIpAddrTable) {
1475         return SIGAR_ENOTIMPL;
1476     }
1477 
1478     *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
1479     rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
1480 
1481     if (rc == ERROR_INSUFFICIENT_BUFFER) {
1482         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1483                          "GetIpAddrTable "
1484                          "realloc ifconf_buf old=%d, new=%d",
1485                          sigar->ifconf_len, size);
1486         sigar->ifconf_len = size;
1487         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
1488                                     sigar->ifconf_len);
1489 
1490         *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
1491         rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
1492     }
1493 
1494     if (rc != NO_ERROR) {
1495         return rc;
1496     }
1497     else {
1498         return SIGAR_OK;
1499     }
1500 }
1501 
1502 #ifndef MIB_IPADDR_PRIMARY
1503 #define MIB_IPADDR_PRIMARY 0x0001
1504 #endif
1505 
sigar_get_netif_ipaddr(sigar_t *sigar, DWORD index, MIB_IPADDRROW **ipaddr)1506 static int sigar_get_netif_ipaddr(sigar_t *sigar,
1507                                   DWORD index,
1508                                   MIB_IPADDRROW **ipaddr)
1509 {
1510     sigar_cache_entry_t *entry;
1511     *ipaddr = NULL;
1512 
1513     if (sigar->netif_addr_rows) {
1514         entry = sigar_cache_get(sigar->netif_addr_rows, index);
1515         if (entry->value) {
1516             *ipaddr = (MIB_IPADDRROW *)entry->value;
1517         }
1518     }
1519     else {
1520         int status, i;
1521         MIB_IPADDRTABLE *mib;
1522 
1523         sigar->netif_addr_rows =
1524             sigar_netif_cache_new(sigar);
1525 
1526         status = sigar_get_ipaddr_table(sigar, &mib);
1527         if (status != SIGAR_OK) {
1528             return status;
1529         }
1530 
1531         for (i=0; i<mib->dwNumEntries; i++) {
1532             MIB_IPADDRROW *row = &mib->table[i];
1533             short type;
1534 
1535 #ifdef SIGAR_USING_MSC6
1536             type = row->unused2;
1537 #else
1538             type = row->wType;
1539 #endif
1540             if (!(type & MIB_IPADDR_PRIMARY)) {
1541                 continue;
1542             }
1543 
1544             entry = sigar_cache_get(sigar->netif_addr_rows,
1545                                     row->dwIndex);
1546             if (!entry->value) {
1547                 entry->value = malloc(sizeof(*row));
1548             }
1549             memcpy(entry->value, row, sizeof(*row));
1550 
1551             if (row->dwIndex == index) {
1552                 *ipaddr = row;
1553             }
1554         }
1555     }
1556 
1557     if (*ipaddr) {
1558         return SIGAR_OK;
1559     }
1560     else {
1561         return ENOENT;
1562     }
1563 }
1564 
1565 #define sigar_GetIpForwardTable \
1566     sigar->iphlpapi.get_ipforward_table.func
1567 
1568 
1569 #define sigar_GetIfTable \
1570     sigar->iphlpapi.get_if_table.func
1571 
1572 #define sigar_GetIfEntry \
1573     sigar->iphlpapi.get_if_entry.func
1574 
sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)1575 static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
1576 {
1577     ULONG size = sigar->ifconf_len;
1578     DWORD rc;
1579 
1580     DLLMOD_INIT(iphlpapi, FALSE);
1581 
1582     if (!sigar_GetIfTable) {
1583         return SIGAR_ENOTIMPL;
1584     }
1585 
1586     *iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
1587     rc = sigar_GetIfTable(*iftable, &size, FALSE);
1588 
1589     if (rc == ERROR_INSUFFICIENT_BUFFER) {
1590         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1591                          "GetIfTable "
1592                          "realloc ifconf_buf old=%d, new=%d",
1593                          sigar->ifconf_len, size);
1594         sigar->ifconf_len = size;
1595         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
1596                                     sigar->ifconf_len);
1597 
1598         *iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
1599         rc = sigar_GetIfTable(*iftable, &size, FALSE);
1600     }
1601 
1602     if (rc != NO_ERROR) {
1603         return rc;
1604     }
1605     else {
1606         return SIGAR_OK;
1607     }
1608 }
1609 
get_mib_ifrow(sigar_t *sigar, const char *name, MIB_IFROW **ifrp)1610 static int get_mib_ifrow(sigar_t *sigar,
1611                          const char *name,
1612                          MIB_IFROW **ifrp)
1613 {
1614     int status, key, cached=0;
1615     sigar_cache_entry_t *entry;
1616 
1617     if (sigar->netif_mib_rows) {
1618         cached = 1;
1619     }
1620     else {
1621         status = sigar_net_interface_list_get(sigar, NULL);
1622         if (status != SIGAR_OK) {
1623             return status;
1624         }
1625     }
1626     key = netif_hash(name);
1627     entry = sigar_cache_get(sigar->netif_mib_rows, key);
1628     if (!entry->value) {
1629         return ENOENT;
1630     }
1631 
1632     *ifrp = (MIB_IFROW *)entry->value;
1633     if (cached) {
1634         /* refresh */
1635         if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) {
1636             return status;
1637         }
1638     }
1639 
1640     return SIGAR_OK;
1641 }
1642 
netif_hash(char *s)1643 int netif_hash(char *s)
1644 {
1645     int hash = 0;
1646     while (*s) {
1647         hash = 31*hash + *s++;
1648     }
1649     return hash;
1650 }
1651 
1652 /* Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211 */
1653 #ifndef IF_TYPE_IEEE80211
1654 #define IF_TYPE_IEEE80211 71
1655 #endif
1656 
1657 SIGAR_DECLARE(int)
sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)1658 sigar_net_interface_list_get(sigar_t *sigar,
1659                              sigar_net_interface_list_t *iflist)
1660 {
1661     MIB_IFTABLE *ift;
1662     int i, status;
1663     int lo=0, eth=0, la=0;
1664 
1665     if (!sigar->netif_mib_rows) {
1666         sigar->netif_mib_rows =
1667             sigar_netif_cache_new(sigar);
1668     }
1669 
1670     if (!sigar->netif_names) {
1671         sigar->netif_names =
1672             sigar_netif_cache_new(sigar);
1673     }
1674 
1675     if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
1676         return status;
1677     }
1678 
1679     if (iflist) {
1680         iflist->number = 0;
1681         iflist->size = ift->dwNumEntries;
1682         iflist->data =
1683             malloc(sizeof(*(iflist->data)) * iflist->size);
1684     }
1685 
1686     for (i=0; i<ift->dwNumEntries; i++) {
1687         char name[16];
1688         int key;
1689         MIB_IFROW *ifr = ift->table + i;
1690         sigar_cache_entry_t *entry;
1691 
1692         if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) {
1693             /* special-case */
1694             sprintf(name, NETIF_LA "%d", la++);
1695         }
1696         else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
1697             sprintf(name, "lo%d", lo++);
1698         }
1699         else if ((ifr->dwType == MIB_IF_TYPE_ETHERNET) ||
1700                  (ifr->dwType == IF_TYPE_IEEE80211))
1701         {
1702             sprintf(name, "eth%d", eth++);
1703         }
1704         else {
1705             continue; /*XXX*/
1706         }
1707 
1708         if (iflist) {
1709             iflist->data[iflist->number++] = sigar_strdup(name);
1710         }
1711 
1712         key = netif_hash(name);
1713         entry = sigar_cache_get(sigar->netif_mib_rows, key);
1714         if (!entry->value) {
1715             entry->value = malloc(sizeof(*ifr));
1716         }
1717         memcpy(entry->value, ifr, sizeof(*ifr));
1718 
1719         /* save dwIndex -> name mapping for use by route_list */
1720         entry = sigar_cache_get(sigar->netif_names, ifr->dwIndex);
1721         if (!entry->value) {
1722             entry->value = sigar_strdup(name);
1723         }
1724     }
1725 
1726     return SIGAR_OK;
1727 }
1728 
sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index, sigar_net_interface_config_t *ifconfig)1729 static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index,
1730                                                 sigar_net_interface_config_t *ifconfig)
1731 {
1732 #ifdef SIGAR_USING_MSC6
1733     return SIGAR_ENOTIMPL;
1734 #else
1735     int status;
1736     PIP_ADAPTER_ADDRESSES aa, addrs;
1737     ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
1738 
1739     status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa);
1740 
1741     if (status != SIGAR_OK) {
1742         return status;
1743     }
1744 
1745     for (addrs = aa; addrs; addrs = addrs->Next) {
1746         PIP_ADAPTER_UNICAST_ADDRESS addr;
1747         if (addrs->IfIndex != index) {
1748             continue;
1749         }
1750         for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) {
1751             struct sockaddr *sa = addr->Address.lpSockaddr;
1752 
1753             if (sa->sa_family == AF_INET6) {
1754                 struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa);
1755 
1756                 sigar_net_address6_set(ifconfig->address6, inet6);
1757                 sigar_net_interface_scope6_set(ifconfig, inet6);
1758                 if (addrs->FirstPrefix) {
1759                     ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength;
1760                 }
1761                 return SIGAR_OK;
1762             }
1763         }
1764     }
1765     return SIGAR_ENOENT;
1766 #endif
1767 }
1768 
1769 SIGAR_DECLARE(int)
sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1770 sigar_net_interface_config_get(sigar_t *sigar,
1771                                const char *name,
1772                                sigar_net_interface_config_t *ifconfig)
1773 {
1774     MIB_IFROW *ifr;
1775     MIB_IPADDRROW *ipaddr;
1776     int status;
1777 
1778     if (!name) {
1779         return sigar_net_interface_config_primary_get(sigar, ifconfig);
1780     }
1781 
1782     status = get_mib_ifrow(sigar, name, &ifr);
1783     if (status != SIGAR_OK) {
1784         return status;
1785     }
1786 
1787     SIGAR_ZERO(ifconfig);
1788 
1789     SIGAR_SSTRCPY(ifconfig->name, name);
1790 
1791     ifconfig->mtu = ifr->dwMtu;
1792 
1793     sigar_net_address_mac_set(ifconfig->hwaddr,
1794                               ifr->bPhysAddr,
1795                               SIGAR_IFHWADDRLEN);
1796 
1797     SIGAR_SSTRCPY(ifconfig->description,
1798                   ifr->bDescr);
1799 
1800     if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) {
1801         ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING;
1802     }
1803 
1804     status = sigar_get_netif_ipaddr(sigar,
1805                                     ifr->dwIndex,
1806                                     &ipaddr);
1807 
1808     if (status == SIGAR_OK) {
1809         sigar_net_address_set(ifconfig->address,
1810                               ipaddr->dwAddr);
1811 
1812         sigar_net_address_set(ifconfig->netmask,
1813                               ipaddr->dwMask);
1814 
1815         if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) {
1816             if (ipaddr->dwBCastAddr) {
1817                 long bcast =
1818                     ipaddr->dwAddr & ipaddr->dwMask;
1819 
1820                 bcast |= ~ipaddr->dwMask;
1821                 ifconfig->flags |= SIGAR_IFF_BROADCAST;
1822 
1823                 sigar_net_address_set(ifconfig->broadcast,
1824                                       bcast);
1825             }
1826         }
1827     }
1828 
1829     /* hack for MS_LOOPBACK_ADAPTER */
1830     if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) {
1831         ifr->dwType = MIB_IF_TYPE_LOOPBACK;
1832     }
1833 
1834     if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
1835         ifconfig->flags |= SIGAR_IFF_LOOPBACK;
1836 
1837         SIGAR_SSTRCPY(ifconfig->type,
1838                       SIGAR_NIC_LOOPBACK);
1839     }
1840     else {
1841         if (ipaddr) {
1842             ifconfig->flags |= SIGAR_IFF_MULTICAST;
1843         }
1844 
1845         SIGAR_SSTRCPY(ifconfig->type,
1846                       SIGAR_NIC_ETHERNET);
1847     }
1848 
1849     sigar_net_interface_ipv6_config_init(ifconfig);
1850     sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig);
1851 
1852     return SIGAR_OK;
1853 }
1854 
1855 #define IS_TCP_SERVER(state, flags) \
1856     ((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN))
1857 
1858 #define IS_TCP_CLIENT(state, flags) \
1859     ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN))
1860 
1861 #define sigar_GetTcpTable \
1862     sigar->iphlpapi.get_tcp_table.func
1863 
net_conn_get_tcp(sigar_net_connection_walker_t *walker)1864 static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
1865 {
1866     sigar_t *sigar = walker->sigar;
1867     int flags = walker->flags;
1868     int i;
1869     DWORD rc, size=0;
1870     PMIB_TCPTABLE tcp;
1871 
1872     DLLMOD_INIT(iphlpapi, FALSE);
1873 
1874     if (!sigar_GetTcpTable) {
1875         return SIGAR_ENOTIMPL;
1876     }
1877 
1878     rc = sigar_GetTcpTable(NULL, &size, FALSE);
1879     if (rc != ERROR_INSUFFICIENT_BUFFER) {
1880         return GetLastError();
1881     }
1882     tcp = malloc(size);
1883     rc = sigar_GetTcpTable(tcp, &size, FALSE);
1884     if (rc) {
1885         free(tcp);
1886         return GetLastError();
1887     }
1888 
1889     /* go in reverse to get LISTEN states first */
1890     for (i = (tcp->dwNumEntries-1); i >= 0; i--) {
1891         sigar_net_connection_t conn;
1892         DWORD state = tcp->table[i].dwState;
1893 
1894         if (!(IS_TCP_SERVER(state, flags) ||
1895               IS_TCP_CLIENT(state, flags)))
1896         {
1897             continue;
1898         }
1899 
1900         conn.local_port  = htons((WORD)tcp->table[i].dwLocalPort);
1901         conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort);
1902 
1903         conn.type = SIGAR_NETCONN_TCP;
1904 
1905         sigar_net_address_set(conn.local_address,
1906                               tcp->table[i].dwLocalAddr);
1907 
1908         sigar_net_address_set(conn.remote_address,
1909                               tcp->table[i].dwRemoteAddr);
1910 
1911         conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
1912 
1913         switch (state) {
1914           case MIB_TCP_STATE_CLOSED:
1915             conn.state = SIGAR_TCP_CLOSE;
1916             break;
1917           case MIB_TCP_STATE_LISTEN:
1918             conn.state = SIGAR_TCP_LISTEN;
1919             break;
1920           case MIB_TCP_STATE_SYN_SENT:
1921             conn.state = SIGAR_TCP_SYN_SENT;
1922             break;
1923           case MIB_TCP_STATE_SYN_RCVD:
1924             conn.state = SIGAR_TCP_SYN_RECV;
1925             break;
1926           case MIB_TCP_STATE_ESTAB:
1927             conn.state = SIGAR_TCP_ESTABLISHED;
1928             break;
1929           case MIB_TCP_STATE_FIN_WAIT1:
1930             conn.state = SIGAR_TCP_FIN_WAIT1;
1931             break;
1932           case MIB_TCP_STATE_FIN_WAIT2:
1933             conn.state = SIGAR_TCP_FIN_WAIT2;
1934             break;
1935           case MIB_TCP_STATE_CLOSE_WAIT:
1936             conn.state = SIGAR_TCP_CLOSE_WAIT;
1937             break;
1938           case MIB_TCP_STATE_CLOSING:
1939             conn.state = SIGAR_TCP_CLOSING;
1940             break;
1941           case MIB_TCP_STATE_LAST_ACK:
1942             conn.state = SIGAR_TCP_LAST_ACK;
1943             break;
1944           case MIB_TCP_STATE_TIME_WAIT:
1945             conn.state = SIGAR_TCP_TIME_WAIT;
1946             break;
1947           case MIB_TCP_STATE_DELETE_TCB:
1948           default:
1949             conn.state = SIGAR_TCP_UNKNOWN;
1950             break;
1951         }
1952 
1953         if (walker->add_connection(walker, &conn) != SIGAR_OK) {
1954             break;
1955         }
1956     }
1957 
1958     free(tcp);
1959     return SIGAR_OK;
1960 }
1961 
net_conn_get_udp(sigar_net_connection_walker_t *walker)1962 static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
1963 {
1964     /* Disabled because it isn't properly implemented and
1965      * cause the windows runtime to abort due to use
1966      * of uninitialized variable in the for-loop below.
1967      * IS_UDP_SERVER(conn, flags) We don't use this
1968      * functionality anyway
1969      */
1970     return SIGAR_ENOTIMPL;
1971 }
1972 
1973 SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)1974 sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
1975 {
1976     int status;
1977 
1978     if (walker->flags & SIGAR_NETCONN_TCP) {
1979         status = net_conn_get_tcp(walker);
1980 
1981         if (status != SIGAR_OK) {
1982             return status;
1983         }
1984     }
1985 
1986     if (walker->flags & SIGAR_NETCONN_UDP) {
1987         status = net_conn_get_udp(walker);
1988 
1989         if (status != SIGAR_OK) {
1990             return status;
1991         }
1992     }
1993 
1994     return SIGAR_OK;
1995 }
1996