HavenDV / H.Pipes

A simple, easy to use, strongly-typed, async wrapper around .NET named pipes.
MIT License
219 stars 26 forks source link

some windows 10 and windows 11 clients can't connect to the PipeServer if hosted in a service #14

Closed PeterPann23 closed 2 years ago

PeterPann23 commented 2 years ago

I have a service that would need to accept client data that runs without elevated permissions I use this code

_server = new PipeServer<T>(pipeName, new NewtonsoftJsonFormatter());
_server.AllowUsersReadWrite();

My developer machine can connect just fine, some other machines however can't. If I take the NuGet package where I wrapped the PipeServer and PipeClient in and create a chat app using Winforms that same machine accepts the client without any issues, both are .net 6.0

If I take the Production client and have it connect to the Winforms test service all seems to work well.

The only difference is that one is hosted in service, the other is in a normal WinForms, with no changes made to the machines that are being problematic.

What am I doing wrong, how can I solve the issue?

HavenDV commented 2 years ago

Hello. I want to note that the code in the service runs with administrator rights. However, if you run pipeServer in a normal application, it also needs administrator rights to work correctly

HavenDV commented 2 years ago

You may also need to set up more advanced permissions.

AllowUsersReadWrite makes this easy for the easy case

public static void AllowUsersReadWrite<T>(this IPipeServer<T> server)
{
    server = server ?? throw new ArgumentNullException(nameof(server));

    server.AddAccessRules(
        new PipeAccessRule(
            new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
            PipeAccessRights.ReadWrite,
            AccessControlType.Allow));
}
PeterPann23 commented 2 years ago

I have the service running as administrator, however, it doesn't accept a connection, is there a way to "trace" the accept/ deny access as I have no luck in the windows event logs and not on any of the events.

Remember, the same class that hosts the service is used in a winforms app and runs without any issues, same users same pc.

HavenDV commented 2 years ago
image

I'm not experienced with tracking down problematic connections. Here, the system class has a rather meager API. I only use WaitForConnectionAsync to wait for new clients.

HavenDV commented 2 years ago

Another idea: perhaps you have some kind of resource cleanup problem (because Dispose is required after pipes is finished), and when creating a new server inside the service, an exception is thrown that the name is already taken? Try to subscribe to all events that the server issues and log them

PeterPann23 commented 2 years ago

I wrote a small test-rig allowing you to get some code to reproduce ... the issue is that the test works on the client machines... there must be a difference not sure where... the sample code I generated

Not sure if my code is "standard"

BackgroundWorker2022030712.txt ClientLog20220307.txt NamedPipeSandbox Code.zip

PeterPann23 commented 2 years ago

looks like, depending on the frameworks installed on the target machines the code fails.
Looking at NamedPipeServerStream I see a lot of code that is obsolete and no longer executes as it's simply ignored, the conditional compilers force Net 6.0 to execute in a not 2.1 as .net is not net6.0 going to a lower framework, perhaps consider 6.0 and 7.0 support

#if NETSTANDARD2_1 

#else 

#endif

Also, some code that only executes on windows is interweaved with platform generic code making it windows only.

HavenDV commented 2 years ago

I met some issues with .Net 6 and .Net Standard. I can try adding an explicit .Net 6 TargetFramework and see if that gives the desired result.

HavenDV commented 2 years ago
image

While adding, I noticed that this API is only available on Windows

PeterPann23 commented 2 years ago

Perhaps also have a look at public async Task StartAsync(CancellationToken cancellationToken = default) in PipeServer.cs it is not communicating the exceptions to the hosting application

HavenDV commented 2 years ago

Perhaps also have a look at public async Task StartAsync(CancellationToken cancellationToken = default) in PipeServer.cs it is not communicating the exceptions to the hosting application

It transmits, but only through an ExceptionOccurred event, because it starts a Worker inside to process incoming signals.

PeterPann23 commented 2 years ago

I met some issues with .Net 6 and .Net Standard. I can try adding an explicit .Net 6 TargetFramework and see if that gives the desired result.

Perhaps NET6_0_OR_GREATER

HavenDV commented 2 years ago

Perhaps also have a look at public async Task StartAsync(CancellationToken cancellationToken = default) in PipeServer.cs it is not communicating the exceptions to the hosting application

It will also explicitly throw an exception if it fails to create a server

PeterPann23 commented 2 years ago

Perhaps also have a look at public async Task StartAsync(CancellationToken cancellationToken = default) in PipeServer.cs it is not communicating the exceptions to the hosting application

It transmits, but only through an ExceptionOccurred event, because it starts a Worker inside to process incoming signals. Perhaps consider the order ...


catch (Exception exception)
{
if (WaitFreePipe)
{
throw;
}
     source.TrySetException(exception);
     break;

}

HavenDV commented 2 years ago

source.TrySetException(exception);

These exceptions will be received here: https://github.com/HavenDV/H.Pipes/blob/f5372ffacece7db168bbd420f404a30b016d7db9/src/libs/H.Pipes/PipeServer.cs#L242-L251

HavenDV commented 2 years ago

Perhaps NET6_0_OR_GREATER

https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/cross-platform-targeting I studied this article again, it still doesn't make sense to add explicit .Net 5/6 targets here, because we don't use specific APIs in them (they implement .Net Standard 2.1). The only plus from their explicit presence is new warnings and nullable markup in dependent libraries

HavenDV commented 2 years ago

However, I've added explicit .Net 5/.Net 6 frameworks (for the ability to call the OperatingSystem.IsWindows() method) to test for the ability to call WaitForPipeDrain. Please check your problem when the new version becomes available on NuGet (in about 10 minutes)