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
\r
24 public class ProxyManager
\r
26 private readonly Config _config;
\r
27 private readonly Control _parent;
\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 {Interval = 1000};
\r
32 private bool _initiated;
\r
33 private DateTime _pacFileTime;
\r
35 public ProxyManager(Config config, Control parent)
\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
130 private void CheckProxy(object sender, EventArgs ev)
\r
134 // Windows 10でプロキシ設定がいつの間にか消えるのに対応するために、
\r
135 // 設定が消えていないか毎秒確認して、消えていたら再設定する。
\r
136 if (IsProxyWorking)
\r
138 File.AppendAllText("proxy.log", $"[{DateTime.Now:G}] proxy setting vanished.\r\n");
\r
139 SetAutoConfigUrl();
\r
142 if (IsProxyWorking)
\r
147 if (_autoConfigRetryCount > 0 && _autoConfigRetryCount % 5 == 0)
\r
150 switch (MessageBox.Show(_parent, "プロキシの自動設定に失敗しました。", "エラー", MessageBoxButtons.AbortRetryIgnore,
\r
151 MessageBoxIcon.Error))
\r
153 case DialogResult.Abort:
\r
155 Environment.Exit(1);
\r
157 case DialogResult.Ignore:
\r
162 _autoConfigRetryCount++;
\r
163 SetAutoConfigUrl();
\r
166 private bool IsProxyWorking =>
\r
167 WebRequest.GetSystemWebProxy().GetProxy(new Uri("http://125.6.184.16/")).IsLoopback;
\r
169 private void SetAutoConfigUrl()
\r
171 var suffix = (DateTime.Now - _pacFileTime < TimeSpan.FromHours(6)
\r
172 ? (int)_pacFileTime.TimeOfDay.TotalSeconds
\r
173 : 0) + _autoConfigRetryCount;
\r
174 _systemProxy.SetAutoConfigUrl(
\r
175 $"http://localhost:{_config.Proxy.Listen}/proxy{(suffix == 0 ? "" : suffix.ToString("x"))}.pac");
\r
178 private void RestoreSystemProxy()
\r
181 _systemProxy.RestoreSettings();
\r
184 public void UpdatePacFile()
\r
186 var pacFile = "proxy.pac";
\r
187 var request = (HttpWebRequest)WebRequest.Create($"https://kancollesniffer.osdn.jp/{pacFile}");
\r
188 if (File.Exists(pacFile))
\r
190 _pacFileTime = File.GetLastWriteTime(pacFile);
\r
191 request.IfModifiedSince = _pacFileTime;
\r
195 var response = (HttpWebResponse)request.GetResponse();
\r
196 var mem = new MemoryStream();
\r
197 using (var stream = response.GetResponseStream())
\r
198 stream?.CopyTo(mem);
\r
200 using (var file = new FileStream(pacFile, FileMode.Create))
\r
202 _pacFileTime = File.GetLastWriteTime(pacFile);
\r
204 // ReSharper disable once EmptyGeneralCatchClause
\r