📄 tdstlsoutputstream.java
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase//Copyright (C) 2004 The jTDS Project////This library is free software; you can redistribute it and/or//modify it under the terms of the GNU Lesser General Public//License as published by the Free Software Foundation; either//version 2.1 of the License, or (at your option) any later version.////This library 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//Lesser General Public License for more details.////You should have received a copy of the GNU Lesser General Public//License along with this library; if not, write to the Free Software//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//package net.sourceforge.jtds.ssl;import java.io.FilterOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.ArrayList;import java.util.List;import net.sourceforge.jtds.jdbc.TdsCore;/** * An output stream that mediates between JSSE and the DB server. * <p/> * SQL Server 2000 has the following requirements: * <ul> * <li>All handshake records are delivered in TDS packets. * <li>The "Client Key Exchange" (CKE), "Change Cipher Spec" (CCS) and * "Finished" (FIN) messages are to be submitted in the delivered in both * the same TDS packet and the same TCP packet. * <li>From then on TLS/SSL records should be transmitted as normal -- the * TDS packet is part of the encrypted application data. * * @author Rob Worsnop * @author Mike Hutchinson * @version $Id: TdsTlsOutputStream.java,v 1.4 2005/04/28 14:29:31 alin_sinpalean Exp $ */class TdsTlsOutputStream extends FilterOutputStream { /** * Used for holding back CKE, CCS and FIN records. */ final private List bufferedRecords = new ArrayList(); private int totalSize; /** * Constructs a TdsTlsOutputStream based on an underlying output stream. * * @param out the underlying output stream */ TdsTlsOutputStream(OutputStream out) { super(out); } /** * Holds back a record for batched transmission. * * @param record the TLS record to buffer * @param len the length of the TLS record to buffer */ private void deferRecord(byte record[], int len) { byte tmp[] = new byte[len]; System.arraycopy(record, 0, tmp, 0, len); bufferedRecords.add(tmp); totalSize += len; } /** * Transmits the buffered batch of records. */ private void flushBufferedRecords() throws IOException { byte tmp[] = new byte[totalSize]; int off = 0; for (int i = 0; i < bufferedRecords.size(); i++) { byte x[] = (byte[])bufferedRecords.get(i); System.arraycopy(x, 0, tmp, off, x.length); off += x.length; } putTdsPacket(tmp, off); bufferedRecords.clear(); totalSize = 0; } public void write(byte[] b, int off, int len) throws IOException { if (len < Ssl.TLS_HEADER_SIZE || off > 0) { // Too short for a TLS packet just write it out.write(b, off, len); return; } // // Extract relevant TLS header fields // int contentType = b[0] & 0xFF; int length = ((b[3] & 0xFF) << 8) | (b[4] & 0xFF); // // Check to see if probably a SSL client hello // if (contentType < Ssl.TYPE_CHANGECIPHERSPEC || contentType > Ssl.TYPE_APPLICATIONDATA || length != len - Ssl.TLS_HEADER_SIZE) { // Assume SSLV2 Client Hello putTdsPacket(b, len); return; } // // Process TLS records // switch (contentType) { case Ssl.TYPE_APPLICATIONDATA: // Application data, just copy to output out.write(b, off, len); break; case Ssl.TYPE_CHANGECIPHERSPEC: // Cipher spec change has to be buffered deferRecord(b, len); break; case Ssl.TYPE_ALERT: // Alert record ignore! break; case Ssl.TYPE_HANDSHAKE: // TLS Handshake records if (len >= (Ssl.TLS_HEADER_SIZE + Ssl.HS_HEADER_SIZE)) { // Long enough for a handshake subheader int hsType = b[5]; int hsLen = (b[6] & 0xFF) << 16 | (b[7] & 0xFF) << 8 | (b[8] & 0xFF); if (hsLen == len - (Ssl.TLS_HEADER_SIZE + Ssl.HS_HEADER_SIZE) && // Client hello has to go in its own TDS packet hsType == Ssl.TYPE_CLIENTHELLO) { putTdsPacket(b, len); break; } // All others have to be deferred and sent as a block deferRecord(b, len); // // Now see if we have a finish record which will flush the // buffered records. // if (hsLen != len - (Ssl.TLS_HEADER_SIZE + Ssl.HS_HEADER_SIZE) || hsType != Ssl.TYPE_CLIENTKEYEXCHANGE) { // This is probably a finish record flushBufferedRecords(); } break; } default: // Short or unknown record output it anyway out.write(b, off, len); break; } } /** * Write a TDS packet containing the TLS record(s). * * @param b the TLS record * @param len the length of the TLS record */ void putTdsPacket(byte[] b, int len) throws IOException { byte tdsHdr[] = new byte[TdsCore.PKT_HDR_LEN]; tdsHdr[0] = TdsCore.PRELOGIN_PKT; tdsHdr[1] = 0x01; tdsHdr[2] = (byte)((len + TdsCore.PKT_HDR_LEN) >> 8); tdsHdr[3] = (byte)(len + TdsCore.PKT_HDR_LEN); out.write(tdsHdr, 0, tdsHdr.length); out.write(b, 0, len); } /* * (non-Javadoc) * * @see java.io.OutputStream#flush() */ public void flush() throws IOException { super.flush(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -