[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