c95824a65d
Full read-only SDK (src/AVEVA.Historian.Client) implementing the CLAUDE.md required
surface against AVEVA Historian's binary WCF protocol — no native AVEVA runtime
dependency. All operations live-verified against a local Historian:
- ProbeAsync, ReadRawAsync, ReadAggregateAsync, ReadAtTimeAsync, ReadEventsAsync
- BrowseTagNamesAsync, GetTagMetadataAsync (17 native data-type codes mapped)
- GetConnectionStatusAsync, GetStoreForwardStatusAsync, GetSystemParameterAsync
- 108/108 unit + integration tests pass
Includes the reverse-engineering toolkit (tools/AVEVA.Historian.ReverseEngineering)
used to decode the protocol: WCF probes, IL inspection via dnlib, and IL-rewrite
instrumentation (instrument-wcf-{write,read}message etc.) plus the .NET Framework
trace harness (tools/AVEVA.Historian.NativeTraceHarness) for parity testing.
Sanitized handoff evidence under docs/reverse-engineering/. Native AVEVA binaries
(current/, aveva-install-x64/, aveva-install-x86/) are gitignored — fetch separately
from the AVEVA installer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.8 KiB
5.8 KiB
WCF Open2 Evidence
Command:
dotnet run --no-build --project tools\AVEVA.Historian.ReverseEngineering -- wcf-open2 localhost 32568
Confirmed:
- Native
CHistoryConnectionWCF.OpenConnection2serializes a byte buffer and callsHistoryServiceContract.IHistoryServiceContract2.OpenConnection2, WCF operationOpen2. - The managed contract for
Open2is reachable through the fully managed WCF/MDAS binding. - The version-1 open buffer layout from
CServiceUtility.SaveOpenConnectionParamsis:ushortpacket version1- strings encoded as
uint32UTF-16 character count followed by UTF-16LE bytes without a null terminator uint32process iduint32password byte length followed by password bytesbyteclient typeushortclient versionuint32connection mode- default metadata namespace: flag byte plus three empty encoded strings
- Empty credential attempts now return a native error buffer instead of
InvalidPacketVersion.
Observed sanitized result:
- Empty credential modes return error bytes
04 AB 00 00 00. - Interpreted as native custom error type
4, code171, this maps toAuthenticationFailedinArchestrA.HistorianAccessError.ErrorValue. - Integrated-security mode
1026with WCF transport security fails before the operation call withProtocolException: The requested upgrade is not supported by 'net.tcp://localhost:32568/Hist'. This proves the server's MDAS/Histendpoint is not using standard WCF transport-security upgrade semantics. - The same version-1 integrated-security buffer succeeds when sent to
net.tcp://localhost:32568/Hist-Integratedthrough the managed WCF Windows transport-security binding. The response has a 32-byte output buffer and no error buffer. Do not commit the output bytes; they are treated as an ephemeral session artifact. - Client-version values
0,4, and11all return the same 32-byte output shape for this version-1 request. - The successful 32-byte output is not yet decoded.
Close(1)returns native return code4;Retr.IsOriginalAllowed(1)also returns native return code4.Close2candidates derived from the output buffer all fail with native error code51: first 16 bytes as .NET Guid, first 16 bytes as RFC4122 Guid, first 16 bytes as hex/base64, and all 32 bytes as hex/base64. Therefore the managed session-open path is known, but the usable client handle/session-token decoding is still unknown. - Decompiled
CClientInfo.DeserializeOpenConnectionOutParamsexpects a different native-consumable output shape: first byte must be packet version2or3, followed by a 4-byte field, a 16-byte field, an 8-byte field, and for version3another 8-byte field. The 32-byte output from the current version-1 managed request does not match that shape. - Earlier integrated-security probing through the no-security MDAS binding could
trigger server-side
ServiceSecurityContext.WindowsIdentitynull-reference failures because that binding does not establish a Windows security context. - The server message
Failed to get user token... check that the username has been added to Historian Usersis authentication/configuration evidence, not packet-version evidence. It indicates the supplied Windows/user credential is not authorized as a Historian user on the target server. - The managed harness now decodes these five-byte buffers as:
- byte
0: native error type - bytes
1..4: little-endian unsigned error code - known names for codes
1,73, and171
- byte
Interpretation:
Hist.Open2byte-buffer framing is confirmed for the legacy version-1 path.- Fully managed integrated Windows session-open is confirmed for the local
2020 Historian when the client uses
/Hist-Integrated. - The remaining blocker is decoding the successful 32-byte
Open2output into the handle/token shape used by close, status, retrieval, and query calls.
Native integrated-auth baseline
Reverse-engineering script:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\Test-AahClientManagedOpen.ps1 -HostName localhost -Port 32568 -IntegratedSecurity -ConnectionWaitSeconds 15
Sanitized result:
Success = trueConnectedToServer = trueConnectionPending = falseConnectionErrorOccurred = falseErrorCode = Success
The native wrapper returns from OpenConnection before the connection is fully
settled, so scripts must poll GetConnectionStatus before treating the open as
usable.
Reverse-engineering read smoke:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\Test-AahClientManagedReadIntegrated.ps1 -TagName __codex_missing_probe_tag__ -LookbackMinutes 1 -MaxRows 1 -ConnectionWaitSeconds 15
Sanitized result:
OpenSuccess = trueConnectedToServer = trueStartQuerySuccess = falseStartQueryErrorCode = TagNotFoundStartQueryErrorDescription = error = 127 (Tag not found)
This is useful positive evidence: the native integrated-auth path reaches the real Historian query service and fails only because the deliberately fake probe tag does not exist.
Known historized tags can be discovered from the local Galaxy Repository:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\Find-GalaxyHistorizedTags.ps1 -Limit 5
Observed candidates:
OtOpcUaParityTest_001.CounterTestMachine_001.TestHistoryValueTestMachine_002.TestHistoryValueTestMachine_003.TestHistoryValueTestMachine_004.TestHistoryValue
Using OtOpcUaParityTest_001.Counter over a 1440-minute lookback through
aahClientManaged.dll returned a successful one-row native query:
StartQuerySuccess = trueRowCount = 1StartDateTime = 2026-04-30T11:00:29.4340342ZEndDateTime = 2026-04-30T11:00:29.4340342ZQuality = 133OpcQuality = 192QualityDetail = 248Value = 0PercentGood = 100