Skip to content

Commit f3bdfa6

Browse files
committed
Split into multiple files
No functional changes. GitHub: #19 Signed-off-by: Lev Stipakov <[email protected]>
1 parent be5549e commit f3bdfa6

File tree

5 files changed

+286
-237
lines changed

5 files changed

+286
-237
lines changed

OpenVPNChild.cs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace OpenVpn
11+
{
12+
class OpenVpnChild
13+
{
14+
StreamWriter logFile;
15+
Process process;
16+
ProcessStartInfo startInfo;
17+
System.Timers.Timer restartTimer;
18+
OpenVpnServiceConfiguration config;
19+
string configFile;
20+
string exitEvent;
21+
22+
public OpenVpnChild(OpenVpnServiceConfiguration config, string configFile)
23+
{
24+
this.config = config;
25+
/// SET UP LOG FILES
26+
/* Because we will be using the filenames in our closures,
27+
* so make sure we are working on a copy */
28+
this.configFile = String.Copy(configFile);
29+
this.exitEvent = Path.GetFileName(configFile) + "_" + Process.GetCurrentProcess().Id.ToString();
30+
var justFilename = System.IO.Path.GetFileName(configFile);
31+
var logFilename = config.logDir + "\\" +
32+
justFilename.Substring(0, justFilename.Length - config.configExt.Length) + ".log";
33+
34+
// FIXME: if (!init_security_attributes_allow_all (&sa))
35+
//{
36+
// MSG (M_SYSERR, "InitializeSecurityDescriptor start_" PACKAGE " failed");
37+
// goto finish;
38+
//}
39+
40+
logFile = new StreamWriter(File.Open(logFilename,
41+
config.logAppend ? FileMode.Append : FileMode.Create,
42+
FileAccess.Write,
43+
FileShare.Read), new UTF8Encoding(false));
44+
logFile.AutoFlush = true;
45+
46+
/// SET UP PROCESS START INFO
47+
string[] procArgs = {
48+
"--config",
49+
"\"" + configFile + "\"",
50+
"--service ",
51+
"\"" + exitEvent + "\"" + " 0"
52+
};
53+
this.startInfo = new System.Diagnostics.ProcessStartInfo()
54+
{
55+
RedirectStandardInput = true,
56+
RedirectStandardOutput = true,
57+
RedirectStandardError = true,
58+
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
59+
60+
FileName = config.exePath,
61+
Arguments = String.Join(" ", procArgs),
62+
WorkingDirectory = config.configDir,
63+
64+
UseShellExecute = false,
65+
/* create_new_console is not exposed -- but we probably don't need it?*/
66+
};
67+
}
68+
69+
// set exit event so that openvpn will terminate
70+
public void SignalProcess()
71+
{
72+
if (restartTimer != null)
73+
{
74+
restartTimer.Stop();
75+
}
76+
try
77+
{
78+
if (!process.HasExited)
79+
{
80+
81+
try
82+
{
83+
var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset, exitEvent);
84+
85+
process.Exited -= Watchdog; // Don't restart the process after exit
86+
87+
waitHandle.Set();
88+
waitHandle.Close();
89+
}
90+
catch (IOException e)
91+
{
92+
config.eventLog.WriteEntry("IOException creating exit event named '" + exitEvent + "' " + e.Message + e.StackTrace);
93+
}
94+
catch (UnauthorizedAccessException e)
95+
{
96+
config.eventLog.WriteEntry("UnauthorizedAccessException creating exit event named '" + exitEvent + "' " + e.Message + e.StackTrace);
97+
}
98+
catch (WaitHandleCannotBeOpenedException e)
99+
{
100+
config.eventLog.WriteEntry("WaitHandleCannotBeOpenedException creating exit event named '" + exitEvent + "' " + e.Message + e.StackTrace);
101+
}
102+
catch (ArgumentException e)
103+
{
104+
config.eventLog.WriteEntry("ArgumentException creating exit event named '" + exitEvent + "' " + e.Message + e.StackTrace);
105+
}
106+
}
107+
}
108+
catch (InvalidOperationException) { }
109+
}
110+
111+
// terminate process after a timeout
112+
public void StopProcess(int timeout)
113+
{
114+
if (restartTimer != null)
115+
{
116+
restartTimer.Stop();
117+
}
118+
try
119+
{
120+
if (!process.WaitForExit(timeout))
121+
{
122+
process.Exited -= Watchdog; // Don't restart the process after kill
123+
process.Kill();
124+
}
125+
}
126+
catch (InvalidOperationException) { }
127+
}
128+
129+
public void Wait()
130+
{
131+
process.WaitForExit();
132+
logFile.Close();
133+
}
134+
135+
public void Restart()
136+
{
137+
if (restartTimer != null)
138+
{
139+
restartTimer.Stop();
140+
}
141+
/* try-catch... because there could be a concurrency issue (write-after-read) here? */
142+
if (!process.HasExited)
143+
{
144+
process.Exited -= Watchdog;
145+
process.Exited += FastRestart; // Restart the process after kill
146+
try
147+
{
148+
process.Kill();
149+
}
150+
catch (InvalidOperationException)
151+
{
152+
Start();
153+
}
154+
}
155+
else
156+
{
157+
Start();
158+
}
159+
}
160+
161+
private void WriteToLog(object sendingProcess, DataReceivedEventArgs e)
162+
{
163+
if (e != null)
164+
logFile.WriteLine(e.Data);
165+
}
166+
167+
/// Restart after 10 seconds
168+
/// For use with unexpected terminations
169+
private void Watchdog(object sender, EventArgs e)
170+
{
171+
config.eventLog.WriteEntry("Process for " + configFile + " exited. Restarting in 10 sec.");
172+
173+
restartTimer = new System.Timers.Timer(10000);
174+
restartTimer.AutoReset = false;
175+
restartTimer.Elapsed += (object source, System.Timers.ElapsedEventArgs ev) =>
176+
{
177+
Start();
178+
};
179+
restartTimer.Start();
180+
}
181+
182+
/// Restart after 3 seconds
183+
/// For use with Restart() (e.g. after a resume)
184+
private void FastRestart(object sender, EventArgs e)
185+
{
186+
config.eventLog.WriteEntry("Process for " + configFile + " restarting in 3 sec");
187+
restartTimer = new System.Timers.Timer(3000);
188+
restartTimer.AutoReset = false;
189+
restartTimer.Elapsed += (object source, System.Timers.ElapsedEventArgs ev) =>
190+
{
191+
Start();
192+
};
193+
restartTimer.Start();
194+
}
195+
196+
public void Start()
197+
{
198+
process = new System.Diagnostics.Process();
199+
200+
process.StartInfo = startInfo;
201+
process.EnableRaisingEvents = true;
202+
203+
process.OutputDataReceived += WriteToLog;
204+
process.ErrorDataReceived += WriteToLog;
205+
process.Exited += Watchdog;
206+
207+
process.Start();
208+
process.BeginErrorReadLine();
209+
process.BeginOutputReadLine();
210+
process.PriorityClass = config.priorityClass;
211+
}
212+
}
213+
}

