package com.sap.dbtech.rte.comm;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.sql.SQLException;
import java.util.Properties;

import com.sap.dbtech.jdbc.exceptions.TimeoutException;
import com.sap.dbtech.util.FullswapMem;
import com.sap.dbtech.util.MessageKey;
import com.sap.dbtech.util.MessageTranslator;
import com.sap.dbtech.util.StructuredBytes;
import com.sap.dbtech.util.StructuredMem;

/*

 @author D031096

 ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


 */
public abstract class BasicSocketComm extends JdbcCommunication {
    
    protected BasicSocketComm(String hostPort, Properties properties)
            throws RTEException {
        serviceType = RteC.SQL_USER_C;
        // this.host = host;
        if (hostPort== null || hostPort.length()==0){hostPort = "localhost";}
        int colon_idx = hostPort.indexOf(":");
        if (colon_idx == -1) {
            this.host = hostPort;
            this.port = this.getDefaultPort();
        } else {
            this.host = hostPort.substring(0, colon_idx);
            try {
                this.port = Integer.parseInt(hostPort.substring(colon_idx + 1));
            } catch (NumberFormatException nformatex) {
                throw new RTEException(
                        MessageTranslator
                                .translate(
                                        MessageKey.ERROR_UNKNOWN_HOST,
                                        hostPort,
                                        nformatex.getMessage(),
                                        new Integer(
                                                RteC.CommunicationErrorCodeMap_C[RteC.SQLSERVER_OR_DB_UNKNOWN_C])));
            }
        }
        String timeout = null;
        if (properties != null) {
            timeout = properties.getProperty("communicationtimeout");
            String servtype = properties.getProperty("connecttype", "");
            if (servtype.equalsIgnoreCase("OLTP"))
                serviceType = RteC.SQL_OLTPUSER_C;
            else if (servtype.equalsIgnoreCase("LIVECACHE"))
                serviceType = RteC.SQL_LVCUSER_C;

//            String socketAlive = properties.getProperty("keepSocketAlive");
//            if (socketAlive != null && socketAlive.equalsIgnoreCase("TRUE")) {
//                 keepSocketAliveAfterInfoRequest = true;
//            }
        }
    
        if (timeout == null) {
            this.socketTimeOut = DEFAULT_TIMEOUT;
        } else {
            try {
                this.socketTimeOut = Integer.parseInt(timeout);
            } catch (NumberFormatException numberFormatEx) {
                this.socketTimeOut = DEFAULT_TIMEOUT;
            }
        }
    } 
    
    abstract protected int getDefaultPort();
    abstract protected void openSocket() throws RTEException;
    abstract protected BasicSocketComm getNewCommunication() throws RTEException;
    /**
     * traces the content of the RTE header on stream for debugging purposes.
     * 
     * @param header
     *            com.sap.dbtech.util.StructuredMem
     * @param stream
     *            java.io.PrintStream
     */
    private static void dumpRteHeader(StructuredMem header, PrintStream stream) {
        stream.println("RTE Header");

        stream.print("ActSendLen: ");
        stream.println(header.getInt4(RteC.Header_ActSendLen_O));
        stream.print("ProtocolID: ");
        stream.println(header.getInt1(RteC.Header_ProtocolID_O));
        stream.print("MessClass: ");
        stream.println(header.getInt1(RteC.Header_MessClass_O));
        stream.print("RTEFlags: ");
        stream.println(header.getInt1(RteC.Header_RTEFlags_O));
        stream.print("ResidualPackets: ");
        stream.println(header.getInt1(RteC.Header_ResidualPackets_O));
        stream.print("SenderRef: ");
        stream.println(header.getInt4(RteC.Header_SenderRef_O));
        stream.print("ReceiverRef: ");
        stream.println(header.getInt4(RteC.Header_ReceiverRef_O));
        stream.print("RTEReturnCode: ");
        stream.println(header.getInt2(RteC.Header_RTEReturnCode_O));
        stream.print("Filler: ");
        stream.println(header.getInt2(RteC.Header_Filler_O));
        stream.print("MaxSendLen: ");
        stream.println(header.getInt4(RteC.Header_MaxSendLen_O));
        //Tracer.traceObject (null, header);
    }

