[jcifs] Even-byte-alignment padding in Write AndX Request

David D. Kilzer ddkilzer at kilzer.net
Fri Jul 16 20:56:45 GMT 2004


Okay, I think I have a handle on what's happening to make the named pipe
connection fail, but I'm still not convinced that jCIFS is talking to
the named pipe correctly on the other end.  (I still think it should be
a session-less connection, although I'm not sure how to get jCIFS to do
that using a named pipe.  I believe Eric's code will do the trick, but I
haven't had a chance to incorporate it yet.)

To help you out, I've send two packet traces in a separate message.  One
is for a successful connection to the database using a third party JDBC
driver, and the other is my hacked up jTDS+jCIFS code.

On to the issues below.


On Thu, Jul 15, 2004 at 11:50:08PM -0400, Michael B Allen wrote:

> On Thu, 15 Jul 2004 22:12:21 -0500, David D. Kilzer wrote:
> 
> > I've now got a full packet returning via Read AndX Response!!  But I'm
> > getting an IndexOutOfBoundsException now (such is progress):
> > 
> > java.lang.IndexOutOfBoundsException
> > 	at java.io.PushbackInputStream.read(PushbackInputStream.java:143)
> > 	at
> > 	jcifs.smb.SmbComReadAndXResponse.readBytesDirectWireFormat(SmbComRe
> > 	adAndXResponse.java:68) at
> > 	jcifs.smb.AndXServerMessageBlock.readAndXWireFormat(AndXServerMessa
> > 	geBlock.java:266) at
> > 	jcifs.smb.AndXServerMessageBlock.readWireFormat(AndXServerMessageBl
> > 	ock.java:103) at jcifs.smb.SmbTransport.run(SmbTransport.java:444)
> > 	at java.lang.Thread.run(Thread.java:536)
> > 
> > A quick debugging session showed that the code is dying in line 3 of
> > SmbComReadAndXResponse.readBytesDirectWireFormat() because 'b' is
> > declared as byte[8] when 175 bytes of data are available to be read.
> > Oops!  I don't have time to track that down just now, but I'm hoping
> > that one of the developers can provide a patch fairly easily (or else
> > I'll go play with JCIFS some more tomorrow).
> 
> That's kinda strange because b is SmbTransport.rcv_buf which is *hard
> coded* with a size of 0xFFFF:
> 
>     private static byte[] rcv_buf = new byte[0xFFFF];

What is happening here is that the jTDS client code is treating the
input stream it gets (in this case from jCIFS) just like it would treat
an input stream from a java.net.Socket object.  The jTDS client code
expects that the underlying implementation will take care of reading
ALL of the data from any packets returned, even if it only asks for 1
byte initially.  So here is what jTDS does:

  - Read 1 byte from input stream using a byte[8] buffer (which
    represents the TDS packet header).
  - If 1 byte was read,
    then read in 7 more bytes into the same byte[8] buffer (offset 1),
    else throw an exception.
  - If the packet type is not recognized, throw an exception.
  - Calculate the length of the TDS packet's payload from the byte[8]
    buffer.
  - Read in the TDS packet payload using a much larger buffer
    (byte[512]).

The problem is that jCIFS assumes that it should look send a Read AndX
Request every time a new request is made to the input stream, so it only
gets 1 byte back from SQL Server 6.5 on the first request(*), and then
fails on the second request because it's broken protocol with SQL Server
6.5.

(*) I hacked jCIFS to always request 512 bytes, which is why you see the
full response in the unsuccessful packet trace.

> > BTW, the last change I made (which triggered the above exception) was to
> > hard-code maxCount and minCount to 512 in the constructor and setParam()
> > methods of SmbComReadAndX:
> > 
> >   this.maxCount = minCount = 512;
> > 
> > Turns out that SQL Server 6.5 will only send back the number of bytes
> > requested by one (or both) of those fields, so when I was getting the
> > other error message earlier, I was only getting 1 byte back instead of
> > the whole TDS packet!
> 
> I don't follow.
> 
>   1) What does your jCIFS code look like to access the IPC resource? 
>   2) Send captures.

Here is the jCIFS code I'm using:

  pipe = new SmbNamedPipe(url.toString(), SmbNamedPipe.PIPE_TYPE_RDWR, auth);
  out = new DataOutputStream(pipe.getNamedPipeOutputStream());
  in = new DataInputStream(pipe.getNamedPipeInputStream());

The 'url' variable is a StringBuffer that will look something like:

  smb://servername/IPC$/sql/query

Or if a SQL Server instance is used:

  smb://servername/IPC$/MSSQL$instancename/sql/query

Captures coming next.

> It sounds like the pipe needs to be in a certain message mode that isn't
> quite set right. There are many options for pipes. If they're not right it
> might half work like you're seeing. I assume you have seen our named pipe
> docs?
> 
>   http://jcifs.samba.org/src/docs/pipes.html

I went back to reread the documentation, although I must admit that I'm
still not sure when to use a CallNamedPipe and when to use a
TransactNamedPipe.  I know I'm using a CallNamedPipe above, although I
initially tried to use a TransactNamedPipe when I first started.

Dave


More information about the jcifs mailing list