CheckCircuit – Blame information for rev 2

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