    /**
     * queries a database for the packet layout
     * 
     * @return com.sap.dbtech.rte.comm.DbPacketLayout a description of the
     *         packet layout
     * @param host
     *            java.lang.String the server name
     * @param dbname
     *            java.lang.String the database name
     * @exception com.sap.dbtech.rte.comm.RTEException
     *                when no connection could be established
     */
    protected DbPacketLayout doInfoRequest(String dbname) throws RTEException {
        DbPacketLayout layout;
        DbPacketLayout result;
        ConnectPacket connectPacket;
        StructuredBytes rawRequest;
        StructuredBytes reply;

        /*
         * send info request
         */
        layout = new DbPacketLayout();
        rawRequest = createRawPacket(RteC.Connect_END_O_C);
        this.buildRTEHeader(rawRequest, RteC.RSQL_INFO_REQUEST_KEEP_ALIVE_C);
        connectPacket = new ConnectPacket(rawRequest.bytes(), dbname, layout,
                this.port, serviceType);
        connectPacket.close();
        this.sendData(rawRequest, connectPacket.length());
        /*
         * read info reply
         */
        try {
            reply = this.receiveConnect();
        } catch (RTEException e) {
            /*try classic infor request*/
            this.release();
            this.openSocket();
            this.buildRTEHeader(rawRequest, RteC.RSQL_INFO_REQUEST_C);
            this.sendData(rawRequest, connectPacket.length());
            reply = this.receiveConnect();
            this.release();
            this.openSocket();
        }
        result = new DbPacketLayout(reply, false, true);
//        if (result.getPortNumber() != this.port) {
//            this.port = result.getPortNumber();
            /*since the unix xserver doesn't understand the keepSocketAliveInfoRequest
             * we have to close the socket and reopen another one*/
//          if (!keepSocketAliveAfterInfoRequest
            // ||result.getPortNumber() != this.port 
                  /*since the unix xserver doesn't understand the keepSocketAliveInfoRequest
                   * we have to close the socket and reopen another one*/
//          ) {
//            this.port = result.getPortNumber();
//            this.release();
//            this.openSocket();
//        }
        return result;
    }

    /**
     * allocates a new communication packet
     * 
     * @return com.sap.dbtech.util.StructuredBytes
     * @param dataSize
     *            int the usable size
     */
    protected static StructuredBytes createRawPacket(int dataSize) {
        return new StructuredBytes(dataSize + RteC.Header_END_O_C);
    }



