CheckCircuit – Blame information for rev 2

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 using System;
2 using System.Collections.Concurrent;
3 using System.IO;
4 using System.Net.Sockets;
5 using System.Net;
6 using System.Threading.Tasks;
7 using System.Threading;
8 using CheckCircuitCode.CommandLine;
9 using CommandLine;
10  
11 namespace CheckCircuitCode
12 {
13 internal class Program
14 {
15 private enum CIRCUIT_STATUS : int
16 {
17 NONE = 0,
18 AUTHENTICATION_FAILED,
19 CIRCUIT_UNAVAILABLE,
20 COMMUNICATION_ERROR
21  
22 }
23  
24 public static TcpClient TcpClient { get; set; }
25 public static bool Verbose { get; private set; }
26  
27 static int Main(string[] args)
28 {
29 var CancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60));
30 var CancellationToken = CancellationTokenSource.Token;
31  
32 return Parser.Default.ParseArguments<ConnectOptions>(args)
33 .MapResult(opts => RunConnectAndReturnExitCode(opts, CancellationToken), errs => 1);
34 }
35  
36 private static int RunConnectAndReturnExitCode(ConnectOptions opts, CancellationToken cancellationToken)
37 {
38 Verbose = opts.Verbose;
39  
40 if (!IPEndPoint.TryParse(opts.Listen, out var listenEndPoint))
41 {
42 Console.WriteLine("Bad listen HOST:PORT format.");
43 return 1;
44 }
45  
46 if (!IPEndPoint.TryParse(opts.Connect, out var connectEndPoint))
47 {
48 Console.WriteLine("Bad connect HOST:PORT format.");
49 return 1;
50 }
51  
52 if (string.IsNullOrEmpty(opts.Password))
53 {
54 Console.WriteLine("Bad password string.");
55 return 1;
56 }
57  
58 if (!int.TryParse(opts.Timeout, out var timeout))
59 {
60 Console.WriteLine("Bad timeout value.");
61 return 1;
62 }
63  
64 var circuitStatus = Task.Run(() => StartClient(connectEndPoint, opts.Password, cancellationToken));
65  
66 return (int)circuitStatus.Result;
67 }
68  
69 private static async Task<CIRCUIT_STATUS> StartClient(IPEndPoint connect, string password, CancellationToken cancellationToken)
70 {
71 try
72 {
73 using (var tcpClient = new TcpClient())
74 {
75 await tcpClient.ConnectAsync(connect.Address, connect.Port, cancellationToken);
76 using (var tcpClientStream = tcpClient.GetStream())
77 {
78 using (var streamReader = new StreamReader(tcpClientStream))
79 {
80 using (var streamWriter = new StreamWriter(tcpClientStream))
81 {
82 do
83 {
84 if (!await Authenticate(streamReader, streamWriter, password))
85 {
86 if (Verbose)
87 {
88 Console.WriteLine("Authentication failed, please check OR port and password.");
89 }
90 return CIRCUIT_STATUS.AUTHENTICATION_FAILED;
91 }
92  
93 do
94 {
95 try
96 {
97 if (await IsCircuitFormed(streamReader, streamWriter))
98 {
99 return CIRCUIT_STATUS.NONE;
100 }
101  
102 return CIRCUIT_STATUS.CIRCUIT_UNAVAILABLE;
103 }
104 catch (ArgumentException)
105 {
106 return CIRCUIT_STATUS.COMMUNICATION_ERROR;
107 }
108  
109 } while (tcpClient.Connected && !cancellationToken.IsCancellationRequested);
110 } while (tcpClient.Connected && !cancellationToken.IsCancellationRequested);
111 }
112 }
113 }
114 }
115 }
116 catch (Exception exception)
117 {
118 if (Verbose)
119 {
120 Console.WriteLine(exception);
121 }
122  
123 return CIRCUIT_STATUS.COMMUNICATION_ERROR;
124 }
125 }
126  
127 public static async Task<bool> Authenticate(StreamReader sr, StreamWriter sw, string password)
128 {
129 var readLineTask = sr.ReadLineAsync();
130 await sw.WriteLineAsync($"AUTHENTICATE \"{password}\"");
131 await sw.FlushAsync();
132 var readLine = await readLineTask;
133  
134 return string.Equals(readLine, @"250 OK", StringComparison.Ordinal);
135 }
136  
137 public static async Task<bool> IsCircuitFormed(StreamReader sr, StreamWriter sw)
138 {
139 var readLineTask = sr.ReadLineAsync();
140 await sw.WriteLineAsync(@"GETINFO status/circuit-established");
141 await sw.FlushAsync();
142 var readLine = await readLineTask;
143  
144 var success = string.Equals(readLine, @"250-status/circuit-established=1", StringComparison.Ordinal);
145 readLine = await sr.ReadLineAsync();
146 if (string.Equals(readLine, @"250 OK", StringComparison.Ordinal))
147 {
148 return success;
149 }
150  
151 throw new ArgumentException("Unable to read response from control port.");
152 }
153  
154 public static async Task SendPayload(ConcurrentDictionary<IntPtr, TcpClient> clients, string payload, CancellationToken CancellationToken)
155 {
156 foreach (var (handle, client) in clients)
157 {
158 if (CancellationToken.IsCancellationRequested)
159 {
160 throw new TaskCanceledException();
161 }
162  
163 try
164 {
165 if (!client.Connected)
166 {
167 continue;
168 }
169  
170 using (var networkStream = client.GetStream())
171 {
172 using (var sw = new StreamWriter(networkStream))
173 {
174 await sw.WriteLineAsync(payload);
175  
176 }
177 }
178 }
179 catch (Exception exception)
180 {
181 if (Verbose)
182 {
183 Console.WriteLine(exception);
184 }
185 }
186 finally
187 {
188 clients.TryRemove(handle, out _);
189 try
190 {
191 client.Close();
192 }
193 catch (ObjectDisposedException exception)
194 {
195 if (Verbose)
196 {
197 Console.WriteLine(exception);
198 }
199 }
200 }
201 }
202 }
203 }
204 }