📄 tdscomm.java
字号:
//
// Copyright 1998 CDS Networks, Inc., Medford Oregon
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All advertising materials mentioning features or use of this software
// must display the following acknowledgement:
// This product includes software developed by CDS Networks, Inc.
// 4. The name of CDS Networks, Inc. may not be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
package net.sourceforge.jtds.jdbc;
import net.sourceforge.jtds.util.HexDump;
import net.sourceforge.jtds.util.Logger;
import java.io.*;
import java.net.*;
import java.sql.Timestamp;
/**
* Handle the communications for a Tds instance.
*
*@author Craig Spannring
*@author Igor Petrovski
*@created 14 September 2001
*@version $Id: TdsComm.java,v 1.1 2002/10/14 10:48:59 alin_sinpalean Exp $
*/
public class TdsComm implements TdsDefinitions {
// in and out are the sockets used for all communication with the
// server.
private DataOutputStream out = null;
private DataInputStream in = null;
// outBuffer is used to construct the physical packets that will
// be sent to the database server.
byte outBuffer[];
int outBufferLen;
// nextOutBufferIndex is an index into outBuffer where the next
// byte of data will be stored while constructing a packet.
int nextOutBufferIndex = 0;
// The type of the TDS packet that is being constructed
// in outBuffer.
int packetType = 0;
// Place to store the incoming data from the DB server.
byte inBuffer[];
// index of next byte that will be 'read' from inBuffer
int inBufferIndex = 0;
// Total Number of bytes stored in inBuffer. (The number includes bytes
// that have been 'read' as well as bytes that still need to be 'read'.
int inBufferLen = 0;
// Track how many packets we have sent and received
int packetsSent = 0;
int packetsReceived = 0;
// Added 2000-06-07. Used to control TDS version-specific behavior.
private int tdsVer = TDS42;
/**
*@todo Does this need to be synchronized?
*/
byte tmpBuf[] = new byte[8];
/**
* Buffer that will be used to return byte[] values by getByte(int, boolean)
* to avoid allocating a new buffer each time if not necessary.
*/
byte resBuffer[] = new byte[256];
/**
* @todo Description of the Field
*/
public final static String cvsVersion = "$Id: TdsComm.java,v 1.1 2002/10/14 10:48:59 alin_sinpalean Exp $";
final static int headerLength = 8;
//
// The following constants are the packet types.
//
// They are the first databayte in the packet and
// define the type of data in that packet.
/**
* @todo Description of the Field
*/
public final static byte QUERY = 1;
/**
* @todo Description of the Field
*/
public final static byte LOGON = 2;
/**
* @todo Description of the Field
*/
public final static byte PROC = 3;
/**
* @todo Description of the Field
*/
public final static byte REPLY = 4;
/**
* @todo Description of the Field
*/
public final static byte CANCEL = 6;
/**
* @todo Description of the Field
*/
public final static byte LOGON70 = 16;
// Added 2000-06-05
// The minimum packet length that a TDS implementation can support
// is 512 bytes. This implementation will not support packets longer
// than 512. This will simplify the connection negotiation.
//
// XXX Some future release of this driver should be modified to
// negotiate longer packet sizes with the DB server.
private final static int maxPacketLength = 512;
// For debuging purposes it would be nice to uniquely identify each Tds
// stream. id will be a unique value for each instance of this class.
private static int nextId = 0;
private int id;
public TdsComm( Socket sock, int tdsVer_ )
throws java.io.IOException
{
out = new DataOutputStream( sock.getOutputStream() );
in = new DataInputStream( sock.getInputStream() );
outBufferLen = maxPacketLength;
outBuffer = new byte[outBufferLen];
inBuffer = new byte[maxPacketLength];
// Added 2000-06-07
tdsVer = tdsVer_;
id = ++nextId;
}
public void close()
{
// nop for now.
}
/*
* private void clearInputStream() throws IOException
* {
* int leftOver = in.available();
* if (leftOver > 0) {
* byte[] tmpBuffer = new byte[leftOver];
* for (int tmpread = 0; tmpread < leftOver; )
* {
* int num = in.read(tmpBuffer, tmpread, leftOver - tmpread);
* if (num < 0) break;
* tmpread += num;
* }
* if (Logger.isActive())
* {
* String dump = net.sourceforge.jtds.util.HexDump.hexDump(tmpBuffer, leftOver);
* String t = (new Timestamp(
* System.currentTimeMillis())).toString();
* Logger.println("Instance " + id + " @ " + t
* + " recevied leftOver"
* + "\n" + dump);
* }
* }
* }
*/
/**
* Start a TDS packet. <br>
* This method should be called to start a logical TDS packet.
*
* @param type Type of the packet. Can be QUERY, LOGON, PROC, REPLY, or
* CANCEL.
*/
public synchronized void startPacket( int type ) throws TdsException
{
if( type!=CANCEL && inBufferIndex!=inBufferLen )
{
// SAfe It's ok to throw this exception so that we will know there
// is a design flaw somewhere, but we should empty the buffer
// however. Otherwise the connection will never close (e.g. if
// SHOWPLAN_ALL is ON, a resultset will be returned by commit
// or rollback and we will never get rid of it). It's true
// that we should find a way to actually process these packets
// but for now, just dump them (we have thrown an exception).
inBufferIndex = inBufferLen;
if( Logger.isActive() )
Logger.println("Unprocessed data in input buffer. Dumping. ["+
inBufferIndex+"/"+inBufferLen+"]");
throw new TdsException("Unprocessed data in input buffer.");
}
// Only one thread at a time can be building an outboudn packet.
// This is primarily a concern with building cancel packets.
// XXX: as why should more than one thread work with the same tds-stream ??? would be fatal anyway
while ( someThreadIsBuildingPacket() ) {
try {
wait();
}
catch ( java.lang.InterruptedException e ) {
// nop
}
}
packetType = type;
nextOutBufferIndex = headerLength;
}
/**
* Is some thread currently building a logical TDS packet?
*
*@return true iff a packet is being built.
*/
public boolean someThreadIsBuildingPacket()
{
return packetType != 0;
}
/**
* append a byte onto the end of the logical TDS packet. <p>
*
* Append a byte onto the end of the logical TDS packet. When a physical
* packet is full send it to the server.
*
*@param b byte to add to the TDS packet
*@exception java.io.IOException @todo Description of Exception
*/
public void appendByte( byte b )
throws java.io.IOException
{
if ( nextOutBufferIndex == outBufferLen ) {
// If we have a full physical packet then ship it out to the
// network.
sendPhysicalPacket( false );
nextOutBufferIndex = headerLength;
}
storeByte( nextOutBufferIndex, b );
nextOutBufferIndex++;
}
// appendByte()
/**
* append an array of bytes onto the end of the logical TDS packet.
*
*@param b bytes to add to the TDS packet
*@exception java.io.IOException @todo Description of Exception
*/
public void appendBytes( byte[] b )
throws java.io.IOException
{
appendBytes( b, b.length, ( byte ) 0 );
}
// appendBytes()
/**
* append an array of bytes onto the end of the logical TDS packet.
*
*@param b bytes to add to the TDS packet
*@param len maximum number of bytes to transmit
*@param pad fill with this byte until len is reached
*@exception java.io.IOException @todo Description of Exception
*/
public void appendBytes( byte[] b, int len, byte pad )
throws java.io.IOException
{
int i = 0;
for ( ; i < b.length && i < len; i++ ) {
appendByte( b[i] );
}
for ( ; i < len; i++ ) {
appendByte( pad );
}
}
/**
* append a short int onto the end of the logical TDS packet. <p>
*
*
*
*@param s short int to add to the TDS packet
*@exception java.io.IOException @todo Description of Exception
*/
public void appendShort( short s )
throws java.io.IOException
{
appendByte( ( byte ) ( ( s >> 8 ) & 0xff ) );
appendByte( ( byte ) ( ( s >> 0 ) & 0xff ) );
}
/**
* Appends a short int onto the end of the logical TDS packet. <p>
*
*
*
*@param s short int to add to the TDS packet
*@exception java.io.IOException @todo Description of Exception
*/
public void appendTdsShort( short s )
throws java.io.IOException
{
appendByte( ( byte ) ( ( s >> 0 ) & 0xff ) );
appendByte( ( byte ) ( ( s >> 8 ) & 0xff ) );
}
/**
* append a Double onto the end of the logical TDS packet. <p>
*
* Append the Double value onto the end of the TDS packet as a SYBFLT8.
*
*@param value Double to add to the TDS packet
*@exception java.io.IOException @todo Description of Exception
*/
public void appendFlt8( Double value )
throws java.io.IOException
{
long l = Double.doubleToLongBits( value.doubleValue() );
appendByte( ( byte ) ( ( l >> 0 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 8 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 16 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 24 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 32 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 40 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 48 ) & 0xff ) );
appendByte( ( byte ) ( ( l >> 56 ) & 0xff ) );
}
public void appendInt( int i )
throws java.io.IOException
{
appendByte( ( byte ) ( ( i >> 24 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 16 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 8 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 0 ) & 0xff ) );
}
public void appendTdsInt( int i )
throws java.io.IOException
{
appendByte( ( byte ) ( ( i >> 0 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 8 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 16 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 24 ) & 0xff ) );
}
public void appendInt64( long i )
throws java.io.IOException
{
appendByte( ( byte ) ( ( i >> 56 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 48 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 40 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 32 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 24 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 16 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 8 ) & 0xff ) );
appendByte( ( byte ) ( ( i >> 0 ) & 0xff ) );
}
/**
* Appends the 16-bit characters from the caller's string, without
* narrowing the characters. Sybase let's the client decide what byte order
* to use but it \ appears that SQLServer 7.0 little-endian byte order.
* Added 2000-06-05
*
*@param s @todo Description of Parameter
*@exception java.io.IOException @todo Description of Exception
*/
public void appendChars( String s ) throws java.io.IOException
{
for ( int i = 0; i < s.length(); ++i ) {
int c = s.charAt( i );
byte b1 = ( byte ) ( c & 0xFF );
byte b2 = ( byte ) ( ( c >> 8 ) & 0xFF );
appendByte( b1 );
appendByte( b2 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -