Guest User

Untitled

a guest
Oct 13th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.35 KB | None | 0 0
  1. using System;
  2. using System.ComponentModel;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Threading;
  6. using Integral.Client.Sources.Util;
  7. using Integral.Common;
  8. using Integral.Common.Net;
  9.  
  10. namespace Integral.Client.Sources
  11. {
  12. /// <summary>
  13. /// The network source is a base class for live sources that implement the INetworkSource interface.
  14. /// </summary>
  15. [Serializable]
  16. internal abstract class NetworkSource : LiveSource, INetworkSource
  17. {
  18. private string _host;
  19. private string _ipaddress;
  20. private int _port;
  21. private string _username;
  22. private string _password;
  23. private bool _isLocal;
  24. private ConnectionState _status;
  25. private bool _hostResolved = false;
  26. private bool _useWindowsAuth = false;
  27.  
  28. [NonSerialized]
  29. private StreamCollection _streams;
  30. [NonSerialized]
  31. private StreamCollection _oldStreams;
  32. [NonSerialized]
  33. private bool _streamsDirty = true;
  34. [NonSerialized]
  35. private WeakMulticastDelegate _connectionStatusChanged;
  36. [NonSerialized]
  37. private WeakMulticastDelegate _connectionProgressChanged;
  38.  
  39. /// <summary>
  40. /// Initializes a new instance of the <see cref="NetworkSource"/> class.
  41. /// </summary>
  42. public NetworkSource()
  43. : base()
  44. {
  45. }
  46.  
  47. /// <summary>
  48. /// Initializes a new instance of the <see cref="NetworkSource"/> class.
  49. /// </summary>
  50. /// <param name="name">The name of the network source.</param>
  51. /// <param name="ipaddress">The ipaddress of the network source.</param>
  52. /// <param name="port">The port of the network source.</param>
  53. /// <param name="username">The username of the network source.</param>
  54. /// <param name="password">The password of the network source.</param>
  55. public NetworkSource(string name, string ipaddress, int port, string username, string password)
  56. : base(name)
  57. {
  58. UpdateHostnameAndIpAddress(ipaddress);
  59. _port = port;
  60. _username = username;
  61. _password = password;
  62. ConnectionInfomationChanged(_host, _ipaddress, _port, _username, _password);
  63. }
  64.  
  65. #region INetworkSource Members
  66.  
  67. /// <summary>
  68. /// Gets or sets the hostname of the <see cref="INetworkEndpoint"/>.
  69. /// </summary>
  70. public string Hostname
  71. {
  72. get
  73. {
  74. if (!_hostResolved)
  75. {
  76. IPAddress addr;
  77. NetworkUtility.DnsResolve(IPAddress, out addr, out _host);
  78. _ipaddress = addr.ToString();
  79. _hostResolved = true;
  80. }
  81. return _host;
  82. }
  83. set
  84. {
  85. if (_host != value)
  86. {
  87. UpdateHostnameAndIpAddress(value);
  88. ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
  89. }
  90. }
  91. }
  92.  
  93. public Boolean UseWindowsAuth
  94. {
  95. get
  96. {
  97. return _useWindowsAuth;
  98. }
  99. set
  100. {
  101. _useWindowsAuth = value;
  102. }
  103. }
  104.  
  105. /// <summary>
  106. /// Gets the IP address of the <see cref="INetworkEndpoint"/>.
  107. /// </summary>
  108. public string IPAddress
  109. {
  110. get
  111. {
  112. return _ipaddress;
  113. }
  114. set
  115. {
  116. if (_ipaddress != value)
  117. {
  118. UpdateHostnameAndIpAddress(value);
  119. ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
  120. }
  121. }
  122. }
  123.  
  124. /// <summary>
  125. /// Gets the port number of the <see cref="INetworkEndpoint"/>.
  126. /// </summary>
  127. public int Port
  128. {
  129. get
  130. {
  131. return _port;
  132. }
  133. set
  134. {
  135. if (_port != value)
  136. {
  137. _port = value;
  138. ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
  139. }
  140. }
  141. }
  142.  
  143. /// <summary>
  144. /// Gets the user name used to login to the <see cref="INetworkEndpoint"/>.
  145. /// </summary>
  146. public string Username
  147. {
  148. get
  149. {
  150. return _username;
  151. }
  152. set
  153. {
  154. if (_username != value)
  155. {
  156. _username = value;
  157. ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
  158. }
  159. }
  160. }
  161.  
  162. /// <summary>
  163. /// Gets the password used to login to the <see cref="INetworkEndpoint"/>.
  164. /// </summary>
  165. public string Password
  166. {
  167. get
  168. {
  169. return _password;
  170. }
  171. set
  172. {
  173. if (_password != value)
  174. {
  175. _password = value;
  176. ConnectionInfomationChanged(Hostname, IPAddress, Port, Username, Password);
  177. }
  178. }
  179. }
  180.  
  181. /// <summary>
  182. /// Gets a value indicating whether this instance is connected.
  183. /// </summary>
  184. /// <value>
  185. /// <c>true</c> if this instance is connected; otherwise, <c>false</c>.
  186. /// </value>
  187. public bool IsConnected
  188. {
  189. get
  190. {
  191. return ConnectionStatus == ConnectionState.Connected ||
  192. ConnectionStatus == ConnectionState.LoggedIn;
  193. }
  194. }
  195.  
  196. /// <summary>
  197. /// Gets a value indicating whether the network endpoint that this instance
  198. /// represents is local to the machine.
  199. /// </summary>
  200. public bool IsLocal
  201. {
  202. get
  203. {
  204. return _isLocal;
  205. }
  206. }
  207.  
  208. /// <summary>
  209. /// Opens a connection to the server.
  210. /// </summary>
  211. public void Open()
  212. {
  213. using (GetBusyLock())
  214. {
  215. OpenInternal();
  216. }
  217. }
  218.  
  219. /// <summary>
  220. /// Opens a connection to the server.
  221. /// </summary>
  222. public void Open(bool preloadData)
  223. {
  224. using (GetBusyLock())
  225. {
  226. OpenInternal();
  227.  
  228. if (preloadData)
  229. {
  230. var streams = this.Streams;
  231. }
  232. }
  233. }
  234.  
  235. private void OpenInternal()
  236. {
  237. // Are we already connected?
  238. if (ConnectionStatus == ConnectionState.Connected ||
  239. ConnectionStatus == ConnectionState.LoggedIn)
  240. {
  241. return;
  242. }
  243.  
  244. // Are we already trying to connect?
  245. if (ConnectionStatus == ConnectionState.Connecting)
  246. {
  247. throw new InvalidOperationException("Cannot have nested open calls.");
  248. }
  249.  
  250. // Indicate that we are connecting
  251. OnConnectionProgressChanged(new ProgressChangedEventArgs(0, null));
  252. ConnectionStatus = ConnectionState.Connecting;
  253.  
  254. try
  255. {
  256. // Let inheritors actually open the connection.
  257. ConnectionStatus = OpenCore();
  258. }
  259. catch (Exception)
  260. {
  261. ConnectionStatus = ConnectionState.Disconnected;
  262. throw;
  263. }
  264. finally
  265. {
  266. OnConnectionProgressChanged(new ProgressChangedEventArgs(100, null));
  267. }
  268. }
  269.  
  270. /// <summary>
  271. /// Closes this connection to the server.
  272. /// </summary>
  273. public void Close()
  274. {
  275. using (GetBusyLock())
  276. {
  277. // Are we already disconnected?
  278. if (ConnectionStatus == ConnectionState.Uninitialized ||
  279. ConnectionStatus == ConnectionState.Disconnected)
  280. {
  281. return;
  282. }
  283.  
  284. // Are we already trying to disconnect?
  285. if (ConnectionStatus == ConnectionState.Disconnecting)
  286. {
  287. throw new InvalidOperationException("Cannot have nested close calls.");
  288. }
  289.  
  290. // Indicate that we are connecting
  291. OnConnectionProgressChanged(new ProgressChangedEventArgs(0, null));
  292. ConnectionStatus = ConnectionState.Disconnecting;
  293.  
  294. // Unrender all our streams.
  295. SafelyUnrenderAllStreams();
  296.  
  297. try
  298. {
  299. // Let inheritors actually close the connection.
  300. CloseCore();
  301. }
  302. finally
  303. {
  304. // Mark all the streams as dirty.
  305. MarkStreamsDirty();
  306.  
  307. // By the end we must be disconnected.
  308. ConnectionStatus = ConnectionState.Disconnected;
  309. OnConnectionProgressChanged(new ProgressChangedEventArgs(100, null));
  310. }
  311. }
  312. }
  313.  
  314. IDisposable GetBusyLock()
  315. {
  316. return new Disposable(() => SetIsBusy(true), () => SetIsBusy(false));
  317. }
  318.  
  319. private int _isBusy = 0;
  320. private Thread _thread;
  321. void SetIsBusy(bool value)
  322. {
  323. lock(SyncRoot)
  324. {
  325. if (value)
  326. {
  327. if (_thread == Thread.CurrentThread)
  328. return;
  329.  
  330. while (_isBusy > 0)
  331. Monitor.Wait(SyncRoot);
  332.  
  333. if (_thread == null)
  334. {
  335. _thread = Thread.CurrentThread;
  336. _isBusy++;
  337. }
  338. }
  339. else
  340. {
  341. if (_thread == Thread.CurrentThread)
  342. _isBusy--;
  343.  
  344. if (_isBusy == 0)
  345. {
  346. _thread = null;
  347. Monitor.Pulse(SyncRoot);
  348. }
  349. }
  350. }
  351. }
  352.  
  353. /// <summary>
  354. /// Current Connection status of this Network Endpoint
  355. /// </summary>
  356. public ConnectionState ConnectionStatus
  357. {
  358. get
  359. {
  360. return _status;
  361. }
  362. protected set
  363. {
  364. if (ConnectionStatus != value)
  365. {
  366. _status = value;
  367. OnConnectionStatusChanged(EventArgs.Empty);
  368. }
  369. }
  370. }
  371.  
  372. /// <summary>
  373. /// Event used to inform users of this instance when the connection status changes.
  374. /// </summary>
  375. public event EventHandler ConnectionStatusChanged
  376. {
  377. add
  378. {
  379. _connectionStatusChanged = WeakMulticastDelegate.CombineUnique(_connectionStatusChanged, value);
  380. }
  381. remove
  382. {
  383. _connectionStatusChanged = WeakMulticastDelegate.Remove(_connectionStatusChanged, value);
  384. }
  385. }
  386.  
  387. /// <summary>
  388. /// Event raised when the progress of the connection changes.
  389. /// </summary>
  390. public event ProgressChangedEventHandler ConnectionProgressChanged
  391. {
  392. add
  393. {
  394. _connectionProgressChanged = WeakMulticastDelegate.CombineUnique(_connectionProgressChanged, value);
  395. }
  396. remove
  397. {
  398. _connectionProgressChanged = WeakMulticastDelegate.Remove(_connectionProgressChanged, value);
  399. }
  400. }
  401.  
  402. /// <summary>
  403. /// Raises the <see cref="E:ConnectionStatusChanged"/> event.
  404. /// </summary>
  405. /// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  406. protected virtual void OnConnectionStatusChanged(EventArgs args)
  407. {
  408. WeakMulticastDelegate handler = _connectionStatusChanged;
  409. if (handler != null)
  410. {
  411. handler.InvokeSafe(new object[] { this, args });
  412. }
  413. }
  414.  
  415. /// <summary>
  416. /// Raises the <see cref="E:ConnectionProgressChanged"/> event.
  417. /// </summary>
  418. /// <param name="args">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
  419. protected virtual void OnConnectionProgressChanged(ProgressChangedEventArgs args)
  420. {
  421. WeakMulticastDelegate handler = _connectionProgressChanged;
  422. if (handler != null)
  423. {
  424. handler.InvokeSafe(new object[] { this, args });
  425. }
  426. }
  427.  
  428. #endregion
  429.  
  430. #region ISource Members
  431.  
  432. /// <summary>
  433. /// Gets the <see cref="SourceType">type</see> of the source.
  434. /// </summary>
  435. public override SourceType Type
  436. {
  437. get
  438. {
  439. if (IsLocal)
  440. {
  441. return base.Type | SourceType.Local;
  442. }
  443. else
  444. {
  445. return base.Type;
  446. }
  447. }
  448. }
  449.  
  450. /// <summary>
  451. /// Gets a <see cref="StreamCollection"/> of <see cref="IStream"/> objects for the source.
  452. /// </summary>
  453. public override StreamCollection Streams
  454. {
  455. get
  456. {
  457. lock (SyncRoot)
  458. {
  459. // If we're connected and need to get the streams, do so.
  460. if (!IsConnected)
  461. return new StreamCollection();
  462.  
  463. if(_streams != null && !_streamsDirty)
  464. return _streams;
  465.  
  466. if(_streams == null)
  467. _streams = new StreamCollection();
  468.  
  469. _streamsDirty = false;
  470. }
  471.  
  472. using (GetBusyLock())
  473. {
  474. _streams = GetStreams(_oldStreams);
  475. }
  476.  
  477. return _streams;
  478. }
  479. }
  480.  
  481. /// <summary>
  482. /// Virtual method to allow inheritors to free resources.
  483. /// </summary>
  484. /// <param name="disposing">Indicates is the instance should free managed resources in
  485. /// addition to unmanaged. True to free both managed and unmanaged resources, false
  486. /// to free just unmanaged.</param>
  487. /// <remarks>Overrides of this method MUST call base.Dispose(bool)!</remarks>
  488. protected override void Dispose(bool disposing)
  489. {
  490. if (disposing)
  491. {
  492. // Close our connection
  493. Close();
  494. }
  495. base.Dispose(disposing);
  496. }
  497.  
  498. #endregion
  499.  
  500. #if !CPE7252
  501. internal object SyncRoot
  502. {
  503. get
  504. {
  505. if (this is IRecorder)
  506. {
  507. object sync = (this as IRecorder).DVRSystem;
  508. if (sync != null)
  509. {
  510. return sync;
  511. }
  512. }
  513. return this;
  514. }
  515. }
  516. #else
  517. protected object SyncRoot = new object();
  518. #endif
  519. /// <summary>
  520. /// Inheritors should override this method to perform the actual open operation.
  521. /// </summary>
  522. protected virtual ConnectionState OpenCore()
  523. {
  524. return ConnectionState.Disconnected;
  525. }
  526.  
  527. /// <summary>
  528. /// Inheritors should override this method to perform the actual close operation.
  529. /// </summary>
  530. protected virtual void CloseCore()
  531. {
  532. }
  533.  
  534. /// <summary>
  535. /// Virtual method for inheritors to take action when the connection information changes.
  536. /// </summary>
  537. protected virtual void OnConnectionInformationChanged(string hostname, string ipaddress, int port, string username, string password)
  538. {
  539. }
  540.  
  541. /// <summary>
  542. /// Inheritors should override this method to actually get the streams for the source.
  543. /// </summary>
  544. protected virtual StreamCollection GetStreams(StreamCollection oldStreams)
  545. {
  546. return null;
  547. }
  548.  
  549. /// <summary>
  550. /// Marks the Streams as dirty so that the next time they are requested,
  551. /// they will be refreshed. This method is automatically called when the
  552. /// network connection is closed.
  553. /// </summary>
  554. protected void MarkStreamsDirty()
  555. {
  556. lock (SyncRoot)
  557. {
  558. if (_streams != null)
  559. {
  560. // 'Disinherit' all the streams.
  561. foreach (IStream stream in _streams)
  562. {
  563. stream.Source = null;
  564. }
  565.  
  566. // Save them off so that if we reconnect, we can use the same instances.
  567. _oldStreams = new StreamCollection(_streams);
  568. _streams = null;
  569. }
  570.  
  571. // Set the dirty flag.
  572. _streamsDirty = true;
  573. }
  574. }
  575.  
  576. /// <summary>
  577. /// Generates a stream collection containing all the new streams, but tries to match
  578. /// each new stream with an old stream. If an old stream is found, it is updated, and
  579. /// added to the resulting stream collection in place of the new stream.
  580. /// </summary>
  581. protected StreamCollection MatchStreams(StreamCollection newStreams, StreamCollection oldStreams)
  582. {
  583. // If there are no old streams, there is nothing to match.
  584. if (oldStreams == null)
  585. {
  586. return newStreams;
  587. }
  588.  
  589. // Create a new collection to hold the result streams.
  590. StreamCollection result = new StreamCollection();
  591. foreach (IStream stream in newStreams)
  592. {
  593. IStream original = oldStreams.FindByNumberAndType(stream.Number, stream.Type);
  594. if (original != null)
  595. {
  596. original.Name = stream.Name;
  597. result.Add(original);
  598. }
  599. else
  600. {
  601. result.Add(stream);
  602. }
  603. }
  604. return result;
  605. }
  606.  
  607.  
  608. private void ConnectionInfomationChanged(string hostname, string ipaddress, int port, string username, string password)
  609. {
  610. // If our connection information is changing, disconnect if we need to.
  611. bool reconnect = false;
  612. if (!UseWindowsAuth && IsConnected)
  613. {
  614. Close();
  615. reconnect = true;
  616. }
  617.  
  618. // Let inheritors know that the connection information changed.
  619. OnConnectionInformationChanged(hostname, ipaddress, port, username, password);
  620.  
  621. // Reconnect if we disconnected above.
  622. if (reconnect)
  623. {
  624. //Open();
  625. }
  626. }
  627.  
  628. private void UpdateHostnameAndIpAddress(string hostnameOrIpAddress)
  629. {
  630. // For now just leave the hostname as what is passed in and indicated that
  631. // it has not been resolved. We'll resolve if anybody actually wants is...
  632. // but usually this is not the case.
  633. _hostResolved = false;
  634. _host = hostnameOrIpAddress;
  635.  
  636. // We do however have to get an IP address, so we'll use the network utility to
  637. // resolve the parameter to get the ipaddress:
  638. IPAddress addr = NetworkUtility.DnsResolve(hostnameOrIpAddress);
  639. if (addr != null && addr != System.Net.IPAddress.None)
  640. {
  641. // We successfully resolved the parameter, set the and address.
  642. _ipaddress = addr.ToString();
  643. }
  644. else
  645. {
  646. // We can't resolve the parameter! Just do the best we can.
  647. _ipaddress = hostnameOrIpAddress;
  648. System.Diagnostics.Trace.WriteLine("DNS Resolution on " + hostnameOrIpAddress + " failed.");
  649. }
  650.  
  651.  
  652. // Now determine if we're local or not:
  653. // Assume we are not local by default.
  654. _isLocal = false;
  655. // We should be able to do some basic checks...
  656. if (hostnameOrIpAddress == "127.0.0.1")
  657. {
  658. _isLocal = true;
  659. }
  660. else if (hostnameOrIpAddress.ToLower() == "localhost")
  661. {
  662. _isLocal = true;
  663. }
  664.  
  665. if (_isLocal)
  666. return;
  667.  
  668. // Ok we couldn't obviosuly determine whether or not this was
  669. // a local address, so let's figure out what the address of the local
  670. // machine is, and see it it matches...
  671. IPHostEntry hostEnty = Dns.GetHostEntry(string.Empty);
  672. foreach (IPAddress address in hostEnty.AddressList)
  673. {
  674. if (System.Net.IPAddress.IsLoopback(address) ||
  675. (address.AddressFamily != AddressFamily.InterNetwork))
  676. {
  677. continue;
  678. }
  679.  
  680. if (address.ToString() != IPAddress)
  681. continue;
  682.  
  683. _isLocal = true;
  684. break;
  685. }
  686. }
  687. }
  688. }
Add Comment
Please, Sign In to add comment