Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connecting via named pipe from windows service (session#0) to desktop app (session #1)

Given:
- the application - desktop GUI (WPF) .NET app
- windows service watching for application (.NET also)

The windows service periodically "pings" application to get sure it's healthy (and if it's not winservice will restart it).
I was going to implement "pinging" via named pipes. To make things simpler I decided to do it with WCF. The application hosts a WCF-service (one operation Ping returning something). The windows service is a client for this WCF-service, invokes it periodically based on a timer.

That's all in Windows 7.
Windows service is running under LocalService (in session#0).
Desktop application is running under currently logged in user (in session#1).

The problem:
Windows service can't see WCF endpoint (with NetNamedPipeBinding) created in and being listened in desktop application. That means that on call via wcf proxy I get this exception: "The pipe endpoint 'net.pipe://localhost/HeartBeat' could not be found on your local machine"

I'm sure code is ok, because another desktop application (in session#1) can see the endpoint.

Obviously here I'm dealing with some security stuff for Win32 system object isolation. But I believe there should be a way to workaround restrictions I've encountered with.
I can sacrifice WCF approach and go the raw NamedPipe way.

like image 749
Shrike Avatar asked Nov 29 '10 11:11

Shrike


People also ask

What is a named pipe connection?

A named pipe is a named, one-way or duplex pipe for communication between the pipe server and one or more pipe clients. All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles, and provides a separate conduit for client/server communication.

What are named pipes in SMB?

A named pipe is a logical connection, similar to a TCP session, between a client and server that are involved in a Common Internet File System (CIFS)/SMB/SMB Version 2 and Version 3 connection.

What is the difference between named pipes and TCP IP?

Local named pipes runs in kernel mode and is extremely fast. For TCP/IP Sockets, data transmissions are more streamlined and have less overhead.

How do you open a named pipe?

A name-pipe can be opened with either open() or fopen() by a single process.


2 Answers

An easier solution might be to use a WCF duplex contract with the Windows service hosting the WCF service. The client App would call an operation on the service to register itself, when it starts up. The Ping would then be an operation invoked periodically by the service on the client's callback contract, to which the App would respond.

Service visibility works this way round, because the Windows service can run with SeCreateGlobalPrivilege, and so the shared memory object via which the pipe name is published by the service can be created in the Global kernel namespace, visible to other sessions. Interactive applications can't easily get that privilege in Windows7, so WCF services in such applications fall back to publishing the pipe in the Local kernel namespace, visible only within their own session.

like image 184
Chris Dickson Avatar answered Sep 22 '22 06:09

Chris Dickson


Finally I've found a solution - using Named Pipes from System.IO.Pipes directly. It's seems that WCF's pipes support implementation doesn't use System.IO.Pipes.

Server:

using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1))
{
    try
    {
        while (true)
        {
            // #1 Connect:
            try
            {
                pipeServer.WaitForConnection();
            }
            catch (ObjectDisposedException)
            {
                yield break;
            }
            if (ae.IsCanceled())
                return;

            // #2: Sending response:
            var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
            try
            {
                pipeServer.Write(response, 0, response.Length);
            }
            catch (ObjectDisposedException)
            {
                return;
            }

            // #3: Disconnect:
            pipeServer.Disconnect();
        }
    }
    finally
    {
        if (pipeServer.IsConnected)
            pipeServer.Disconnect();
    }
}

Client:

using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In))
{
    try
    {
        try
        {
            pipeClient.Connect(TIMEOUT);
        }
        catch(TimeoutException ex)
        {
            // nobody answers to us
            continue;
        }
        using (var sr = new StreamReader(pipeClient))
        {
            string temp;
            while ((temp = sr.ReadLine()) != null)
            {
                // got response
            }
        }
    }
    catch(Exception ex)
    {
        // pipe error
        throw;
    }
}
like image 23
Shrike Avatar answered Sep 21 '22 06:09

Shrike