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 string _prevAutoConfigUrl;
\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
34 public ProxyManager(Config config, Control parent)
\r
38 SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
\r
39 _timer.Tick += CheckProxy;
\r
42 public bool ApplyConfig()
\r
44 if (!_config.Proxy.Auto)
\r
45 RestoreSystemProxy();
\r
46 if (_config.Proxy.UseUpstream)
\r
48 HttpProxy.UpstreamProxyHost = "127.0.0.1";
\r
49 HttpProxy.UpstreamProxyPort = _config.Proxy.UpstreamPort;
\r
51 HttpProxy.IsEnableUpstreamProxy = _config.Proxy.UseUpstream;
\r
53 if (!HttpProxy.IsInListening || _config.Proxy.Listen != _prevProxyPort)
\r
56 result = StartProxy();
\r
58 if (_config.Proxy.Auto && result)
\r
60 if (_prevAutoConfigUrl == null)
\r
62 SystemProxy.AdjustLocalIntranetZoneFlags();
\r
63 _prevAutoConfigUrl = SystemProxy.AutoConfigUrl;
\r
65 SetAndCheckAutoConfigUrl();
\r
67 _prevProxyPort = _config.Proxy.Listen;
\r
71 private bool StartProxy()
\r
75 HttpProxy.Startup(_config.Proxy.Listen, false, false);
\r
77 catch (SocketException e)
\r
79 if (e.SocketErrorCode != SocketError.AddressAlreadyInUse &&
\r
80 e.SocketErrorCode != SocketError.AccessDenied)
\r
84 if (WarnConflictPortNumber(_config.Proxy.Listen, _config.Proxy.Auto) == DialogResult.No ||
\r
85 !_config.Proxy.Auto)
\r
87 RestoreSystemProxy();
\r
90 HttpProxy.Startup(0, false, false);
\r
91 _config.Proxy.Listen = HttpProxy.LocalPort;
\r
96 private DialogResult WarnConflictPortNumber(int port, bool auto)
\r
98 var msg = $"ポート番号{port}は他のアプリケーションが使用中です。";
\r
99 var cap = "ポート番号の衝突";
\r
101 ? MessageBox.Show(_parent, msg + "自動的に別の番号を割り当てますか?", cap,
\r
102 MessageBoxButtons.YesNo, MessageBoxIcon.Question)
\r
103 : MessageBox.Show(_parent, msg + "設定ダイアログでポート番号を変更してください。", cap,
\r
104 MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
\r
107 private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
\r
109 if (e.Mode != PowerModes.Resume || !_config.Proxy.Auto)
\r
111 SystemProxy.Refresh();
\r
114 public void Shutdown()
\r
117 if (_config.Proxy.Auto)
\r
118 RestoreSystemProxy();
\r
119 SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
\r
122 private void ShutdownProxy()
\r
124 HttpProxy.Shutdown();
\r
127 private void SetAndCheckAutoConfigUrl()
\r
129 SetAutoConfigUrl();
\r
130 _initiated = false;
\r
134 private void CheckProxy(object sender, EventArgs ev)
\r
138 // Windows 10でプロキシ設定がいつの間にか消えるのに対応するために、
\r
139 // 設定が消えていないか毎秒確認して、消えていたら再設定する。
\r
140 if (IsProxyWorking)
\r
142 File.AppendAllText("proxy.log", $"[{DateTime.Now:G}] proxy setting vanished.\r\n");
\r
143 SetAutoConfigUrl();
\r
146 if (IsProxyWorking)
\r
151 if (_autoConfigRetryCount > 0 && _autoConfigRetryCount % 5 == 0)
\r
154 switch (MessageBox.Show(_parent, "プロキシの自動設定に失敗しました。", "エラー", MessageBoxButtons.AbortRetryIgnore,
\r
155 MessageBoxIcon.Error))
\r
157 case DialogResult.Abort:
\r
158 Application.Exit();
\r
160 case DialogResult.Ignore:
\r
165 _autoConfigRetryCount++;
\r
166 SetAutoConfigUrl();
\r
169 private bool IsProxyWorking =>
\r
170 WebRequest.GetSystemWebProxy().GetProxy(new Uri("http://125.6.184.16/")).IsLoopback;
\r
172 private void SetAutoConfigUrl()
\r
174 var count = _autoConfigRetryCount == 0 ? "" : _autoConfigRetryCount.ToString();
\r
175 SystemProxy.AutoConfigUrl = $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac";
\r
178 private void RestoreSystemProxy()
\r
181 if (_prevAutoConfigUrl == null)
\r
183 if (_prevAutoConfigUrl == "")
\r
185 SystemProxy.AutoConfigUrl = "";
\r
188 HttpWebRequest request;
\r
191 request = WebRequest.CreateHttp(_prevAutoConfigUrl);
\r
192 if (!request.Address.IsLoopback)
\r
193 throw new Exception();
\r
197 // httpではなくloopbackでもない
\r
198 SystemProxy.AutoConfigUrl = _prevAutoConfigUrl;
\r
203 request.GetResponse().Dispose();
\r
208 SystemProxy.AutoConfigUrl = "";
\r
211 SystemProxy.AutoConfigUrl = _prevAutoConfigUrl;
\r
214 public void UpdatePacFile()
\r
216 var request = (HttpWebRequest)WebRequest.Create("https://kancollesniffer.osdn.jp/proxy.pac");
\r
217 if (File.Exists("proxy.pac"))
\r
219 var date = File.GetLastWriteTime("proxy.pac");
\r
220 request.IfModifiedSince = date;
\r
224 var response = (HttpWebResponse)request.GetResponse();
\r
225 using (var stream = response.GetResponseStream())
\r
226 using (var file = new FileStream("proxy.pac", FileMode.OpenOrCreate))
\r
227 stream?.CopyTo(file);
\r
229 // ReSharper disable once EmptyGeneralCatchClause
\r