[CONJ-147] JDBC Unix local socket handling code bug Created: 2015-03-27  Updated: 2015-09-17  Resolved: 2015-09-17

Status: Closed
Project: MariaDB Connector/J
Component/s: Other
Affects Version/s: 1.1.6, 1.1.7, 1.1.8, 1.1.9, 1.2.0
Fix Version/s: 1.3.0

Type: Bug Priority: Critical
Reporter: Geoffrey Rutherford Assignee: Diego Dupin
Resolution: Fixed Votes: 0
Labels: None
Environment:

Unix/Linux


Sprint: Sprint connector/j 1.3.0

 Description   

UnixDomainSocket.UnixSocketInputStream ignores the offset argument when reading and writing data resulting in data corruption when the offset is greater than zero.



 Comments   
Comment by Geoffrey Rutherford [ 2015-03-27 ]

Just changed it for me and suggest the following code:

{{

    class UnixSocketInputStream extends InputStream
    {
        @Override
        public int read (byte[] b,
                         int    off,
                         int    len) throws IOException
        {
            int     bytes   = 0;
 
            try
            {
                if (off > 0)
                {
                    int     size    = (len < 10240) ? len : 10240;
                    byte[]  data    = new byte[size];
 
                    do
                    {
                        size = (len < 10240) ? len : 10240;
                        size = recv (fd, data, size, 0);
 
                        if (size > 0)
                        {
                            System.arraycopy (data, 0, b, off, size);
 
                            bytes += size;
                            off   += size;
                            len   -= size;
                        }
                        
                    } while ((len > 0) && (size > 0));
                }
                else
                {
                    bytes = recv (fd, b, len, 0);
                }
            }
            
            catch (LastErrorException lee)
            {
               throw new IOException ("native read() failed : " + formatError( lee));
            }
            
            return (bytes);
        }
        
        @Override
        public int read () throws IOException
        {
            byte[]  b       = new byte[1];
            int     bytes   = read (b);
 
            return ((bytes == 0) ? -1 : (b[0] & 0xff));
        }
        
        @Override
        public int read (byte[] b) throws IOException
        {
            return read (b, 0, b.length);
        }
    }
 
   class UnixSocketOutputStream extends OutputStream
    {
        @Override
        public void write (byte[]    b,
                           int       off,
                           int       len) throws IOException
        {
            int     bytes   = 0;
            
            try
            {
                if (off > 0)
                {
                    int     size    = (len < 10240) ? len : 10240;
                    byte[]  data    = new byte[size];
 
                    do
                    {
                        size = (len < 10240) ? len : 10240;
 
                        System.arraycopy (b, off,
                                          data, 0, size);
                        
                        bytes = send (fd, data, size, 0);
 
                        if (bytes > 0)
                        {
                            off += bytes;
                            len -= bytes;
                            
                        }
                        
                    } while ((len > 0) && (bytes > 0));
                }
                else
                {
                    bytes = send (fd, b, len ,0);
                }
                
                if (bytes != len)
                {
                    throw new IOException ("can't write " + len + "bytes");
                }
            }
            
            catch (LastErrorException lee)
            {
                throw new IOException ("native write() failed : " + formatError (lee));
            }
        }
        
        @Override
        public void write (int b) throws IOException
        {
              write (new byte[]{(byte) b});
        }
        
        @Override
        public void write (byte[] b) throws IOException
        {
              write (b, 0, b.length);
        }
    }
 

}}

Comment by Geoffrey Rutherford [ 2015-03-27 ]

And for the full job just replace your code with the following:

package org.mariadb.jdbc.internal.mysql;
 
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Structure;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.List;
 
public class UnixDomainSocket extends Socket
{
    static public final int AF_UNIX     = 1;
    static public final int SOCK_STREAM = Platform.isSolaris () ? 2 : 1;
    static public final int PROTOCOL    = 0;
 
    static public class SockAddr extends Structure
    {
        public short  sun_family    = 0;
        public byte[] sun_path      = null;
 
        public SockAddr (String sunPath)
        {
            byte[]  arr     = sunPath.getBytes ();
            int     size    = arr.length;
            
            sun_family     = AF_UNIX;
            sun_path       = new byte[size +1];
            sun_path[size] = (byte) 0;
            
            System.arraycopy (arr, 0, sun_path, 0, size);
            allocateMemory   ();
        }
 
        @Override
        protected List getFieldOrder ()
        {
            return Arrays.asList (new String[] {"sun_family", "sun_path"});
        }
    }
 
    static public native int socket  (int domain, int type, int protocol) throws LastErrorException;
    static public native int connect (int sockfd, SockAddr sockaddr, int addrlen) throws LastErrorException;
    static public native int recv    (int fd, byte[] buffer, int count, int flags) throws LastErrorException;
    static public native int send    (int fd, byte[] buffer, int count, int flags) throws LastErrorException;
    static public native int close   (int fd) throws LastErrorException;
    
    static public native String strerror (int errno);
 
    static
    {
        if (Platform.isSolaris ())
        {
            System.loadLibrary ("nsl");
            System.loadLibrary ("socket");
        }
        
        if (!Platform.isWindows () && !Platform.isWindowsCE ())
        {
            Native.register ("c");
        }
    }
    
