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>
9.4 KiB
9.4 KiB
WCF Contract Evidence
Local run evidence
current\aahClient.dllexport inventory ran successfully. SHA256:77a778988e2d8f2d0e88113f8c8b0788a0ef34fa5134938a353976778144dc83.ArchestrA.HistorianAccess.OpenConnectionsucceeded againstlocalhost:32568usingHistorianConnectionArgswithConnectionType=ProcessandReadOnly=true.- Holding that native connection open produced established TCP sessions from the
native PowerShell process to
127.0.0.1:32568; the server-side listener was owned bySMSvcHost.exe, consistent with WCF Net.TCP port sharing. - The managed harness command
dotnet run --no-build --project tools\AVEVA.Historian.ReverseEngineering -- wcf-probe localhost 32568successfully calledGetVthrough fully managed WCF/MDAS:net.tcp://localhost:32568/Histreturned version11net.tcp://localhost:32568/Retrreturned version4net.tcp://localhost:32568/Statreturned version0net.tcp://localhost:32568/Trxreturned version2net.tcp://localhost:32568/Storagedid not listen on this local installnet.tcp://localhost:32568/HistCertand/Hist-Integratedreset when called with the plain managedGetVcontract, while prefixed variants such as/HCAP/HistCertreturnedEndpointNotFoundSanitized output is stored indocs\reverse-engineering\wcf-probe-localhost.json.
netsh traceandpktmonproduced ETL files under%TEMP%\histsdk-captures, but their converted PCAPNG files contained zero packets. Built-in Windows packet capture is not sufficient for loopback evidence on this machine.- A dedicated managed certificate-binding probe now reaches
HistCert.GetVthrough MDAS over WCF Net.TCP transport security:net.tcp://localhost:32568/HistCertreturned version11net.tcp://10.100.0.48:32568/HistCertinitially failed endpoint identity validation because the server certificate presented DNS identitylocalhost- the same remote endpoint returned version
11when the client supplied endpoint DNS identitylocalhostSanitized outputs are stored indocs\reverse-engineering\wcf-cert-probe-localhost-latest.json,docs\reverse-engineering\wcf-cert-probe-remote-latest.json, anddocs\reverse-engineering\wcf-cert-probe-remote-localhost-identity-latest.json.
- The same remote server also accepts the plain managed WCF/MDAS probe on the
expected non-security-specific service paths:
net.tcp://10.100.0.48:32568/Histreturned version11net.tcp://10.100.0.48:32568/Retrreturned version4net.tcp://10.100.0.48:32568/Statreturned version0net.tcp://10.100.0.48:32568/Trxreturned version2Sanitized output is stored indocs\reverse-engineering\wcf-probe-remote-latest.json.
- Managed remote
Open2evidence matches localhost: integrated Windows auth succeeds onnet.tcp://10.100.0.48:32568/Hist-Integrated, while the same Windows transport binding fails on plain/Histbefore dispatch. The successful returned handle is accepted byRetr.IsOriginalAllowed. Session output bytes and transient handle values are redacted indocs\reverse-engineering\wcf-open2-remote-latest.json. - Managed remote
StartQuery2evidence is still negative but sharper: all 22 reconstructedDataQueryRequestvariants successfully open the integrated session and passRetr.IsOriginalAllowed, thenStartQuery2returnsfalsewith zero response and error sizes. The legacyStartQuerycall returns code238for each request and also returns zero response size/no response buffer. Sanitized request hashes are stored indocs\reverse-engineering\wcf-start-query-remote-latest.json. - A later bounded managed replay of the first byte-matched full-history
candidate used the same integrated open and
Retr.IsOriginalAllowedpath;StartQuery2still returnedfalsewith zero response/error sizes, while legacyStartQueryfaulted with a server null-reference. This keepsOpen2as useful connection evidence, but not as a viable replacement for the nativeOpenConnection3session state required by query reads. - Managed wildcard tag browse remains positive evidence for an
Open2-backed operation:Retr.StartLikeTagNameSearchreturned0, and oneGetLikeTagnamesbatch returned the deterministic 66-byte single-tag buffer with SHA-2562d450a55f392aed0026e9a957fefa3b116aab6ec81912c5d824c6b9a1ff5a4a1. - Managed remote scalar tag calls also accept the integrated session handle:
Retr.GetTagTypeFromNamereturns code0and tag type1forOtOpcUaParityTest_001.Counter;Retr.IsManualTagreturns code0andfalse; legacyRetr.GetTagInfoFromNamereturns238with zero metadata bytes. FiveGetTgByNmtag-name buffer variants and fiveGetTgtag-id buffer variants all return238, sequence0, and zero output bytes. This suggests the calls are reaching server logic but the metadata-returning contract shape or request buffer is still incomplete. Sanitized output is stored indocs\reverse-engineering\wcf-tag-info-remote-latest.json.
Decompiled service contracts
current\aahClientManaged.dll contains WCF contracts with namespace aa:
HistoryServiceContract.IHistoryServiceContract[ServiceContract(Name = "Hist", Namespace = "aa")]GetInterfaceVersionas operationGetVOpenConnectionas operationOpenCloseConnectionas operationCloseValidateClientas operationVldCUpdateClientStatusas operationUpdCAddTagsasAddT,RegisterTagsasRTagAddStreamValuesasAddS,SetClientTimeOutasSetT
HistoryServiceContract.IHistoryServiceContract2[ServiceContract(Name = "Hist", Namespace = "aa")]- byte-buffer session open uses
OpenConnection2as operationOpen2 - extended client status uses
UpdC2/UpdC3 - extended write and maintenance calls include
EnsT,DelT,AddS2,ExKey,ValCl, andGetI
RetrievalServiceContract.IRetrievalServiceContract[ServiceContract(Name = "Retr", Namespace = "aa")]StartQuery,GetNextQueryResultBuffer,EndQueryuse default operation names- tag type/name helpers and tag info calls use default operation names
RetrievalServiceContract.IRetrievalServiceContract2/3/4- extended bool/error-buffer variants
- SQL/recordset byte stream calls
- tag query calls
QTB,QTG,QTE - event query calls use default operation names
- extended property calls include
GetTgByNm2andGetTepByNm
StorageServiceContract.IStorageServiceContract[ServiceContract(Name = "Storage", Namespace = "aa")]- storage/session, metadata, streamed-value, block, snapshot, and delete-tag calls
StatusServiceContract.IStatusServiceContract[ServiceContract(Name = "Stat", Namespace = "aa")]GetInterfaceVersionasGetV- server time, timezone, DB case sensitivity, and logging use default operation names
StatusServiceContract.IStatusServiceContract2- extended status operations include
GetSystemParameter,GetTimeZoneNames, license checks, historian info, and process/ping helpers - ping and historian-info helpers use aliases
PNGS,PNGP, andGETHI
- extended status operations include
TransactionServiceContract.ITransactionServiceContract[ServiceContract(Name = "Trx", Namespace = "aa")]- snapshot forwarding and non-streamed value transactions
aahMDASEncoder.ClientMessageEncoder wraps an inner WCF encoder and exposes
media/content type application/x-mdas. This means the first managed driver
transport target should be WCF Net.TCP plus the MDAS content-type encoder, not
the earlier speculative raw-frame layer.
Current unknowns
- Endpoint URI paths
net.tcp://{host}:32568/Hist,/Retr,/Stat, and/Trxare confirmed forGetVcalls on the local 2020 install. - Relay and local WCF probe evidence also identify security-specific history
endpoints
/HistCertand/Hist-Integrated./HistCertis confirmed as aHistcontract endpoint when called with MDAS over TLS transport security;/Hist-Integratedremains the Windows negotiate endpoint for integrated session open. - Managed
Open2evidence confirms/Hist-Integratedis the correct endpoint for integrated Windows auth. The plain/Histendpoint rejects the Windows transport-security upgrade before dispatching the operation. - The storage contract is confirmed statically, but
/Storagewas not a listening endpoint in the local probe; storage may be routed through session-specific storage/shard endpoints. Hist.OpenConnectionreaches server logic, but the native password/session packet encoding is not decoded yet. Seewcf-open-localhost.md.Hist.Open2is confirmed reachable with a managed version-1 byte buffer. Empty credentials return custom native error171(AuthenticationFailed), and the harness decodes observed five-byte error buffers as type plus little-endian error code. This confirms framing has progressed past packet-version rejection. Seewcf-open2-localhost.md.Statis reachable, butCStatusConnectionWCF.GetServerTimeis a no-op stub in the decompiled native WCF path and handle-dependent status calls fail with handle0. Seewcf-status-localhost.md.- Query request and response byte-buffer layouts are still proprietary payloads
inside WCF operations such as
StartQueryandGetNextQueryResultBuffer. - Write payload layouts remain out of scope until read/query payloads are decoded and fixture-backed.