using System.Linq; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.Net; using System.Net.Sockets; using System.Text; using UMC.Data; using UMC.Net; using UMC.Web; namespace UMC.Proxy { class HttpBridgeClient : NetBridge, UMC.Host.IDoWorker { private static ConcurrentDictionary _bridgeClients = new ConcurrentDictionary(); // // System.Collections.Concurrent.ConcurrentDictionary public static void Start(String key, String host, int port, int count) { if (_bridgeClients.Count > 0) { var vs = _bridgeClients.Values.ToArray(); foreach (var vi in vs) { vi._Stop(); } _bridgeClients.Clear(); } for (var i = 0; i < count; i++) { try { Connect(key, host, port, i, true); } catch { break; } } } String host, ip; int port, index; static void Connect(String host, String ip, int port, int index, bool start) { var client = new Socket(SocketType.Stream, ProtocolType.Tcp); client.Connect(ip, port); var buffers = new byte[2000]; var writer = new UMC.Net.TextWriter((b, c, l) => client.Send(b, c, l, SocketFlags.None), buffers); writer.Write($"GET / HTTP/1.1\r\n"); writer.Write("Connection: upgrade\r\n"); writer.Write("umc-request-protocol: bridge\r\n"); writer.Write("Upgrade: websocket\r\n"); if (index == 0 && start) { writer.Write($"umc-bridge-number: -1\r\n"); } else { writer.Write($"umc-bridge-number: {index}\r\n"); } writer.Write($"Host: {host}\r\n\r\n"); writer.Flush(); writer.Dispose(); int i = client.Receive(buffers); var end = UMC.Data.Utility.FindIndex(buffers, 0, i, UMC.Net.MimeResponse.HeaderEnd); if (end > -1) { var headSize = end + 4; HttpStatusCode m_StatusCode; var header = new NameValueCollection(); if (ResponseHeader(buffers, 0, headSize, header, out m_StatusCode)) { if (m_StatusCode == HttpStatusCode.SwitchingProtocols) { var bridgeClient = new HttpBridgeClient(); bridgeClient.host = host; bridgeClient.ip = ip; bridgeClient.index = index; bridgeClient.port = port; bridgeClient.Bridge(client); if (i > end + 4) { bridgeClient.Receive(buffers, headSize, i - headSize); } _bridgeClients.TryAdd(bridgeClient.GetHashCode(), bridgeClient); } } } else { client.Disconnect(true); client.Close(); } } public static String ServerChange(int states) { var sb = new StringBuilder(); switch (states % 3) { case 0: { var secret = UMC.Data.WebResource.Instance().Provider["appSecret"]; if (String.IsNullOrEmpty(secret)) { sb.AppendLine("获取失败:\a应用未注册,请注册应用。"); } else { var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest(); var ns = new System.Collections.Specialized.NameValueCollection(); UMC.Proxy.Utility.Sign(webr, secret); try { var meta = JSON.Deserialize(webr.Get().ReadAsString()); if (meta.ContainsKey("msg")) { sb.AppendLine($"获取失败:\a{meta["msg"]}。"); } else { var scheme = meta["scheme"] ?? "http"; if (IsRunning) { sb.AppendLine($"服务状态:\b已连接"); } else { sb.AppendLine($"服务状态:未连接"); } sb.AppendLine($"Web VPN :{scheme}://{meta["domain"]}/"); sb.AppendLine($"流量过期:{meta["expireTime"]}"); sb.AppendLine($"剩余流量:{meta["allowSize"]}"); sb.AppendLine($"上行流量:{meta["inputSize"]}"); sb.AppendLine($"下行流量:{meta["outputSize"]}"); sb.AppendLine(); sb.AppendLine("特别注意:\a过期后剩余流量将会清零!!!"); } } catch //(Exception ex) { sb.AppendLine($"Web VPN:\a未连网"); } } } break; case 1: if (_bridgeClients.Count > 0) { sb.AppendLine("正在关停Web VPN服务。"); Stop(); } else { sb.AppendLine("Web VPN服务未开启。"); } break; case 2: { var secret = UMC.Data.WebResource.Instance().Provider["appSecret"]; if (String.IsNullOrEmpty(secret)) { sb.AppendLine($"Web VPN开启失败!!!"); sb.AppendLine("失败原因:\a应用未注册,请注册应用。"); } else if (_bridgeClients.Count > 0) { return ServerChange(0); } else { var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest(); UMC.Proxy.Utility.Sign(webr, secret); try { var meta = JSON.Deserialize(webr.Get().ReadAsString()); var scheme = meta["scheme"] ?? "http"; if (meta.ContainsKey("domain") == false) { sb.AppendLine($"Web VPN开启失败!!!"); sb.AppendLine("失败原因:\a域名未注册,请注册域名。"); } else if (meta.ContainsKey("msg")) { sb.AppendLine($"Web VPN开启失败!!!"); sb.AppendLine($"失败原因:\a{meta["msg"]}。"); } else { var ip = meta["ip"]; var port = UMC.Data.Utility.IntParse(meta["port"], 0); try { Start(meta["domain"], ip, port, 4); var bridgeUrl = $"{scheme}://{meta["domain"]}"; sb.AppendLine($"Web VPN :\b{bridgeUrl}"); sb.AppendLine($"服务状态:\a正连接"); sb.AppendLine($"剩余流量:{meta["allowSize"]}"); sb.AppendLine($"上行流量:{meta["inputSize"]}"); sb.AppendLine($"下行流量:{meta["outputSize"]}"); sb.AppendLine($"过期天数:{meta["expireTime"]}"); sb.AppendLine(); sb.AppendLine($"特别注意:\a过期后剩余流量将会清零!!!"); var provider = Data.WebResource.Instance().Provider; if (String.Equals(provider.Attributes["bridge"], bridgeUrl) == false) { provider.Attributes["bridge"] = bridgeUrl; var key = meta["key"]; var pdomain = provider["domain"]; var domain = meta["domain"]; if (String.IsNullOrEmpty(pdomain) || pdomain.StartsWith(key)) { provider.Attributes["scheme"] = scheme; provider.Attributes["domain"] = domain; UMC.Proxy.WebServlet.MainDomain = domain; } } provider.Attributes["webvpn"] = "true"; var pc = Reflection.Configuration("assembly") ?? new ProviderConfiguration(); pc.Add(provider); Reflection.Configuration("assembly", pc); } catch (Exception ex) { sb.AppendLine($"Web VPN开启失败!!!"); sb.AppendLine($"失败原因:{ex.Message}"); } } } catch (Exception ex) { sb.AppendLine($"Web VPN开启失败!!!"); sb.AppendLine($"失败原因:\a{ex.Message}"); } } } break; } return sb.ToString(); } public static bool IsRunning => _bridgeClients.Count > 0; public static void Stop() { lock (_bridgeClients) { for (var i = 0; i < _bridgeClients.Count; i++) { try { _bridgeClients[i]?._Stop(); } catch { } } _bridgeClients.Clear(); } var provider = Data.WebResource.Instance().Provider; provider.Attributes["webvpn"] = "false"; var pc = Reflection.Configuration("assembly") ?? new ProviderConfiguration(); pc.Add(provider); Reflection.Configuration("assembly", pc); } public override void Close() { base.Close(); _bridgeClients.TryRemove(this.GetHashCode(), out var _); if (_stoped == false) { HttpMimeServier.Register(10, this); } } bool _stoped; void _Stop() { _stoped = true; base.Close(); } HttpMimeRequest Bridge(int pid) { return new HttpBridgeRequest(new HttpBridgeMime(pid, this)); } public bool Remove(int pid) { HttpMimeRequest httpMime; return this.Clients.TryRemove(pid, out httpMime); } ConcurrentDictionary Clients = new ConcurrentDictionary(); protected override void Read(int pid, byte[] buffer, int index, int length) { if (length > 0) { HttpMimeRequest proxy = this.Clients.GetOrAdd(pid, this.Bridge); try { proxy.Receive(buffer, index, length); } catch (Exception ex) { Utility.Error("Bridge", ex.ToString()); } finally { if (proxy.IsHttpFormatError) { this.Clients.TryRemove(pid, out proxy); this.Write(pid, Array.Empty(), 0, 0); } else if (proxy.IsWebSocket == false && proxy.IsMimeFinish) { this.Clients.TryRemove(pid, out proxy); } } } else { HttpMimeRequest mimeBody; if (this.Clients.TryRemove(pid, out mimeBody)) { mimeBody.ReceiveException(new Exception("穿透传输中止")); } } } void Host.IDoWorker.DoWork() { try { Connect(host, ip, port, this.index, false); } catch { HttpMimeServier.Register(30, this); } } } }