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