Skip to content

Commit a5f2c65

Browse files
committed
Add native SCTP connector
1 parent 16bdcc8 commit a5f2c65

5 files changed

Lines changed: 92 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The first production milestone is M3UA over a transport abstraction. SCCP, TCAP,
4545
| Observability | Phase 7 profile added for commercial metrics, trace categories, and health signals |
4646
| Deployment profiles | Phase 7 profiles added for commercial Linux and local development use |
4747
| Phase 7 status | Commercialization foundation complete; commercial production remains blocked on native SCTP verification, external lab evidence, signing, and SBOM |
48-
| Native SCTP implementation | Phase 8 started: Linux SCTP socket probe, socket factory, endpoint connection planner, and native socket adapter added; full production readiness still requires native transport completion and lab verification |
48+
| Native SCTP implementation | Phase 8 started: Linux SCTP socket probe, socket factory, endpoint connection planner, native socket adapter, and client connector added; full production readiness still requires native transport completion and lab verification |
4949

5050
## Requirements
5151

docs/PHASE8_NATIVE_SCTP.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,14 @@ using NativeSctpSocketAdapter adapter = new(socket, options);
4747
```
4848

4949
The adapter exposes lifecycle state and `SctpTransportHealth` snapshots. It currently sends and receives complete socket messages through the native socket API; SCTP ancillary metadata handling is tracked separately before production readiness can be claimed.
50+
51+
## Connector
52+
53+
`NativeSctpConnector` builds a connection plan, optionally binds the local endpoint, applies `SctpConnectionOptions.ConnectTimeout`, and returns an established `NativeSctpSocketAdapter`.
54+
55+
```csharp
56+
NativeSctpConnector connector = new();
57+
NativeSctpSocketAdapter socket = await connector.ConnectAsync(options);
58+
```
59+
60+
The connector is Linux-native only through `NativeSctpSocketFactory`; unsupported platforms fail before attempting network I/O.

docs/SCTP_TRANSPORT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,5 @@ The probe does not mark the transport production-ready by itself. It is the firs
130130
`NativeSctpConnectionPlanner` resolves configured SCTP endpoints to `IPEndPoint` values before native bind/connect attempts.
131131

132132
`NativeSctpSocketAdapter` wraps an SCTP socket as `ISctpSocket` and reports `SctpTransportHealth` snapshots for native associations.
133+
134+
`NativeSctpConnector` performs the client-side bind/connect path and returns an established native adapter.

src/sigtran.net.Tests/Program.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
Run("Native SCTP socket factory creates or reports unsupported platform", NativeSctpSocketFactoryCreatesOrReportsUnsupportedPlatform);
3535
Run("Native SCTP connection planner resolves endpoints", NativeSctpConnectionPlannerResolvesEndpoints);
3636
Run("Native SCTP socket adapter reports lifecycle health", NativeSctpSocketAdapterReportsLifecycleHealth);
37+
Run("Native SCTP connector reports unsupported platform safely", NativeSctpConnectorReportsUnsupportedPlatformSafely);
3738
Run("TCAP BER element encodes short and long lengths", TcapBerElementEncodesShortAndLongLengths);
3839
Run("TCAP transaction identifiers use BER context tags", TcapTransactionIdentifiersUseBerContextTags);
3940
Run("TCAP BER Invoke component round-trips", TcapBerInvokeComponentRoundTrips);
@@ -471,6 +472,26 @@ static void NativeSctpSocketAdapterReportsLifecycleHealth()
471472
AssertEqual((uint)SctpPayloadProtocolIdentifiers.M3ua, health.DefaultPayloadProtocolIdentifier, "native adapter PPID");
472473
}
473474

475+
static void NativeSctpConnectorReportsUnsupportedPlatformSafely()
476+
{
477+
NativeSctpConnector connector = new();
478+
NativeSctpPlatformCapability capability = NativeSctpPlatform.Probe();
479+
SctpConnectionOptions options = new(
480+
new SctpEndpoint("127.0.0.1", 2905),
481+
connectTimeout: TimeSpan.FromMilliseconds(10));
482+
483+
if (!capability.CanCreateSocket)
484+
{
485+
NativeSctpUnavailableException exception = AssertThrows<NativeSctpUnavailableException>(() =>
486+
connector.ConnectAsync(options).GetAwaiter().GetResult());
487+
AssertEqual(capability.Status, exception.Capability.Status, "native SCTP connector unsupported status");
488+
}
489+
else
490+
{
491+
Assert(capability.CanCreateSocket, capability.Describe());
492+
}
493+
}
494+
474495
static void TcapBerElementEncodesShortAndLongLengths()
475496
{
476497
Span<byte> shortBuffer = stackalloc byte[8];
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Net.Sockets;
2+
3+
namespace sigtran.net.Layers.SCTP;
4+
5+
/// <summary>
6+
/// Connects native SCTP client associations.
7+
/// </summary>
8+
public sealed class NativeSctpConnector
9+
{
10+
private readonly INativeSctpSocketFactory _socketFactory;
11+
private readonly NativeSctpConnectionPlanner _planner;
12+
13+
/// <summary>Creates a native SCTP connector.</summary>
14+
/// <param name="socketFactory">The socket factory.</param>
15+
/// <param name="planner">The connection planner.</param>
16+
public NativeSctpConnector(
17+
INativeSctpSocketFactory? socketFactory = null,
18+
NativeSctpConnectionPlanner? planner = null)
19+
{
20+
_socketFactory = socketFactory ?? new NativeSctpSocketFactory();
21+
_planner = planner ?? new NativeSctpConnectionPlanner();
22+
}
23+
24+
/// <summary>Connects a native SCTP association.</summary>
25+
/// <param name="options">The SCTP connection options.</param>
26+
/// <param name="ct">A cancellation token.</param>
27+
/// <returns>The connected native SCTP socket adapter.</returns>
28+
public async Task<NativeSctpSocketAdapter> ConnectAsync(SctpConnectionOptions options, CancellationToken ct = default)
29+
{
30+
ArgumentNullException.ThrowIfNull(options);
31+
32+
NativeSctpConnectionPlan plan = await _planner.BuildAsync(options, ct).ConfigureAwait(false);
33+
Socket socket = _socketFactory.CreateSocket();
34+
NativeSctpSocketAdapter? adapter = null;
35+
36+
try
37+
{
38+
if (plan.LocalEndpoint is not null)
39+
{
40+
socket.Bind(plan.LocalEndpoint);
41+
}
42+
43+
using CancellationTokenSource timeout = CancellationTokenSource.CreateLinkedTokenSource(ct);
44+
timeout.CancelAfter(options.ConnectTimeout);
45+
await socket.ConnectAsync(plan.RemoteEndpoint, timeout.Token).ConfigureAwait(false);
46+
47+
adapter = new NativeSctpSocketAdapter(socket, options, SctpAssociationState.Established);
48+
return adapter;
49+
}
50+
catch
51+
{
52+
adapter?.MarkFailed();
53+
socket.Dispose();
54+
throw;
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)