    protected String        path        = null;
    protected InputStream   is          = null;
    protected OutputStream  os          = null;
    protected SockAddr      sockaddr    = null;
    protected int           fd          = -1;
 
    protected class UnixSocketInputStream extends InputStream
    {
        @Override
        public int read (byte[] b,
                         int    off,
                         int    len) throws IOException
        {
            int     bytes   = 0;
 
            try
            {
                if (off > 0)
                {
                    int     size    = (len < 10240) ? len : 10240;
                    byte[]  data    = new byte[size];
 
                    do
                    {
                        size = (len < 10240) ? len : 10240;
                        size = recv (fd, data, size, 0);
 
                        if (size > 0)
                        {
                            System.arraycopy (data, 0, b, off, size);
 
                            bytes += size;
                            off   += size;
                            len   -= size;
                        }
                        
                    } while ((len > 0) && (size > 0));
                }
                else
                {
                    bytes = recv (fd, b, len, 0);
                }
            }
            
            catch (LastErrorException lee)
            {
               throw new IOException ("native read() failed : " + formatError( lee));
            }
            
            return (bytes);
        }
        
        @Override
        public int read () throws IOException
        {
            byte[]  b       = new byte[1];
            int     bytes   = read (b);
 
            return ((bytes == 1) ? b[0] : -1);
        }
        
        @Override
        public int read (byte[] b) throws IOException
        {
            return read (b, 0, b.length);
        }
    }
 
    class UnixSocketOutputStream extends OutputStream
    {
        @Override
        public void write (byte[]    b,
                           int       off,
                           int       len) throws IOException
        {
            int     bytes   = 0;
            
            try
            {
                if (off > 0)
                {
                    int     size    = (len < 10240) ? len : 10240;
                    byte[]  data    = new byte[size];
 
                    do
                    {
                        size = (len < 10240) ? len : 10240;
 
                        System.arraycopy (b, off,
                                          data, 0, size);
                        
                        bytes = send (fd, data, size, 0);
 
                        if (bytes > 0)
                        {
                            off += bytes;
                            len -= bytes;
                            
                        }
                        
                    } while ((len > 0) && (bytes > 0));
                }
                else
                {
                    bytes = send (fd, b, len ,0);
                }
                
                if (bytes != len)
                {
                    throw new IOException ("can't write " + len + "bytes");
                }
            }
            
            catch (LastErrorException lee)
            {
                throw new IOException ("native write() failed : " + formatError (lee));
            }
        }
        
        @Override
        public void write (int b) throws IOException
        {
              write (new byte[]{(byte) b});
        }
        
        @Override
        public void write (byte[] b) throws IOException
        {
              write (b, 0, b.length);
        }
    }
 
    static String formatError(LastErrorException lee)
    {
        String  estr    = null;
        
        try
        {
            estr = strerror (lee.getErrorCode ());
        }
        
        catch (Throwable t)
        {
            estr = lee.getMessage ();
        }
        
        return (estr);
    }
 
 
    public UnixDomainSocket(String  spath) throws IOException
    {
        if (Platform.isWindows() ||Platform.isWindowsCE())
        {
            throw new IOException("Unix domain sockets are not supported on Windows");
        }
        
        path     = spath;
        sockaddr = new SockAddr (path);
        
        try
        {
            fd = socket (AF_UNIX,
                         SOCK_STREAM,
                         PROTOCOL);
        }
        
        catch ( LastErrorException lee)
        {
            throw new IOException ("native socket() failed : " + formatError (lee));
        }
    }
 
    @Override
    public void close () throws IOException
    {
        if (fd >= 0)
        {
            int     fdc = fd;
            
            fd = -1;
 
            try
            {
                close (fdc);
            }
 
            catch(LastErrorException lee)
            {
                throw new IOException ("native close() failed : " + formatError (lee));
            }
        }
    }
 
    @Override
    public void connect(SocketAddress endpoint) throws IOException
    {
        connect (endpoint, 0);
    }
 
    @Override
    public void connect(SocketAddress endpoint, int timeout) throws IOException
    {
        try
        {
            if (connect (fd, sockaddr, sockaddr.size ()) != 0)
            {
                throw new IOException(strerror(Native.getLastError()));
            }
        }
        
        catch (LastErrorException lee)
        {
            throw new IOException ("native connect() failed : " + formatError (lee));
        }
        
        is = new UnixSocketInputStream  ();
        os = new UnixSocketOutputStream ();
    }
    
    @Override
    public InputStream getInputStream ()
    {
        return (is);
    }
    
    @Override
    public OutputStream getOutputStream ()
    {
        return (os);
    }
    
    @Override
    public void setTcpNoDelay (boolean  b)
    {
    }
    
    @Override
    public void setKeepAlive (boolean   b)
    {
    }
    
    @Override
    public void setReceiveBufferSize (int   size)
    {
    }
    
    @Override
    public void setSendBufferSize (int  size)
    {   
    }
    
    @Override
    public void setSoLinger (boolean    b,
                             int        i)
    {
    }
    
    @Override
    public void setSoTimeout (int   timeout)
    {
    }
    
    @Override
    public void shutdownInput ()
    {
    }
    
    @Override
    public void shutdownOutput ()
    {
    }
}

Comment by Diego Dupin [ 2015-09-17 ]

Done in next version 1.3.0.

Generated at Thu Feb 08 03:13:31 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.