Files
DP44/enriched-partialglm/Common/DTS.Common.IConnection/EthernetConnection.md
2026-04-17 14:55:32 -04:00

193 lines
12 KiB
Markdown

---
source_files:
- Common/DTS.Common.IConnection/EthernetConnection/RESTConnection.cs
- Common/DTS.Common.IConnection/EthernetConnection/EthernetConnection.cs
generated_at: "2026-04-16T11:48:39.886921+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "21dfcca726b35e5d"
---
# Documentation: IConnection Implementations
## 1. Purpose
This module provides two implementations of the `IConnection` interface for network communication within the DTS system. `EthernetConnection` is a full TCP socket wrapper that manages asynchronous socket operations, connection lifecycle, and keep-alive configuration for hardware devices. `RESTConnection` is a stub/skeleton implementation that immediately completes all operations without actual network I/O, designed to satisfy the `IConnection` interface contract for scenarios where REST-based communication replaces traditional socket connections.
---
## 2. Public Interface
### EthernetConnection (DTS.Common)
#### Properties
| Signature | Description |
|-----------|-------------|
| `bool IsSoftDisconnected { get; private set; }` | Returns `true` if the connection has been soft-disconnected. |
| `bool RequiresKeepAliveReset { get; set; }` | When `true`, `SoftConnect()` performs additional handshake on command port 8200 before connecting. |
| `Socket Sock` | The underlying `System.Net.Sockets.Socket` instance. Publicly accessible. |
| `bool Connected` | Returns `Sock != null && Sock.Connected`. |
| `string ConnectString` | Returns the connection string (format: `"host:port"`). |
| `SocketFlags Flags { get; set; }` | Socket flags used for send/receive operations. |
#### Events
| Signature | Description |
|-----------|-------------|
| `event EventHandler OnDisconnected` | Raised when `KeepAliveErrorReceived()` is invoked, indicating connection loss. |
#### Methods
| Signature | Description |
|-----------|-------------|
| `void Create(string connectString, string hostIPAddress)` | Creates and configures the underlying socket with keep-alive settings. Stores connection parameters. |
| `Socket CreateSock(string connectString, string hostIPAddress)` | Factory method that creates a configured `Socket` with TCP NoDelay, KeepAlive, and buffer sizes from `DFConstantsAndEnums`. Binds to `hostIPAddress` if provided. |
| `void SoftDisconnect()` | If `HardwareConstants.AllowSoftDisconnects` is true, disconnects and disposes the socket, sets `IsSoftDisconnected = true`. |
| `void SoftConnect()` | Reconnects a soft-disconnected socket. Optionally performs keep-alive reset via port 8200 if `RequiresKeepAliveReset` is true. Retries connection up to 3 times. |
| `void KeepAliveErrorReceived()` | Shuts down, closes, and disposes the socket; invokes `OnDisconnected` event. |
| `string GetConnectionData()` | Returns a string with local and remote endpoints, or empty string if unavailable. |
| `IAsyncResult BeginConnect(AsyncCallback cb, object state)` | Begins asynchronous connection. Throws if socket is null, `Connect_String` is empty/malformed, or port is invalid. |
| `void EndConnect(IAsyncResult ar)` | Completes the connection. Logs success with endpoints. |
| `IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, object state)` | Begins asynchronous disconnect. Throws `SocketException(WSAEISCONN)` if socket is not connected. |
| `void EndDisconnect(IAsyncResult asyncResult)` | Completes the disconnect operation. |
| `IAsyncResult BeginAccept(AsyncCallback callback, object state)` | Begins asynchronous accept for incoming connections. |
| `IConnection EndAccept(IAsyncResult asyncResult)` | Returns a new `EthernetConnection` wrapping the accepted socket. |
| `IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)` | Begins asynchronous send. Throws if socket is null, callback is null, or socket is not connected. |
| `int EndSend(IAsyncResult ar)` | Completes the send; returns bytes sent. Sets `Sock = null` on exception. |
| `Task<int> SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend)` | Task-based async wrapper over BeginSend/EndSend. |
| `IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)` | Begins asynchronous receive. Throws if socket is null or callback is null. |
| `int EndReceive(IAsyncResult ar)` | Completes the receive; returns bytes received. |
| `void Bind(int port)` | Binds socket to local endpoint resolved via DNS. |
| `void Listen(int backlog)` | Starts listening for incoming connections. |
| `void Dispose()` | Disposes the socket and resources. |
---
### RESTConnection (DTS.DASLib.Connection)
#### Properties
| Signature | Description |
|-----------|-------------|
| `bool IConnection.IsSoftDisconnected` | Always returns `false`. |
| `SocketFlags IConnection.Flags { get; set; }` | Stored value, defaults to `SocketFlags.None`. |
| `string IConnection.ConnectString` | Returns the stored `_ConnectString`. |
| `bool IConnection.Connected` | Returns `_bConnected` (set by `BeginConnect`/`BeginDisconnect`). |
#### Events
| Signature | Description |
|-----------|-------------|
| `event EventHandler OnDisconnected` | Defined but never invoked in the source. |
#### Methods
| Signature | Description |
|-----------|-------------|
| `void IConnection.Create(string connectString)` | Stores `connectString` in `_ConnectString`. |
| `void IConnection.Create(string connectString, string hostIPAddress)` | Stores both parameters in private fields. |
| `IAsyncResult IConnection.BeginConnect(AsyncCallback callback, object callbackObject)` | Sets `_bConnected = true`; returns an already-completed `AsyncNoResult`. |
| `void IConnection.EndConnect(IAsyncResult ar)` | No-op. |
| `IAsyncResult IConnection.BeginDisconnect(bool reuseSocket, AsyncCallback callback, object state)` | Sets `_bConnected = false`; returns an already-completed `AsyncNoResult`. |
| `void IConnection.EndDisconnect(IAsyncResult asyncResult)` | No-op. |
| `IAsyncResult IConnection.BeginAccept(AsyncCallback callback, object state)` | Returns an already-completed `AsyncNoResult`. |
| `IConnection IConnection.EndAccept(IAsyncResult asyncResult)` | Returns `this`. |
| `IAsyncResult IConnection.BeginSend(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend, AsyncCallback callback, object callbackObject)` | Returns an already-completed `AsyncNoResult`. |
| `int IConnection.EndSend(IAsyncResult ar)` | Returns `0`. |
| `IAsyncResult IConnection.BeginReceive(byte[] receiveBuffer, int bufferStartOffset, int maxSizeToReceive, AsyncCallback callback, object callbackObject)` | Returns an already-completed `AsyncNoResult`. |
| `int IConnection.EndReceive(IAsyncResult ar)` | Returns `0`. |
| `Task<int> IConnection.SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend)` | Task wrapper over BeginSend/EndSend. |
| `void IConnection.Bind(int port)` | No-op (commented as "not really needed"). |
| `void IConnection.Listen(int backlog)` | No-op. |
| `void IConnection.KeepAliveErrorReceived()` | No-op. |
| `void IConnection.SoftConnect()` | No-op. |
| `void IConnection.SoftDisconnect()` | No-op. |
| `string IConnection.GetConnectionData()` | Returns `"$(_ConnectString) - $(_hostIPAddress)"`. |
| `void Dispose()` | Standard dispose pattern; no actual resource cleanup. |
#### Internal Class: AsyncNoResult
An `IAsyncResult` implementation used to represent immediately-completed operations.
| Member | Description |
|--------|-------------|
| `bool IsCompleted` | Returns `true` if `_executionState != PENDING`. |
| `WaitHandle AsyncWaitHandle` | Lazily-created `ManualResetEvent`. |
| `object AsyncState` | Returns the state object passed to constructor. |
| `bool CompletedSynchronously` | Returns `true` if `_executionState == COMPLETED_SYNC`. |
| `void SetCompleted(bool completedSync)` | Transitions from PENDING to COMPLETED_SYNC or COMPLETED_ASYNC; invokes callback. Throws `InvalidOperationException` if already completed. |
---
## 3. Invariants
### EthernetConnection
- **Connect string format**: Must be `"hostname:port"` where port is a valid integer. Validated in `BeginConnect`.
- **Socket creation prerequisite**: `Sock` must be created via `Create()` before calling `BeginConnect`, `BeginSend`, `BeginReceive`, `BeginAccept`, `BeginDisconnect`, `Bind`, or `Listen`. All these methods throw if `Sock` is null.
- **Connection state for send**: `BeginSend` throws if `Sock.Connected` is `false`.
- **Connection state for disconnect**: `BeginDisconnect` throws `SocketException(DFConstantsAndEnums.WSAEISCONN)` if `Sock.Connected` is `false`.
- **Callback requirement**: `BeginSend` and `BeginReceive` throw if callback is null.
- **Soft disconnect gate**: `SoftDisconnect()` and `SoftConnect()` do nothing if `HardwareConstants.AllowSoftDisconnects` is `false`.
- **Keep-alive configuration**: All sockets created via `CreateSock` have keep-alive enabled with values from `DFConstantsAndEnums.LocalKeepAliveTimeOutMS` and `DFConstantsAndEnums.LocalKeepAliveRetryIntervalMS`.
### RESTConnection
- **No actual I/O**: All Begin* methods return immediately with `CompletedSynchronously = true`.
- **Send/Receive return zero**: `EndSend` and `EndReceive` always return `0`.
- **IsSoftDisconnected**: Always `false`.
- **AsyncNoResult state machine**: `SetCompleted` can only be called once; subsequent calls throw `InvalidOperationException`.
---
## 4. Dependencies
### EthernetConnection depends on:
- `DTS.Common.Interface.Connection.IConnection` - Interface being implemented.
- `DTS.Common.Utilities.Logging.APILogger` - Used for logging throughout.
- `DTS.Common.DASResource.DFConstantsAndEnums` - Provides `SendBufferSizeBytes`, `ReceiveBufferSizeBytes`, `LocalKeepAliveTimeOutMS`, `LocalKeepAliveRetryIntervalMS`, `WSAEISCONN`.
- `DTS.Common.Enums.DASFactory` - Namespace imported but no direct usage visible in source.
- `DTS.Common.Enums.Hardware.HardwareConstants.AllowSoftDisconnects` - Controls soft disconnect behavior.
- `System.Net.Sockets.Socket` - Core socket functionality.
- `System.Net.Dns`, `System.Net.IPEndPoint`, `System.Net.IPAddress` - Network addressing.
### RESTConnection depends on:
- `DTS.Common.Interface.Connection.IConnection` - Interface being implemented.
- `DTS.Common.Utilities.Logging` - Namespace imported but no direct usage visible in source.
- `System.Net.Sockets.SocketFlags` - Used for the `Flags` property.
- `System.Threading` - `ManualResetEvent`, `Interlocked`, `Thread.VolatileRead`.
### What depends on these modules:
- Unclear from source alone. Both implement `IConnection`, suggesting consumers depend on that interface rather than concrete types directly.
---
## 5. Gotchas
### EthernetConnection
1. **Dead code in `Create(string connectString)`**: The single-parameter overload contains a commented-out recursive call with the comment `"this is recursive!"`. The method body is effectively empty and does nothing.
2. **Counterintuitive error code in `BeginDisconnect`**: When the socket is *not* connected, `BeginDisconnect` throws `SocketException(WSAEISCONN)`. The constant name suggests "is connected" which is the opposite of the actual condition being checked.
3. **SoftConnect has hardcoded command port logic**: When `RequiresKeepAliveReset` is true, `SoftConnect()` connects to port 8200 and sends `<60,5,4>` before connecting to the actual target port. This appears to be device-specific protocol behavior embedded in the connection class.
4. **Socket is public and mutable**: The `Sock` field is public, allowing external code to modify or replace it, potentially bypassing the class's invariants.
5. **EndSend nullifies socket on exception**: If `EndSend` throws, it sets `Sock = null` before re-throwing. This is not documented and could surprise callers.
6. **Thread.Sleep in SoftConnect/SoftDisconnect**: Both methods use `Thread.Sleep` (50ms and 100ms/1000ms respectively), which blocks the calling thread.
### RESTConnection
1. **No-op implementations**: Most methods do nothing or return immediately. This is by design but could cause confusion if developers expect actual network behavior.
2. **OnDisconnected never raised**: The event is declared but never invoked anywhere in the class.
3. **Namespace mismatch**: The file path suggests `DTS.Common.IConnection` but the namespace is `DTS.DASLib.Connection`. This may indicate a historical refactoring or organizational inconsistency.
4. **Unused imports**: `System.CodeDom`, `System.Collections.Specialized`, `System.Runtime.Remoting.Messaging` are imported but not used in the source.