/// <param name="socketFactory">An implementation of the <see cref="ISocketFactory"/> interface that can be used to make new unicast and multicast sockets. Cannot be null.</param>
/// <exception cref="System.ArgumentNullException">The <paramref name="socketFactory"/> argument is null.</exception>
/// <param name="socketFactory">An implementation of the <see cref="ISocketFactory"/> interface that can be used to make new unicast and multicast sockets. Cannot be null.</param>
/// <param name="localPort">The specific local port to use for all sockets created by this instance. Specify zero to indicate the system should choose a free port itself.</param>
/// <param name="multicastTimeToLive">The multicast time to live value for multicast sockets. Technically this is a number of router hops, not a 'Time'. Must be greater than zero.</param>
/// <exception cref="System.ArgumentNullException">The <paramref name="socketFactory"/> argument is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">The <paramref name="multicastTimeToLive"/> argument is less than or equal to zero.</exception>
if(multicastTimeToLive<=0)thrownewArgumentOutOfRangeException("multicastTimeToLive","multicastTimeToLive must be greater than zero.");
_BroadcastListenSocketSynchroniser=newobject();
_SendSocketSynchroniser=newobject();
_LocalPort=localPort;
_SocketFactory=socketFactory;
_RequestParser=newHttpRequestParser();
_ResponseParser=newHttpResponseParser();
_MulticastTtl=multicastTimeToLive;
}
#endregion
#regionPublicMethods
/// <summary>
/// Causes the server to begin listening for multicast messages, being SSDP search requests and notifications.
/// </summary>
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
/// Causes the server to stop listening for multicast messages, being SSDP search requests and notifications.
/// </summary>
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
publicvoidStopListeningForBroadcasts()
{
ThrowIfDisposed();
lock(_BroadcastListenSocketSynchroniser)
{
if(_BroadcastListenSocket!=null)
{
_BroadcastListenSocket.Dispose();
_BroadcastListenSocket=null;
}
}
}
/// <summary>
/// Sends a message to a particular address (uni or multicast) and port.
/// </summary>
/// <param name="messageData">A byte array containing the data to send.</param>
/// <param name="destination">A <see cref="IpEndPointInfo"/> representing the destination address for the data. Can be either a multicast or unicast destination.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="messageData"/> argument is null.</exception>
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
/// Sends a message to the SSDP multicast address and port.
/// </summary>
/// <param name="messageData">A byte array containing the data to send.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="messageData"/> argument is null.</exception>
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
/// Stops listening for search responses on the local, unicast socket.
/// </summary>
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
publicvoidStopListeningForResponses()
{
ThrowIfDisposed();
lock(_SendSocketSynchroniser)
{
varsocket=_SendSocket;
_SendSocket=null;
if(socket!=null)
socket.Dispose();
}
}
#endregion
#regionPublicProperties
/// <summary>
/// Gets or sets a boolean value indicating whether or not this instance is shared amongst multiple <see cref="SsdpDeviceLocatorBase"/> and/or <see cref="ISsdpDevicePublisher"/> instances.
/// </summary>
/// <remarks>
/// <para>If true, disposing an instance of a <see cref="SsdpDeviceLocatorBase"/>or a <see cref="ISsdpDevicePublisher"/> will not dispose this comms server instance. The calling code is responsible for managing the lifetime of the server.</para>
/// </remarks>
publicboolIsShared
{
get{return_IsShared;}
set{_IsShared=value;}
}
#endregion
#regionOverrides
/// <summary>
/// Stops listening for requests, disposes this instance and all internal resources.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "t", Justification = "Capturing task to local variable removes compiler warning, task is not otherwise required.")]
privatevoidListenToSocket(IUdpSocketsocket)
{
// Tasks are captured to local variables even if we don't use them just to avoid compiler warnings.
vart=Task.Run(async()=>
{
varcancelled=false;
while(!cancelled)
{
try
{
varresult=awaitsocket.ReceiveAsync();
if(result.ReceivedBytes>0)
{
// Strange cannot convert compiler error here if I don't explicitly
// assign or cast to Action first. Assignment is easier to read,