OpenVPNServiceConfiguration.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Diagnostics;
2+
3+
namespace OpenVpn
4+
{
5+
class OpenVpnServiceConfiguration
6+
{
7+
public string exePath { get; set; }
8+
public string configExt { get; set; }
9+
public string configDir { get; set; }
10+
public string logDir { get; set; }
11+
public bool logAppend { get; set; }
12+
public System.Diagnostics.ProcessPriorityClass priorityClass { get; set; }
13+
14+
public EventLog eventLog { get; set; }
15+
}
16+
}

OpenVpnService.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<BootstrapperEnabled>true</BootstrapperEnabled>
3333
</PropertyGroup>
3434
<PropertyGroup>
35-
<StartupObject>OpenVpn.OpenVpnService</StartupObject>
35+
<StartupObject>OpenVpn.Program</StartupObject>
3636
</PropertyGroup>
3737
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
3838
<PlatformTarget>x86</PlatformTarget>
@@ -93,6 +93,9 @@
9393
<WarningLevel>4</WarningLevel>
9494
</PropertyGroup>
9595
<ItemGroup>
96+
<Compile Include="OpenVPNChild.cs" />
97+
<Compile Include="OpenVPNServiceConfiguration.cs" />
98+
<Compile Include="Program.cs" />
9699
<Compile Include="ProjectInstaller.cs">
97100
<SubType>Component</SubType>
98101
</Compile>

Program.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.ServiceProcess;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace OpenVpn
9+
{
10+
internal class Program
11+
{
12+
public static int Main(string[] args)
13+
{
14+
if (args.Length == 0)
15+
{
16+
ServiceBase.Run(new OpenVpnService());
17+
}
18+
else if (args[0] == "-install")
19+
{
20+
try
21+
{
22+
ProjectInstaller.Install();
23+
}
24+
catch (Exception e)
25+
{
26+
Console.Error.WriteLine(e.Message);
27+
Console.Error.WriteLine(e.StackTrace);
28+
return 1;
29+
}
30+
}
31+
else if (args[0] == "-remove")
32+
{
33+
try
34+
{
35+
ProjectInstaller.Stop();
36+
ProjectInstaller.Uninstall();
37+
}
38+
catch (Exception e)
39+
{
40+
Console.Error.WriteLine(e.Message);
41+
Console.Error.WriteLine(e.StackTrace);
42+
return 1;
43+
}
44+
}
45+
else
46+
{
47+
Console.Error.WriteLine("Unknown command: " + args[0]);
48+
return 1;
49+
}
50+
return 0;
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)