11// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
22// SPDX-License-Identifier: MIT
33using System ;
4- using System . Collections . Generic ;
54using System . Net ;
65using System . Net . Sockets ;
76
8- using Microsoft . Extensions . DependencyInjection ;
97using Microsoft . Extensions . Logging ;
108
11- using Smdn . Net . MuninPlugin ;
12-
139namespace Smdn . Net . MuninNode ;
1410
1511/// <summary>
1612/// Implement a <c>Munin-Node</c> that acts as a node on the localhost and only accepts connections from the local loopback address (127.0.0.1, ::1).
1713/// </summary>
18- public class LocalNode : NodeBase {
14+ public abstract partial class LocalNode : NodeBase {
1915 private const string DefaultHostName = "munin-node.localhost" ;
20- private static readonly int MaxClients = 1 ;
21-
22- public override string HostName { get ; }
23- public IPEndPoint LocalEndPoint { get ; }
24-
25- /// <inheritdoc cref="LocalNode(IReadOnlyCollection{IPlugin}, string, int, IServiceProvider)"/>
26- public LocalNode (
27- IReadOnlyCollection < IPlugin > plugins ,
28- int port ,
29- IServiceProvider ? serviceProvider = null
30- )
31- : this (
32- plugins : plugins ,
33- hostName : DefaultHostName ,
34- port : port ,
35- serviceProvider : serviceProvider
36- )
37- {
38- }
39-
40- /// <summary>
41- /// Initializes a new instance of the <see cref="LocalNode"/> class.
42- /// </summary>
43- /// <param name="plugins">
44- /// The collection of plugins provided by this node.
45- /// </param>
46- /// <param name="hostName">
47- /// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
48- /// </param>
49- /// <param name="port">
50- /// The port number on which this node accepts connections.
51- /// </param>
52- /// <param name="serviceProvider">
53- /// The <see cref="IServiceProvider"/>.
54- /// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
55- /// </param>
56- /// <remarks>
57- /// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
58- /// </remarks>
59- public LocalNode (
60- IReadOnlyCollection < IPlugin > plugins ,
61- string hostName ,
62- int port ,
63- IServiceProvider ? serviceProvider = null
64- )
65- : this (
66- pluginProvider : new PluginProvider ( plugins ?? throw new ArgumentNullException ( nameof ( plugins ) ) ) ,
67- hostName : hostName ,
68- port : port ,
69- serviceProvider : serviceProvider
70- )
71- {
72- }
7316
7417 /// <summary>
7518 /// Initializes a new instance of the <see cref="LocalNode"/> class.
7619 /// </summary>
77- /// <param name="pluginProvider">
78- /// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
79- /// </param>
80- /// <param name="hostName">
81- /// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
82- /// </param>
83- /// <param name="port">
84- /// The port number on which this node accepts connections.
85- /// </param>
86- /// <param name="serviceProvider">
87- /// The <see cref="IServiceProvider"/>.
88- /// This constructor overload attempts to get a service of <see cref="ILoggerFactory"/>, to create an <see cref="ILogger"/>.
89- /// </param>
90- /// <remarks>
91- /// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
92- /// </remarks>
93- public LocalNode (
94- IPluginProvider pluginProvider ,
95- string hostName ,
96- int port ,
97- IServiceProvider ? serviceProvider = null
98- )
99- : this (
100- pluginProvider : pluginProvider ?? throw new ArgumentNullException ( nameof ( pluginProvider ) ) ,
101- hostName : hostName ,
102- port : port ,
103- logger : serviceProvider ? . GetService < ILoggerFactory > ( ) ? . CreateLogger < LocalNode > ( )
104- )
105- {
106- }
107-
108- /// <summary>
109- /// Initializes a new instance of the <see cref="LocalNode"/> class.
110- /// </summary>
111- /// <param name="pluginProvider">
112- /// The <see cref="IPluginProvider"/> that provides <see cref="IPlugin"/>s for this node.
113- /// </param>
114- /// <param name="hostName">
115- /// The hostname advertised by this node. This value is used as the display name for HTML generated by Munin.
116- /// </param>
117- /// <param name="port">
118- /// The port number on which this node accepts connections.
119- /// </param>
12020 /// <param name="logger">
12121 /// The <see cref="ILogger"/> to report the situation.
12222 /// </param>
123- /// <remarks>
124- /// Most Munin-Node uses port 4949 by default, but it is recommended to use other port numbers to avoid conflicts with other nodes.
125- /// </remarks>
126- public LocalNode (
127- IPluginProvider pluginProvider ,
128- string hostName ,
129- int port ,
23+ protected LocalNode (
13024 ILogger ? logger = null
13125 )
13226 : base (
133- pluginProvider : pluginProvider ,
13427 logger : logger
13528 )
13629 {
137- if ( hostName == null )
138- throw new ArgumentNullException ( nameof ( hostName ) ) ;
139- if ( hostName . Length == 0 )
140- throw ExceptionUtils . CreateArgumentMustBeNonEmptyString ( nameof ( hostName ) ) ;
141-
142- HostName = hostName ;
143-
144- if ( Socket . OSSupportsIPv6 ) {
145- LocalEndPoint = new IPEndPoint (
146- address : IPAddress . IPv6Loopback ,
147- port : port
148- ) ;
149- }
150- #pragma warning disable IDE0045
151- else if ( Socket . OSSupportsIPv4 ) {
152- #pragma warning restore IDE0045
153- LocalEndPoint = new IPEndPoint (
154- address : IPAddress . Loopback ,
155- port : port
156- ) ;
157- }
158- else {
159- throw new NotSupportedException ( ) ;
160- }
16130 }
16231
32+ /// <summary>
33+ /// Gets the <see cref="EndPoint"/> to be bound as the <c>Munin-Node</c>'s endpoint.
34+ /// </summary>
35+ /// <returns>
36+ /// An <see cref="EndPoint"/>.
37+ /// The default implementation returns an <see cref="IPEndPoint"/> with the port number <c>0</c>
38+ /// and <see cref="IPAddress.IPv6Loopback"/>/<see cref="IPAddress.Loopback"/>.
39+ /// </returns>
40+ protected virtual EndPoint GetLocalEndPointToBind ( )
41+ => new IPEndPoint (
42+ address :
43+ Socket . OSSupportsIPv6
44+ ? IPAddress . IPv6Loopback
45+ : Socket . OSSupportsIPv4
46+ ? IPAddress . Loopback
47+ : throw new NotSupportedException ( ) ,
48+ port : 0
49+ ) ;
50+
16351 protected override Socket CreateServerSocket ( )
16452 {
53+ const int MaxClients = 1 ;
54+
16555 Socket ? server = null ;
16656
16757 try {
168- var endPoint = new IPEndPoint (
169- address : Socket . OSSupportsIPv6 ? IPAddress . IPv6Any : IPAddress . Any ,
170- port : LocalEndPoint . Port
171- ) ;
58+ var endPoint = GetLocalEndPointToBind ( ) ;
17259
17360 server = new Socket (
17461 endPoint . AddressFamily ,
@@ -186,9 +73,7 @@ protected override Socket CreateServerSocket()
18673 return server ;
18774 }
18875 catch {
189- #pragma warning disable CA1508
19076 server ? . Dispose ( ) ;
191- #pragma warning restore CA1508
19277 throw ;
19378 }
19479 }
0 commit comments