OSDN Git Service

proxy.pacが小さくなると内容が壊れるのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ProxyManager.cs
1 // Copyright (C) 2017 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\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
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\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
14 \r
15 using System;\r
16 using System.IO;\r
17 using System.Net;\r
18 using System.Net.Sockets;\r
19 using System.Windows.Forms;\r
20 using Microsoft.Win32;\r
21 \r
22 namespace KancolleSniffer\r
23 {\r
24     public class ProxyManager\r
25     {\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 \r
34         public ProxyManager(Config config, Control parent)\r
35         {\r
36             _config = config;\r
37             _parent = parent;\r
38             SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;\r
39             _timer.Tick += CheckProxy;\r
40         }\r
41 \r
42         public bool ApplyConfig()\r
43         {\r
44             if (!_config.Proxy.Auto)\r
45                 RestoreSystemProxy();\r
46             if (_config.Proxy.UseUpstream)\r
47             {\r
48                 HttpProxy.UpstreamProxyHost = "127.0.0.1";\r
49                 HttpProxy.UpstreamProxyPort = _config.Proxy.UpstreamPort;\r
50             }\r
51             HttpProxy.IsEnableUpstreamProxy = _config.Proxy.UseUpstream;\r
52             var result = true;\r
53             if (!HttpProxy.IsInListening || _config.Proxy.Listen != _prevProxyPort)\r
54             {\r
55                 ShutdownProxy();\r
56                 result = StartProxy();\r
57             }\r
58             if (_config.Proxy.Auto && result)\r
59             {\r
60                 SetAndCheckAutoConfigUrl();\r
61             }\r
62             _prevProxyPort = _config.Proxy.Listen;\r
63             return result;\r
64         }\r
65 \r
66         private bool StartProxy()\r
67         {\r
68             try\r
69             {\r
70                 HttpProxy.Startup(_config.Proxy.Listen, false, false);\r
71             }\r
72             catch (SocketException e)\r
73             {\r
74                 if (e.SocketErrorCode != SocketError.AddressAlreadyInUse &&\r
75                     e.SocketErrorCode != SocketError.AccessDenied)\r
76                 {\r
77                     throw;\r
78                 }\r
79                 if (WarnConflictPortNumber(_config.Proxy.Listen, _config.Proxy.Auto) == DialogResult.No ||\r
80                     !_config.Proxy.Auto)\r
81                 {\r
82                     RestoreSystemProxy();\r
83                     return false;\r
84                 }\r
85                 HttpProxy.Startup(0, false, false);\r
86                 _config.Proxy.Listen = HttpProxy.LocalPort;\r
87             }\r
88             return true;\r
89         }\r
90 \r
91         private DialogResult WarnConflictPortNumber(int port, bool auto)\r
92         {\r
93             var msg = $"ポート番号{port}は他のアプリケーションが使用中です。";\r
94             var cap = "ポート番号の衝突";\r
95             return auto\r
96                 ? MessageBox.Show(_parent, msg + "自動的に別の番号を割り当てますか?", cap,\r
97                     MessageBoxButtons.YesNo, MessageBoxIcon.Question)\r
98                 : MessageBox.Show(_parent, msg + "設定ダイアログでポート番号を変更してください。", cap,\r
99                     MessageBoxButtons.OK, MessageBoxIcon.Exclamation);\r
100         }\r
101 \r
102         private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)\r
103         {\r
104             if (e.Mode != PowerModes.Resume || !_config.Proxy.Auto)\r
105                 return;\r
106             SystemProxy.Refresh();\r
107         }\r
108 \r
109         public void Shutdown()\r
110         {\r
111             ShutdownProxy();\r
112             if (_config.Proxy.Auto)\r
113                 RestoreSystemProxy();\r
114             SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;\r
115         }\r
116 \r
117         private void ShutdownProxy()\r
118         {\r
119             HttpProxy.Shutdown();\r
120         }\r
121 \r
122         private void SetAndCheckAutoConfigUrl()\r
123         {\r
124             SetAutoConfigUrl();\r
125             _initiated = false;\r
126             _timer.Start();\r
127         }\r
128 \r
129         private void CheckProxy(object sender, EventArgs ev)\r
130         {\r
131             if (_initiated)\r
132             {\r
133                 // Windows 10でプロキシ設定がいつの間にか消えるのに対応するために、\r
134                 // 設定が消えていないか毎秒確認して、消えていたら再設定する。\r
135                 if (IsProxyWorking)\r
136                     return;\r
137                 File.AppendAllText("proxy.log", $"[{DateTime.Now:G}] proxy setting vanished.\r\n");\r
138                 SetAutoConfigUrl();\r
139                 return;\r
140             }\r
141             if (IsProxyWorking)\r
142             {\r
143                 _initiated = true;\r
144                 return;\r
145             }\r
146             if (_autoConfigRetryCount > 0 && _autoConfigRetryCount % 5 == 0)\r
147             {\r
148                 _timer.Stop();\r
149                 switch (MessageBox.Show(_parent, "プロキシの自動設定に失敗しました。", "エラー", MessageBoxButtons.AbortRetryIgnore,\r
150                     MessageBoxIcon.Error))\r
151                 {\r
152                     case DialogResult.Abort:\r
153                         Shutdown();\r
154                         Environment.Exit(1);\r
155                         break;\r
156                     case DialogResult.Ignore:\r
157                         return;\r
158                 }\r
159                 _timer.Start();\r
160             }\r
161             _autoConfigRetryCount++;\r
162             SetAutoConfigUrl();\r
163         }\r
164 \r
165         private bool IsProxyWorking =>\r
166             WebRequest.GetSystemWebProxy().GetProxy(new Uri("http://125.6.184.16/")).IsLoopback;\r
167 \r
168         private void SetAutoConfigUrl()\r
169         {\r
170             var count = _autoConfigRetryCount == 0 ? "" : _autoConfigRetryCount.ToString();\r
171             _systemProxy.SetAutoConfigUrl(\r
172                 $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac");\r
173         }\r
174 \r
175         private void RestoreSystemProxy()\r
176         {\r
177             _timer.Stop();\r
178             _systemProxy.RestoreSettings();\r
179         }\r
180 \r
181         public void UpdatePacFile()\r
182         {\r
183             var request = (HttpWebRequest)WebRequest.Create("https://kancollesniffer.osdn.jp/proxy.pac");\r
184             if (File.Exists("proxy.pac"))\r
185             {\r
186                 var date = File.GetLastWriteTime("proxy.pac");\r
187                 request.IfModifiedSince = date;\r
188             }\r
189             try\r
190             {\r
191                 var response = (HttpWebResponse)request.GetResponse();\r
192                 var mem = new MemoryStream();\r
193                 using (var stream = response.GetResponseStream())\r
194                     stream?.CopyTo(mem);\r
195                 mem.Position = 0;\r
196                 using (var file = new FileStream("proxy.pac", FileMode.Create))\r
197                     mem.CopyTo(file);\r
198             }\r
199             // ReSharper disable once EmptyGeneralCatchClause\r
200             catch\r
201             {\r
202             }\r
203         }\r
204     }\r
205 }