Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.ComponentModel;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- using Integral.Client.Sources.Util;
- using Integral.Common;
- using Integral.Common.Net;
- namespace Integral.Client.Sources
- {
- /// <summary>
- /// The network source is a base class for live sources that implement the INetworkSource interface.
- /// </summary>
- [Serializable]
- internal abstract class NetworkSource : LiveSource, INetworkSource
- {
- private string _host;
- private string _ipaddress;
- private int _port;
- private string _username;
- private string _password;
- private bool _isLocal;
- private ConnectionState _status;
- private bool _hostResolved = false;
- private bool _useWindowsAuth = false;
- [NonSerialized]
- private StreamCollection _streams;
- [NonSerialized]
- private StreamCollection _oldStreams;
- [NonSerialized]
- private bool _streamsDirty = true;
- [NonSerialized]
- private WeakMulticastDelegate _connectionStatusChanged;
- [NonSerialized]
- private WeakMulticastDelegate _connectionProgressChanged;
- /// <summary>
- /// Initializes a new instance of the <see cref="NetworkSource"/> class.
- /// </summary>
- public NetworkSource()
- : base()
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="NetworkSource"/> class.
- /// </summary>
- /// <param name="name">The name of the network source.</param>
- /// <param name="ipaddress">The ipaddress of the network source.</param>
- /// <param name="port">The port of the network source.</param>
- /// <param name="username">The username of the network source.</param>
- /// <param name="password">The password of the network source.</param>
- public NetworkSource(string name, string ipaddress, int port, string username, string password)
- : base(name)
- {
- UpdateHostnameAndIpAddress(ipaddress);
- _port = port;
- _username = username;
- _password = password;
- ConnectionInfomationChanged(_host, _ipaddress, _port, _username, _password);
- }
- #region INetworkSource Members
- /// <summary>
- /// Gets or sets the hostname of the <see cref="INetworkEndpoint"/>.
- /// </summary>
- public string Hostname
- {
- get
- {
- if (!_hostResolved)
- {
- IPAddress addr;
- NetworkUtility.DnsResolve(IPAddress, out addr, out _host);
- _ipaddress = addr.ToString();
- _hostResolved = true;
- }
- return _host;
- }
- set
- {
- if (_host != value)
- {
- UpdateHostnameAndIpAddress(value);
- ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
- }
- }
- }
- public Boolean UseWindowsAuth
- {
- get
- {
- return _useWindowsAuth;
- }
- set
- {
- _useWindowsAuth = value;
- }
- }
- /// <summary>
- /// Gets the IP address of the <see cref="INetworkEndpoint"/>.
- /// </summary>
- public string IPAddress
- {
- get
- {
- return _ipaddress;
- }
- set
- {
- if (_ipaddress != value)
- {
- UpdateHostnameAndIpAddress(value);
- ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
- }
- }
- }
- /// <summary>
- /// Gets the port number of the <see cref="INetworkEndpoint"/>.
- /// </summary>
- public int Port
- {
- get
- {
- return _port;
- }
- set
- {
- if (_port != value)
- {
- _port = value;
- ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
- }
- }
- }
- /// <summary>
- /// Gets the user name used to login to the <see cref="INetworkEndpoint"/>.
- /// </summary>
- public string Username
- {
- get
- {
- return _username;
- }
- set
- {
- if (_username != value)
- {
- _username = value;
- ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
- }
- }
- }
- /// <summary>
- /// Gets the password used to login to the <see cref="INetworkEndpoint"/>.
- /// </summary>
- public string Password
- {
- get
- {
- return _password;
- }
- set
- {
- if (_password != value)
- {
- _password = value;
- ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
- }
- }
- }
- /// <summary>
- /// Gets a value indicating whether this instance is connected.
- /// </summary>
- /// <value>
- /// <c>true</c> if this instance is connected; otherwise, <c>false</c>.
- /// </value>
- public bool IsConnected
- {
- get
- {
- return ConnectionStatus == ConnectionState.Connected ||
- ConnectionStatus == ConnectionState.LoggedIn;
- }
- }
- /// <summary>
- /// Gets a value indicating whether the network endpoint that this instance
- /// represents is local to the machine.
- /// </summary>
- public bool IsLocal
- {
- get
- {
- return _isLocal;
- }
- }
- /// <summary>
- /// Opens a connection to the server.
- /// </summary>
- public void Open()
- {
- using (GetBusyLock())
- {
- OpenInternal();
- }
- }
- /// <summary>
- /// Opens a connection to the server.
- /// </summary>
- public void Open(bool preloadData)
- {
- using (GetBusyLock())
- {
- OpenInternal();
- if (preloadData)
- {
- var streams = this.Streams;
- }
- }
- }
- private void OpenInternal()
- {
- // Are we already connected?
- if (ConnectionStatus == ConnectionState.Connected ||
- ConnectionStatus == ConnectionState.LoggedIn)
- {
- return;
- }
- // Are we already trying to connect?
- if (ConnectionStatus == ConnectionState.Connecting)
- {
- throw new InvalidOperationException("Cannot have nested open calls.");
- }
- // Indicate that we are connecting
- OnConnectionProgressChanged(new ProgressChangedEventArgs(0, null));
- ConnectionStatus = ConnectionState.Connecting;
- try
- {
- // Let inheritors actually open the connection.
- ConnectionStatus = OpenCore();
- }
- catch (Exception)
- {
- ConnectionStatus = ConnectionState.Disconnected;
- throw;
- }
- finally
- {
- OnConnectionProgressChanged(new ProgressChangedEventArgs(100, null));
- }
- }
- /// <summary>
- /// Closes this connection to the server.
- /// </summary>
- public void Close()
- {
- using (GetBusyLock())
- {
- // Are we already disconnected?
- if (ConnectionStatus == ConnectionState.Uninitialized ||
- ConnectionStatus == ConnectionState.Disconnected)
- {
- return;
- }
- // Are we already trying to disconnect?
- if (ConnectionStatus == ConnectionState.Disconnecting)
- {
- throw new InvalidOperationException("Cannot have nested close calls.");
- }
- // Indicate that we are connecting
- OnConnectionProgressChanged(new ProgressChangedEventArgs(0, null));
- ConnectionStatus = ConnectionState.Disconnecting;
- // Unrender all our streams.
- SafelyUnrenderAllStreams();
- try
- {
- // Let inheritors actually close the connection.
- CloseCore();
- }
- finally
- {
- // Mark all the streams as dirty.
- MarkStreamsDirty();
- // By the end we must be disconnected.
- ConnectionStatus = ConnectionState.Disconnected;
- OnConnectionProgressChanged(new ProgressChangedEventArgs(100, null));
- }
- }
- }
- IDisposable GetBusyLock()
- {
- return new Disposable(() => SetIsBusy(true), () => SetIsBusy(false));
- }
- private int _isBusy = 0;
- private Thread _thread;
- void SetIsBusy(bool value)
- {
- lock(SyncRoot)
- {
- if (value)
- {
- if (_thread == Thread.CurrentThread)
- return;
- while (_isBusy > 0)
- Monitor.Wait(SyncRoot);
- if (_thread == null)
- {
- _thread = Thread.CurrentThread;
- _isBusy++;
- }
- }
- else
- {
- if (_thread == Thread.CurrentThread)
- _isBusy--;
- if (_isBusy == 0)
- {
- _thread = null;
- Monitor.Pulse(SyncRoot);
- }
- }
- }
- }
- /// <summary>
- /// Current Connection status of this Network Endpoint
- /// </summary>
- public ConnectionState ConnectionStatus
- {
- get
- {
- return _status;
- }
- protected set
- {
- if (ConnectionStatus != value)
- {
- _status = value;
- OnConnectionStatusChanged(EventArgs.Empty);
- }
- }
- }
- /// <summary>
- /// Event used to inform users of this instance when the connection status changes.
- /// </summary>
- public event EventHandler ConnectionStatusChanged
- {
- add
- {
- _connectionStatusChanged = WeakMulticastDelegate.CombineUnique(_connectionStatusChanged, value);
- }
- remove
- {
- _connectionStatusChanged = WeakMulticastDelegate.Remove(_connectionStatusChanged, value);
- }
- }
- /// <summary>
- /// Event raised when the progress of the connection changes.
- /// </summary>
- public event ProgressChangedEventHandler ConnectionProgressChanged
- {
- add
- {
- _connectionProgressChanged = WeakMulticastDelegate.CombineUnique(_connectionProgressChanged, value);
- }
- remove
- {
- _connectionProgressChanged = WeakMulticastDelegate.Remove(_connectionProgressChanged, value);
- }
- }
- /// <summary>
- /// Raises the <see cref="E:ConnectionStatusChanged"/> event.
- /// </summary>
- /// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
- protected virtual void OnConnectionStatusChanged(EventArgs args)
- {
- WeakMulticastDelegate handler = _connectionStatusChanged;
- if (handler != null)
- {
- handler.InvokeSafe(new object[] { this, args });
- }
- }
- /// <summary>
- /// Raises the <see cref="E:ConnectionProgressChanged"/> event.
- /// </summary>
- /// <param name="args">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
- protected virtual void OnConnectionProgressChanged(ProgressChangedEventArgs args)
- {
- WeakMulticastDelegate handler = _connectionProgressChanged;
- if (handler != null)
- {
- handler.InvokeSafe(new object[] { this, args });
- }
- }
- #endregion
- #region ISource Members
- /// <summary>
- /// Gets the <see cref="SourceType">type</see> of the source.
- /// </summary>
- public override SourceType Type
- {
- get
- {
- if (IsLocal)
- {
- return base.Type | SourceType.Local;
- }
- else
- {
- return base.Type;
- }
- }
- }
- /// <summary>
- /// Gets a <see cref="StreamCollection"/> of <see cref="IStream"/> objects for the source.
- /// </summary>
- public override StreamCollection Streams
- {
- get
- {
- lock (SyncRoot)
- {
- // If we're connected and need to get the streams, do so.
- if (!IsConnected)
- return new StreamCollection();
- if(_streams != null && !_streamsDirty)
- return _streams;
- if(_streams == null)
- _streams = new StreamCollection();
- _streamsDirty = false;
- }
- using (GetBusyLock())
- {
- _streams = GetStreams(_oldStreams);
- }
- return _streams;
- }
- }
- /// <summary>
- /// Virtual method to allow inheritors to free resources.
- /// </summary>
- /// <param name="disposing">Indicates is the instance should free managed resources in
- /// addition to unmanaged. True to free both managed and unmanaged resources, false
- /// to free just unmanaged.</param>
- /// <remarks>Overrides of this method MUST call base.Dispose(bool)!</remarks>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- // Close our connection
- Close();
- }
- base.Dispose(disposing);
- }
- #endregion
- #if !CPE7252
- internal object SyncRoot
- {
- get
- {
- if (this is IRecorder)
- {
- object sync = (this as IRecorder).DVRSystem;
- if (sync != null)
- {
- return sync;
- }
- }
- return this;
- }
- }
- #else
- protected object SyncRoot = new object();
- #endif
- /// <summary>
- /// Inheritors should override this method to perform the actual open operation.
- /// </summary>
- protected virtual ConnectionState OpenCore()
- {
- return ConnectionState.Disconnected;
- }
- /// <summary>
- /// Inheritors should override this method to perform the actual close operation.
- /// </summary>
- protected virtual void CloseCore()
- {
- }
- /// <summary>
- /// Virtual method for inheritors to take action when the connection information changes.
- /// </summary>
- protected virtual void OnConnectionInformationChanged(string hostname, string ipaddress, int port, string username, string password)
- {
- }
- /// <summary>
- /// Inheritors should override this method to actually get the streams for the source.
- /// </summary>
- protected virtual StreamCollection GetStreams(StreamCollection oldStreams)
- {
- return null;
- }
- /// <summary>
- /// Marks the Streams as dirty so that the next time they are requested,
- /// they will be refreshed. This method is automatically called when the
- /// network connection is closed.
- /// </summary>
- protected void MarkStreamsDirty()
- {
- lock (SyncRoot)
- {
- if (_streams != null)
- {
- // 'Disinherit' all the streams.
- foreach (IStream stream in _streams)
- {
- stream.Source = null;
- }
- // Save them off so that if we reconnect, we can use the same instances.
- _oldStreams = new StreamCollection(_streams);
- _streams = null;
- }
- // Set the dirty flag.
- _streamsDirty = true;
- }
- }
- /// <summary>
- /// Generates a stream collection containing all the new streams, but tries to match
- /// each new stream with an old stream. If an old stream is found, it is updated, and
- /// added to the resulting stream collection in place of the new stream.
- /// </summary>
- protected StreamCollection MatchStreams(StreamCollection newStreams, StreamCollection oldStreams)
- {
- // If there are no old streams, there is nothing to match.
- if (oldStreams == null)
- {
- return newStreams;
- }
- // Create a new collection to hold the result streams.
- StreamCollection result = new StreamCollection();
- foreach (IStream stream in newStreams)
- {
- IStream original = oldStreams.FindByNumberAndType(stream.Number, stream.Type);
- if (original != null)
- {
- original.Name = stream.Name;
- result.Add(original);
- }
- else
- {
- result.Add(stream);
- }
- }
- return result;
- }
- private void ConnectionInfomationChanged(string hostname, string ipaddress, int port, string username, string password)
- {
- // If our connection information is changing, disconnect if we need to.
- bool reconnect = false;
- if (!UseWindowsAuth && IsConnected)
- {
- Close();
- reconnect = true;
- }
- // Let inheritors know that the connection information changed.
- OnConnectionInformationChanged(hostname, ipaddress, port, username, password);
- // Reconnect if we disconnected above.
- if (reconnect)
- {
- //Open();
- }
- }
- private void UpdateHostnameAndIpAddress(string hostnameOrIpAddress)
- {
- // For now just leave the hostname as what is passed in and indicated that
- // it has not been resolved. We'll resolve if anybody actually wants is...
- // but usually this is not the case.
- _hostResolved = false;
- _host = hostnameOrIpAddress;
- // We do however have to get an IP address, so we'll use the network utility to
- // resolve the parameter to get the ipaddress:
- IPAddress addr = NetworkUtility.DnsResolve(hostnameOrIpAddress);
- if (addr != null && addr != System.Net.IPAddress.None)
- {
- // We successfully resolved the parameter, set the and address.
- _ipaddress = addr.ToString();
- }
- else
- {
- // We can't resolve the parameter! Just do the best we can.
- _ipaddress = hostnameOrIpAddress;
- System.Diagnostics.Trace.WriteLine("DNS Resolution on " + hostnameOrIpAddress + " failed.");
- }
- // Now determine if we're local or not:
- // Assume we are not local by default.
- _isLocal = false;
- // We should be able to do some basic checks...
- if (hostnameOrIpAddress == "127.0.0.1")
- {
- _isLocal = true;
- }
- else if (hostnameOrIpAddress.ToLower() == "localhost")
- {
- _isLocal = true;
- }
- if (_isLocal)
- return;
- // Ok we couldn't obviosuly determine whether or not this was
- // a local address, so let's figure out what the address of the local
- // machine is, and see it it matches...
- IPHostEntry hostEnty = Dns.GetHostEntry(string.Empty);
- foreach (IPAddress address in hostEnty.AddressList)
- {
- if (System.Net.IPAddress.IsLoopback(address) ||
- (address.AddressFamily != AddressFamily.InterNetwork))
- {
- continue;
- }
- if (address.ToString() != IPAddress)
- continue;
- _isLocal = true;
- break;
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment