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

224 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common.IConnection/EthernetConnection/RESTConnection.cs
- Common/DTS.Common.IConnection/EthernetConnection/EthernetConnection.cs
generated_at: "2026-04-16T02:09:04.702798+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "21dfcca726b35e5d"
---
# Documentation: `RESTConnection` and `EthernetConnection` Classes
## 1. Purpose
This module provides two concrete implementations of the `IConnection` interface for network communication: `RESTConnection`, a stub implementation that simulates connection operations without actual network activity (intended for REST-based or mock scenarios), and `EthernetConnection`, a full-featured implementation using `System.Net.Sockets.Socket` for real-time Ethernet communication with hardware devices. `RESTConnection` exists to satisfy interface contracts in environments where actual socket communication is unnecessary or undesirable (e.g., testing, REST API interactions), while `EthernetConnection` handles real socket operations including connection establishment, data transfer, keep-alive configuration, and soft disconnect/reconnect workflows for embedded hardware.
## 2. Public Interface
### `RESTConnection` (namespace `DTS.DASLib.Connection`)
- **`bool IConnection.IsSoftDisconnected => false`**
Always returns `false`; does not support soft disconnect semantics.
- **`SocketFlags IConnection.Flags { get; set; }`**
Gets/sets socket flags (unused; always `SocketFlags.None`).
- **`string IConnection.ConnectString => _ConnectString`**
Returns the stored connection string (e.g., `"host:port"`), set via `Create`.
- **`bool IConnection.Connected => _bConnected`**
Returns internal `_bConnected` state (set to `true` on `BeginConnect`, `false` on `BeginDisconnect`).
- **`event EventHandler OnDisconnected`**
Declared but never raised (no invocation in source).
- **`void IConnection.Create(string connectString)`**
Stores `connectString` in `_ConnectString`.
- **`void IConnection.Create(string connectString, string hostIPAddress)`**
Stores `connectString` and `hostIPAddress` in respective fields.
- **`IAsyncResult IConnection.BeginConnect(AsyncCallback callback, object callbackObject)`**
Sets `_bConnected = true` and returns a *synchronously completed* `IAsyncResult` via `GetAlreadyCompleted`.
- **`IAsyncResult IConnection.BeginDisconnect(bool reuseSocket, AsyncCallback callback, object state)`**
Sets `_bConnected = false` and returns a *synchronously completed* `IAsyncResult`.
- **`IAsyncResult IConnection.BeginSend(...)` / `BeginReceive(...)` / `BeginAccept(...)`**
All return *synchronously completed* `IAsyncResult` instances; no actual I/O.
- **`void IConnection.EndConnect(...)` / `EndDisconnect(...)` / `EndSend(...)` / `EndReceive(...)` / `EndAccept(...)`**
No-op implementations. `EndSend`/`EndReceive` return `0`. `EndAccept` returns `this`.
- **`void IConnection.Bind(int port)`**
Stub; no-op.
- **`void IConnection.Listen(int backlog)`**
Stub; no-op.
- **`void IConnection.KeepAliveErrorReceived()`**
Stub; no-op.
- **`string IConnection.GetConnectionData()`**
Returns `"{_ConnectString} - {_hostIPAddress}"`.
- **`Task<int> IConnection.SendAsync(...)`**
Wraps `BeginSend`/`EndSend` using `Task.Factory.FromAsync`; returns a completed task with result `0`.
- **`void IConnection.SoftConnect()` / `SoftDisconnect()`**
Stubs; no-op.
- **`void Dispose()` / `~RESTConnection()`**
Implements `IDisposable`; marks `_disposed = true` but performs no socket cleanup.
### `EthernetConnection` (namespace `DTS.Common`)
- **`bool IsSoftDisconnected { get; private set; }`**
Tracks soft-disconnect state; `true` after successful `SoftDisconnect()`.
- **`bool Connected => Sock != null && Sock.Connected`**
Reflects underlying socket state.
- **`string ConnectString => Connect_String`**
Returns stored connection string.
- **`SocketFlags Flags { get; set; }`**
Gets/sets socket flags used in `BeginSend`/`BeginReceive`.
- **`Socket Sock`**
Public field holding the underlying `Socket` instance.
- **`event EventHandler OnDisconnected`**
Raised in `KeepAliveErrorReceived()`.
- **`void Create(string connectString, string hostIPAddress)`**
Stores `connectString` and `hostIPAddress`, then calls `CreateSock` to initialize `Sock`.
- **`Socket CreateSock(string connectString, string hostIPAddress)`**
Creates and configures a `Socket` with:
- `NoDelay = true` (Nagle disabled)
- `KeepAlive = true`
- Buffer sizes from `DFConstantsAndEnums.SendBufferSizeBytes` / `ReceiveBufferSizeBytes`
- Custom keep-alive parameters from `DFConstantsAndEnums.LocalKeepAliveTimeOutMS` / `LocalKeepAliveRetryIntervalMS`
- Optional binding to `hostIPAddress` if provided.
- **`void SoftDisconnect()`**
If `HardwareConstants.AllowSoftDisconnects` is `true` and socket is connected:
- Disconnects and disposes `Sock`
- Sets `IsSoftDisconnected = true`
- Logs action.
- **`void SoftConnect()`**
If `AllowSoftDisconnects` is `true` and socket is not connected:
- Parses `Connect_String` as `"host:port"`.
- If `RequiresKeepAliveReset` is `true`, connects to port `8200`, sends `<60,5,4>`, receives response, then disconnects.
- Retries up to 3 times to connect to `host:port` (1s delay between attempts).
- Sets `IsSoftDisconnected = false`, logs success.
- **`void KeepAliveErrorReceived()`**
Shuts down, closes, and disposes `Sock`, sets `Sock = null`, and raises `OnDisconnected`.
- **`string GetConnectionData()`**
Returns `"local: {LocalEndPoint}, Remote: {RemoteEndPoint}"` or `""` on error.
- **`IAsyncResult BeginConnect(AsyncCallback, object)`**
Validates `Sock`, `Connect_String`, and port format; delegates to `Sock.BeginConnect`.
- **`void EndConnect(IAsyncResult)`**
Calls `Sock.EndConnect`, logs connection details.
- **`IAsyncResult BeginDisconnect(bool, AsyncCallback, object)`**
Validates `Sock`; throws if socket is `null` or *not* connected (`SocketException WSAEISCONN`); delegates to `Sock.BeginDisconnect`.
- **`void EndDisconnect(IAsyncResult)`**
Calls `Sock.EndDisconnect`.
- **`IAsyncResult BeginAccept(AsyncCallback, object)`**
Validates `Sock`; delegates to `Sock.BeginAccept`.
- **`IConnection EndAccept(IAsyncResult)`**
Calls `Sock.EndAccept`, wraps result in a *new* `EthernetConnection` instance.
- **`void Bind(int port)`**
Validates `Sock`; binds to first DNS-resolved IP address on `port`.
- **`void Listen(int backlog)`**
Validates `Sock`; calls `Sock.Listen`.
- **`IAsyncResult BeginSend(byte[], int, int, AsyncCallback, object)`**
Validates `Sock`, callback, and connection state; throws if not connected; delegates to `Sock.BeginSend`.
- **`int EndSend(IAsyncResult)`**
Calls `Sock.EndSend`; sets `Sock = null` on exception.
- **`Task<int> SendAsync(...)`**
Wraps `BeginSend`/`EndSend` via `Task.Factory.FromAsync`.
- **`IAsyncResult BeginReceive(byte[], int, int, AsyncCallback, object)`**
Validates `Sock` and callback; delegates to `Sock.BeginReceive`.
- **`int EndReceive(IAsyncResult)`**
Calls `Sock.EndReceive`.
- **`void Dispose()` / `~EthernetConnection()`**
Implements `IDisposable`; safely shuts down/disposes `Sock` in `Dispose(bool)`.
## 3. Invariants
- **`RESTConnection`**:
- `_bConnected` is the sole source of truth for connection state; never updated by external I/O.
- All `Begin*`/`End*` operations are synchronous and return immediately; no async state is maintained.
- `IsSoftDisconnected` is always `false`; soft disconnect logic is absent.
- `Connected` reflects `_bConnected`, which is manually toggled by `BeginConnect`/`BeginDisconnect`.
- **`EthernetConnection`**:
- `Connected` depends on `Sock != null && Sock.Connected`; `Sock` may be `null` after errors or disposal.
- `SoftDisconnect()` and `SoftConnect()` only execute if `HardwareConstants.AllowSoftDisconnects` is `true`.
- `SoftConnect()` requires `Connect_String` to be in `"host:port"` format; port must be parseable as `int`.
- `BeginDisconnect` throws `SocketException` if socket is not connected (per `WSAEISCONN`).
- `BeginSend`/`BeginReceive` throw if socket is not connected or callback is `null`.
- `KeepAliveErrorReceived()` guarantees `Sock` is `null` after execution (disposal path).
## 4. Dependencies
### `RESTConnection`:
- **Imports**:
- `DTS.Common.Interface.Connection` (for `IConnection`)
- `DTS.Common.Utilities.Logging` (for `APILogger`, but *not used* in this file)
- Standard .NET libraries (`System.Net.Sockets`, `System.Threading`, etc.)
- **Depended on by**: Any code requiring an `IConnection` instance where network activity is unnecessary (e.g., unit tests, REST-based workflows).
### `EthernetConnection`:
- **Imports**:
- `DTS.Common.Interface.Connection` (`IConnection`)
- `DTS.Common.DASResource` (for `Strings.EthernetConnection_*_Err*` exception messages)
- `DTS.Common.Enums.DASFactory` (for `HardwareConstants.AllowSoftDisconnects`)
- `DTS.Common.Utilities.Logging` (for `APILogger`)
- `DFConstantsAndEnums` (for buffer sizes, keep-alive timeouts, `WSAEISCONN`)
- **Depended on by**: Higher-level connection management logic (e.g., device initialization, data acquisition pipelines) requiring real Ethernet communication.
## 5. Gotchas
- **`RESTConnection`**:
- `IsSoftDisconnected` is hardcoded to `false`; callers expecting soft-disconnect behavior will be misled.
- `OnDisconnected` is declared but never raised; event subscriptions have no effect.
- `Begin*`/`End*` methods are *synchronous stubs*; using them in async contexts may cause deadlocks or incorrect assumptions about I/O latency.
- `EndSend`/`EndReceive` always return `0`—no actual bytes sent/received.
- `SoftConnect`/`SoftDisconnect` are no-ops despite being part of `IConnection`.
- **`EthernetConnection`**:
- `SoftConnect()` uses `Thread.Sleep` (50ms/100ms/1000ms) for timing; this is blocking and may cause issues in high-throughput or UI contexts.
- `SoftConnect()` sends `<60,5,4>` to port `8200` for keep-alive setup; this is a hardcoded protocol-specific command (device-dependent).
- `BeginDisconnect` throws `SocketException` if socket is not connected—*not* an error condition per se, but callers must handle this exception to avoid crashes.
- `EndSend` sets `Sock = null` on exception; this may cause subsequent operations to fail unexpectedly.
- `Bind` uses the *first* DNS-resolved IP address (`AddressList[0]`), which may be non-deterministic or IPv6 in some environments.
- `CreateSock` uses `IOControlCode.KeepAliveValues` with hardcoded `KeepAliveOn = 1`; this may conflict with system-wide settings.
- `IsSoftDisconnected` is not reset to `false` in `SoftConnect` if `AllowSoftDisconnects` is `false`—only if soft disconnect logic runs.
- **Both**:
- Neither class validates `connectString` format in `Create(string)` alone (only in `Create(string, string)` or `BeginConnect`).
- `RESTConnection` and `EthernetConnection` share the same `IConnection` interface but have wildly different semantics; callers must know which implementation they hold.
- `RESTConnection`s `GetConnectionData()` returns a string with `_hostIPAddress`, but `_hostIPAddress` is never used in `RESTConnection` beyond storage—no binding or resolution occurs.
None identified beyond those above.