[jcifs] Problems detecting named pipe EOF

Josh Cooper josh.nw at gmail.com
Tue Jan 22 19:05:50 GMT 2008


I am having some difficulties getting JCIFS to detect EOF when reading
from an SmbNamedPipe InputStream.

First, I changed createnp.c as follows:

while(ReadFile(inFile, buf, bufferSize, &bytesRead, NULL) > 0 &&
bytesRead> 0) // CHANGE
{
    WriteFile(outFile, buf, bytesRead, &bytesRead, NULL);
}

printf("Success: operation performed successfully\r\n");

if ( inFile != h ) // CHANGE
    CloseHandle(inFile);
if ( outFile != h ) // CHANGE
    CloseHandle(outFile);

FlushFileBuffers(h); // CHANGE
DisconnectNamedPipe(h);
CloseHandle(h);

1. In the ReadFile/WriteFile loop, we have to check the number of
bytes read. Otherwise, we get into an infinitely loop when reading
from a file and we're at EOF.
2. Only close the inFile/outFile handles if they're different from the
pipe, otherwise, we never gracefully disconnect the client and the
client gets STATUS_PIPE_BROKEN
3. Call FlushFileBuffers on the pipe handle, so that the client can
read the data before the server exits.

Next, I launch createnp as the named pipe server (byte mode). It reads
from the file in.txt and writes the output to the pipe:

  createnp \\.\pipe\foo /I in.txt /M 0x2 /P 0x0

Everything works fine when using createf.exe as the named pipe client:

  createf \\<server>\IPC$\foo  /O out.txt

The client connects to the server, the server reads the contents of
in.txt and writes it to the pipe, which the client reads and writes to
out.txt. Using Ethereal, I see that the client receives a
STATUS_PIPE_DISCONNECTED in the last ReadAndXResponse. This causes the
client to break out of its ReadFile/WriteFile loop as expected, and
send SmbComClose, etc

Next, I wrote a simple JCIFS client:

public class PipeTest
{
    public static void main( String[] argv ) throws Exception
    {
        LogStream.setLevel( 6 );

        SmbNamedPipe pipe = new
SmbNamedPipe("smb://<domain>;<user>:<password>@<server>/IPC$/foo",
SmbNamedPipe.PIPE_TYPE_RDONLY);
        InputStream in = pipe.getNamedPipeInputStream();
        try
        {
            int n;
            byte[] buf = new byte[64 * 1024];

            while ((n = in.read(buf, 0, buf.length)) > 0)
            {
                Hexdump.hexdump( System.out, buf, 0, n );
            }
        }
        finally
        {
            in.close();
        }
    }
}

It successfully connects to the named pipe server and reads the data.

00000: 68 65 6C 6C 6F 20 0D 0A                          |hello ..        |

It then sends another read request:

read: fid=16384,off=0,len=65536
read: len=65536,r=4286,fp=8
SmbComReadAndX[command=SMB_COM_READ_ANDX,received=false,errorCode=0,flags=0x0018,flags2=0xC003,signSeq=0,tid=2048,pid=26359,uid=2048,mid=5,wordCount=12,byteCount=0,andxCommand=0xFF,andxOffset=0,fid=16384,offset=8,maxCount=1024,minCount=1024,openTimeout=-1,remaining=1024,offset=8]
00000: FF 53 4D 42 2E 00 00 00 00 18 03 C0 00 00 00 00  |ÿSMB.......À....|
00010: 00 00 00 00 00 00 00 00 00 08 F7 66 00 08 05 00  |..........÷f....|
00020: 0C FF 00 DE DE 00 40 08 00 00 00 00 04 00 04 FF  |.ÿ.ÞÞ. at ........ÿ|
00030: FF FF FF 00 04 00 00 00 00 00 00                 |ÿÿÿ........     |

And receives the following response, which contains
STATUS_PIPE_DISCONNECTED (0xc00000b0).

New data read: Transport1[XXX<20>/10.0.10.98:445]
00000: FF 53 4D 42 2E B0 00 00 C0 98 03 C0 00 00 00 00  |ÿSMB.°..À..À....|
00010: 00 00 00 00 00 00 00 00 00 08 F7 66 00 08 05 00  |..........÷f....|

But the Transport thread seems to discard the response. And the
calling thread eventually times-out:

jcifs.util.transport.TransportException: Transport1 timedout waiting
for response to
SmbComReadAndX[command=SMB_COM_READ_ANDX,received=false,errorCode=0,flags=0x0018,flags2=0xC003,signSeq=0,tid=2048,pid=26359,uid=2048,mid=5,wordCount=12,byteCount=0,andxCommand=0xFF,andxOffset=0,fid=16384,offset=8,maxCount=1024,minCount=1024,openTimeout=-1,remaining=1024,offset=8]
 at jcifs.util.transport.Transport.sendrecv(Transport.java:76)
 at jcifs.smb.SmbTransport.send(SmbTransport.java:606)
 at jcifs.smb.SmbSession.send(SmbSession.java:239)
 at jcifs.smb.SmbTree.send(SmbTree.java:109)
 at jcifs.smb.SmbFile.send(SmbFile.java:695)
 at jcifs.smb.SmbFileInputStream.readDirect(SmbFileInputStream.java:160)
 at jcifs.smb.SmbFileInputStream.read(SmbFileInputStream.java:121)
 at PipeTest.main(PipeTest.java:26)

I did a comparison of Ethereal captures, and noted the following
differences in the final ReadAndXRequest:

1. flags2: 0xc807 (createf) vs 0xc003 (jcifs): since createf is using
native Win32 APIs it makes sense that it supports extended security
negotiation and security signatures
2. processId: are different as expected
3. offset: surprisingly createf sends an offset of 0, whereas jcifs
sends an offset of 8 (the length of data "hello \r\n" we've read thus
far)
4. maxCount, minCount: 4292 (createf), 1024 (jcifs)
5. remaining: 64K (createf), 1024 (jcifs)

In the final ReadAndXResponse I see the following differences:

1. flags2: same as above
2. processId: same as above

I have been able to work around the problem by using a message-type
named pipe server and having it write a 0 byte "message" prior to
flushing the pipe and disconnecting the client. The JCIFS client
handles this as an SmbComBlankResponse, and in.read returns -1 as
expected.

I can send you the ethereal traces separately if needed.

Am I doing something wrong?

Thanks in advance,
Josh


More information about the jcifs mailing list