[jcifs] Problems detecting named pipe EOF

Michael B Allen miallen at ioplex.com
Tue Jan 22 20:08:27 GMT 2008


On Tue, 22 Jan 2008 11:05:50 -0800
"Josh Cooper" <josh.nw at gmail.com> wrote:

> 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

Interesting. I will make a note of this for conisderation in a future
version of the named pipe test programs.

> 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:

That's not good.

> 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

None of this seems like a problem. Sounds like all relatively harmless
differences.

> 
> 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?

No.

Sounds like a simple bug.

With the current code, what I would expect to happen in this case is that
an SmbException should be thrown for the STATUS_PIPE_DISCONNECTED. My
instinct is to find out where that status code is getting "discarded"
and fix it so that it generates the appropriate SmbException.

Then, I would explore catching the STATUS_PIPE_DISCONNECTED SmbException
an returning -1 from read().

If you come up with a patch I would appreciate a copy. I'll add this to
the TODO list but I don't know when I'm going to get around to fixing it.

Mike

-- 
Michael B Allen
PHP Active Directory SPNEGO SSO
http://www.ioplex.com/


More information about the jcifs mailing list