1 // Copyright (C) 2017 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // Licensed under the Apache License, Version 2.0 (the "License");
\r
4 // you may not use this file except in compliance with the License.
\r
5 // You may obtain a copy of the License at
\r
7 // http://www.apache.org/licenses/LICENSE-2.0
\r
9 // Unless required by applicable law or agreed to in writing, software
\r
10 // distributed under the License is distributed on an "AS IS" BASIS,
\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 // See the License for the specific language governing permissions and
\r
13 // limitations under the License.
\r
18 using System.Net.Sockets;
\r
19 using System.Windows.Forms;
\r
20 using Microsoft.Win32;
\r
22 namespace KancolleSniffer.Net
\r
24 public class ProxyManager
\r
26 private readonly Control _parent;
\r
27 private readonly Config _config;
\r
28 private readonly SystemProxy _systemProxy = new SystemProxy();
\r
29 private int _prevProxyPort;
\r
30 private int _autoConfigRetryCount;
\r
31 private readonly Timer _timer = new Timer();
\r
32 private bool _initiated;
\r
33 private DateTime _pacFileTime;
\r
35 public ProxyManager(Control parent, Config config)
\r
39 SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
\r
40 _timer.Tick += CheckProxy;
\r
43 public bool ApplyConfig()
\r
45 if (!_config.Proxy.Auto)
\r
46 RestoreSystemProxy();
\r
47 if (_config.Proxy.UseUpstream)
\r
49 HttpProxy.UpstreamProxyHost = "127.0.0.1";
\r
50 HttpProxy.UpstreamProxyPort = _config.Proxy.UpstreamPort;
\r
52 HttpProxy.IsEnableUpstreamProxy = _config.Proxy.UseUpstream;
\r
54 if (!HttpProxy.IsInListening || _config.Proxy.Listen != _prevProxyPort)
\r
57 result = StartProxy();
\r
59 if (_config.Proxy.Auto && result)
\r
61 SetAndCheckAutoConfigUrl();
\r
63 _prevProxyPort = _config.Proxy.Listen;
\r
67 private bool StartProxy()
\r
71 HttpProxy.Startup(_config.Proxy.Listen, false, false);
\r
73 catch (SocketException e)
\r
75 if (e.SocketErrorCode != SocketError.AddressAlreadyInUse &&
\r
76 e.SocketErrorCode != SocketError.AccessDenied)
\r
80 if (WarnConflictPortNumber(_config.Proxy.Listen, _config.Proxy.Auto) == DialogResult.No ||
\r
81 !_config.Proxy.Auto)
\r
83 RestoreSystemProxy();
\r
86 HttpProxy.Startup(0, false, false);
\r
87 _config.Proxy.Listen = HttpProxy.LocalPort;
\r
92 private DialogResult WarnConflictPortNumber(int port, bool auto)
\r
94 var msg = $"ポート番号{port}は他のアプリケーションが使用中です。";
\r
95 var cap = "ポート番号の衝突";
\r
97 ? MessageBox.Show(_parent, msg + "自動的に別の番号を割り当てますか?", cap,
\r
98 MessageBoxButtons.YesNo, MessageBoxIcon.Question)
\r
99 : MessageBox.Show(_parent, msg + "設定ダイアログでポート番号を変更してください。", cap,
\r
100 MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
\r
103 private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
\r
105 if (e.Mode != PowerModes.Resume || !_config.Proxy.Auto)
\r
107 SystemProxy.Refresh();
\r
110 public void Shutdown()
\r
113 if (_config.Proxy.Auto)
\r
114 RestoreSystemProxy();
\r
115 SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
\r
118 private void ShutdownProxy()
\r
120 HttpProxy.Shutdown();
\r
123 private void SetAndCheckAutoConfigUrl()
\r
125 SetAutoConfigUrl();
\r
126 _initiated = false;
\r
127 _timer.Interval = 5000;
\r
131 private void CheckProxy(object sender, EventArgs ev)
\r
135 // Windows 10でプロキシ設定がいつの間にか消えるのに対応するために、
\r
136 // 設定が消えていないか毎秒確認して、消えていたら再設定する。
\r
137 if (IsProxyWorking)
\r
139 File.AppendAllText("proxy.log", $"[{DateTime.Now:G}] proxy setting vanished.\r\n");
\r
140 SetAutoConfigUrl();
\r
143 if (IsProxyWorking)
\r
146 _timer.Interval = 1000;
\r
149 if (_autoConfigRetryCount > 0 && _autoConfigRetryCount % 6 == 0)
\r
152 switch (MessageBox.Show(_parent, "プロキシの自動設定に失敗しました。", "エラー", MessageBoxButtons.AbortRetryIgnore,
\r
153 MessageBoxIcon.Error))
\r
155 case DialogResult.Abort:
\r
157 Environment.Exit(1);
\r
159 case DialogResult.Ignore:
\r
164 _autoConfigRetryCount++;
\r
165 SetAutoConfigUrl();
\r
168 private bool IsProxyWorking =>
\r
169 WebRequest.GetSystemWebProxy().GetProxy(new Uri("http://125.6.184.16/")).IsLoopback;
\r
171 private void SetAutoConfigUrl()
\r
173 var suffix = (DateTime.Now - _pacFileTime < TimeSpan.FromHours(6)
\r
174 ? (int)_pacFileTime.TimeOfDay.TotalSeconds
\r
175 : 0) + _autoConfigRetryCount;
\r
176 _systemProxy.SetAutoConfigUrl(
\r
177 $"http://localhost:{_config.Proxy.Listen}/proxy{(suffix == 0 ? "" : suffix.ToString("x"))}.pac");
\r
180 private void RestoreSystemProxy()
\r
183 _systemProxy.RestoreSettings();
\r
186 public void UpdatePacFile()
\r
188 var pacFile = "proxy.pac";
\r
189 var request = (HttpWebRequest)WebRequest.Create($"https://kancollesniffer.osdn.jp/{pacFile}");
\r
190 if (File.Exists(pacFile))
\r
192 _pacFileTime = File.GetLastWriteTime(pacFile);
\r
193 request.IfModifiedSince = _pacFileTime;
\r
197 var response = (HttpWebResponse)request.GetResponse();
\r
198 var mem = new MemoryStream();
\r
199 using (var stream = response.GetResponseStream())
\r
200 stream?.CopyTo(mem);
\r
202 using (var file = new FileStream(pacFile, FileMode.Create))
\r
204 _pacFileTime = File.GetLastWriteTime(pacFile);
\r
206 // ReSharper disable once EmptyGeneralCatchClause
\r