Files

106 lines
3.2 KiB
C#

// 32feet.NET - Personal Area Networking for .NET
//
// InTheHand.Net.Sockets.NetworkStream
//
// Copyright (c) 2018-2022 In The Hand Ltd, All rights reserved.
// This source code is licensed under the MIT License
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace InTheHand.Net.Sockets
{
/// <exclude/>
public abstract class NonSocketNetworkStream : NetworkStream
{
/// <exclude/>
public NonSocketNetworkStream() : base(GetAConnectedSocket(), false)
{
}
internal static Socket GetAConnectedSocket()
{
Socket s = SocketPair.GetConnectedSocket();
Debug.Assert(s != null);
Debug.Assert(s.Connected);
return s;
}
}//class
internal sealed class SocketPair
{
Socket m_cli;
[SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields",
Justification = "m_svr is there to stop the Socket's Finalization.")]
Socket m_svr;
static SocketPair m_SocketPair;
//--------
internal static Socket GetConnectedSocket()
{
// No need for locking etc here, as it's ok to make one or more (not
// many hopefully however!) The socket (is meant!) to be only used on
// initialising the base NetworkStream, so it doesn't matter if the
// SocketPair is finalized either. Better to create only one, hence
// why we cache it.
// Careful of a race between accessing it, it becoming null, and the
// Finalizer running, so keep a reference locally.
SocketPair sp = m_SocketPair;
if (sp == null || !sp.Alive)
m_SocketPair = sp = SocketPair.Create();
return sp.m_cli;
}
//--------
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
internal static SocketPair Create()
{
try
{
return Create(AddressFamily.InterNetworkV6);
}
catch
{
return Create(AddressFamily.InterNetwork);
}
}
internal static SocketPair Create(AddressFamily af)
{
return new SocketPair(af);
}
//--------
private SocketPair(AddressFamily af)
{
using (Socket lstnr = new Socket(af, SocketType.Stream, ProtocolType.Unspecified))
{
lstnr.Bind(new IPEndPoint(
af == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0));
lstnr.Listen(1);
EndPoint svrEp = lstnr.LocalEndPoint;
m_cli = new Socket(svrEp.AddressFamily, lstnr.SocketType, lstnr.ProtocolType);
m_cli.Connect(svrEp);
m_svr = lstnr.Accept();
}
}
//--------
private bool Alive
{
get
{
return m_cli != null // just for safety, shouldn't occur
&& m_cli.Connected;
}
}
}
}