0

Is it possible to create a multiclient pipe? With one server and multiple clients? From the official documentation I have read that " A pipe server could use a single pipe instance to connect with multiple pipe clients by connecting to and disconnecting from each client in sequence, but performance would be poor" ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa365594(v=vs.85).aspx ). Is this behaviour standard (can be done using some flags or something like that) or I have to implement this behaviour by myself? I have written a test with multiply clients, but when I trying to connect by the second client, I got error STATUS_PIPE_NOT_AVAILABLE.

There is my code, it quite big, but functions test_multiple_client and test_multiple_client2 is the same

void test_mutiple_client( PVOID arg )
{
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;
    IO_STATUS_BLOCK iosb;
    HANDLE thread = 0, event = 0, client = 0;
    NTSTATUS r;
    CLIENT_ID id;
    LARGE_INTEGER timeout;
    ULONG i;

    us.Buffer = pipename;
    us.Length = sizeof pipename - 2;
    us.MaximumLength = us.Length;

    oa.Length = sizeof oa;
    oa.RootDirectory = 0;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = 0;
    oa.SecurityQualityOfService = 0;

    r = NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, NotificationEvent, 0 );
    ok(r == STATUS_SUCCESS, "return wrong (%08lx)\n", r);


    r = NtOpenFile( &client, GENERIC_READ | GENERIC_WRITE, &oa, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0 );
    ok(r == STATUS_SUCCESS, "return wrong %08lx\n", r);
    dprintf("mc: client1 pipe created\n");

    int thread_id = __sync_add_and_fetch(&g__clientsCounter, 1);
    while (g__clientsCounter != 2);
    dprintf("thread %d stated\n", thread_id);

    r = NtReadFile( client, event, 0, 0, &iosb, &i, sizeof i, 0, 0 );
    if (r == STATUS_PENDING)
        r = NtWaitForSingleObject( event, TRUE, 0 );
    ok (r == STATUS_SUCCESS, "read %ld returned %08lx\n", i, r);
    ok (i == 13, "lol?????");

    r = NtClose( client );
    ok( r == STATUS_SUCCESS, "return wrong %08lx\n", r);

}

void test_mutiple_client2( PVOID arg )
{
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;
    IO_STATUS_BLOCK iosb;
    HANDLE thread = 0, event = 0, client = 0;
    NTSTATUS r;
    CLIENT_ID id;
    LARGE_INTEGER timeout;
    ULONG i;

    us.Buffer = pipename;
    us.Length = sizeof pipename - 2;
    us.MaximumLength = us.Length;

    oa.Length = sizeof oa;
    oa.RootDirectory = 0;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = 0;
    oa.SecurityQualityOfService = 0;

    r = NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, NotificationEvent, 0 );
    ok(r == STATUS_SUCCESS, "return wrong (%08lx)\n", r);


    r = NtOpenFile( &client, GENERIC_READ | GENERIC_WRITE, &oa, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0 );
    ok(r == STATUS_SUCCESS, "return wrong %08lx\n", r);
    dprintf("mc: client1 pipe created\n");

    int thread_id = __sync_add_and_fetch(&g__clientsCounter, 1);
    while (g__clientsCounter != 2);
    dprintf("thread %d stated\n", thread_id);

    r = NtReadFile( client, event, 0, 0, &iosb, &i, sizeof i, 0, 0 );
    if (r == STATUS_PENDING)
        r = NtWaitForSingleObject( event, TRUE, 0 );
    ok (r == STATUS_SUCCESS, "read %ld returned %08lx\n", i, r);
    ok (i == 13, "lol?????");

    r = NtClose( client );
    ok( r == STATUS_SUCCESS, "return wrong %08lx\n", r);

}

void test_multiple_connections( )
{
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING us;
    IO_STATUS_BLOCK iosb;
    HANDLE pipe = 0, thread = 0, event = 0;
    NTSTATUS r;
    CLIENT_ID id;
    LARGE_INTEGER timeout;
    ULONG i;

    us.Buffer = pipename;
    us.Length = sizeof pipename - 2;
    us.MaximumLength = us.Length;

    oa.Length = sizeof oa;
    oa.RootDirectory = 0;
    oa.ObjectName = &us;
    oa.Attributes = OBJ_CASE_INSENSITIVE;
    oa.SecurityDescriptor = 0;
    oa.SecurityQualityOfService = 0;

    timeout.QuadPart = -10000LL;
    r = NtCreateNamedPipeFile( &pipe, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,
                &oa, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF, 0, TRUE,
                TRUE, FALSE, /*Unlimited*/ -1, 0, 0, &timeout );
    ok( r == STATUS_SUCCESS, "return wrong %08lx\n", r);
    dprintf("mc: server pipe created\n");

    r = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE,
                                 NULL, 0, 0, &test_mutiple_client, NULL, &thread, &id );
    ok( r == STATUS_SUCCESS, "failed to create thread\n" );

    r = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE,
                                 NULL, 0, 0, &test_mutiple_client2, NULL, &thread, &id );
    ok( r == STATUS_SUCCESS, "failed to create thread\n" );

    r = NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, NotificationEvent, 0 );
    ok(r == STATUS_SUCCESS, "return wrong (%08lx)\n", r);


    r = NtFsControlFile( pipe, event, 0, 0, &iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0 );
    if (r == STATUS_PENDING) {
        dprintf("mc: pending\n");
        r = NtWaitForSingleObject( event, TRUE, 0 );
    }
    ok( r == STATUS_SUCCESS, "failed to listen %08lx\n", r );
    dprintf("mc: server pipe listen\n");

    i = 13;

    while (g__clientsCounter != 2);
    dprintf("server started\n");

    r = NtWriteFile( pipe, event, 0, 0, &iosb, &i, sizeof i, 0, 0 );
    if (r == STATUS_PENDING)
        r = NtWaitForSingleObject( event, TRUE, 0 );
    ok (r == STATUS_SUCCESS, "write %ld returned %08lx\n", i, r);
    dprintf("server write data\n");


    r = NtClose( pipe );
    ok( r == STATUS_SUCCESS, "return wrong %08lx\n", r);

}

The output is

mc: server pipe created
mc: pending
mc: server pipe listen
mc: client1 pipe created
478: return wrong c00000ac
mc: client1 pipe created
thread 2 stated
488: read 2013057864 returned c0000008
489: lol?????492: return wrong c0000008
server started
thread 1 stated
server write data
4 failed, 38 passed

I also have seen an answer of stack ( Number of Clients that can connect to a Named Pipe ) where mentioned that windows pipes can hold up to 256 clients

Community
  • 1
  • 1
Lobster
  • 635
  • 2
  • 12
  • 30
  • Why do you think that a pipe can be created using NtCreateFile under Windows? – Frankie_C Mar 13 '16 at 13:32
  • Why are you using the lower level NT functions instead of the higher level kernel functions? In any case, to handle multiple clients in parallel, use a separate thread for each connected client, or use overlapped I/O. – Remy Lebeau Mar 13 '16 at 15:17
  • Is this kernel-mode code? – Harry Johnston Mar 14 '16 at 02:45
  • @HarryJohnston yes, it is – Lobster Mar 15 '16 at 07:39
  • RtlCreateUserThread is undocumented (so you shouldn't be using it anyway) but according to what I can find on the internet it creates a *user mode* thread, which won't be able to run kernel-mode code. You probably want PsCreateSystemThread instead. – Harry Johnston Mar 15 '16 at 07:56

0 Answers0