    /**
     * sleep on this connection. used only for debugging.
     */
    protected static void sleep() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException exc) {
            // ignore
        }
    }

 
    /**
     * opens a connection to a SAP DB kernel
     * 
     * @return com.sap.sapdb.SocketComm
     * @param hostname
     *            java.lang.String the server name
     * @param dbname
     *            java.lang.String the database name
     * @exception com.sap.sapdb.RTEException.
     */
    public void connectDB(String dbname) throws RTEException {
//        BasicSocketComm result;
        DbPacketLayout layout = null;

        /*
         * info request
         */
         layout = this.doInfoRequest(dbname);

        //layout.dumpOn (System.out, "after Info request");
        /*
         * do actual connect
         */
        this.dbSession = true;
        this.dbname = dbname;
        this.packetLayout = this.dbConnectExchange(dbname, layout);
        //result.packetLayout.dumpOn (System.out, "after connect exchange");
    }

    /**
     * opens a connection to a dbm- or repm-server
     * 
     * @return com.sap.sapdb.SocketComm
     * @param hostname
     *            java.lang.String the server name
     * @param dbname
     *            java.lang.String the database name
     * @param dbroot
     *            java.lang.String (optional) the location of database
     *            executables
     * @param dbname
     *            java.lang.String the name of the server program
     * @exception com.sap.sapdb.RTEException
     *                when no connection can be established
     */
    public void connectAdmin(String dbname, String dbroot, String pgm)
            throws RTEException {

        PacketLayout layout = new CserverPacketLayout();
        this.sendAdminConnect(dbname, dbroot, pgm, layout);
        this.receiveConnect();
        this.packetLayout = layout;
    }

    /**
     */
    public String toString() {
        String result;

        result = super.toString() + " on " + this.socket;
        return result;
    }

    /**
     * tests whether the SecureCommunicationunication is still valid.
     * 
     * @return boolean
     */
    public boolean isConnected() {
        return this.socket != null;
    }

    /**
     * Code to perform when this object is garbage collected. make sure that the
     * socket is closed to prevent accumulation of handles.
     */
    protected void finalize() throws Throwable {
        if (this.socket != null) {
            this.release();
        }
        super.finalize();
    }

    /**
     * fills the RTE-specific header with standard values
     * 
     * @param messClass
     *            int a value from {@link RteC  RteC.RSQL_*}
     */
    protected void buildRTEHeader(StructuredBytes packet, int messClass) {
        packet.putInt4(0, RteC.Header_ActSendLen_O);
        packet.putInt1(3, RteC.Header_ProtocolID_O);
        packet.putInt1(messClass, RteC.Header_MessClass_O);
        packet.putInt1(0, RteC.Header_RTEFlags_O);
        packet.putInt1(0, RteC.Header_ResidualPackets_O);
        packet.putInt4(senderRef, RteC.Header_SenderRef_O);
        packet.putInt4(receiverRef, RteC.Header_ReceiverRef_O);
        packet.putInt2(0, RteC.Header_RTEReturnCode_O);
        packet.putInt2(0, RteC.Header_Filler_O);
        packet.putInt4(maxSendLen, RteC.Header_MaxSendLen_O);
        return;
    }

    /**
     * closes the socket connection.
     */
    private void closeSocket() {
        try {
            this.socket.close();
        } catch (java.io.IOException ioExc) {
            // ignore
        } finally {
            this.socket = null;
        }
        return;
    }



    /**
     * mimics the C-API sqlarequest
     * 
     * @param len
     *            int
     * @exception com.sap.sapdb.RTEException
     */
    public void sqlarequest(StructuredMem userPacket, int len)
            throws RTEException {
        this.request(userPacket, len);
    }

    /**
     * mimics the C-API sqlarelease
     * 
     * @exception com.sap.sapdb.RTEException
     */
    public void sqlarelease() throws RTEException {
        this.release();
        return;
    }

    /**
     * mimics the C-API sqlareceive
     * 
     * @return StructuredMem
     * @exception com.sap.sapdb.RTEException.
     */
    public StructuredMem sqlareceive() throws RTEException {
        return this.receive();
    }

    /**
     * sends a cancel request for the current request (not implemented).
     */
    public void cancel() throws java.sql.SQLException {
        DbPacketLayout layout;
        StructuredBytes rawRequest;
        ConnectPacket connectPacket;
        BasicSocketComm cancelConnection;

        try {
            layout = new DbPacketLayout();
            // create connect
            // set cancel request
            cancelConnection = this.getNewCommunication();
            rawRequest = createRawPacket(RteC.Connect_END_O_C);
            this.buildRTEHeader(rawRequest, RteC.RSQL_USER_CANCEL_REQUEST_C);
            rawRequest.putInt4(this.senderRef, RteC.Header_ReceiverRef_O);
            connectPacket = new ConnectPacket(rawRequest.bytes(), dbname,
                    layout, this.port, serviceType);
            // send connect
            connectPacket.close();
            cancelConnection.sendData(rawRequest, connectPacket.length());
            // close, no reply expected
            cancelConnection.closeSocket();
        } catch (RTEException exc) {
            throw new java.sql.SQLException(exc.getMessage());
        }
    }

    /**
     * Writes logically <i>len </i> bytes of <i>data </i>. The RTE-header is
     * filled and the whiole packet is sent.
     * 
     * @param packet
     *            StructuredBytes
     * @param len
     *            int
     * @exception com.sap.sapdb.jdbc.RTEException.
     */
    protected void sendData(StructuredBytes packet, int len)
            throws RTEException {
        OutputStream ostream;

        //Tracer.println ("send: (" + len + ") " + this); //#print
        //Tracer.whereAmI ();
        this.setActSendLen(packet, len);
        try {
            if (outstream == null)
                outstream = socket.getOutputStream();
            ostream = outstream;
        } catch (IOException ioExc1) {
            throw new RTEException("sendData: getOutputStream failed",
                    RteC.CommunicationErrorCodeMap_C[RteC.SQLSEND_LINE_DOWN_C]);
        }
        try {
            ostream.write(packet.bytes(), 0, len + RteC.Header_END_O_C);
        } catch (IOException ioExc2) {
            TimeoutException.println( MessageTranslator
                    .translate(MessageKey.ERROR_SEND_WRITE, String.valueOf(this.senderRef), ioExc2.getMessage()));
            throw new RTEException(MessageTranslator
                    .translate(MessageKey.ERROR_SEND_WRITE, String.valueOf(this.senderRef), ioExc2.getMessage()),
                    RteC.CommunicationErrorCodeMap_C[RteC.SQLSEND_LINE_DOWN_C]);
        }
        return;
    }
    /**
     * sends connect packet for SAP DB kernel.
     * 
     * @param dbname
     *            java.lang.String the database name
     * @param layout
     *            PacketLayout a suggestion for the packet layout
     * @exception com.sap.sapdb.jdbc.RTEException.
     */
    private void sendDbConnect(String dbname, PacketLayout layout, int myport)
            throws RTEException {
        StructuredBytes rawRequest;
        ConnectPacket connectPacket;

        rawRequest = createRawPacket(layout.maxDataLength());
        this.buildRTEHeader(rawRequest, RteC.RSQL_USER_CONN_REQUEST_C);
        connectPacket = new ConnectPacket(rawRequest.bytes(), dbname, layout,
                myport, serviceType);
        connectPacket.close();
        this.sendData(rawRequest, connectPacket.length());
    }

    /**
     * sends connect packet for dbm- or repm-Server.
     * 
     * @param db
     *            java.lang.String the database name
     * @param dbroot
     *            java.lang.String (optional) location of database executables
     * @param pgm
     *            java.lang.String name of server program
     * @param PacketLayout
     *            layout
     * @exception com.sap.sapdb.jdbc.RTEException.
     */
    private void sendAdminConnect(String dbname, String dbroot, String pgm,
            PacketLayout layout) throws RTEException {
        StructuredBytes rawRequest;
        ConnectPacket connectPacket;

        rawRequest = createRawPacket(layout.maxDataLength());
        this.buildRTEHeader(rawRequest, RteC.RSQL_CTRL_CONN_REQUEST_C);
        connectPacket = new ConnectPacket(rawRequest.bytes(), dbname, layout,
                this.port, serviceType);
        connectPacket.addConnectString(dbroot, RteC.ARGID_DBROOT_C);
        connectPacket.addConnectString(pgm, RteC.ARGID_SERVERPGM_C);
        connectPacket.close();
        this.sendData(rawRequest, connectPacket.length());
        return;
    }

    /**
     * sends client data to the server.
     * 
     * @param userPacket
     *            StructuredMem
     * @param len
     *            int
     * @exception com.sap.sapdb.RTEException
     */
    public void request(StructuredMem userPacket, int len) throws RTEException {
//        if (Tracer.traceAny_C && Tracer.isOn(9)) {
//            Tracer.traceObject("REQUEST:", (Traceable)userPacket, len + 24);
//        }
        StructuredBytes rawPacket = ((RteSocketPacket) userPacket).rteHeader;
        this.buildRTEHeader(rawPacket, RteC.RSQL_USER_DATA_REQUEST_C);
        this.sendData(rawPacket, len);
    }

    /**
     * closes the connection
     */
    public void release() {
        try {
            StructuredBytes rawPacket = createRawPacket(0);
            this.buildRTEHeader(rawPacket, RteC.RSQL_USER_RELEASE_REQUEST_C);
            this.sendData(rawPacket, 0);
            try {
                Thread.sleep(1);
            } catch (InterruptedException ignored) {
            }
            //             Object o = new Object();
            //             synchronized(o) {
            //                 try { o.wait(5); } catch(InterruptedException ignored) {}
            //             }
            this.socket.close();
        } catch (java.io.IOException ioexc) {
            // ignore
        } catch (RTEException rteexc) {
            // ignore
        } finally {
            this.socket = null;
        }
    }

    /**
     * tries to reconnect after a timeout
     * 
     * @exception com.sap.dbtech.rte.comm.RTEException.
     */
    public void reconnect() throws RTEException {
        try {
            this.socket.close();
            this.socket = null;
        } catch (Exception ignore) {
            this.socket = null;
        }
        this.openSocket();
        if (this.dbSession) {
            this.connectDB(this.dbname);
//            this.dbConnectExchange(this.dbname, this.packetLayout);
        } else {
            throw new RTEException(MessageTranslator
                    .translate(MessageKey.ERROR_ADMIN_RECONNECT),
                    RteC.CommunicationErrorCodeMap_C[RteC.SQLTIMEOUT_C]);
        }
    }

    /**
     * blocks to wait for a reply
     * 
     * @return StructuredMem
     * @exception com.sap.dbtech.rte.comm.RTEException
     */
    protected StructuredMem receiveData() throws RTEException {
        boolean firstPacket = true;
        java.io.InputStream instream;
        byte[] header = new byte[RteC.Header_END_O_C];
        int headerLength;
        int dataLength = 0;
        int bytesRead = 0;
        int actSendLength;
        int chunkRead;
        byte[] readBuf = null;
        StructuredBytes replyHeader = null;
        StructuredBytes result = null;
        int rteRC;

        //Tracer.println ("receiveData: " + this); //#print
        //Tracer.whereAmI ();
        try {
            /*
             * get input stream
             */
            instream = this.instream;
            while (firstPacket || (bytesRead < dataLength)) {
                //Tracer.println ("firstPacket: " + firstPacket); //#print
                //Tracer.println ("dataLength: " + dataLength); //#print
                //Tracer.println ("bytesRead: " + bytesRead); //#print
                /*
                 * read header
                 */
                //System.out.print ("reading: "); //#print
                headerLength = instream.read(header, 0, RteC.Header_END_O_C);
                if (headerLength != RteC.Header_END_O_C) {
                    RTEException rteExc = new RTEException(
                            MessageTranslator
                                    .translate(MessageKey.ERROR_DATA_RECVFAILED),
                            RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
                    throw rteExc;
                }
                if (firstPacket) {
                    replyHeader = this.replyMem(header);
                    firstPacket = false;
                    rteRC = replyHeader.getInt2(RteC.Header_RTEReturnCode_O);
                    if (rteRC != 0) {
                        throw new CommunicationException(rteRC);
                    }
                    dataLength = replyHeader.getInt4(RteC.Header_MaxSendLen_O)
                            - headerLength;
                    //Tracer.print ("packetLen: " + dataLength); //#print
                    //Tracer.println ("dataLength: " + dataLength); //#print
                    /*
                     * alloc result
                     */
                    readBuf = new byte[dataLength];
                    result = new StructuredBytes(readBuf);
                }
                /*
                 * get length of residual packet
                 */
                actSendLength = replyHeader.getInt4(RteC.Header_ActSendLen_O)
                        - headerLength;
                //System.out.print (" actSendLength: " + actSendLength + " |
                // "); //#print
                if ((actSendLength < 0)
                        || (bytesRead + actSendLength > readBuf.length)) {
                    //Tracer.println ("actSendLength out of bounds: " +
                    // actSendLength);
                }
                /*
                 * read bytes
                 */
                while (actSendLength > 0) {
                    try {
                        chunkRead = instream.read(readBuf, bytesRead,
                                actSendLength);
                        //System.out.print (chunkRead + ", ");//#print
                    } catch (ArrayIndexOutOfBoundsException arrayExc) {
                        //Tracer.println ("replyHeader");
                        //replyHeader.traceOn (Tracer.getLog());
                        //Tracer.println ("received packet");
                        //result.traceOn (Tracer.getLog(), bytesRead - 1000,
                        // bytesRead + 1000);
                        throw new ArrayIndexOutOfBoundsException(
                                MessageTranslator.translate(
                                        MessageKey.ERROR_CHUNKOVERFLOW, Integer
                                                .toString(actSendLength),
                                        Integer.toString(bytesRead), Integer
                                                .toString(readBuf.length)));
                    }
                    if (chunkRead < 0) {
                        throw new RTEException(
                                MessageTranslator
                                        .translate(MessageKey.ERROR_DATA_RECVFAILED),
                                RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
                    }
                    bytesRead += chunkRead;
                    actSendLength -= chunkRead;
                }
            }
            //System.out.println (" -- Done!");
        } catch (java.io.IOException ioexc) {
            throw new RTEException(
                    MessageTranslator.translate(
                            MessageKey.ERROR_DATA_RECVFAILED_REASON, ioexc
                                    .getMessage()),
                    RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
        }
//        if (Tracer.traceAny_C && Tracer.isOn(9)) {
//            Tracer.traceObject("REPLY:", result);
//        }
        return result;
    }

    /**
     * receives a reply to a pending request.
     * 
     * @return StructuredMem
     * @exception com.sap.sapdb.RTEException.
     */
    public StructuredMem receive() throws RTEException {
        return this.receiveData();
    }

    /**
     * returns the port to connect to the vserver. There seems to be no method
     * getprotbyname in java.net.
     * 
     * @return int
     */
    protected int lookupPort() {
        return this.port;
    }

    public boolean isChallengeResponseSupported() throws SQLException {
        return this.packetLayout.isChallengeResponseSupported();
    }
    /**
     * creates a new request packet. Clients are expected to reuse these packets
     * and to request additional packets only when packets are used in parallel
     * 
     * @return StructuredMem
     */
    public StructuredMem getRequestPacket() {
        StructuredBytes result;

        result = new RteSocketPacket(this.packetLayout.maxCmdDataLength());
        return result;
    }

    /**
     * creceive the connect reply
     */
    protected StructuredBytes receiveConnect() throws RTEException {
        int expectedReplyLen = RteC.Header_END_O_C + RteC.Connect_END_O_C;
        byte[] connectReply = new byte[expectedReplyLen];
        int replyLen;
//        InputStream instream;
        StructuredBytes reply;

        try {
            // try a first read.
            replyLen = this.instream.read(connectReply, 0, expectedReplyLen);
            // Look if the header is at least there. 25 bytes should be able
            // to travel in one socket read.
            if (replyLen < (RteC.Header_END_O_C + 1)) {
                throw new RTEException(
                        MessageTranslator
                                .translate(MessageKey.ERROR_RECV_CONNECT),
                        RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
            }
            this.remoteSwapping = connectReply[RteC.Header_END_O_C + 1];
            reply = this.replyMem(connectReply);
            int fullReplyLen = reply.getInt4(RteC.Header_ActSendLen_O);
            if (fullReplyLen < 0 || fullReplyLen > 500 * 1024) {
                throw new RTEException(
                        MessageTranslator
                                .translate(MessageKey.ERROR_REPLY_GARBLED),
                        RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
            }
            while (replyLen < fullReplyLen) {
                int nowreceived = this.instream.read(connectReply, replyLen,
                        fullReplyLen - replyLen);
                if (nowreceived == -1) {
                    throw new RTEException(MessageTranslator.translate(
                            MessageKey.ERROR_CONNECT_RECVFAILED,
                            "End of file before packet was read."),
                            RteC.CommunicationErrorCodeMap_C[RteC.SQLNOTOK_C]);
                }
                try {
                    Thread.sleep(1);
                } catch (InterruptedException irx) {
                }
                replyLen += nowreceived;
            }
        } catch (IOException ioexc) {
            throw new RTEException(MessageTranslator.translate(
                    MessageKey.ERROR_CONNECT_RECVFAILED, ioexc.getMessage()),
                    RteC.CommunicationErrorCodeMap_C[RteC.SQLNOTOK_C]);
        }
        /*
         * try { replyLen = this.instream.read (connectReply, 0,
         * expectedReplyLen); if (replyLen < RteC.Header_END_O_C) { throw new
         * RTEException
         * (MessageTranslator.translate(MessageKey.ERROR_RECV_CONNECT),
         * RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]); }
         * this.remoteSwapping = connectReply [RteC.Header_END_O_C + 1]; reply =
         * this.replyMem (connectReply); transmittedReplyLen = reply.getInt4
         * (RteC.Header_ActSendLen_O); if (transmittedReplyLen != replyLen) {
         * throw new RTEException
         * (MessageTranslator.translate(MessageKey.ERROR_REPLY_GARBLED),
         * RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]); } }
         * catch (java.io.IOException ioexc) { throw new RTEException
         * (MessageTranslator.translate(MessageKey.ERROR_CONNECT_RECVFAILED,
         * ioexc.getMessage ()),
         * RteC.CommunicationErrorCodeMap_C[RteC.SQLNOTOK_C]); }
         */

        /*
         * use connect information
         */
        this.senderRef = reply.getInt4(RteC.Header_SenderRef_O);
        int replyRC = reply.getInt2(RteC.Header_RTEReturnCode_O);
        if (replyRC != 0) {
            throw new RTEException(RteC.getCommunicationError(replyRC), RteC
                    .getCommunicationErrorMapCode(replyRC));
        }
        return reply;
    }

    /**
     * sends and receives the connect packet.
     * 
     * @param dbname
     *            java.lang.String the database name
     * @param layout
     *            com.sap.dbtech.rte.comm.PacketLayout
     * @exception com.sap.dbtech.rte.comm.RTEException.
     */
    private PacketLayout dbConnectExchange(String dbname, PacketLayout layout)
            throws RTEException {
        StructuredBytes connectReply;

        this.sendDbConnect(dbname, layout, this.port);
        connectReply = this.receiveConnect();
        layout = new DbPacketLayout(connectReply, true, true);
        return layout;
    }

    /**
     * sets the len of client data in the RTE-header
     * 
     * @param sendLen
     *            int
     */
    protected void setActSendLen(StructuredBytes rawPacket, int sendLen) {
        sendLen += RteC.Header_END_O_C;
        rawPacket.putInt4(sendLen, RteC.Header_ActSendLen_O);
        rawPacket.putInt4(sendLen, RteC.Header_MaxSendLen_O);
        return;
    }

    /**
     * converts the raw reply into a readable StructuredMem. This is done by
     * wrapping the bytes into an appropriate reader, not by converting the
     * actual data.
     * 
     * @return com.sap.dbtech.util.StructuredMem
     * @param buf
     *            byte[]
     */
    protected StructuredBytes replyMem(byte[] buf) throws RTEException {
        StructuredBytes result;
        switch (this.remoteSwapping) {
        case RteC.notSwapped_C:
            result = new StructuredBytes(buf);
            break;
        case RteC.fullSwapped_C:
            result = new FullswapMem(buf);
            break;
        default:
            throw new RTEException(MessageTranslator
                    .translate(MessageKey.ERROR_INVALID_SWAPPING), -708);
        }
        return result;
    }
    
    public int getKernelTaskID() {
        return senderRef;
    }

    protected String dbname;

    protected int port;

    protected String host;

    protected int maxSendLen;

    protected int receiverRef;

    protected int senderRef;

    protected OutputStream outstream;

    protected InputStream instream;

//    private static int counter = 0;

    protected static int DEFAULT_TIMEOUT = 0;

    protected int socketTimeOut;

    protected boolean dbSession;

    protected PacketLayout packetLayout;

    protected int remoteSwapping;

    public static final int controlPacketSize_C = 16384;

    protected Socket socket;

    protected int serviceType;

 
}
