[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