[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