sigar/src/os/win32/win32_sigar.c

2735 lines
70 KiB
C
Raw Normal View History

2006-07-16 01:46:36 +08:00
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
2004-06-22 06:37:04 +08:00
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_pdh.h"
#include "sigar_os.h"
#include "sigar_util.h"
#include <shellapi.h>
#define USING_WIDE_S(s) (s)->using_wide
#define USING_WIDE() USING_WIDE_S(sigar)
#define PERFBUF_SIZE 8192
#define PERF_TITLE_PROC 230
#define PERF_TITLE_PROC_KEY "230"
#define PERF_TITLE_CPU_KEY "238"
2004-12-05 09:18:57 +08:00
#define PERF_TITLE_DISK_KEY "236"
2004-06-22 06:37:04 +08:00
#define PERF_TITLE_CPU_USER 142
#define PERF_TITLE_CPU_IDLE 1746
#define PERF_TITLE_CPU_SYS 144
typedef enum {
PERF_IX_CPU_USER,
PERF_IX_CPU_IDLE,
PERF_IX_CPU_SYS,
PERF_IX_CPU_MAX
} perf_cpu_offsets_t;
#define PERF_TITLE_CPUTIME 6
2005-11-24 01:51:19 +08:00
#define PERF_TITLE_PAGE_FAULTS 28
2004-06-22 06:37:04 +08:00
#define PERF_TITLE_MEM_VSIZE 174
#define PERF_TITLE_MEM_SIZE 180
#define PERF_TITLE_THREAD_CNT 680
#define PERF_TITLE_HANDLE_CNT 952
#define PERF_TITLE_PID 784
#define PERF_TITLE_PPID 1410
#define PERF_TITLE_PRIORITY 682
#define PERF_TITLE_START_TIME 684
typedef enum {
PERF_IX_CPUTIME,
2005-11-24 01:51:19 +08:00
PERF_IX_PAGE_FAULTS,
2004-06-22 06:37:04 +08:00
PERF_IX_MEM_VSIZE,
PERF_IX_MEM_SIZE,
PERF_IX_THREAD_CNT,
PERF_IX_HANDLE_CNT,
PERF_IX_PID,
PERF_IX_PPID,
PERF_IX_PRIORITY,
PERF_IX_START_TIME,
PERF_IX_MAX
} perf_proc_offsets_t;
2004-12-05 09:18:57 +08:00
typedef enum {
PERF_IX_DISK_READ,
PERF_IX_DISK_WRITE,
2005-04-07 09:23:49 +08:00
PERF_IX_DISK_READ_BYTES,
PERF_IX_DISK_WRITE_BYTES,
PERF_IX_DISK_QUEUE,
2004-12-05 09:18:57 +08:00
PERF_IX_DISK_MAX
} perf_disk_offsets_t;
#define PERF_TITLE_DISK_READ 208
#define PERF_TITLE_DISK_WRITE 210
2005-04-07 09:23:49 +08:00
#define PERF_TITLE_DISK_READ_BYTES 220
#define PERF_TITLE_DISK_WRITE_BYTES 222
2005-04-07 10:11:00 +08:00
#define PERF_TITLE_DISK_QUEUE 1028
2004-12-05 09:18:57 +08:00
2004-06-22 06:37:04 +08:00
/*
* diff is:
* ExW -> ExA
* wcounter -> counter
*/
#define MyRegQueryValue() \
(USING_WIDE() ? \
RegQueryValueExW(sigar->handle, \
wcounter_key, NULL, &type, \
sigar->perfbuf, \
&bytes) : \
2004-06-22 06:37:04 +08:00
RegQueryValueExA(sigar->handle, \
counter_key, NULL, &type, \
sigar->perfbuf, \
&bytes))
2004-06-22 06:37:04 +08:00
#define PERF_VAL(ix) \
perf_offsets[ix] ? \
*((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
2005-05-12 07:17:39 +08:00
/* 1/100ns units to seconds */
#define NS100_2SEC(t) ((t) / 10000000)
2005-05-12 07:37:22 +08:00
#define PERF_VAL_CPU(ix) \
NS100_2SEC(PERF_VAL(ix))
static DWORD perfbuf_init(sigar_t *sigar)
{
if (!sigar->perfbuf) {
sigar->perfbuf = malloc(PERFBUF_SIZE);
sigar->perfbuf_size = PERFBUF_SIZE;
}
return sigar->perfbuf_size;
}
static DWORD perfbuf_grow(sigar_t *sigar)
{
sigar->perfbuf_size += PERFBUF_SIZE;
sigar->perfbuf =
realloc(sigar->perfbuf, sigar->perfbuf_size);
return sigar->perfbuf_size;
}
static PERF_OBJECT_TYPE *get_perf_object(sigar_t *sigar, char *counter_key,
DWORD *err)
2004-06-22 06:37:04 +08:00
{
DWORD retval, type, bytes;
2004-06-22 06:37:04 +08:00
WCHAR wcounter_key[MAX_PATH+1];
PERF_DATA_BLOCK *block;
PERF_OBJECT_TYPE *object;
2004-06-22 06:37:04 +08:00
*err = SIGAR_OK;
2004-06-22 06:37:04 +08:00
if (USING_WIDE()) {
SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
}
bytes = perfbuf_init(sigar);
2004-06-22 06:37:04 +08:00
while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
if (retval == ERROR_MORE_DATA) {
bytes = perfbuf_grow(sigar);
2004-06-22 06:37:04 +08:00
}
else {
*err = retval;
2004-06-22 06:37:04 +08:00
return NULL;
}
}
block = (PERF_DATA_BLOCK *)sigar->perfbuf;
object = PdhFirstObject(block);
2004-06-22 06:37:04 +08:00
/*
* only seen on windows 2003 server when pdh.dll
* functions are in use by the same process.
* confucius say what the fuck.
*/
if (object->NumInstances == PERF_NO_INSTANCES) {
2005-01-29 00:33:12 +08:00
int i;
2005-01-29 00:33:12 +08:00
for (i=0; i<block->NumObjectTypes; i++) {
if (object->NumInstances != PERF_NO_INSTANCES) {
return object;
}
object = PdhNextObject(object);
}
return NULL;
}
else {
return object;
}
2004-06-22 06:37:04 +08:00
}
static void get_sysinfo(sigar_t *sigar)
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
sigar->ncpu = sysinfo.dwNumberOfProcessors;
sigar->pagesize = sysinfo.dwPageSize;
}
/* for C# bindings */
SIGAR_DECLARE(sigar_t *) sigar_new(void)
{
sigar_t *sigar;
if (sigar_open(&sigar) != SIGAR_OK) {
return NULL;
}
return sigar;
}
2005-12-21 07:09:34 +08:00
static sigar_wtsapi_t sigar_wtsapi = {
"wtsapi32.dll",
NULL,
{ "WTSEnumerateSessionsA", NULL },
{ "WTSFreeMemory", NULL },
{ "WTSQuerySessionInformationA", NULL },
{ NULL, NULL }
};
static sigar_iphlpapi_t sigar_iphlpapi = {
"iphlpapi.dll",
NULL,
{ "GetIpForwardTable", NULL },
{ "GetIfTable", NULL },
{ "GetIfEntry", NULL },
{ "GetTcpTable", NULL },
{ "GetUdpTable", NULL },
{ "AllocateAndGetTcpExTableFromStack", NULL },
{ "AllocateAndGetUdpExTableFromStack", NULL },
{ "GetNetworkParams", NULL },
{ "GetAdaptersInfo", NULL },
{ NULL, NULL }
};
static sigar_advapi_t sigar_advapi = {
"advapi32.dll",
NULL,
{ "ConvertStringSidToSidA", NULL },
{ "QueryServiceStatusEx", NULL },
{ NULL, NULL }
};
static sigar_ntdll_t sigar_ntdll = {
"ntdll.dll",
NULL,
{ "NtQuerySystemInformation", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_psapi = {
"psapi.dll",
NULL,
{ "EnumProcessModules", NULL },
{ "EnumProcesses", NULL },
2005-12-21 07:09:34 +08:00
{ "GetModuleFileNameExA", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_winsta = {
"winsta.dll",
NULL,
{ "WinStationQueryInformationW", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_kernel = {
"kernel32.dll",
NULL,
{ "GlobalMemoryStatusEx", NULL },
{ NULL, NULL }
};
2005-12-21 07:09:34 +08:00
#define DLLMOD_COPY(name) \
2005-12-21 12:58:02 +08:00
memcpy(&(sigar->##name), &sigar_##name, sizeof(sigar_##name))
2005-12-21 07:09:34 +08:00
#define DLLMOD_INIT(name, all) \
sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->##name), all)
#define DLLMOD_FREE(name) \
sigar_dllmod_free((sigar_dll_module_t *)&(sigar->##name))
static void sigar_dllmod_free(sigar_dll_module_t *module)
{
if (module->handle) {
FreeLibrary(module->handle);
module->handle = NULL;
}
}
static int sigar_dllmod_init(sigar_t *sigar,
sigar_dll_module_t *module,
int all)
{
sigar_dll_func_t *funcs = &module->funcs[0];
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
int rc, success;
if (module->handle == INVALID_HANDLE_VALUE) {
return ENOENT; /* XXX better rc */
}
if (module->handle) {
return SIGAR_OK;
}
module->handle = LoadLibrary(module->name);
if (!(success = (module->handle ? TRUE : FALSE))) {
rc = GetLastError();
/* dont try again */
module->handle = INVALID_HANDLE_VALUE;
}
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"LoadLibrary(%s): %s",
module->name,
success ?
"OK" :
sigar_strerror(sigar, rc));
}
if (!success) {
return rc;
}
while (funcs->name) {
funcs->func = GetProcAddress(module->handle, funcs->name);
if (!(success = (funcs->func ? TRUE : FALSE))) {
rc = GetLastError();
}
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetProcAddress(%s:%s): %s",
module->name, funcs->name,
success ?
"OK" :
sigar_strerror(sigar, rc));
}
if (all && !success) {
return rc;
}
funcs++;
}
return SIGAR_OK;
}
2005-12-21 12:58:02 +08:00
int sigar_os_open(sigar_t **sigar_ptr)
2004-06-22 06:37:04 +08:00
{
LONG result;
HINSTANCE h;
OSVERSIONINFO version;
2005-12-21 07:09:34 +08:00
int i;
2005-12-21 12:58:02 +08:00
sigar_t *sigar;
2004-06-22 06:37:04 +08:00
2005-12-21 12:58:02 +08:00
*sigar_ptr = sigar = malloc(sizeof(*sigar));
sigar->machine = ""; /* local machine */
sigar->using_wide = 0; /*XXX*/
2004-06-22 06:37:04 +08:00
2005-12-21 12:58:02 +08:00
sigar->perfbuf = NULL;
sigar->perfbuf_size = 0;
2004-06-22 06:37:04 +08:00
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
2004-07-01 05:20:19 +08:00
2004-07-01 06:43:48 +08:00
/*
* 4 == NT 4.0
* 5 == 2000, XP, 2003 Server
*/
2005-12-21 12:58:02 +08:00
sigar->winnt = (version.dwMajorVersion == 4);
2005-12-21 12:58:02 +08:00
if (USING_WIDE_S(sigar)) {
2004-06-22 06:37:04 +08:00
WCHAR wmachine[MAX_PATH+1];
2005-12-21 12:58:02 +08:00
SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine));
2004-06-22 06:37:04 +08:00
result = RegConnectRegistryW(wmachine,
HKEY_PERFORMANCE_DATA,
2005-12-21 12:58:02 +08:00
&sigar->handle);
2004-06-22 06:37:04 +08:00
}
else {
2005-12-21 12:58:02 +08:00
result = RegConnectRegistryA(sigar->machine,
2004-06-22 06:37:04 +08:00
HKEY_PERFORMANCE_DATA,
2005-12-21 12:58:02 +08:00
&sigar->handle);
2004-06-22 06:37:04 +08:00
}
2005-12-21 12:58:02 +08:00
get_sysinfo(sigar);
2004-06-22 06:37:04 +08:00
2005-12-21 07:09:34 +08:00
DLLMOD_COPY(wtsapi);
DLLMOD_COPY(iphlpapi);
DLLMOD_COPY(advapi);
DLLMOD_COPY(ntdll);
DLLMOD_COPY(psapi);
DLLMOD_COPY(winsta);
DLLMOD_COPY(kernel);
2005-12-21 12:58:02 +08:00
sigar->log_level = -1; /* else below segfaults */
2005-12-21 07:09:34 +08:00
/* XXX init early for use by javasigar.c */
2005-12-21 12:58:02 +08:00
sigar_dllmod_init(sigar,
(sigar_dll_module_t *)&sigar->advapi,
2005-12-21 07:09:34 +08:00
FALSE);
2005-12-21 12:58:02 +08:00
sigar->pinfo.pid = -1;
sigar->ws_version = 0;
sigar->ncpu = 0;
sigar->peb = NULL;
2004-06-22 06:37:04 +08:00
return result;
}
int sigar_os_close(sigar_t *sigar)
{
int retval;
2005-12-21 07:09:34 +08:00
DLLMOD_FREE(wtsapi);
DLLMOD_FREE(iphlpapi);
DLLMOD_FREE(advapi);
DLLMOD_FREE(ntdll);
DLLMOD_FREE(psapi);
DLLMOD_FREE(winsta);
DLLMOD_FREE(kernel);
2005-12-21 07:09:34 +08:00
2004-06-22 06:37:04 +08:00
if (sigar->perfbuf) {
free(sigar->perfbuf);
}
retval = RegCloseKey(sigar->handle);
if (sigar->ws_version != 0) {
WSACleanup();
}
if (sigar->peb) {
free(sigar->peb);
}
free(sigar);
return retval;
}
2005-03-12 14:19:34 +08:00
char *sigar_os_error_string(sigar_t *sigar, int err)
2004-06-22 06:37:04 +08:00
{
switch (err) {
case SIGAR_NO_SUCH_PROCESS:
return "No such process";
break;
}
2004-06-22 06:37:04 +08:00
return NULL;
}
#define sigar_GlobalMemoryStatusEx \
sigar->kernel.memory_status.func
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
DLLMOD_INIT(kernel, TRUE);
2004-06-22 06:37:04 +08:00
if (sigar_GlobalMemoryStatusEx) {
MEMORYSTATUSEX memstat;
memstat.dwLength = sizeof(memstat);
if (!sigar_GlobalMemoryStatusEx(&memstat)) {
return GetLastError();
}
mem->total = memstat.ullTotalPhys;
mem->free = memstat.ullAvailPhys;
}
else {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
mem->total = memstat.dwTotalPhys;
mem->free = memstat.dwAvailPhys;
}
2004-06-22 06:37:04 +08:00
mem->used = mem->total - mem->free;
2004-06-22 06:37:04 +08:00
sigar_mem_calc_ram(sigar, mem);
mem->actual_free = mem->free;
mem->actual_used = mem->used;
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
swap->total = memstat.dwTotalPageFile;
swap->free = memstat.dwAvailPageFile;
swap->used = swap->total - swap->free;
return SIGAR_OK;
}
static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
DWORD *perf_offsets,
DWORD *num, DWORD *err)
2004-06-22 06:37:04 +08:00
{
PERF_OBJECT_TYPE *object = get_perf_object(sigar, "238", err);
2004-06-22 06:37:04 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i;
if (!object) {
return NULL;
}
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_CPU_SYS:
perf_offsets[PERF_IX_CPU_SYS] = offset;
break;
case PERF_TITLE_CPU_USER:
perf_offsets[PERF_IX_CPU_USER] = offset;
break;
case PERF_TITLE_CPU_IDLE:
perf_offsets[PERF_IX_CPU_IDLE] = offset;
break;
}
}
if (num) {
*num = object->NumInstances;
}
return PdhFirstInstance(object);
}
2005-12-21 07:09:34 +08:00
#define sigar_NtQuerySystemInformation \
sigar->ntdll.query_sys_info.func
static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
DWORD idx,
PERF_COUNTER_BLOCK *counter_block,
DWORD *perf_offsets)
{
cpu->idle = 0;
if (perf_offsets[PERF_IX_CPU_IDLE]) {
2005-05-12 07:37:22 +08:00
cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE);
}
else {
/* windows NT and 2000 do not have an Idle counter */
sigar_cpu_count(sigar);
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
DWORD retval, num;
/* XXX unhardcode 16 */
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
/* into the lungs of hell */
2005-12-21 07:09:34 +08:00
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
if (idx == -1) {
int i;
for (i=0; i<num; i++) {
2005-05-12 07:17:39 +08:00
cpu->idle += NS100_2SEC(info[i].IdleTime.QuadPart);
}
}
else if (idx < num) {
2005-05-12 07:17:39 +08:00
cpu->idle = NS100_2SEC(info[idx].IdleTime.QuadPart);
}
else {
return ERROR_INVALID_DATA;
}
}
else {
return ERROR_INVALID_FUNCTION;
}
}
return SIGAR_OK;
}
static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
2004-06-22 06:37:04 +08:00
{
int status;
2004-06-22 06:37:04 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_BLOCK *counter_block;
DWORD perf_offsets[PERF_IX_CPU_MAX], err;
2004-06-22 06:37:04 +08:00
SIGAR_ZERO(cpu);
memset(&perf_offsets, 0, sizeof(perf_offsets));
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
2004-06-22 06:37:04 +08:00
if (!inst) {
2004-08-28 07:06:46 +08:00
return err;
2004-06-22 06:37:04 +08:00
}
/* first instance is total, rest are per-cpu */
counter_block = PdhGetCounterBlock(inst);
2005-05-12 07:37:22 +08:00
cpu->sys = PERF_VAL_CPU(PERF_IX_CPU_SYS);
cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER);
status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
2004-06-22 06:37:04 +08:00
cpu->nice = 0; /* no nice here */
2004-11-22 09:51:34 +08:00
cpu->wait = 0; /*N/A?*/
cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait;
if (status != SIGAR_OK) {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
"unable to determine idle cpu time: %s",
sigar_strerror(sigar, status));
}
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
DWORD retval, num;
int i;
/* XXX unhardcode 16 */
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
/* into the lungs of hell */
2005-12-21 07:09:34 +08:00
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
SIGAR_ZERO(cpu);
for (i=0; i<num; i++) {
2005-05-12 07:17:39 +08:00
cpu->idle += NS100_2SEC(info[i].IdleTime.QuadPart);
cpu->user += NS100_2SEC(info[i].UserTime.QuadPart);
cpu->sys += NS100_2SEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
cpu->total += cpu->idle + cpu->user + cpu->sys;
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
return sigar_cpu_ntsys_get(sigar, cpu);
}
else {
return sigar_cpu_perflib_get(sigar, cpu);
}
}
static int sigar_cpu_list_perflib_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
2004-06-22 06:37:04 +08:00
{
int status, i, j, hthread=0;
PERF_INSTANCE_DEFINITION *inst;
DWORD perf_offsets[PERF_IX_CPU_MAX], num, err;
2004-06-22 06:37:04 +08:00
memset(&perf_offsets, 0, sizeof(perf_offsets));
/* first instance is total, rest are per-cpu */
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err);
2004-06-22 06:37:04 +08:00
if (!inst) {
return err;
2004-06-22 06:37:04 +08:00
}
if (!sigar->winnt) {
/* skip Processor _Total instance (NT doesnt have one) */
--num;
inst = PdhNextInstance(inst);
}
2004-06-22 06:37:04 +08:00
sigar_cpu_count(sigar);
sigar_cpu_list_create(cpulist);
/*
* if hyper-threading was detected and ncpu is less than
* the number of counter instances, assume there is a counter
* for each logical processor.
* XXX assuming this is correct until have something to test on.
*/
if (sigar->ht_enabled && ((sigar->ncpu * sigar->lcpu) == num)) {
2004-06-22 06:37:04 +08:00
hthread = 1;
}
for (i=0; i<num; i++) {
PERF_COUNTER_BLOCK *counter_block;
sigar_cpu_t *cpu;
if (hthread && (i % sigar->lcpu)) {
2004-06-22 06:37:04 +08:00
/* merge times of logical processors */
cpu = &cpulist->data[cpulist->number-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
counter_block = PdhGetCounterBlock(inst);
2005-05-12 07:37:22 +08:00
cpu->sys += PERF_VAL_CPU(PERF_IX_CPU_SYS);
cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER);
get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
cpu->nice = cpu->wait = 0; /*N/A*/
/*XXX adding up too much here if xeon, but not using this atm*/
2004-06-22 06:37:04 +08:00
cpu->total += cpu->sys + cpu->user + cpu->idle;
inst = PdhNextInstance(inst);
2004-06-22 06:37:04 +08:00
}
return SIGAR_OK;
}
static int sigar_cpu_list_ntsys_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
DWORD retval, num;
int status, i, j, hthread=0;
/* XXX unhardcode 16 */
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
/* into the lungs of hell */
2005-12-21 07:09:34 +08:00
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
sigar_cpu_count(sigar);
sigar_cpu_list_create(cpulist);
/*
* if hyper-threading was detected and ncpu is less than
* the number of counter instances, assume there is a counter
* for each logical processor.
* XXX assuming this is correct until have something to test on.
*/
if (sigar->ht_enabled && ((sigar->ncpu * sigar->lcpu) == num)) {
hthread = 1;
}
for (i=0; i<num; i++) {
sigar_cpu_t *cpu;
sigar_uint64_t idle, user, sys;
if (hthread && (i % sigar->lcpu)) {
/* merge times of logical processors */
cpu = &cpulist->data[cpulist->number-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
2005-05-12 07:17:39 +08:00
idle = NS100_2SEC(info[i].IdleTime.QuadPart);
user = NS100_2SEC(info[i].UserTime.QuadPart);
sys = NS100_2SEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
cpu->idle += idle;
cpu->user += user;
cpu->sys += sys;
cpu->nice = cpu->wait = 0; /*N/A*/
cpu->total += idle + user + sys;
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
return sigar_cpu_list_ntsys_get(sigar, cpulist);
}
else {
return sigar_cpu_list_perflib_get(sigar, cpulist);
}
}
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
uptime->uptime = GetTickCount() / 1000;
return SIGAR_OK;
}
/*
* there is no api for this info.
* closest i've seen is enumerating the entire process table
* and calculating an average based on process times.
*/
SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
return SIGAR_ENOTIMPL;
}
#define get_process_object(sigar, err) \
get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
2004-06-22 06:37:04 +08:00
static int sigar_proc_list_get_perf(sigar_t *sigar,
sigar_proc_list_t *proclist)
2004-06-22 06:37:04 +08:00
{
2004-06-22 06:37:04 +08:00
PERF_OBJECT_TYPE *object;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, err;
2004-06-22 06:37:04 +08:00
DWORD perf_offsets[PERF_IX_MAX];
perf_offsets[PERF_IX_PID] = 0;
object = get_process_object(sigar, &err);
2004-06-22 06:37:04 +08:00
if (!object) {
return err;
2004-06-22 06:37:04 +08:00
}
/*
* note we assume here:
* block->NumObjectTypes == 1
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
*
* which should always be the case.
*/
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_PID:
perf_offsets[PERF_IX_PID] = offset;
break;
}
}
sigar_proc_list_create(proclist);
2004-06-22 06:37:04 +08:00
for (i=0, inst = PdhFirstInstance(object);
i<object->NumInstances;
i++, inst = PdhNextInstance(inst))
{
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
DWORD pid = PERF_VAL(PERF_IX_PID);
if (pid == 0) {
continue; /* dont include the system Idle process */
}
2004-06-22 06:37:04 +08:00
SIGAR_PROC_LIST_GROW(proclist);
proclist->data[proclist->number++] = pid;
2004-06-22 06:37:04 +08:00
}
return SIGAR_OK;
}
#define sigar_EnumProcesses \
sigar->psapi.enum_processes.func
SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
DLLMOD_INIT(psapi, FALSE);
if (sigar_EnumProcesses) {
DWORD retval, *pids;
DWORD size = 0, i;
do {
/* re-use the perfbuf */
if (size == 0) {
size = perfbuf_init(sigar);
}
else {
size = perfbuf_grow(sigar);
}
if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf,
sigar->perfbuf_size,
&retval))
{
return GetLastError();
}
} while (retval == sigar->perfbuf_size); //unlikely
pids = (DWORD *)sigar->perfbuf;
proclist->number = 0;
proclist->size = retval / sizeof(DWORD);
proclist->data =
malloc(sizeof(*(proclist->data)) * proclist->size);
for (i=0; i<proclist->size; i++) {
DWORD pid = pids[i];
if (pid == 0) {
continue; /* dont include the system Idle process */
}
proclist->data[proclist->number++] = pid;
}
return SIGAR_OK;
}
else {
return sigar_proc_list_get_perf(sigar, proclist);
}
}
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
sigar_proc_stat_t *procstat)
{
int status = /* XXX optimize */
sigar_proc_count(sigar, &procstat->total);
return status;
}
#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
static HANDLE open_process(sigar_pid_t pid)
{
return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
}
2006-03-04 10:23:02 +08:00
/*
* Pretty good explanation of counters:
* http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory
*/
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
int status = get_proc_info(sigar, pid);
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
2006-03-04 10:23:02 +08:00
procmem->size = pinfo->size; /* "Virtual Bytes" */
procmem->resident = pinfo->resident; /* "Working Set" */
procmem->share = SIGAR_FIELD_NOTIMPL;
2005-11-24 01:51:19 +08:00
procmem->page_faults = pinfo->page_faults;
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
SIGAR_DECLARE(int)
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_name_t *proccredname)
{
HANDLE proc, token;
DWORD len;
int success;
TOKEN_USER *user = NULL;
TOKEN_PRIMARY_GROUP *group = NULL;
SID_NAME_USE type;
char domain[SIGAR_CRED_NAME_MAX];
/* XXX cache lookup */
if (!(proc = open_process(pid))) {
return GetLastError();
}
if (!OpenProcessToken(proc, TOKEN_DAC, &token)) {
CloseHandle(proc);
return GetLastError();
}
CloseHandle(proc);
success =
!GetTokenInformation(token, TokenUser, NULL, 0, &len) &&
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(user = malloc(len)) &&
GetTokenInformation(token, TokenUser, user, len, &len);
if (success) {
DWORD domain_len = sizeof(domain);
DWORD user_len = sizeof(proccredname->user);
success = LookupAccountSid(NULL, user->User.Sid,
proccredname->user, &user_len,
domain, &domain_len, &type);
}
if (user != NULL) {
free(user);
}
if (!success) {
CloseHandle(token);
return GetLastError();
}
success =
!GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) &&
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(group = malloc(len)) &&
GetTokenInformation(token, TokenPrimaryGroup, group, len, &len);
if (success) {
DWORD domain_len = sizeof(domain);
DWORD group_len = sizeof(proccredname->group);
success = LookupAccountSid(NULL, group->PrimaryGroup,
proccredname->group, &group_len,
domain, &domain_len, &type);
}
if (group != NULL) {
free(group);
}
CloseHandle(token);
if (!success) {
return GetLastError();
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
return SIGAR_ENOTIMPL;
}
#define FILETIME2SEC(ft) \
2005-05-12 07:17:39 +08:00
NS100_2SEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime))
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
HANDLE proc = open_process(pid);
FILETIME start_time, exit_time, system_time, user_time;
if (!proc) {
return GetLastError();
}
if (!GetProcessTimes(proc,
&start_time, &exit_time,
&system_time, &user_time))
{
return GetLastError();
}
CloseHandle(proc);
if (start_time.dwHighDateTime) {
proctime->start_time = FileTimeToTime(&start_time) / 1000;
}
else {
proctime->start_time = 0;
}
proctime->user = FILETIME2SEC(user_time);
proctime->sys = FILETIME2SEC(system_time);
proctime->total = proctime->user + proctime->sys;
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = get_proc_info(sigar, pid);
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
memcpy(procstate->name, pinfo->name, sizeof(procstate->name));
procstate->state = pinfo->state;
procstate->ppid = pinfo->ppid;
procstate->priority = pinfo->priority;
procstate->nice = SIGAR_FIELD_NOTIMPL;
procstate->tty = SIGAR_FIELD_NOTIMPL;
2005-11-23 05:48:52 +08:00
procstate->threads = pinfo->threads;
2005-11-23 09:28:51 +08:00
procstate->processor = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
static int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
{
PERF_OBJECT_TYPE *object;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, err;
2004-06-22 06:37:04 +08:00
DWORD perf_offsets[PERF_IX_MAX];
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
time_t timenow = time(NULL);
if (pinfo->pid == pid) {
if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
memset(&perf_offsets, 0, sizeof(perf_offsets));
object = get_process_object(sigar, &err);
if (object == NULL) {
return err;
}
2004-06-22 06:37:04 +08:00
pinfo->pid = pid;
pinfo->mtime = timenow;
2004-06-22 06:37:04 +08:00
/*
* note we assume here:
* block->NumObjectTypes == 1
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
*
* which should always be the case.
*/
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_CPUTIME:
perf_offsets[PERF_IX_CPUTIME] = offset;
break;
2005-11-24 01:51:19 +08:00
case PERF_TITLE_PAGE_FAULTS:
perf_offsets[PERF_IX_PAGE_FAULTS] = offset;
break;
2004-06-22 06:37:04 +08:00
case PERF_TITLE_MEM_VSIZE:
perf_offsets[PERF_IX_MEM_VSIZE] = offset;
break;
case PERF_TITLE_MEM_SIZE:
perf_offsets[PERF_IX_MEM_SIZE] = offset;
break;
case PERF_TITLE_THREAD_CNT:
perf_offsets[PERF_IX_THREAD_CNT] = offset;
break;
case PERF_TITLE_HANDLE_CNT:
perf_offsets[PERF_IX_HANDLE_CNT] = offset;
break;
case PERF_TITLE_PID:
perf_offsets[PERF_IX_PID] = offset;
break;
case PERF_TITLE_PPID:
perf_offsets[PERF_IX_PPID] = offset;
break;
case PERF_TITLE_PRIORITY:
perf_offsets[PERF_IX_PRIORITY] = offset;
break;
case PERF_TITLE_START_TIME:
perf_offsets[PERF_IX_START_TIME] = offset;
break;
}
}
for (i=0, inst = PdhFirstInstance(object);
i<object->NumInstances;
i++, inst = PdhNextInstance(inst))
{
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID);
if (this_pid != pid) {
continue;
}
pinfo->state = 'R'; /* XXX? */
SIGAR_W2A(PdhInstanceName(inst),
pinfo->name, sizeof(pinfo->name));
2006-03-04 10:23:02 +08:00
pinfo->size = PERF_VAL(PERF_IX_MEM_VSIZE);
pinfo->resident = PERF_VAL(PERF_IX_MEM_SIZE);
2004-06-22 06:37:04 +08:00
pinfo->ppid = PERF_VAL(PERF_IX_PPID);
pinfo->priority = PERF_VAL(PERF_IX_PRIORITY);
pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT);
2005-11-23 05:48:52 +08:00
pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT);
2005-11-24 01:51:19 +08:00
pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
return SIGAR_NO_SUCH_PROCESS;
2004-06-22 06:37:04 +08:00
}
2004-07-29 05:47:14 +08:00
static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
int status;
2004-08-03 10:45:26 +08:00
char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg;
2004-07-29 05:47:14 +08:00
HANDLE proc = open_process(pid);
if (!proc) {
return GetLastError();
}
status = sigar_proc_args_peb_get(sigar, proc, procargs);
2004-07-29 05:47:14 +08:00
CloseHandle(proc);
return status;
2004-07-29 05:47:14 +08:00
}
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
if (pid == sigar->pid) {
return sigar_parse_proc_args(sigar, NULL, procargs);
2004-06-22 06:37:04 +08:00
}
else {
return sigar_remote_proc_args_get(sigar, pid, procargs);
}
}
static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
UCHAR *ptr, *env;
env = ptr = (UCHAR*)GetEnvironmentStrings();
while (*ptr) {
char *val;
int klen, vlen, status;
char key[128]; /* XXX is there a max key size? */
if (*ptr == '=') {
ptr += strlen(ptr)+1;
continue;
}
val = strchr(ptr, '=');
if (val == NULL) {
break; /*XXX*/
}
klen = val - ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
ptr += klen + 1 + vlen + 1;
}
FreeEnvironmentStrings(env);
return SIGAR_OK;
}
static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
FARPROC rgetenv, fstrlen;
HANDLE proc, thread, kdll;
PVOID data=NULL;
const char *key;
char *value;
DWORD rv, thrid, bytes, datalen=0, size;
LPVOID addr;
if (!(kdll = GetModuleHandle("msvcrt.dll"))) {
return GetLastError();
}
if (!(rgetenv = GetProcAddress(kdll, "getenv"))) {
return GetLastError();
}
if (!(kdll = GetModuleHandle("kernel32.dll"))) {
return GetLastError();
}
if (!(fstrlen = GetProcAddress(kdll, "lstrlenA"))) {
return GetLastError();
}
if (!(proc = OpenProcess(MAXIMUM_ALLOWED, 0, (DWORD)pid))) {
return GetLastError();
}
key = procenv->key;
size = procenv->klen+1;
addr = VirtualAllocEx(proc, NULL, size,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!addr) {
CloseHandle(proc);
return GetLastError();
}
if (!WriteProcessMemory(proc, addr, (char*)&key[0], size, 0)) {
VirtualFreeEx(proc, addr, size, 0);
CloseHandle(proc);
return GetLastError();
}
thread = CreateRemoteThread(proc, NULL, 0,
(LPTHREAD_START_ROUTINE)rgetenv,
addr, 0, &thrid);
if (!thread) {
VirtualFreeEx(proc, addr, size, 0);
CloseHandle(proc);
return GetLastError();
}
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, (LPDWORD)(&data));
CloseHandle(thread);
VirtualFreeEx(proc, addr, size, 0);
if (!data) {
CloseHandle(proc);
return SIGAR_OK;
}
thread = CreateRemoteThread(proc, NULL, 0,
(LPTHREAD_START_ROUTINE)fstrlen,
data, 0, &thrid);
if (!thread) {
CloseHandle(proc);
return GetLastError();
}
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, &datalen);
CloseHandle(thread);
if (!datalen) {
CloseHandle(proc);
return GetLastError();
}
value = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
datalen);
if (!value) {
CloseHandle(proc);
return GetLastError();
}
if (ReadProcessMemory(proc, data, value,
datalen+1, &bytes))
{
procenv->env_getter(procenv->data,
key, strlen(key),
value, bytes-1);
HeapFree(GetProcessHeap(), 0, value);
}
else {
CloseHandle(proc);
return GetLastError();
}
CloseHandle(proc);
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
if (pid == sigar->pid) {
if (procenv->type == SIGAR_PROC_ENV_KEY) {
char value[32767]; /* max size from msdn docs */
DWORD retval =
GetEnvironmentVariable(procenv->key, value, sizeof(value));
if (retval == 0) {
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
return SIGAR_OK;
}
return GetLastError();
}
else if (retval > sizeof(value)) {
/* XXX shouldnt happen */
return GetLastError();
}
procenv->env_getter(procenv->data,
procenv->key, procenv->klen,
value, retval);
return SIGAR_OK;
}
else {
return sigar_local_proc_env_get(sigar, pid, procenv);
}
}
else {
if (procenv->type == SIGAR_PROC_ENV_KEY) {
return sigar_remote_proc_env_get(sigar, pid, procenv);
}
else {
return SIGAR_ENOTIMPL;
}
}
}
SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
int status;
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
pinfo->pid = -1; /* force update */
if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) {
return status;
}
procfd->total = pinfo->handles;
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
int status = SIGAR_OK;
HANDLE proc = open_process(pid);
if (!proc) {
return GetLastError();
}
2004-08-02 04:31:42 +08:00
status = sigar_proc_exe_peb_get(sigar, proc, procexe);
2004-08-02 04:42:18 +08:00
if (procexe->cwd[0] != '\0') {
/* strip trailing '\' */
int len = strlen(procexe->cwd);
if (procexe->cwd[len-1] == '\\') {
procexe->cwd[len-1] = '\0';
}
/* uppercase driver letter */
procexe->cwd[0] = toupper(procexe->cwd[0]);
/* e.g. C:\ */
strncpy(procexe->root, procexe->cwd, 3);
procexe->root[3] = '\0';
}
else {
procexe->root[0] = '\0';
}
if (procexe->name[0] != '\0') {
/* uppercase driver letter */
procexe->name[0] = toupper(procexe->name[0]);
}
2004-06-22 06:37:04 +08:00
return status;
}
2005-12-21 07:09:34 +08:00
#define sigar_EnumProcessModules \
sigar->psapi.enum_modules.func
#define sigar_GetModuleFileNameEx \
sigar->psapi.get_module_name.func
SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
2004-06-22 14:12:51 +08:00
{
HANDLE proc;
HMODULE modules[1024];
DWORD size = 0;
unsigned int i;
2004-06-22 14:12:51 +08:00
2005-12-21 07:09:34 +08:00
if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) {
return SIGAR_ENOTIMPL;
2004-06-22 14:12:51 +08:00
}
if (!(proc = open_process(pid))) {
2004-06-22 14:12:51 +08:00
return GetLastError();
}
2005-12-21 07:09:34 +08:00
if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) {
CloseHandle(proc);
2004-06-22 14:12:51 +08:00
return GetLastError();
}
for (i=0; i<(size/sizeof(HMODULE)); i++) {
int status;
char name[MAX_PATH];
2004-06-22 14:12:51 +08:00
2005-12-21 07:09:34 +08:00
if (!sigar_GetModuleFileNameEx(proc, modules[i],
name, sizeof(name)))
{
continue;
}
2004-06-22 14:12:51 +08:00
status = procmods->module_getter(procmods->data,
name, strlen(name));
2004-06-22 14:12:51 +08:00
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
}
2004-06-22 14:12:51 +08:00
CloseHandle(proc);
2004-06-22 14:12:51 +08:00
return SIGAR_OK;
}
2004-11-17 12:56:00 +08:00
#define FT2INT64(ft) \
((__int64)((__int64)(ft).dwHighDateTime << 32 | \
(__int64)(ft).dwLowDateTime))
SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
FILETIME start, exit, sys, user;
DWORD retval;
if (id != 0) {
return SIGAR_ENOTIMPL;
}
retval = GetThreadTimes(GetCurrentThread(),
&start, &exit, &sys, &user);
if (retval == 0) {
return GetLastError();
}
cpu->user = FT2INT64(user) * 100;
cpu->sys = FT2INT64(sys) * 100;
cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100;
return SIGAR_OK;
}
2004-06-22 06:37:04 +08:00
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
return fsp->type;
}
SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
sigar_file_system_t *fsp;
char name[256];
char *ptr = name;
/* XXX: hmm, Find{First,Next}Volume not available in my sdk */
DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
if (len == 0) {
return GetLastError();
}
sigar_file_system_list_create(fslist);
while (*ptr) {
DWORD flags, serialnum=0;
char fsname[1024];
UINT type;
fsname[0] = '\0';
GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
&flags, fsname, sizeof(fsname));
type = GetDriveType(ptr);
if (!serialnum && (type == DRIVE_FIXED)) {
ptr += strlen(ptr)+1;
continue; /* ignore unformatted partitions */
}
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
SIGAR_SSTRCPY(fsp->dir_name, ptr);
SIGAR_SSTRCPY(fsp->dev_name, ptr);
switch (type) {
case DRIVE_FIXED:
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
break;
case DRIVE_REMOTE:
fsp->type = SIGAR_FSTYPE_NETWORK;
break;
case DRIVE_CDROM:
fsp->type = SIGAR_FSTYPE_CDROM;
break;
case DRIVE_RAMDISK:
fsp->type = SIGAR_FSTYPE_RAM_DISK;
break;
case DRIVE_REMOVABLE:
/* XXX */
default:
fsp->type = SIGAR_FSTYPE_NONE;
break;
}
/* we set fsp->type, just looking up sigar.c:fstype_names[type] */
sigar_fs_type_get(fsp);
if (*fsname == '\0') {
SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name);
}
else {
SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */
}
ptr += strlen(ptr)+1;
}
return SIGAR_OK;
}
2004-12-05 09:18:57 +08:00
static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar,
DWORD *perf_offsets,
DWORD *num, DWORD *err)
{
PERF_OBJECT_TYPE *object =
get_perf_object(sigar, PERF_TITLE_DISK_KEY, err);
2004-12-05 09:18:57 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, found=0;
2004-12-05 09:18:57 +08:00
if (!object) {
return NULL;
}
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_DISK_READ:
perf_offsets[PERF_IX_DISK_READ] = offset;
found = 1;
2004-12-05 09:18:57 +08:00
break;
case PERF_TITLE_DISK_WRITE:
perf_offsets[PERF_IX_DISK_WRITE] = offset;
found = 1;
2004-12-05 09:18:57 +08:00
break;
2005-04-07 09:23:49 +08:00
case PERF_TITLE_DISK_READ_BYTES:
perf_offsets[PERF_IX_DISK_READ_BYTES] = offset;
found = 1;
2005-04-07 09:23:49 +08:00
break;
case PERF_TITLE_DISK_WRITE_BYTES:
perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset;
found = 1;
2005-04-07 09:23:49 +08:00
break;
case PERF_TITLE_DISK_QUEUE:
perf_offsets[PERF_IX_DISK_QUEUE] = offset;
found = 1;
2005-04-07 09:23:49 +08:00
break;
2004-12-05 09:18:57 +08:00
}
}
if (!found) {
*err = ENOENT;
return NULL;
}
2004-12-05 09:18:57 +08:00
if (num) {
*num = object->NumInstances;
}
return PdhFirstInstance(object);
}
static int get_disk_metrics(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
DWORD i, err;
PERF_OBJECT_TYPE *object =
get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err);
2004-12-05 09:18:57 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD perf_offsets[PERF_IX_DISK_MAX];
if (!object) {
return err;
}
memset(&perf_offsets, 0, sizeof(perf_offsets));
inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
if (!inst) {
return err;
}
for (i=0, inst = PdhFirstInstance(object);
i<object->NumInstances;
i++, inst = PdhNextInstance(inst))
{
char drive[MAX_PATH];
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset);
SIGAR_W2A(name, drive, sizeof(drive));
2005-04-28 02:54:42 +08:00
if (sigar_isdigit(*name)) {
char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */
if (ptr) {
++ptr;
SIGAR_SSTRCPY(drive, ptr);
}
else {
/* XXX NT is a number only "0", how to map? */
}
}
2004-12-05 09:18:57 +08:00
if (strnEQ(drive, dirname, 2)) {
fsusage->disk_reads = PERF_VAL(PERF_IX_DISK_READ);
fsusage->disk_writes = PERF_VAL(PERF_IX_DISK_WRITE);
2005-04-07 09:23:49 +08:00
fsusage->disk_read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES);
fsusage->disk_write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES);
fsusage->disk_queue = PERF_VAL(PERF_IX_DISK_QUEUE);
2004-12-05 09:18:57 +08:00
return SIGAR_OK;
}
}
return ENOENT;
}
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int)
sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
BOOL retval;
ULARGE_INTEGER avail, total, free;
2004-12-05 09:18:57 +08:00
int status;
2004-06-22 06:37:04 +08:00
/* prevent dialog box if A:\ drive is empty */
UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
retval = GetDiskFreeSpaceEx(dirname,
&avail, &total, &free);
/* restore previous error mode */
SetErrorMode(errmode);
if (!retval) {
return GetLastError();
}
fsusage->total = total.QuadPart / 1024;
fsusage->free = free.QuadPart / 1024;
fsusage->avail = avail.QuadPart / 1024;
2005-04-27 03:55:21 +08:00
fsusage->used = fsusage->total - fsusage->free;
2004-06-22 06:37:04 +08:00
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
/* N/A */
fsusage->files = SIGAR_FIELD_NOTIMPL;
fsusage->free_files = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
2004-12-05 09:18:57 +08:00
status = get_disk_metrics(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
SIGAR_DISK_STATS_NOTIMPL(fsusage);
2004-12-05 09:18:57 +08:00
}
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
2004-06-22 06:37:04 +08:00
{
int i, status;
sigar_cpu_info_t *info;
sigar_cpu_count(sigar);
sigar_cpu_info_list_create(cpu_infos);
2004-06-22 06:37:04 +08:00
info = &cpu_infos->data[cpu_infos->number++];
status = sigar_cpu_info_get(sigar, info);
if (status != SIGAR_OK) {
return status;
}
if (sigar->ncpu > 1) {
for (i=1; i<sigar->ncpu; i++) {
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
2004-06-22 06:37:04 +08:00
memcpy(&cpu_infos->data[cpu_infos->number++],
info, sizeof(*info));
}
}
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_GetNetworkParams \
sigar->iphlpapi.get_net_params.func
#define sigar_GetAdaptersInfo \
sigar->iphlpapi.get_adapters_info.func
static int sigar_get_adapters_info(sigar_t *sigar,
PIP_ADAPTER_INFO *adapter)
2005-12-21 10:31:06 +08:00
{
ULONG size = sigar->ifconf_len;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetAdaptersInfo) {
return SIGAR_ENOTIMPL;
}
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
rc = sigar_GetAdaptersInfo(*adapter, &size);
2005-12-21 10:31:06 +08:00
if (rc == ERROR_BUFFER_OVERFLOW) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetAdaptersInfo "
"realloc ifconf_buf old=%d, new=%d",
sigar->ifconf_len, size);
sigar->ifconf_len = size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
sigar->ifconf_len);
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
rc = sigar_GetAdaptersInfo(*adapter, &size);
2005-12-21 10:31:06 +08:00
}
if (rc != NO_ERROR) {
return GetLastError();
}
else {
return SIGAR_OK;
}
}
2005-07-12 06:40:31 +08:00
SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar,
sigar_net_info_t *netinfo)
{
2005-12-21 10:31:06 +08:00
PIP_ADAPTER_INFO adapter;
2005-07-12 07:54:39 +08:00
FIXED_INFO *info;
ULONG len = 0;
2005-07-12 06:40:31 +08:00
IP_ADDR_STRING *ip;
2005-07-12 07:54:39 +08:00
DWORD rc;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
2005-07-12 07:54:39 +08:00
2005-12-21 07:09:34 +08:00
if (!sigar_GetNetworkParams) {
2005-07-12 06:40:31 +08:00
return SIGAR_ENOTIMPL;
}
SIGAR_ZERO(netinfo);
2005-12-21 07:09:34 +08:00
rc = sigar_GetNetworkParams(NULL, &len);
2005-07-12 07:54:39 +08:00
if (rc != ERROR_BUFFER_OVERFLOW) {
return rc;
}
2005-07-12 06:40:31 +08:00
2005-07-12 07:54:39 +08:00
info = malloc(len);
2005-12-21 07:09:34 +08:00
rc = sigar_GetNetworkParams(info, &len);
2005-07-12 07:54:39 +08:00
if (rc != NO_ERROR) {
free(info);
return rc;
2005-07-12 06:40:31 +08:00
}
2005-07-12 07:54:39 +08:00
SIGAR_SSTRCPY(netinfo->host_name, info->HostName);
SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName);
2005-07-12 06:40:31 +08:00
SIGAR_SSTRCPY(netinfo->primary_dns,
2005-07-12 07:54:39 +08:00
info->DnsServerList.IpAddress.String);
2005-07-12 06:40:31 +08:00
2005-07-12 07:54:39 +08:00
if ((ip = info->DnsServerList.Next)) {
2005-07-12 06:40:31 +08:00
SIGAR_SSTRCPY(netinfo->secondary_dns,
ip->IpAddress.String);
}
2005-07-12 07:54:39 +08:00
free(info);
2005-07-12 06:40:31 +08:00
if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) {
2005-12-21 10:31:06 +08:00
return SIGAR_OK;
}
2005-12-21 10:31:06 +08:00
while (adapter) {
/* should only be 1 */
if (adapter->GatewayList.IpAddress.String[0]) {
SIGAR_SSTRCPY(netinfo->default_gateway,
adapter->GatewayList.IpAddress.String);
}
2005-07-18 01:46:07 +08:00
#if 0
2005-12-21 10:31:06 +08:00
if (apapters->DhcpEnabled) {
SIGAR_SSTRCPY(netinfo->dhcp_server,
apdaters->DhcpServer.IpAddress.String);
}
2005-12-21 10:31:06 +08:00
#endif
adapter = adapter->Next;
}
2005-07-12 06:40:31 +08:00
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_GetIpForwardTable \
sigar->iphlpapi.get_ipforward_table.func
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
2005-12-21 07:09:34 +08:00
PMIB_IPFORWARDTABLE buffer = NULL;
2004-06-22 06:37:04 +08:00
ULONG bufsize = 0;
DWORD rc, i;
MIB_IPFORWARDTABLE *ipt;
sigar_net_route_t *route;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIpForwardTable) {
2004-06-22 06:37:04 +08:00
return SIGAR_ENOTIMPL;
}
2005-12-21 07:09:34 +08:00
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
2004-06-22 06:37:04 +08:00
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
buffer = malloc(bufsize);
2005-12-21 07:09:34 +08:00
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
2004-06-22 06:37:04 +08:00
if (rc != NO_ERROR) {
free(buffer);
return GetLastError();
}
sigar_net_route_list_create(routelist);
routelist->size = routelist->number = 0;
2005-12-21 07:09:34 +08:00
ipt = buffer;
2004-06-22 06:37:04 +08:00
for (i=0; i<ipt->dwNumEntries; i++) {
MIB_IPFORWARDROW *ipr = ipt->table + i;
SIGAR_NET_ROUTE_LIST_GROW(routelist);
route = &routelist->data[routelist->number++];
SIGAR_ZERO(route); /* XXX: other fields */
2006-07-05 03:33:03 +08:00
sigar_net_address_set(route->destination,
ipr->dwForwardDest);
sigar_net_address_set(route->mask,
ipr->dwForwardMask);
sigar_net_address_set(route->gateway,
ipr->dwForwardNextHop);
route->metric = ipr->dwForwardMetric1;
2005-07-13 02:45:28 +08:00
route->flags = SIGAR_RTF_UP;
2006-07-05 03:33:03 +08:00
if ((ipr->dwForwardDest == 0) &&
(ipr->dwForwardMask == 0))
2005-07-13 02:45:28 +08:00
{
route->flags |= SIGAR_RTF_GATEWAY;
}
2004-06-22 06:37:04 +08:00
}
free(buffer);
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_GetIfTable \
sigar->iphlpapi.get_if_table.func
static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIfTable) {
return SIGAR_ENOTIMPL;
}
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
if (rc == ERROR_INSUFFICIENT_BUFFER) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2005-12-21 10:31:06 +08:00
"GetIfTable "
"realloc ifconf_buf old=%d, new=%d",
sigar->ifconf_len, size);
sigar->ifconf_len = size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
sigar->ifconf_len);
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
}
if (rc != NO_ERROR) {
return GetLastError();
}
else {
return SIGAR_OK;
}
}
2006-03-05 06:12:18 +08:00
static int get_mib_ifrow(sigar_t *sigar,
const char *name,
MIB_IFROW **ifrp)
2004-06-22 06:37:04 +08:00
{
DWORD rc, i;
MIB_IFTABLE *ift;
MIB_IFROW *ifr;
DWORD lo=0, eth=0;
int status, type, inst;
if ((status = sigar_get_iftype(name, &type, &inst)) != SIGAR_OK) {
2004-06-22 06:37:04 +08:00
return status;
}
if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
return status;
2004-06-22 06:37:04 +08:00
}
for (i=0; i<ift->dwNumEntries; i++) {
ifr = ift->table + i;
if (!(ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL)) {
continue;
}
if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
if ((type == IFTYPE_LO) && (inst == lo)) {
break;
}
++lo;
}
else if (ifr->dwType == MIB_IF_TYPE_ETHERNET) {
if ((type == IFTYPE_ETH) && (inst == eth)) {
break;
}
++eth;
}
ifr = NULL;
}
if (!ifr) {
return ENOENT;
}
2006-03-05 06:12:18 +08:00
*ifrp = ifr;
return SIGAR_OK;
}
int sigar_get_ifentry_config(sigar_t *sigar,
sigar_net_interface_config_t *ifconfig)
{
MIB_IFROW *ifr;
int status;
status = get_mib_ifrow(sigar, ifconfig->name, &ifr);
if (status != SIGAR_OK) {
return status;
}
ifconfig->mtu = ifr->dwMtu;
2006-07-06 05:33:59 +08:00
sigar_net_address_mac_set(ifconfig->hwaddr,
ifr->bPhysAddr,
SIGAR_IFHWADDRLEN);
2006-03-05 06:12:18 +08:00
2006-03-05 06:28:09 +08:00
SIGAR_SSTRCPY(ifconfig->description,
ifr->bDescr);
2006-03-05 06:12:18 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
MIB_IFROW *ifr;
int status;
status = get_mib_ifrow(sigar, name, &ifr);
if (status != SIGAR_OK) {
return status;
}
2004-06-22 06:37:04 +08:00
ifstat->rx_bytes = ifr->dwInOctets;
ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts;
ifstat->rx_errors = ifr->dwInErrors;
ifstat->rx_dropped = ifr->dwInDiscards;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
2005-05-14 08:02:33 +08:00
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
ifstat->tx_bytes = ifr->dwOutOctets;
ifstat->tx_packets = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts;
ifstat->tx_errors = ifr->dwOutErrors;
ifstat->tx_dropped = ifr->dwOutDiscards;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
2006-03-07 09:08:23 +08:00
ifstat->speed = ifr->dwSpeed;
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
2005-05-07 14:00:55 +08:00
#define IS_TCP_SERVER(state, flags) \
((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN))
#define IS_TCP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN))
2005-12-21 07:09:34 +08:00
#define sigar_GetTcpTable \
sigar->iphlpapi.get_tcp_table.func
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status, i;
DWORD rc, size=0;
2004-06-22 06:37:04 +08:00
PMIB_TCPTABLE tcp;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetTcpTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetTcpTable(NULL, &size, FALSE);
2004-06-22 06:37:04 +08:00
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
2004-06-23 07:44:46 +08:00
tcp = malloc(size);
2005-12-21 07:09:34 +08:00
rc = sigar_GetTcpTable(tcp, &size, FALSE);
2004-06-22 06:37:04 +08:00
if (rc) {
free(tcp);
return GetLastError();
}
/* go in reverse to get LISTEN states first */
for (i = (tcp->dwNumEntries-1); i >= 0; i--) {
2004-06-22 06:37:04 +08:00
sigar_net_connection_t conn;
DWORD state = tcp->table[i].dwState;
2005-05-07 14:00:55 +08:00
if (!(IS_TCP_SERVER(state, flags) ||
IS_TCP_CLIENT(state, flags)))
{
continue;
2004-06-22 06:37:04 +08:00
}
conn.local_port = htons((WORD)tcp->table[i].dwLocalPort);
conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort);
conn.type = SIGAR_NETCONN_TCP;
sigar_net_address_set(conn.local_address,
tcp->table[i].dwLocalAddr);
2004-06-22 06:37:04 +08:00
sigar_net_address_set(conn.remote_address,
tcp->table[i].dwRemoteAddr);
2004-06-22 06:37:04 +08:00
2005-03-12 12:49:38 +08:00
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
2005-03-11 12:45:09 +08:00
switch (state) {
case MIB_TCP_STATE_CLOSED:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_CLOSE;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_LISTEN:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_LISTEN;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_SYN_SENT:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_SYN_SENT;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_SYN_RCVD:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_SYN_RECV;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_ESTAB:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_ESTABLISHED;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_FIN_WAIT1:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_FIN_WAIT1;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_FIN_WAIT2:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_FIN_WAIT2;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_CLOSE_WAIT:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_CLOSE_WAIT;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_CLOSING:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_CLOSING;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_LAST_ACK:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_LAST_ACK;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_TIME_WAIT:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_TIME_WAIT;
2005-03-11 12:45:09 +08:00
break;
case MIB_TCP_STATE_DELETE_TCB:
default:
2005-03-12 01:11:30 +08:00
conn.state = SIGAR_TCP_UNKNOWN;
2005-03-11 12:45:09 +08:00
break;
}
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
2004-06-22 06:37:04 +08:00
}
free(tcp);
return SIGAR_OK;
}
2005-05-07 14:00:55 +08:00
#define IS_UDP_SERVER(conn, flags) \
((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port)
#define IS_UDP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port)
2005-12-21 07:09:34 +08:00
#define sigar_GetUdpTable \
sigar->iphlpapi.get_udp_table.func
static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
2004-06-22 06:37:04 +08:00
int status;
2005-12-21 07:09:34 +08:00
DWORD rc, size=0, i;
2004-06-22 06:37:04 +08:00
PMIB_UDPTABLE udp;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
2006-06-20 08:02:47 +08:00
if (!sigar_GetUdpTable) {
2005-12-21 07:09:34 +08:00
return SIGAR_ENOTIMPL;
}
rc = sigar_GetUdpTable(NULL, &size, FALSE);
2004-06-22 06:37:04 +08:00
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
2004-06-23 07:44:46 +08:00
udp = malloc(size);
2005-12-21 07:09:34 +08:00
rc = sigar_GetUdpTable(udp, &size, FALSE);
2004-06-22 06:37:04 +08:00
if (rc) {
free(udp);
return GetLastError();
}
for (i = 0; i < udp->dwNumEntries; i++) {
sigar_net_connection_t conn;
2005-05-07 14:00:55 +08:00
if (!(IS_UDP_SERVER(conn, flags) ||
IS_UDP_CLIENT(conn, flags)))
2004-06-22 06:37:04 +08:00
{
continue;
}
conn.local_port = htons((WORD)udp->table[i].dwLocalPort);
conn.remote_port = 0;
2004-06-22 06:37:04 +08:00
conn.type = SIGAR_NETCONN_UDP;
sigar_net_address_set(conn.local_address,
udp->table[i].dwLocalAddr);
2004-06-22 06:37:04 +08:00
sigar_net_address_set(conn.remote_address, 0);
2004-06-22 06:37:04 +08:00
2005-03-12 12:49:38 +08:00
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
2004-06-22 06:37:04 +08:00
}
free(udp);
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
int status;
if (walker->flags & SIGAR_NETCONN_TCP) {
status = net_conn_get_tcp(walker);
2004-06-22 06:37:04 +08:00
if (status != SIGAR_OK) {
return status;
}
}
if (walker->flags & SIGAR_NETCONN_UDP) {
status = net_conn_get_udp(walker);
2004-06-22 06:37:04 +08:00
if (status != SIGAR_OK) {
return status;
}
}
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_GetTcpExTable \
sigar->iphlpapi.get_tcpx_table.func
#define sigar_GetUdpExTable \
sigar->iphlpapi.get_udpx_table.func
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar,
int protocol,
2004-06-22 06:37:04 +08:00
unsigned long port,
sigar_pid_t *pid)
{
DWORD rc, i;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
2005-03-20 11:20:28 +08:00
if (protocol == SIGAR_NETCONN_TCP) {
PMIB_TCPEXTABLE tcp;
2004-06-22 06:37:04 +08:00
2005-12-21 07:09:34 +08:00
if (!sigar_GetTcpExTable) {
2005-03-20 11:20:28 +08:00
return SIGAR_ENOTIMPL;
}
2005-03-16 11:49:54 +08:00
2005-12-21 07:09:34 +08:00
rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(),
2, 2);
2004-06-22 06:37:04 +08:00
2005-03-20 11:20:28 +08:00
if (rc) {
return GetLastError();
}
for (i=0; i<tcp->dwNumEntries; i++) {
if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) {
continue;
}
if (htons((WORD)tcp->table[i].dwLocalPort) != port) {
continue;
}
*pid = tcp->table[i].dwProcessId;
return SIGAR_OK;
}
2004-06-22 06:37:04 +08:00
}
2005-03-20 11:20:28 +08:00
else if (protocol == SIGAR_NETCONN_UDP) {
PMIB_UDPEXTABLE udp;
2004-06-22 06:37:04 +08:00
2005-12-21 07:09:34 +08:00
if (!sigar_GetUdpExTable) {
2005-03-20 11:20:28 +08:00
return SIGAR_ENOTIMPL;
2004-06-22 06:37:04 +08:00
}
2005-12-21 07:09:34 +08:00
rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(),
2, 2);
2005-03-20 11:20:28 +08:00
if (rc) {
return GetLastError();
2004-06-22 06:37:04 +08:00
}
2005-03-20 11:20:28 +08:00
for (i=0; i<udp->dwNumEntries; i++) {
if (htons((WORD)udp->table[i].dwLocalPort) != port) {
continue;
}
2004-06-22 06:37:04 +08:00
2005-03-20 11:20:28 +08:00
*pid = udp->table[i].dwProcessId;
return SIGAR_OK;
}
}
else {
return SIGAR_ENOTIMPL;
2004-06-22 06:37:04 +08:00
}
return ENOENT;
}
#include <lm.h>
static int sigar_who_net_sessions(sigar_t *sigar,
sigar_who_list_t *wholist)
{
NET_API_STATUS status;
LPSESSION_INFO_10 buffer=NULL, ptr;
DWORD entries=0, total_entries=0;
DWORD resume_handle=0;
DWORD i;
do {
status = NetSessionEnum(NULL, /* server name */
NULL, /* client name */
NULL, /* user name */
10, /* level */
(LPBYTE*)&buffer,
MAX_PREFERRED_LENGTH,
&entries,
&total_entries,
&resume_handle);
if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) {
if ((ptr = buffer)) {
for (i=0; i<entries; i++) {
sigar_who_t *who;
if (!ptr) {
break;
}
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];
who->time = (time(NULL) - ptr->sesi10_time);
SIGAR_W2A((LPCWSTR)ptr->sesi10_username,
who->user, sizeof(who->user));
SIGAR_W2A((LPCWSTR)ptr->sesi10_cname,
who->host, sizeof(who->host));
SIGAR_SSTRCPY(who->device, "network share");
ptr++;
}
}
}
else {
break;
}
if (buffer) {
NetApiBufferFree(buffer);
buffer = NULL;
}
} while (status == ERROR_MORE_DATA);
if (buffer) {
NetApiBufferFree(buffer);
}
return SIGAR_OK;
}
static int get_logon_info(HKEY users,
char *username,
sigar_who_t *who)
{
DWORD status, size, type;
HKEY key;
char key_name[MAX_PATH];
char value[256];
FILETIME wtime;
who->time = 0;
sprintf(key_name, "%s\\Volatile Environment", username);
if (RegOpenKey(users, key_name, &key) != ERROR_SUCCESS) {
return ENOENT;
}
status = RegQueryInfoKey(key,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
&wtime);
if (status == ERROR_SUCCESS) {
FileTimeToLocalFileTime(&wtime, &wtime);
who->time = FileTimeToTime(&wtime) / 1000000;
}
size = sizeof(value);
status = RegQueryValueEx(key, "CLIENTNAME",
NULL, &type, value, &size);
if (status == ERROR_SUCCESS) {
if ((value[0] != '\0') && !strEQ(value, "Console")) {
SIGAR_SSTRCPY(who->host, value);
}
}
size = sizeof(value);
status = RegQueryValueEx(key, "SESSIONNAME",
NULL, &type, value, &size);
if (status == ERROR_SUCCESS) {
SIGAR_SSTRCPY(who->device, value);
}
RegCloseKey(key);
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_ConvertStringSidToSid \
sigar->advapi.convert_string_sid.func
static int sigar_who_registry(sigar_t *sigar,
sigar_who_list_t *wholist)
{
HKEY users;
2005-10-02 13:52:33 +08:00
DWORD index=0, status;
2005-12-21 07:09:34 +08:00
if (!sigar_ConvertStringSidToSid) {
return ENOENT;
}
status = RegOpenKey(HKEY_USERS, NULL, &users);
if (status != ERROR_SUCCESS) {
return status;
}
while (1) {
char subkey[MAX_PATH];
char username[SIGAR_CRED_NAME_MAX];
char domain[SIGAR_CRED_NAME_MAX];
DWORD subkey_len = sizeof(subkey);
DWORD username_len = sizeof(username);
DWORD domain_len = sizeof(domain);
PSID sid;
SID_NAME_USE type;
status = RegEnumKeyEx(users, index, subkey, &subkey_len,
NULL, NULL, NULL, NULL);
if (status != ERROR_SUCCESS) {
break;
}
2005-10-02 13:52:33 +08:00
index++;
if ((subkey[0] == '.') || strstr(subkey, "_Classes")) {
continue;
}
2005-12-21 07:09:34 +08:00
if (!sigar_ConvertStringSidToSid(subkey, &sid)) {
continue;
}
if (LookupAccountSid(NULL, /* server */
sid,
username, &username_len,
domain, &domain_len,
&type))
{
sigar_who_t *who;
2005-10-02 13:52:33 +08:00
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];
SIGAR_SSTRCPY(who->user, username);
SIGAR_SSTRCPY(who->host, domain);
SIGAR_SSTRCPY(who->device, "console");
2005-10-02 13:52:33 +08:00
get_logon_info(users, subkey, who);
}
LocalFree(sid);
}
RegCloseKey(users);
return SIGAR_OK;
}
2005-12-21 07:09:34 +08:00
#define sigar_WTSEnumerateSessions \
sigar->wtsapi.enum_sessions.func
#define sigar_WTSFreeMemory \
sigar->wtsapi.free_mem.func
#define sigar_WTSQuerySessionInformation \
sigar->wtsapi.query_session.func
#define sigar_WinStationQueryInformation \
sigar->winsta.query_info.func
static int sigar_who_wts(sigar_t *sigar,
sigar_who_list_t *wholist)
{
2005-10-02 13:52:33 +08:00
DWORD count=0, i;
WTS_SESSION_INFO *sessions = NULL;
2005-12-21 07:09:34 +08:00
if (DLLMOD_INIT(wtsapi, TRUE) != SIGAR_OK) {
2005-10-02 14:03:36 +08:00
sigar_log(sigar, SIGAR_LOG_DEBUG,
"Terminal Services api functions not available");
return ENOENT;
}
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(winsta, FALSE);
if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) {
return GetLastError();
}
for (i=0; i<count; i++) {
DWORD bytes;
LPTSTR buffer;
DWORD sessionId = sessions[i].SessionId;
WINSTATION_INFO station_info;
sigar_who_t *who;
if (sessions[i].State != WTSActive) {
continue;
}
buffer = NULL;
bytes = 0;
2005-12-21 07:09:34 +08:00
if (sigar_WTSQuerySessionInformation(0,
sessionId,
WTSClientProtocolType,
&buffer,
&bytes))
{
2005-10-11 01:00:30 +08:00
int isConsole =
(*buffer == WTS_PROTOCOL_TYPE_CONSOLE);
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(buffer);
2005-10-11 01:00:30 +08:00
if (isConsole) {
continue;
}
}
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];
SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName);
buffer = NULL;
bytes = 0;
2005-12-21 07:09:34 +08:00
if (sigar_WTSQuerySessionInformation(0,
sessionId,
WTSClientAddress,
&buffer,
&bytes))
{
PWTS_CLIENT_ADDRESS client =
(PWTS_CLIENT_ADDRESS)buffer;
sprintf(who->host, "%u.%u.%u.%u",
client->Address[2],
client->Address[3],
client->Address[4],
client->Address[5]);
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(buffer);
}
else {
SIGAR_SSTRCPY(who->host, "unknown");
}
buffer = NULL;
bytes = 0;
2005-12-21 07:09:34 +08:00
if (sigar_WTSQuerySessionInformation(0,
sessionId,
WTSUserName,
&buffer,
&bytes))
{
SIGAR_SSTRCPY(who->user, buffer);
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(buffer);
}
else {
SIGAR_SSTRCPY(who->user, "unknown");
}
buffer = NULL;
bytes = 0;
2005-12-21 07:09:34 +08:00
if (sigar_WinStationQueryInformation &&
sigar_WinStationQueryInformation(0,
sessionId,
WinStationInformation,
&station_info,
sizeof(station_info),
&bytes))
{
who->time =
FileTimeToTime(&station_info.ConnectTime) / 1000000;
}
else {
who->time = 0;
}
}
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(sessions);
return SIGAR_OK;
}
2005-10-02 13:52:33 +08:00
int sigar_who_list_get_win32(sigar_t *sigar,
sigar_who_list_t *wholist)
{
sigar_who_net_sessions(sigar, wholist);
sigar_who_registry(sigar, wholist);
sigar_who_wts(sigar, wholist);
return SIGAR_OK;
}
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
return SIGAR_OK;
}