Skip to content

Commit 0be0bcc

Browse files
committed
improve to disable re-start after disposing and properly throw ObjectDisposedException
1 parent cb93ea2 commit 0be0bcc

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,18 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
4444

4545
private Socket? server;
4646

47-
public EndPoint LocalEndPoint => server?.LocalEndPoint ?? throw new InvalidOperationException("not yet bound or already disposed");
47+
public EndPoint LocalEndPoint {
48+
get {
49+
ThrowIfDisposed();
50+
51+
return server?.LocalEndPoint ?? throw new InvalidOperationException("not yet bound or already disposed");
52+
}
53+
}
4854

4955
private readonly ArrayBufferWriter<byte> responseBuffer = new(initialCapacity: 1024); // TODO: define best initial capacity
5056

57+
private bool disposed;
58+
5159
protected NodeBase(
5260
IAccessRule? accessRule,
5361
ILogger? logger
@@ -94,6 +102,8 @@ ValueTask DisposeAsyncCore()
94102
server?.Dispose();
95103
server = null;
96104

105+
disposed = true;
106+
97107
#if !SYSTEM_NET_SOCKETS_SOCKET_DISCONNECTASYNC_REUSESOCKET_CANCELLATIONTOKEN
98108
return default;
99109
#endif
@@ -115,6 +125,14 @@ protected virtual void Dispose(bool disposing)
115125
server?.Close();
116126
server?.Dispose();
117127
server = null!;
128+
129+
disposed = true;
130+
}
131+
132+
protected void ThrowIfDisposed()
133+
{
134+
if (disposed)
135+
throw new ObjectDisposedException(GetType().FullName);
118136
}
119137

120138
protected void ThrowIfPluginProviderIsNull()
@@ -127,6 +145,8 @@ protected void ThrowIfPluginProviderIsNull()
127145

128146
public void Start()
129147
{
148+
ThrowIfDisposed();
149+
130150
if (server is not null)
131151
throw new InvalidOperationException("already started");
132152

@@ -153,6 +173,8 @@ public async ValueTask AcceptAsync(
153173
CancellationToken cancellationToken
154174
)
155175
{
176+
ThrowIfDisposed();
177+
156178
Logger?.LogInformation("starting to accept");
157179

158180
try {
@@ -186,6 +208,8 @@ public async ValueTask AcceptSingleSessionAsync(
186208
CancellationToken cancellationToken = default
187209
)
188210
{
211+
ThrowIfDisposed();
212+
189213
if (server is null)
190214
throw new InvalidOperationException("not started or already closed");
191215

tests/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,38 @@ Func<NodeBase, TcpClient, StreamWriter, StreamReader, CancellationToken, Task> a
140140
}
141141
}
142142

143+
[Test]
144+
public async Task Dispose()
145+
{
146+
await using var node = CreateNode();
147+
148+
Assert.That(node.Dispose, Throws.Nothing, "Dispose() #1");
149+
150+
Assert.That(() => _ = node.LocalEndPoint, Throws.TypeOf<ObjectDisposedException>());
151+
Assert.That(node.Start, Throws.TypeOf<ObjectDisposedException>());
152+
Assert.That(async () => await node.AcceptAsync(false, default), Throws.TypeOf<ObjectDisposedException>());
153+
Assert.That(async () => await node.AcceptSingleSessionAsync(default), Throws.TypeOf<ObjectDisposedException>());
154+
155+
Assert.That(node.Dispose, Throws.Nothing, "Dispose() #2");
156+
Assert.That(node.DisposeAsync, Throws.Nothing, "DisposeAsync() after Dispose()");
157+
}
158+
159+
[Test]
160+
public async Task DisposeAsync()
161+
{
162+
await using var node = CreateNode();
163+
164+
Assert.That(node.DisposeAsync, Throws.Nothing, "DisposeAsync() #1");
165+
166+
Assert.That(() => _ = node.LocalEndPoint, Throws.TypeOf<ObjectDisposedException>());
167+
Assert.That(node.Start, Throws.TypeOf<ObjectDisposedException>());
168+
Assert.That(async () => await node.AcceptAsync(false, default), Throws.TypeOf<ObjectDisposedException>());
169+
Assert.That(async () => await node.AcceptSingleSessionAsync(default), Throws.TypeOf<ObjectDisposedException>());
170+
171+
Assert.That(node.DisposeAsync, Throws.Nothing, "DisposeAsync() #2");
172+
Assert.That(node.Dispose, Throws.Nothing, "Dispose() after DisposeAsync()");
173+
}
174+
143175
[Test]
144176
public async Task Start()
145177
{

0 commit comments

Comments
 (0)