fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Layout:
- src/ .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
MxAsbClient, probes, tests, harnesses. Executable spec.
- design/ Architectural plan for the Rust port (M0–M6), error
model, protocol invariants, risks (R1–R16), adversarial
review log (review.md).
- rust/ Rust workspace. M0 skeleton + M1 codec parity.
mxaccess-codec: 215 unit tests + 2 cross-implementation
parity tests (byte-identical against .NET reference).
Other crates are M0 stubs awaiting M2+.
- captures/ Frida + netsh + pcap evidence per CLAUDE.md
("captures are evidence, not throwaway logs").
- analysis/ Decompiled C# (frida/proxy/decompiled-*),
Ghidra exports for native DLLs (`exports/` only —
working state at `projects/` and AVEVA's input
binaries at `input/` are gitignored).
- docs/ Reverse-engineering reference docs.
- tools/ Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/ Rust CI: fmt + build + test + clippy on Windows.
- LICENSE MIT (Joseph Doherty, 2026).
Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly
Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
493 lines
18 KiB
C#
493 lines
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.ServiceModel;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using ArchestrAServices.Common;
|
|
using Asb.Base.V2.ContractTypes;
|
|
|
|
namespace Asb.Base.V2;
|
|
|
|
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
|
|
public abstract class BaseV2Shim : IAuthenticateAsb
|
|
{
|
|
private sealed class ConnectionContext : IDisposable
|
|
{
|
|
private readonly TimeSpan keepAliveTimeout;
|
|
|
|
private readonly Timer timer;
|
|
|
|
private bool disposed;
|
|
|
|
public IContextChannel ConnectionChannel { get; private set; }
|
|
|
|
public IBaseV2 ConnectionImplementation { get; }
|
|
|
|
public ConnectionContext(IBaseV2 implementation, TimerCallback keepAliveTimeoutCallback, Guid connectionId, TimeSpan keepAliveTimeout)
|
|
{
|
|
ConnectionChannel = ((OperationContext.Current == null) ? null : OperationContext.Current.Channel);
|
|
ConnectionImplementation = implementation;
|
|
timer = new Timer(keepAliveTimeoutCallback, connectionId, (int)keepAliveTimeout.TotalMilliseconds, -1);
|
|
this.keepAliveTimeout = keepAliveTimeout;
|
|
}
|
|
|
|
~ConnectionContext()
|
|
{
|
|
Dispose(disposing: false);
|
|
}
|
|
|
|
public void RestartTimer()
|
|
{
|
|
timer.Change((int)keepAliveTimeout.TotalMilliseconds, -1);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if (disposed)
|
|
{
|
|
return;
|
|
}
|
|
disposed = true;
|
|
if (disposing)
|
|
{
|
|
if (ConnectionChannel != null)
|
|
{
|
|
ConnectionChannel.Close();
|
|
ConnectionChannel = null;
|
|
}
|
|
if (timer != null)
|
|
{
|
|
timer.Dispose();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static readonly ReaderWriterLockSlim implementationLock = new ReaderWriterLockSlim();
|
|
|
|
private static readonly Dictionary<Guid, ConnectionContext> implementations = new Dictionary<Guid, ConnectionContext>();
|
|
|
|
private static readonly TimeSpan defaultKeepAliveTimeout = TimeSpan.FromSeconds(30.0);
|
|
|
|
public virtual ConnectionState DownstreamConnectionState { get; set; }
|
|
|
|
protected virtual TimeSpan KeepAliveTimeout => defaultKeepAliveTimeout;
|
|
|
|
public ConnectResponse Connect(ConnectRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("Connect entry [ConId]", request.ConnectionId);
|
|
ServiceTrace.LogResume("Connect entry, connection Id {0} ", request.ConnectionId);
|
|
ConnectResponse connectResponse = SystemAuthenticationServiceAuthentication.ProcessClientConnection(request);
|
|
ServiceTrace.LogVerbose("BaseV2Shim.Connect started new SysAuthenticator for connection Id {0}", connectResponse.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogSuspend("Connect exit, connection Id {0}, success = {1}", request.ConnectionId, connectResponse.Result.Success);
|
|
ServiceTrace.LogCsv("Connect exit [ConId Success]", request.ConnectionId, connectResponse.Result.Success);
|
|
return connectResponse;
|
|
}
|
|
|
|
public AuthenticateMeResponse AuthenticateMe(AuthenticateMeRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("AuthenticateMe entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("AuthenticateMe entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
ArchestrAResult archestrAResult = ArchestrAResult.MakeResult(ArchestrAError.OperationFailed, 0);
|
|
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
|
|
if (serviceAuthenticator != null)
|
|
{
|
|
if (serviceAuthenticator.ProcessClientAuthenticateMe(request))
|
|
{
|
|
ServiceTrace.LogVerbose("AuthenticateMe found authenticator and validated request message, establishing serivce implementation for connect Id {0})", serviceAuthenticator.ConnectionId);
|
|
ConsumerMetadata metadata = ConsumerMetadata.Create(request.ConsumerMetaData);
|
|
archestrAResult = CheckConsumerMetadata(metadata, serviceAuthenticator.ConnectionId);
|
|
if (archestrAResult.Success)
|
|
{
|
|
archestrAResult = CreateServiceImplmentation(serviceAuthenticator, metadata);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
archestrAResult = ArchestrAResult.MakeResult(ArchestrAError.ApplicationAuthenticationError, 0);
|
|
string message = string.Format(CultureInfo.CurrentCulture, "AuthenticateMe unable to authenticate client for ConnectionId {0}", new object[1] { serviceAuthenticator.ConnectionId });
|
|
ServiceTrace.LogWarning(message);
|
|
archestrAResult.AddErrorMessage(message);
|
|
}
|
|
}
|
|
if (!archestrAResult.Success)
|
|
{
|
|
OnDisconnect(request.ConnectionValidator.ConnectionId);
|
|
}
|
|
ServiceTrace.LogSuspend("AuthenticateMe exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, archestrAResult.Success);
|
|
ServiceTrace.LogCsv("AuthenticateMe exit [ConId Success]", request.ConnectionValidator.ConnectionId, archestrAResult.Success);
|
|
return new AuthenticateMeResponse(archestrAResult, DownstreamConnectionState);
|
|
}
|
|
|
|
public KeepAliveResponse KeepAlive(KeepAliveRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("KeepAlive entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("KeepAlive entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
ArchestrAResult result = ArchestrAResult.MakeResult(ArchestrAError.OperationFailed, 0);
|
|
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
|
|
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
|
|
{
|
|
implementationLock.EnterReadLock();
|
|
bool flag;
|
|
ConnectionContext value;
|
|
try
|
|
{
|
|
flag = implementations.TryGetValue(request.ConnectionValidator.ConnectionId, out value);
|
|
}
|
|
finally
|
|
{
|
|
implementationLock.ExitReadLock();
|
|
}
|
|
if (flag && value != null)
|
|
{
|
|
value.RestartTimer();
|
|
IBaseV2 connectionImplementation = value.ConnectionImplementation;
|
|
try
|
|
{
|
|
result = EnsureValidResult(connectionImplementation.KeepAlive());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ServiceTrace.LogWarning("KeepAlive caught exception from implementation for connection Id {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
|
|
if (ex.InnerException != null)
|
|
{
|
|
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ServiceTrace.LogResume("KeepAlive exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("KeepAlive exit [ConId]", request.ConnectionValidator.ConnectionId);
|
|
return new KeepAliveResponse(result, DownstreamConnectionState);
|
|
}
|
|
|
|
public GetStatusItemsResponse GetStatusItems(GetStatusItemsRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("GetStatusItems entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("GetStatusItems entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
GetStatusItemsResponse getStatusItemsResponse = new GetStatusItemsResponse(ArchestrAResult.MakeResult(ArchestrAError.InvalidConnectionId, 0), null, DownstreamConnectionState);
|
|
IBaseV2 implementation = GetImplementation<IBaseV2>(request);
|
|
if (implementation != null)
|
|
{
|
|
try
|
|
{
|
|
getStatusItemsResponse.Result = EnsureValidResult(implementation.GetStatusItems(out var items));
|
|
List<string> list = items.ToList();
|
|
list.Add("ServiceLoadTime");
|
|
getStatusItemsResponse.Items = list.ToArray();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ServiceTrace.LogWarning("GetStatusItems caught exception from implementation for ConnectionId {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
|
|
getStatusItemsResponse.Result.AddErrorMessage(ex.Message);
|
|
if (ex.InnerException != null)
|
|
{
|
|
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
|
|
getStatusItemsResponse.Result.AddErrorMessage(ex.InnerException.Message);
|
|
}
|
|
getStatusItemsResponse.Result.ResultCodeAsError = ArchestrAError.OperationFailed;
|
|
}
|
|
}
|
|
ServiceTrace.LogSuspend("GetStatusItems exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, getStatusItemsResponse.Result.Success);
|
|
ServiceTrace.LogCsv("GetStatusItems exit [ConId Success]", request.ConnectionValidator.ConnectionId, getStatusItemsResponse.Result.Success);
|
|
return getStatusItemsResponse;
|
|
}
|
|
|
|
public GetStatusResponse GetStatus(GetStatusRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("GetStatus entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("GetStatus entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
GetStatusResponse getStatusResponse = new GetStatusResponse(ArchestrAResult.MakeResult(ArchestrAError.InvalidConnectionId, 0), null, DownstreamConnectionState);
|
|
IBaseV2 implementation = GetImplementation<IBaseV2>(request);
|
|
if (implementation != null)
|
|
{
|
|
try
|
|
{
|
|
getStatusResponse.Result = EnsureValidResult(implementation.GetStatus(request.ItemsToReturn, out var items));
|
|
List<NamedValue> list = items.ToList();
|
|
list.Add(new NamedValue
|
|
{
|
|
Name = "ServiceLoadTime",
|
|
Value = Value.Create(implementation.ServiceLoadTime)
|
|
});
|
|
getStatusResponse.Items = list.ToArray();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ServiceTrace.LogWarning("GetStatus caught exception from implementation for ConnectionId {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
|
|
getStatusResponse.Result.AddErrorMessage(ex.Message);
|
|
if (ex.InnerException != null)
|
|
{
|
|
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
|
|
getStatusResponse.Result.AddErrorMessage(ex.InnerException.Message);
|
|
}
|
|
getStatusResponse.Result.ResultCodeAsError = ArchestrAError.OperationFailed;
|
|
}
|
|
}
|
|
ServiceTrace.LogSuspend("GetStatus exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, getStatusResponse.Result.Success);
|
|
ServiceTrace.LogCsv("GetStatus exit [ConId Success]", request.ConnectionValidator.ConnectionId, getStatusResponse.Result.Success);
|
|
return getStatusResponse;
|
|
}
|
|
|
|
public RenewResponse Renew(RenewRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
ServiceTrace.LogCsv("Renew entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("Renew entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
RenewResponse renewResponse = SystemAuthenticationServiceAuthentication.ProcessClientRenew(request);
|
|
ServiceTrace.LogSuspend("Renew exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, renewResponse.Result.Success);
|
|
ServiceTrace.LogCsv("Renew exit [ConId Success]", request.ConnectionValidator.ConnectionId, renewResponse.Result.Success);
|
|
return renewResponse;
|
|
}
|
|
|
|
public void UpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfigurationRequest request)
|
|
{
|
|
if (request != null)
|
|
{
|
|
ServiceTrace.LogCsv("UpdateSystemAuthenticationConfiguration entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("UpdateSystemAuthenticationConfiguration entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
SystemAuthenticationServiceAuthentication.ProcessClientUpdateSystemAuthenticationConfiguration(request);
|
|
ServiceTrace.LogSuspend("UpdateSystemAuthenticationConfiguration exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogCsv("UpdateSystemAuthenticationConfiguration exit [ConId]", request.ConnectionValidator.ConnectionId);
|
|
}
|
|
}
|
|
|
|
public void Disconnect(DisconnectRequest request)
|
|
{
|
|
if (request != null)
|
|
{
|
|
ServiceTrace.LogCsv("Disconnect entry [ConnId]", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogResume("Disconnect entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
|
|
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
|
|
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
|
|
{
|
|
OnDisconnect(request.ConnectionValidator.ConnectionId);
|
|
serviceAuthenticator.ProcessClientDisconnect(request);
|
|
}
|
|
ServiceTrace.LogSuspend("Disconnect exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
|
|
ServiceTrace.LogCsv("Disconnect exit [ConId]", request.ConnectionValidator.ConnectionId);
|
|
}
|
|
}
|
|
|
|
protected UserToken DecryptUserToken(Guid connectionId, UserTokenContract wireToken)
|
|
{
|
|
if (wireToken == null)
|
|
{
|
|
return null;
|
|
}
|
|
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(connectionId);
|
|
if (serviceAuthenticator == null || !serviceAuthenticator.SecureSessionEstablished)
|
|
{
|
|
throw new InvalidOperationException("Cannot decrypt user token due to session in wrong state");
|
|
}
|
|
UserToken userToken = new UserToken
|
|
{
|
|
Encryption = wireToken.Encryption,
|
|
HostName = wireToken.HostName,
|
|
IdType = wireToken.IdType,
|
|
LocationId = wireToken.LocationId,
|
|
UserName = wireToken.UserName,
|
|
Validity = wireToken.Validity
|
|
};
|
|
if (wireToken.Password != null)
|
|
{
|
|
byte[] bytes = serviceAuthenticator.Decypher(wireToken.Password, serviceAuthenticator.EncryptionKey);
|
|
userToken.Password = Encoding.UTF8.GetString(bytes);
|
|
}
|
|
if (wireToken.SamlToken != null)
|
|
{
|
|
userToken.SamlToken = serviceAuthenticator.Decypher(wireToken.SamlToken, serviceAuthenticator.EncryptionKey);
|
|
}
|
|
if (wireToken.JwtToken != null)
|
|
{
|
|
byte[] bytes2 = serviceAuthenticator.Decypher(wireToken.JwtToken, serviceAuthenticator.EncryptionKey);
|
|
userToken.JwtToken = Encoding.UTF8.GetString(bytes2);
|
|
}
|
|
if (wireToken.X509Certificate != null)
|
|
{
|
|
userToken.X509Certificate = serviceAuthenticator.Decypher(wireToken.X509Certificate, serviceAuthenticator.EncryptionKey);
|
|
}
|
|
return userToken;
|
|
}
|
|
|
|
protected static ArchestrAResult EnsureValidResult(ArchestrAResult result)
|
|
{
|
|
if (result == null)
|
|
{
|
|
return ArchestrAResult.MakeErrorResult("Service returned no result");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private ArchestrAResult CreateServiceImplmentation(SystemAuthenticationServiceAuthentication authenticator, ConsumerMetadata metadata)
|
|
{
|
|
ArchestrAResult result = ArchestrAResult.MakeGoodResult();
|
|
IBaseV2 implementation = GetImplementation();
|
|
if (implementation == null)
|
|
{
|
|
result = ArchestrAResult.MakeResult(ArchestrAError.Unknown, 0);
|
|
string message = string.Format(CultureInfo.CurrentCulture, "AuthenticateMe could not create a service implementation object for ConnectionId {0}", new object[1] { authenticator.ConnectionId });
|
|
ServiceTrace.LogWarning(message);
|
|
result.AddErrorMessage(message);
|
|
return result;
|
|
}
|
|
try
|
|
{
|
|
ServiceTrace.LogCsv("AuthenticateMe found authenticator and validated request message, calling implementation OnConnect [ConId]", authenticator.ConnectionId);
|
|
ServiceTrace.LogVerbose("AuthenticateMe found authenticator and validated request message, calling implementation OnConnect for connection Id {0}", authenticator.ConnectionId);
|
|
implementation.ServiceLoadTime = DateTime.UtcNow;
|
|
implementation.ConnectionId = authenticator.ConnectionId;
|
|
implementation.OnConnect(authenticator.Lifetime, metadata);
|
|
CreateConnectionContext(authenticator.ConnectionId, implementation);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
result = ArchestrAResult.MakeResult(ArchestrAError.Unknown, 0);
|
|
ServiceTrace.LogWarning("AuthenticateMe caught exception from implementation for ConnectionId {0}: {1}", authenticator.ConnectionId, ex.Message);
|
|
result.AddErrorMessage(ex.Message);
|
|
if (ex.InnerException != null)
|
|
{
|
|
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
|
|
result.AddErrorMessage(ex.InnerException.Message);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private void CreateConnectionContext(Guid connectionId, IBaseV2 implementation)
|
|
{
|
|
implementationLock.EnterWriteLock();
|
|
try
|
|
{
|
|
implementations.Add(connectionId, new ConnectionContext(implementation, KeepaliveHandler, connectionId, KeepAliveTimeout));
|
|
ServiceTrace.LogVerbose("AuthenticateMe added implementation for connection Id {0}", connectionId);
|
|
}
|
|
finally
|
|
{
|
|
implementationLock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
private static void OnDisconnect(Guid connectionId)
|
|
{
|
|
IBaseV2 baseV = null;
|
|
bool flag = false;
|
|
implementationLock.EnterWriteLock();
|
|
try
|
|
{
|
|
flag = implementations.TryGetValue(connectionId, out var value);
|
|
if (flag)
|
|
{
|
|
implementations.Remove(connectionId);
|
|
ServiceTrace.LogVerbose("OnDisconnect removed implementation for ConnectionId {0}", connectionId);
|
|
baseV = value.ConnectionImplementation;
|
|
value.Dispose();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ServiceTrace.LogVerbose("OnDisconnect handled an exception: {0}", ex);
|
|
}
|
|
finally
|
|
{
|
|
implementationLock.ExitWriteLock();
|
|
}
|
|
if (flag && baseV != null)
|
|
{
|
|
try
|
|
{
|
|
ServiceTrace.LogCsv("OnDisconnect found authenticator and validated request message, calling implementation OnDisconnect Id =", connectionId);
|
|
baseV.OnDisconnect();
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
ServiceTrace.LogWarning("OnDisconnect caught exception from implementation for ConnectionId {0}: {1}", connectionId, ex2.Message);
|
|
if (ex2.InnerException != null)
|
|
{
|
|
ServiceTrace.LogWarning(" {0}", ex2.InnerException.Message);
|
|
}
|
|
}
|
|
}
|
|
SysAuthenticatorServiceCache.RemoveServiceAuthenticator(connectionId);
|
|
}
|
|
|
|
private static void KeepaliveHandler(object connectionId)
|
|
{
|
|
try
|
|
{
|
|
OnDisconnect((Guid)connectionId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ServiceTrace.LogVerbose("KeepaliveHandler handled an exception {0}", ex);
|
|
}
|
|
}
|
|
|
|
protected virtual ArchestrAResult CheckConsumerMetadata(ConsumerMetadata metadata, Guid connectionId)
|
|
{
|
|
return ArchestrAResult.MakeGoodResult();
|
|
}
|
|
|
|
protected abstract IBaseV2 GetImplementation();
|
|
|
|
protected static T GetImplementation<T>(ConnectedRequest request) where T : class, IBaseV2
|
|
{
|
|
if (request == null)
|
|
{
|
|
return null;
|
|
}
|
|
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
|
|
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
|
|
{
|
|
implementationLock.EnterReadLock();
|
|
bool flag;
|
|
ConnectionContext value;
|
|
try
|
|
{
|
|
flag = implementations.TryGetValue(request.ConnectionValidator.ConnectionId, out value);
|
|
}
|
|
finally
|
|
{
|
|
implementationLock.ExitReadLock();
|
|
}
|
|
if (flag && value != null)
|
|
{
|
|
value.RestartTimer();
|
|
return value.ConnectionImplementation as T;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|