Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Process.Start without creating a child process (port handle inheritance)?

I have a WCF service in a self hosted application using TCP bindings. If I start an external process "commandLineApp" from the application, that continues even after my application has closed, I run into problems next time the WCF service is started by my application.

WCF says that the address/port is already in use. If I close the external application (that isn't using WCF or any sockets at all) before restarting my application, the WCF service starts just fine.

It looks like that the socket handles from my application is somehow inherited by the new process "commandLineApp", and not released until that process has exited.

How do I prevent the other process from inheriting the handles (or becoming a child process?) from my main application? Currently I'm using Process.Start to launch the other process, using UseShellExecute set to False because I need to set both EnvironmentVarables and RedirectStandardOutput/Error.

I think the child process setup is prevented if I set UseShellExecute = true, but then I don't get all features I need.

Are there any way around this problem? See example code below.

ProcessStartInfo psi = new ProcessStartInfo();    
psi.FileName = "commandLineApp.exe";
psi.Arguments = "/someParameter";
psi.EnvironmentVariables.Add("...", "...");
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;

Process process = new Process();
process.StartInfo = psi;
process.Start();
// Monitor if process with PID = process.Id is running
// ...

Edit - Additional information: Doing "netstat -noa" indicates that the port is used with state LISTEN by the previous PID of the main application, but there is no process with that PID anymore. As soon as I close "commandLineApp", the port isn't listed by the netstat command anymore.

WCF services are closed like this before the main application exit:

try
{
    serviceHost.Close(TimeSpan.FromSeconds(4));
}
catch (Exception)
{
    serviceHost.Abort();
}
like image 716
tpe Avatar asked Jul 10 '14 12:07

tpe


1 Answers

I was wrong in the above comment: SO_REUSEADDR would only apply if the handle had been closed, but it seems like socket handles truly are inherited by child processes and there is no easy way to prevent this. This seems like a very stupid design decision, particularly since some places noted that the handle can't be used in the child if any LSPs are installed.

If you had more control over the call to WSASocket, you might be able to pass the WSA_FLAG_NO_HANDLE_INHERIT flag, but this is going to be hard to accomplish inside WCF. Here's a couple other options:

Option #1: Call CreateProcess yourself and pass FALSE for bInheritHandles.

Option #2: Create a helper process before you set up WCF (or any other sockets). Communicate with it via named pipes. Start the child process from this helper instead of from the main process.

like image 121
Dark Falcon Avatar answered Sep 28 '22 02:09

Dark Falcon