From 05f0f6f688cde8fe62bbbeb620ee07dd06a8859a Mon Sep 17 00:00:00 2001 From: Ben Ridley Date: Wed, 3 Mar 2021 15:35:04 +1100 Subject: [PATCH] Add idiomatic wrappers to be exposed publically, and hide low-level WinAPI operations Signed-off-by: Ben Ridley --- collector/cs.go | 4 +- collector/os.go | 16 +++--- headers/netapi32/netapi32.go | 66 +++++++++++++++--------- headers/sysinfoapi/sysinfoapi.go | 86 +++++++++++++++++++++++++++----- 4 files changed, 126 insertions(+), 46 deletions(-) diff --git a/collector/cs.go b/collector/cs.go index a7ee1311..63e87274 100644 --- a/collector/cs.go +++ b/collector/cs.go @@ -72,13 +72,13 @@ func (c *CSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, er ch <- prometheus.MustNewConstMetric( c.LogicalProcessors, prometheus.GaugeValue, - float64(systemInfo.DwNumberOfProcessors), + float64(systemInfo.NumberOfProcessors), ) ch <- prometheus.MustNewConstMetric( c.PhysicalMemoryBytes, prometheus.GaugeValue, - float64(mem.UllTotalPhys), + float64(mem.TotalPhys), ) hostname, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSHostname) diff --git a/collector/os.go b/collector/os.go index aa914f39..5d3f9e42 100644 --- a/collector/os.go +++ b/collector/os.go @@ -158,7 +158,7 @@ type Win32_OperatingSystem struct { } func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) { - nwgi, _, err := netapi32.NetWkstaGetInfo() + nwgi, err := netapi32.GetWorkstationInfo() if err != nil { return nil, err } @@ -241,13 +241,13 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) ( prometheus.GaugeValue, 1.0, fmt.Sprintf("Microsoft %s", pn), // Caption - fmt.Sprintf("%d.%d.%s", nwgi.Wki102_ver_major, nwgi.Wki102_ver_minor, bn), // Version + fmt.Sprintf("%d.%d.%s", nwgi.VersionMajor, nwgi.VersionMinor, bn), // Version ) ch <- prometheus.MustNewConstMetric( c.PhysicalMemoryFreeBytes, prometheus.GaugeValue, - float64(gmse.UllAvailPhys), + float64(gmse.AvailPhys), ) ch <- prometheus.MustNewConstMetric( @@ -272,7 +272,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) ( ch <- prometheus.MustNewConstMetric( c.VirtualMemoryFreeBytes, prometheus.GaugeValue, - float64(gmse.UllAvailPageFile), + float64(gmse.AvailPageFile), ) // Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value. @@ -287,7 +287,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) ( ch <- prometheus.MustNewConstMetric( c.ProcessMemoryLimitBytes, prometheus.GaugeValue, - float64(gmse.UllTotalVirtual), + float64(gmse.TotalVirtual), ) ch <- prometheus.MustNewConstMetric( @@ -299,7 +299,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) ( ch <- prometheus.MustNewConstMetric( c.Users, prometheus.GaugeValue, - float64(nwgi.Wki102_logged_on_users), + float64(nwgi.LoggedOnUsers), ) ch <- prometheus.MustNewConstMetric( @@ -311,13 +311,13 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) ( ch <- prometheus.MustNewConstMetric( c.VirtualMemoryBytes, prometheus.GaugeValue, - float64(gmse.UllTotalPageFile), + float64(gmse.TotalPageFile), ) ch <- prometheus.MustNewConstMetric( c.VisibleMemoryBytes, prometheus.GaugeValue, - float64(gmse.UllTotalPhys), + float64(gmse.TotalPhys), ) return nil, nil diff --git a/headers/netapi32/netapi32.go b/headers/netapi32/netapi32.go index d7605c04..441ccfd2 100644 --- a/headers/netapi32/netapi32.go +++ b/headers/netapi32/netapi32.go @@ -9,14 +9,25 @@ import ( // WKSTAInfo102 is a wrapper of WKSTA_Info_102 //https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102 -type WKSTAInfo102 struct { - Wki102_platform_id uint32 +type wKSTAInfo102 struct { + wki102_platform_id uint32 wki102_computername *uint16 wki102_langroup *uint16 - Wki102_ver_major uint32 - Wki102_ver_minor uint32 + wki102_ver_major uint32 + wki102_ver_minor uint32 wki102_lanroot *uint16 - Wki102_logged_on_users uint32 + wki102_logged_on_users uint32 +} + +// WorkstationInfo is an idiomatic wrapper of WKSTAInfo102 +type WorkstationInfo struct { + PlatformId uint32 + ComputerName string + LanGroup string + VersionMajor uint32 + VersionMinor uint32 + LanRoot string + LoggedOnUsers uint32 } var ( @@ -57,33 +68,42 @@ var NetApiStatus = map[uint32]string{ // NetApiBufferFree frees the memory other network management functions use internally to return information. // https://docs.microsoft.com/en-us/windows/win32/api/lmapibuf/nf-lmapibuf-netapibufferfree -func NetApiBufferFree(buffer *WKSTAInfo102) { +func netApiBufferFree(buffer *wKSTAInfo102) { procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer))) } // NetWkstaGetInfo returns information about the configuration of a workstation. +// WARNING: The caller must call netApiBufferFree to free the memory allocated by this function. // https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo -func NetWkstaGetInfo() (WKSTAInfo102, uint32, error) { - // Struct - var lpwi *WKSTAInfo102 - pLpwi := uintptr(unsafe.Pointer(&lpwi)) - - // Null value - var nullptr = uintptr(0) - - // Level +func netWkstaGetInfo() (*wKSTAInfo102, uint32, error) { + var lpwi *wKSTAInfo102 pLevel := uintptr(102) - // Func call - r1, _, _ := procNetWkstaGetInfo.Call(nullptr, pLevel, pLpwi) + r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi))) if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 { - return WKSTAInfo102{}, ret, errors.New(NetApiStatus[ret]) + return nil, ret, errors.New(NetApiStatus[ret]) } - // Derence the pointer and return the object so we can safely clear the buffer. - var deref WKSTAInfo102 = *lpwi - defer NetApiBufferFree(lpwi) - - return deref, 0, nil + return lpwi, 0, nil +} + +// GetWorkstationInfo is an idiomatic wrapper for netWkstaGetInfo +func GetWorkstationInfo() (WorkstationInfo, error) { + info, _, err := netWkstaGetInfo() + if err != nil { + return WorkstationInfo{}, err + } + workstationInfo := WorkstationInfo{ + PlatformId: info.wki102_platform_id, + ComputerName: windows.UTF16PtrToString(info.wki102_computername), + LanGroup: windows.UTF16PtrToString(info.wki102_langroup), + VersionMajor: info.wki102_ver_major, + VersionMinor: info.wki102_ver_minor, + LanRoot: windows.UTF16PtrToString(info.wki102_lanroot), + LoggedOnUsers: info.wki102_logged_on_users, + } + // Free the memory allocated by netapi + netApiBufferFree(info) + return workstationInfo, nil } diff --git a/headers/sysinfoapi/sysinfoapi.go b/headers/sysinfoapi/sysinfoapi.go index 181baab9..8ea8ff67 100644 --- a/headers/sysinfoapi/sysinfoapi.go +++ b/headers/sysinfoapi/sysinfoapi.go @@ -1,6 +1,7 @@ package sysinfoapi import ( + "fmt" "unicode/utf16" "unsafe" @@ -9,7 +10,7 @@ import ( // MemoryStatusEx is a wrapper for MEMORYSTATUSEX // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex -type MemoryStatusEx struct { +type memoryStatusEx struct { dwLength uint32 DwMemoryLoad uint32 UllTotalPhys uint64 @@ -21,6 +22,18 @@ type MemoryStatusEx struct { UllAvailExtendedVirtual uint64 } +// MemoryStatus is an idiomatic wrapper for MemoryStatusEx +type MemoryStatus struct { + MemoryLoad uint32 + TotalPhys uint64 + AvailPhys uint64 + TotalPageFile uint64 + AvailPageFile uint64 + TotalVirtual uint64 + AvailVirtual uint64 + AvailExtendedVirtual uint64 +} + // wProcessorArchitecture is a wrapper for the union found in LP_SYSTEM_INFO // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info type wProcessorArchitecture struct { @@ -28,14 +41,27 @@ type wProcessorArchitecture struct { WProcessorArchitecture uint16 } +// ProcessorArchitecture is an idiomatic wrapper for wProcessorArchitecture +type ProcessorArchitecture uint16 + +// Idiomatic values for wProcessorArchitecture +const ( + AMD64 ProcessorArchitecture = 9 + ARM = 5 + ARM64 = 12 + IA64 = 6 + INTEL = 0 + UNKNOWN = 0xffff +) + // LpSystemInfo is a wrapper for LPSYSTEM_INFO // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info -type LpSystemInfo struct { +type lpSystemInfo struct { Arch wProcessorArchitecture DwPageSize uint32 - LpMinimumApplicationAddress *byte - LpMaximumApplicationAddress *byte - DwActiveProcessorMask *uint32 + LpMinimumApplicationAddress uintptr + LpMaximumApplicationAddress uintptr + DwActiveProcessorMask uint32 DwNumberOfProcessors uint32 DwProcessorType uint32 DwAllocationGranularity uint32 @@ -43,6 +69,20 @@ type LpSystemInfo struct { WProcessorRevision uint16 } +// SystemInfo is an idiomatic wrapper for LpSystemInfo +type SystemInfo struct { + Arch ProcessorArchitecture + PageSize uint32 + MinimumApplicationAddress uintptr + MaximumApplicationAddress uintptr + ActiveProcessorMask uint32 + NumberOfProcessors uint32 + ProcessorType uint32 + AllocationGranularity uint32 + ProcessorLevel uint16 + ProcessorRevision uint16 +} + // WinComputerNameFormat is a wrapper for COMPUTER_NAME_FORMAT type WinComputerNameFormat int @@ -68,27 +108,47 @@ var ( // GlobalMemoryStatusEx retrieves information about the system's current usage of both physical and virtual memory. // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex -func GlobalMemoryStatusEx() (MemoryStatusEx, error) { - var mse MemoryStatusEx +func GlobalMemoryStatusEx() (MemoryStatus, error) { + var mse memoryStatusEx mse.dwLength = (uint32)(unsafe.Sizeof(mse)) pMse := uintptr(unsafe.Pointer(&mse)) r1, _, err := procGlobalMemoryStatusEx.Call(pMse) if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false { - // returned false - return MemoryStatusEx{}, err + return MemoryStatus{}, err } - return mse, nil + return MemoryStatus{ + MemoryLoad: mse.DwMemoryLoad, + TotalPhys: mse.UllTotalPhys, + AvailPhys: mse.UllAvailPhys, + TotalPageFile: mse.UllTotalPageFile, + AvailPageFile: mse.UllAvailPageFile, + TotalVirtual: mse.UllTotalVirtual, + AvailVirtual: mse.UllAvailVirtual, + AvailExtendedVirtual: mse.UllAvailExtendedVirtual, + }, nil } // GetSystemInfo wraps the GetSystemInfo function from sysinfoapi // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo -func GetSystemInfo() LpSystemInfo { - var info LpSystemInfo +func GetSystemInfo() SystemInfo { + var info lpSystemInfo pInfo := uintptr(unsafe.Pointer(&info)) procGetSystemInfo.Call(pInfo) - return info + fmt.Printf("%+v", info) + return SystemInfo{ + Arch: ProcessorArchitecture(info.Arch.WProcessorArchitecture), + PageSize: info.DwPageSize, + MinimumApplicationAddress: info.LpMinimumApplicationAddress, + MaximumApplicationAddress: info.LpMinimumApplicationAddress, + ActiveProcessorMask: info.DwActiveProcessorMask, + NumberOfProcessors: info.DwNumberOfProcessors, + ProcessorType: info.DwProcessorType, + AllocationGranularity: info.DwAllocationGranularity, + ProcessorLevel: info.WProcessorLevel, + ProcessorRevision: info.WProcessorRevision, + } } // GetComputerName wraps the GetComputerNameW function in a more Go-like way