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