[jcifs] LARGE_READX / LARGE_WRITEX support
Thomas Krammer
Thomas_Krammer at avid.com
Wed Oct 19 15:03:34 GMT 2005
Hi,
the attached patch adds LARGE_READX / LARGE_WRITEX support to jCIFS
1.2.6. It also fixes some problems I found along the way.
1) Debug output in Transport.java
The patch removes some debug output that is printed to stdout.
2) Integer overflow in SmbTransport.java
If you execute the following code:
SmbFile serverFile = ....
SmbRandomAccessFile ra = new SmbRandomAccessFile(serverFile, "rw");
int BUFFER_SIZE = Short.MAX_VALUE;
byte[] buffer = new byte[BUFFER_SIZE];
ra.read(buffer);
you will get the following exception:
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=10207,uid=2048,mid=475,wordCount=12,byteCount=0,andxCommand=0xFF,andxOffset=0,fid=16384,offset=0,maxCount=32767,minCount=32767,openTimeout=-1,remaining=0,offset=0]
at jcifs.util.transport.Transport.sendrecv(Transport.java:74)
at jcifs.smb.SmbTransport.send(SmbTransport.java:580)
at jcifs.smb.SmbSession.send(SmbSession.java:229)
at jcifs.smb.SmbTree.send(SmbTree.java:102)
at jcifs.smb.SmbFile.send(SmbFile.java:688)
at jcifs.smb.SmbRandomAccessFile.read(SmbRandomAccessFile.java:86)
at jcifs.smb.SmbRandomAccessFile.read(SmbRandomAccessFile.java:69)
The reason for this error is an integer overflow in
SmbTransport.doRecv() line 422. If the specified buffer size is greater
than Short.MAX_VALUE - SMB_HEADER_LENGTH the package size gets negative
and the package is rejected. That's because Encdec.dec_uint16be returns
a short instead of an int.
Please note that there are more similar errors in Encdec (for example
dec_uint32be returns an int instead of a long). I didn't fix those
additional errors.
3) LARGE_READX and LARGE_WRITEX support
The patch adds LARGE_READX and LARGE_WRITEX support for
SmbFileInputStream, SmbFileOutputStream and SmbRandomAccessFile. This
significantly increases the performance when transferring files from and
to Windows servers.
For example transferring a 183 MB file (using streams):
modified 1.2.6 original 1.2.6
Download 23 sec 39 sec
Upload 26 sec 40 sec
Client: Windows XP SP 2, Java 1.4.2_08
Server: Windows XP SP 2
The test used a 128k buffer to transfer the data from the InputStream to
the OutputStream.
Bye,
Thomas
-------------- next part --------------
diff -Naur ../jcifs_1.2.6_org/src/jcifs/smb/SmbConstants.java src/jcifs/smb/SmbConstants.java
--- ../jcifs_1.2.6_org/src/jcifs/smb/SmbConstants.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/smb/SmbConstants.java Tue Oct 18 12:16:06 2005
@@ -13,7 +13,7 @@
static final int DEFAULT_RESPONSE_TIMEOUT = 10000;
static final int DEFAULT_SO_TIMEOUT = 15000;
static final int DEFAULT_RCV_BUF_SIZE = 60416;
- static final int DEFAULT_SND_BUF_SIZE = 16644;
+ static final int DEFAULT_SND_BUF_SIZE = 60416;
static final int DEFAULT_SSN_LIMIT = 250;
static final InetAddress LADDR = Config.getLocalHost();
@@ -61,6 +61,8 @@
static final int CAP_LOCK_AND_READ = 0x0100;
static final int CAP_NT_FIND = 0x0200;
static final int CAP_DFS = 0x1000;
+ static final int CAP_LARGE_READX = 0x4000;
+ static final int CAP_LARGE_WRITEX = 0x8000;
// file attribute encoding
static final int ATTR_READONLY = 0x01;
@@ -117,7 +119,10 @@
( USE_NTSMBS ? CAP_NT_SMBS : 0 ) |
( USE_NTSTATUS ? CAP_STATUS32 : 0 ) |
( USE_UNICODE ? CAP_UNICODE : 0 ) |
- CAP_DFS;
+ CAP_DFS |
+ CAP_LARGE_READX |
+ CAP_LARGE_WRITEX;
+
static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 );
static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES );
static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false );
diff -Naur ../jcifs_1.2.6_org/src/jcifs/smb/SmbFileInputStream.java src/jcifs/smb/SmbFileInputStream.java
--- ../jcifs_1.2.6_org/src/jcifs/smb/SmbFileInputStream.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/smb/SmbFileInputStream.java Wed Oct 19 14:00:24 2005
@@ -32,6 +32,7 @@
private long fp;
private int readSize, openFlags;
+ private int readSizeFile;
private byte[] tmp = new byte[1];
SmbFile file;
@@ -73,6 +74,12 @@
}
readSize = Math.min( file.tree.session.transport.rcv_buf_size - 70,
file.tree.session.transport.server.maxBufferSize - 70 );
+
+ if(file.tree.session.transport.hasCapability(SmbConstants.CAP_LARGE_READX)) {
+ readSizeFile = Math.min(SmbConstants.RCV_BUF_SIZE - 70, 0xF000);
+ } else {
+ readSizeFile = readSize;
+ }
}
/**
@@ -143,7 +150,9 @@
int r, n;
do {
- r = len > readSize ? readSize : len;
+ int blockSize = (file.getType() == SmbFile.TYPE_FILESYSTEM) ? readSizeFile : readSize;
+
+ r = len > blockSize ? blockSize : len;
if( file.log.level > 2 )
file.log.println( "read: len=" + len + ",r=" + r + ",fp=" + fp );
diff -Naur ../jcifs_1.2.6_org/src/jcifs/smb/SmbFileOutputStream.java src/jcifs/smb/SmbFileOutputStream.java
--- ../jcifs_1.2.6_org/src/jcifs/smb/SmbFileOutputStream.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/smb/SmbFileOutputStream.java Wed Oct 19 13:57:14 2005
@@ -34,6 +34,7 @@
private SmbFile file;
private boolean append, useNTSmbs;
private int openFlags, writeSize;
+ private int writeSizeFile;
private long fp;
private byte[] tmp = new byte[1];
private SmbComWriteAndX reqx;
@@ -138,7 +139,14 @@
}
file.open( openFlags, SmbFile.ATTR_NORMAL, 0 );
this.openFlags &= ~(SmbFile.O_CREAT | SmbFile.O_TRUNC); /* in case close and reopen */
- writeSize = file.tree.session.transport.snd_buf_size - 70;
+ writeSize = Math.min( file.tree.session.transport.snd_buf_size - 70,
+ file.tree.session.transport.server.maxBufferSize - 70 );
+
+ if(file.tree.session.transport.hasCapability(SmbConstants.CAP_LARGE_WRITEX)) {
+ writeSizeFile = Math.min(SmbConstants.SND_BUF_SIZE - 70, 0xF000);
+ } else {
+ writeSizeFile = writeSize;
+ }
useNTSmbs = file.tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS );
if( useNTSmbs ) {
@@ -217,7 +225,9 @@
int w;
do {
- w = len > writeSize ? writeSize : len;
+ int blockSize = (file.getType() == SmbFile.TYPE_FILESYSTEM) ? writeSizeFile : writeSize;
+
+ w = len > blockSize ? blockSize : len;
if( useNTSmbs ) {
reqx.setParam( file.fid, fp, len - w, b, off, w );
file.send( reqx, rspx );
diff -Naur ../jcifs_1.2.6_org/src/jcifs/smb/SmbRandomAccessFile.java src/jcifs/smb/SmbRandomAccessFile.java
--- ../jcifs_1.2.6_org/src/jcifs/smb/SmbRandomAccessFile.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/smb/SmbRandomAccessFile.java Wed Oct 19 14:20:45 2005
@@ -54,8 +54,20 @@
throw new IllegalArgumentException( "Invalid mode" );
}
file.open( openFlags, SmbFile.ATTR_NORMAL, options );
- readSize = file.tree.session.transport.rcv_buf_size - 70;
- writeSize = file.tree.session.transport.snd_buf_size - 70;
+
+ if(file.tree.session.transport.hasCapability(SmbConstants.CAP_LARGE_READX)) {
+ readSize = Math.min(SmbConstants.RCV_BUF_SIZE - 70, 0xF000);
+ } else {
+ readSize = file.tree.session.transport.rcv_buf_size - 70;
+ }
+
+ if(file.tree.session.transport.hasCapability(SmbConstants.CAP_LARGE_WRITEX)) {
+ writeSize = Math.min(SmbConstants.SND_BUF_SIZE - 70, 0xF000);
+ } else {
+ writeSize = Math.min( file.tree.session.transport.snd_buf_size - 70,
+ file.tree.session.transport.server.maxBufferSize - 70 );
+ }
+
fp = 0L;
}
@@ -184,7 +196,7 @@
if((read( tmp, 0, 2 )) < 0 ) {
throw new SmbException( "EOF" );
}
- return Encdec.dec_uint16be( tmp, 0 );
+ return (short)Encdec.dec_uint16be( tmp, 0 );
}
public final int readUnsignedShort() throws SmbException {
if((read( tmp, 0, 2 )) < 0 ) {
diff -Naur ../jcifs_1.2.6_org/src/jcifs/util/Encdec.java src/jcifs/util/Encdec.java
--- ../jcifs_1.2.6_org/src/jcifs/util/Encdec.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/util/Encdec.java Tue Oct 18 14:45:09 2005
@@ -72,9 +72,9 @@
/* Decode integers
*/
- public static short dec_uint16be( byte[] src, int si )
+ public static int dec_uint16be( byte[] src, int si )
{
- return (short)(((src[si] & 0xFF) << 8) | (src[si + 1] & 0xFF));
+ return ((src[si] & 0xFF) << 8) | (src[si + 1] & 0xFF);
}
public static int dec_uint32be( byte[] src, int si )
{
diff -Naur ../jcifs_1.2.6_org/src/jcifs/util/transport/Transport.java src/jcifs/util/transport/Transport.java
--- ../jcifs_1.2.6_org/src/jcifs/util/transport/Transport.java Fri Oct 07 17:56:54 2005
+++ src/jcifs/util/transport/Transport.java Tue Oct 18 15:18:47 2005
@@ -147,7 +147,6 @@
public synchronized void connect( long timeout ) throws TransportException {
switch (state) {
case 0:
-System.out.println( name + ": connect: state=" + state );
break;
case 3:
return; // already connected
@@ -180,7 +179,6 @@
throw te;
}
state = 3; /* Success! */
-System.out.println( name + ": connected: state=" + state );
return;
default:
te = new TransportException( "Invalid state: " + state );
@@ -192,12 +190,10 @@
case 0: /* not connected - just return */
return;
case 3: /* connected - go ahead and disconnect */
-System.out.println( name + ": disconnecting: state=" + state + ",mapsize=" + response_map.size() + ",hard=" + hard);
if (response_map.size() != 0 && !hard) {
break; /* outstanding requests */
}
doDisconnect( hard );
-System.out.println( name + ": disconnected: state=" + state );
case 4: /* in error - reset the transport */
thread = null;
state = 0;
@@ -235,7 +231,6 @@
}
state = 2; // run connected
run_thread.notify();
-System.out.println( name + ": run connected" );
}
}
More information about the jcifs
mailing list