MultiHostStream.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. using System;
  2. using System.Net;
  3. using System.IO;
  4. using System.Collections;
  5. using System.Threading;
  6. namespace ByteFX.Data.Common
  7. {
  8. internal enum MultiHostStreamErrorType
  9. {
  10. Connecting,
  11. Reading,
  12. Writing
  13. }
  14. /// <summary>
  15. /// Summary description for MultiHostStream.
  16. /// </summary>
  17. internal abstract class MultiHostStream : Stream
  18. {
  19. protected Stream stream;
  20. protected int readTimeOut;
  21. protected Exception baseException;
  22. /// <summary>
  23. /// Constructs a new MultiHostStream object with the given parameters
  24. /// </summary>
  25. /// <param name="hostList"></param>
  26. /// <param name="port"></param>
  27. /// <param name="readTimeOut"></param>
  28. /// <param name="connectTimeOut"></param>
  29. public MultiHostStream(string hostList, int port, int readTimeOut, int connectTimeOut)
  30. {
  31. this.readTimeOut = readTimeOut;
  32. ProcessHosts( hostList, port, connectTimeOut );
  33. }
  34. // abstract members
  35. protected abstract void TimeOut(MultiHostStreamErrorType error);
  36. protected abstract void Error(string msg);
  37. protected abstract bool CreateStream( IPAddress ip, string host, int port );
  38. protected abstract bool CreateStream (string fileName);
  39. protected abstract bool DataAvailable
  40. {
  41. get;
  42. }
  43. private void ProcessHosts( string hostList, int port, int connectTimeOut )
  44. {
  45. int startTime = Environment.TickCount;
  46. int toTicks = connectTimeOut * 1000;
  47. // support Unix sockets
  48. if (hostList.StartsWith ("/"))
  49. {
  50. CreateStream (hostList);
  51. return;
  52. }
  53. //
  54. // Host name can contain multiple hosts, seperated by &.
  55. string [] dnsHosts = hostList.Split('&');
  56. Hashtable ips = new Hashtable();
  57. //
  58. // Each host name specified may contain multiple IP addresses
  59. // Lets look at the DNS entries for each host name
  60. foreach(string h in dnsHosts)
  61. {
  62. IPHostEntry hostAddress = Dns.GetHostByName(h);
  63. foreach (IPAddress addr in hostAddress.AddressList)
  64. ips.Add( addr, hostAddress.HostName );
  65. }
  66. IPAddress[] keys = new IPAddress[ ips.Count ];
  67. ips.Keys.CopyTo( keys, 0 );
  68. if ((Environment.TickCount - startTime) > toTicks)
  69. {
  70. TimeOut(MultiHostStreamErrorType.Connecting);
  71. return;
  72. }
  73. // make sure they gave us at least one host
  74. if (ips.Count == 0)
  75. {
  76. Error("You must specify at least one host");
  77. return;
  78. }
  79. int index = 0;
  80. // now choose a random server if there are more than one
  81. if (ips.Count > 1)
  82. {
  83. System.Random random = new Random((int)DateTime.Now.Ticks);
  84. index = random.Next(ips.Count-1);
  85. }
  86. //
  87. // Lets step through our hosts until we get a connection
  88. for (int i=0; i < ips.Count; i++)
  89. {
  90. if ((Environment.TickCount - startTime) > toTicks)
  91. {
  92. TimeOut(MultiHostStreamErrorType.Connecting);
  93. return;
  94. }
  95. if (CreateStream( (IPAddress)keys[i], (string)ips[keys[i]], port ))
  96. return;
  97. }
  98. }
  99. public override int ReadByte()
  100. {
  101. int start = Environment.TickCount;
  102. int ticks = readTimeOut * 1000;
  103. while ((Environment.TickCount - start) < ticks)
  104. {
  105. if (DataAvailable)
  106. {
  107. int b = stream.ReadByte();
  108. return b;
  109. }
  110. else
  111. Thread.Sleep(0);
  112. }
  113. TimeOut(MultiHostStreamErrorType.Reading);
  114. return -1;
  115. }
  116. public override int Read(byte[] buffer, int offset, int count)
  117. {
  118. int numToRead = count;
  119. int start = Environment.TickCount;
  120. int ticks = readTimeOut * 1000;
  121. try
  122. {
  123. while (numToRead > 0 && (Environment.TickCount - start) < ticks)
  124. {
  125. if (DataAvailable)
  126. {
  127. int bytes_read = stream.Read( buffer, offset, numToRead);
  128. if (bytes_read == 0)
  129. return (count - numToRead);
  130. offset += bytes_read;
  131. numToRead -= bytes_read;
  132. }
  133. else
  134. Thread.Sleep(0);
  135. }
  136. }
  137. catch (Exception ex)
  138. {
  139. Console.WriteLine(ex.Message);
  140. }
  141. if (numToRead > 0)
  142. TimeOut(MultiHostStreamErrorType.Reading);
  143. return count;
  144. }
  145. public override bool CanRead
  146. {
  147. get { return stream.CanRead; }
  148. }
  149. public override bool CanWrite
  150. {
  151. get { return stream.CanWrite; }
  152. }
  153. public override bool CanSeek
  154. {
  155. get { return stream.CanSeek; }
  156. }
  157. public override long Length
  158. {
  159. get { return stream.Length; }
  160. }
  161. public override long Position
  162. {
  163. get { return stream.Position; }
  164. set { stream.Position = value; }
  165. }
  166. public override void Flush()
  167. {
  168. stream.Flush();
  169. }
  170. public override void SetLength(long length)
  171. {
  172. stream.SetLength( length );
  173. }
  174. public override void Write(byte[] buffer, int offset, int count)
  175. {
  176. stream.Write( buffer, offset, count );
  177. }
  178. public override long Seek( long offset, SeekOrigin origin )
  179. {
  180. return stream.Seek( offset, origin );
  181. }
  182. }
  183. }