KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > internetcds > jdbc > tds > TdsComm


1 //
2
// Copyright 1998 CDS Networks, Inc., Medford Oregon
3
//
4
// All rights reserved.
5
//
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions are met:
8
// 1. Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// 2. Redistributions in binary form must reproduce the above copyright
11
// notice, this list of conditions and the following disclaimer in the
12
// documentation and/or other materials provided with the distribution.
13
// 3. All advertising materials mentioning features or use of this software
14
// must display the following acknowledgement:
15
// This product includes software developed by CDS Networks, Inc.
16
// 4. The name of CDS Networks, Inc. may not be used to endorse or promote
17
// products derived from this software without specific prior
18
// written permission.
19
//
20
// THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
21
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
// ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
24
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
// SUCH DAMAGE.
31
//
32

33
34 package com.internetcds.jdbc.tds;
35
36 import java.io.*;
37 import java.net.*;
38 import com.internetcds.util.HexDump;
39 import com.internetcds.util.Logger;
40 import java.sql.Timestamp JavaDoc;
41
42 /**
43  * Handle the communications for a Tds instance.
44  *
45  * @version $Id: TdsComm.java,v 1.1 2006/06/23 10:39:30 sinisa Exp $
46  * @author Craig Spannring
47  * @author Igor Petrovski
48  */

49 public class TdsComm implements TdsDefinitions
50 {
51    public static final String JavaDoc cvsVersion = "$Id: TdsComm.java,v 1.1 2006/06/23 10:39:30 sinisa Exp $";
52     //Dusan
53
static int z = 0;
54
55    static final int headerLength = 8;
56
57    //
58
// The following constants are the packet types.
59
//
60
// They are the first databayte in the packet and
61
// define the type of data in that packet.
62
public static final byte QUERY = 1;
63    public static final byte LOGON = 2;
64    public static final byte PROC = 3;
65    public static final byte REPLY = 4;
66    public static final byte CANCEL = 6;
67    public static final byte LOGON70 = 16; // Added 2000-06-05
68

69
70    // The minimum packet length that a TDS implementation can support
71
// is 512 bytes. This implementation will not support packets longer
72
// than 512. This will simplify the connection negotiation.
73
//
74
// XXX Some future release of this driver should be modified to
75
// negotiate longer packet sizes with the DB server.
76
private static final int maxPacketLength = 4096;
77
78    // in and out are the sockets used for all communication with the
79
// server.
80
private DataOutputStream out = null;
81    private DataInputStream in = null;
82
83
84    // outBuffer is used to construct the physical packets that will
85
// be sent to the database server.
86
byte outBuffer[];
87
88    // nextOutBufferIndex is an index into outBuffer where the next
89
// byte of data will be stored while constructing a packet.
90
int nextOutBufferIndex = 0;
91
92    // The type of the TDS packet that is being constructed
93
// in outBuffer.
94
int packetType = 0;
95
96
97    // Place to store the incoming data from the DB server.
98
byte inBuffer[];
99
100    // index of next byte that will be 'read' from inBuffer
101
int inBufferIndex = 0;
102
103    // Total Number of bytes stored in inBuffer. (The number includes bytes
104
// that have been 'read' as well as bytes that still need to be 'read'.
105
int inBufferLen = 0;
106
107    // Track how many packets we have sent and received
108
int packetsSent = 0;
109    int packetsReceived = 0;
110
111    // For debuging purposes it would be nice to uniquely identify each Tds
112
// stream. id will be a unique value for each instance of this class.
113
static int id = 0;
114
115    // Added 2000-06-07. Used to control TDS version-specific behavior.
116

117    private int tdsVer = TDS42;
118
119    public TdsComm(Socket sock, int tdsVer_)
120       throws java.io.IOException JavaDoc
121    {
122       out = new DataOutputStream(sock.getOutputStream());
123       in = new DataInputStream(sock.getInputStream());
124       outBuffer = new byte[4096];
125       inBuffer = new byte[4096];
126       // Added 2000-06-07
127
tdsVer = tdsVer_;
128
129       id++;
130    }
131
132    public void close()
133    {
134       // nop for now.
135
}
136
137
138    /**
139     * start a TDS packet.
140     *
141     * <br>
142     * This method should be called to start a logical TDS packet.
143     *
144     * @param type Type of the packet. Can be QUERY, LOGON, PROC,
145     * REPLY, or CANCEL.
146     */

147    public synchronized void startPacket(int type)
148    {
149       // Only one thread at a time can be building an outboudn packet.
150
// This is primarily a concern with building cancel packets.
151
while(someThreadIsBuildingPacket())
152       {
153          try
154          {
155             wait();
156          }
157          catch (java.lang.InterruptedException JavaDoc e)
158          {
159             // nop
160
}
161       }
162       
163       packetType = type;
164       nextOutBufferIndex = headerLength;
165    }
166
167    /**
168     * Is some thread currently building a logical TDS packet?
169     *
170     * @return true iff a packet is being built.
171     */

172    public boolean someThreadIsBuildingPacket()
173    {
174       return packetType!=0;
175    }
176
177
178    /**
179     * append a byte onto the end of the logical TDS packet.
180     *
181     * <p>
182     * Append a byte onto the end of the logical TDS packet. When a
183     * physical packet is full send it to the server.
184     *
185     * @param b byte to add to the TDS packet
186     */

187    public void appendByte(byte b)
188       throws java.io.IOException JavaDoc
189    {
190       if (nextOutBufferIndex == maxPacketLength)
191       {
192          // If we have a full physical packet then ship it out to the
193
// network.
194
sendPhysicalPacket(false);
195          nextOutBufferIndex = headerLength;
196       }
197
198       storeByte(nextOutBufferIndex, b);
199       nextOutBufferIndex++;
200       
201       
202    } // appendByte()
203

204
205    /**
206     * append an array of bytes onto the end of the logical TDS packet.
207     *
208     * @param b bytes to add to the TDS packet
209     */

210    public void appendBytes(byte[] b)
211       throws java.io.IOException JavaDoc
212    {
213       appendBytes(b, b.length, (byte)0);
214    } // appendBytes()
215

216
217
218    /**
219     * append an array of bytes onto the end of the logical TDS packet.
220     *
221     * @param b bytes to add to the TDS packet
222     * @param len maximum number of bytes to transmit
223     * @param pad fill with this byte until len is reached
224     */

225    public void appendBytes(byte[] b, int len, byte pad)
226       throws java.io.IOException JavaDoc
227    {
228       int i = 0;
229       for (; i<b.length && i<len; i++)
230       {
231          appendByte(b[i]);
232       }
233       for (; i<len; i++)
234       {
235          appendByte(pad);
236       }
237    }
238
239
240    /**
241     * append a short int onto the end of the logical TDS packet.
242     * <p>
243     * @param s short int to add to the TDS packet
244     */

245    public void appendShort(short s)
246       throws java.io.IOException JavaDoc
247    {
248       appendByte((byte)((s>>8)&0xff));
249       appendByte((byte)((s>>0)&0xff));
250    }
251
252    /**
253     * Appends a short int onto the end of the logical TDS packet.
254     * <p>
255     * @param s short int to add to the TDS packet
256     */

257    public void appendTdsShort(short s)
258       throws java.io.IOException JavaDoc
259    {
260       appendByte((byte)((s>>0)&0xff));
261       appendByte((byte)((s>>8)&0xff));
262    }
263
264
265    /**
266     * append a Double onto the end of the logical TDS packet.
267     * <p>
268     * Append the Double value onto the end of the TDS packet as a
269     * SYBFLT8.
270     *
271     * @param value Double to add to the TDS packet
272     */

273    public void appendFlt8(Double JavaDoc value)
274       throws java.io.IOException JavaDoc
275    {
276       long l = Double.doubleToLongBits(value.doubleValue());
277
278       appendByte((byte)((l>>0)&0xff));
279       appendByte((byte)((l>>8)&0xff));
280       appendByte((byte)((l>>16)&0xff));
281       appendByte((byte)((l>>24)&0xff));
282       appendByte((byte)((l>>32)&0xff));
283       appendByte((byte)((l>>40)&0xff));
284       appendByte((byte)((l>>48)&0xff));
285       appendByte((byte)((l>>56)&0xff));
286    }
287
288    public void appendInt(int i)
289       throws java.io.IOException JavaDoc
290    {
291       appendByte((byte)((i>>24)&0xff));
292       appendByte((byte)((i>>16)&0xff));
293       appendByte((byte)((i>>8)&0xff));
294       appendByte((byte)((i>>0)&0xff));
295    }
296
297    public void appendTdsInt(int i)
298       throws java.io.IOException JavaDoc
299    {
300       appendByte((byte)((i>>0)&0xff));
301       appendByte((byte)((i>>8)&0xff));
302       appendByte((byte)((i>>16)&0xff));
303       appendByte((byte)((i>>24)&0xff));
304    }
305
306
307    public void appendInt64(long i)
308       throws java.io.IOException JavaDoc
309    {
310       appendByte((byte)((i>>56)&0xff));
311       appendByte((byte)((i>>48)&0xff));
312       appendByte((byte)((i>>40)&0xff));
313       appendByte((byte)((i>>32)&0xff));
314       appendByte((byte)((i>>24)&0xff));
315       appendByte((byte)((i>>16)&0xff));
316       appendByte((byte)((i>>8)&0xff));
317       appendByte((byte)((i>>0)&0xff));
318    }
319
320    /**
321     * Appends the 16-bit characters from the caller's string, without
322     * narrowing the characters.
323     *
324     * Sybase let's the client decide what byte order to use but it \
325     * appears that SQLServer 7.0 little-endian byte order.
326     *
327     * Added 2000-06-05
328     */

329    public void appendChars(String JavaDoc s) throws java.io.IOException JavaDoc {
330        
331        for (int i = 0; i < s.length(); ++i) {
332            int c = s.charAt(i);
333            byte b1 = (byte)(c & 0xFF);
334            byte b2 = (byte)((c >> 8) & 0xFF);
335            appendByte(b1);
336            appendByte(b2);
337        }
338    }
339
340     /*
341      * Stefan Bodewig 2000-06-21
342      *
343      * removed appendString() to keep the encoding to and from the
344      * server charset in on place - i.e. Tds.
345      *
346      * It had to be Tds as we need to specify the length for the
347      * String as well, sometimes before we send the actual data,
348      * sometimes after we've sent them.
349      *
350      * If we need to know the length beforehand in Tds, we'd have to
351      * convert the data twice, once to get the length and once to send
352      * them.
353      */

354 // public void appendString(
355
// String s,
356
// int length,
357
// byte pad)
358
// throws java.io.IOException
359
// {
360
// int i;
361
// byte dst[];
362
//
363
//
364
// dst = encoder.getBytes(s.substring(0, (length<=s.length() ? length
365
// : s.length())));
366
//
367
// for(i=0; i<dst.length; i++)
368
// {
369
// appendByte(dst[i]);
370
// }
371
//
372
// for(; i<length; i++)
373
// {
374
// appendByte(pad);
375
// }
376
// }
377

378
379    /**
380     * Send the logical packet.
381     * <p>
382     * Send the logical packet the has been constructed. */

383    public synchronized void sendPacket()
384       throws java.io.IOException JavaDoc
385    {
386       sendPhysicalPacket(true);
387       nextOutBufferIndex = 0;
388       packetType = 0;
389       notify();
390    }
391
392
393    /**
394     * store a byte of data at a particular location in the outBuffer.
395     *
396     * @param index position in outBuffer to store data
397     * @param value value to store in the outBuffer.
398     */

399    private void storeByte(
400       int index,
401       byte value)
402    {
403       outBuffer[index] = value;
404       
405    }
406
407    /**
408     * store a short integer of data at a particular location in the outBuffer.
409     *
410     * @param index position in outBuffer to store data
411     * @param value value to store in the outBuffer.
412     */

413    private void storeShort(
414       int index,
415       short s)
416    {
417       outBuffer[index] = (byte)((s>>8) & 0xff);
418       outBuffer[index+1] = (byte)((s>>0) & 0xff);
419    }
420
421
422    /**
423     * send the data in the outBuffer.
424     * <p>
425     * Fill in the TDS packet header data and send the data in outBuffer
426     * to the DB server.
427     *
428     * @param isLastSegment is this the last physical packet that makes
429     * up the physical packet?
430     */

431    private void sendPhysicalPacket(boolean isLastSegment)
432       throws java.io.IOException JavaDoc
433    {
434       if (nextOutBufferIndex>headerLength
435          || packetType == CANCEL)
436       {
437          // packet type
438
storeByte(0, (byte)(packetType & 0xff));
439          storeByte(1, isLastSegment ? (byte)1 : (byte)0);
440          storeShort(2, (short)nextOutBufferIndex);
441          storeByte(4, (byte)0);
442          storeByte(5, (byte)0);
443          storeByte(6, (byte)(tdsVer == TDS70 ? 1 : 0));
444          storeByte(7, (byte)0);
445             //Dusan
446
z++;
447 /* if (z==7) {
448             
449             storeByte(18, "1".getBytes()[0]);
450             storeByte(20, (byte)0);
451             storeByte(21, "#".getBytes()[0]);
452             storeByte(22, "1".getBytes()[0]);
453             storeByte(23, "(".getBytes()[0]);
454             storeByte(24, "@".getBytes()[0]);
455             storeByte(25, "P".getBytes()[0]);
456             storeByte(26, "1".getBytes()[0]);
457             storeByte(31, (byte)0);
458             
459 }
460 */

461          out.write(outBuffer, 0, nextOutBufferIndex);
462          packetsSent++;
463             for(int j=0; j < outBuffer.length; j++)
464             storeByte(j, (byte)0);
465
466
467          if (Logger.isActive())
468          {
469             String JavaDoc dump = HexDump.hexDump(outBuffer, nextOutBufferIndex);
470             String JavaDoc t = (new Timestamp JavaDoc(
471                System.currentTimeMillis())).toString();
472             Logger.println("Instance " + id + " @ " + t
473                            + " sent packet #" + packetsSent + "\n" + dump);
474          }
475       }
476    }
477
478    /**
479     * peek at the next byte of data.
480     * <p>
481     * This returns the next byte of data that would be returned
482     * by getByte(), but does not actually consume the data.
483     *
484     * <b>Note-</b> We can't synchronize this method (or most of the other
485     * methods in this class) because of the way cancels are handled.
486     * If a thread is waiting for a response from the server the
487     * cancelController class must be able to call sendPacket() to
488     * cancel the request.
489     *
490     * @return The next byte of data that will be returned by getByte()
491     *
492     * @exception com.internetcds.jdbc.tds.TdsException
493     * @exception java.io.IOException
494     */

495    public byte peek()
496       throws com.internetcds.jdbc.tds.TdsException,
497       java.io.IOException JavaDoc
498    {
499       
500       // XXX RACE CONDITION- It is possible that two threads
501
// could be modifying inBuffer at the same time. We need
502
// to synchronized based on inBuffer itself.
503
byte result = getByte();
504       backup();
505       return result;
506    }
507
508
509    /**
510     * put the most recently read byte of data back in the inBuffer.
511     * <p>
512     * This function effectivly ungets the last byte read.
513     * It is guaranteed to be able to unget the last byte read.
514     * Trying to unget multiple bytes is not recomended and will
515     * only work so long as all the bytes were in the same
516     * physical TDS network packet.
517     *
518     * @author Craig Spannring
519     */

520    public void backup()
521    {
522       inBufferIndex--;
523
524       // make sure we have fallen of the beginning of the buffer
525
// throw an array out of bounds error if we've gone back too far.
526
byte b = inBuffer[inBufferIndex];
527    }
528
529
530    /**
531     * read a byte of data from the DB server.
532     * <p>
533     * This will return the next byte of data from the DB server.
534     * <p>
535     * <B>Warning</B> If there is not data available this method
536     * will block.
537     */

538    public byte getByte()
539       throws com.internetcds.jdbc.tds.TdsException,
540       java.io.IOException JavaDoc
541    {
542       byte result;
543
544       if (inBufferIndex >= inBufferLen)
545       {
546          // out of data, read another physical packet.
547
getPhysicalPacket();
548       }
549
550       result = inBuffer[inBufferIndex++];
551       return result;
552    }
553
554    public byte[] getBytes(int len)
555       throws com.internetcds.jdbc.tds.TdsException,
556       java.io.IOException JavaDoc
557    {
558       byte result[] = new byte[len];
559       int i;
560
561       for(i=0; i<len; i++)
562       {
563          result[i] = getByte();
564       }
565       
566       return result;
567    }
568
569    /**
570     * Reads bytes or characters (depending on TDS version) and constructs a
571     * string with them.
572     *
573     * Sybase will let the client choose byte ordering, but SQLServer 7.0
574     * wants little endian only. In the interest of simplicity, just use
575     * little endian regardless of the type of server.
576     *
577     * Added 2000-06-05.
578     */

579    public String JavaDoc getString(int len)
580       throws com.internetcds.jdbc.tds.TdsException,
581       java.io.IOException JavaDoc
582    {
583       if (tdsVer == TDS70) {
584          char[] chars = new char[len];
585          for (int i = 0; i < len; ++i) {
586             int lo = getByte() & 0xFF;
587             int hi = getByte() & 0xFF;
588             chars[i] = (char)(lo | (hi << 8));
589          }
590          return new String JavaDoc(chars);
591       }
592       else
593          return new String JavaDoc(getBytes(len));
594    }
595
596    public void skip(int i)
597       throws com.internetcds.jdbc.tds.TdsException,
598       java.io.IOException JavaDoc
599    {
600       for(; i>0; i--)
601       {
602          getByte();
603       }
604    } // skip()
605

606    public int getNetShort()
607       throws TdsException, java.io.IOException JavaDoc
608    {
609       byte tmp[] = new byte[2];
610       tmp[0] = getByte();
611       tmp[1] = getByte();
612       return ntohs(tmp, 0);
613    }
614
615    public int getTdsShort()
616       throws com.internetcds.jdbc.tds.TdsException, java.io.IOException JavaDoc
617    {
618       int lo = ((int)getByte() & 0xff);
619       int hi = ((int)getByte() & 0xff) << 8;
620       return lo | hi;
621    }
622
623    public int getTdsInt()
624       throws com.internetcds.jdbc.tds.TdsException, java.io.IOException JavaDoc
625    {
626       int result;
627
628       int b1 = ((int)getByte() & 0xff);
629       int b2 = ((int)getByte() & 0xff) << 8;
630       int b3 = ((int)getByte() & 0xff) << 16;
631       int b4 = ((int)getByte() & 0xff) << 24;
632
633       result = b4 | b3 | b2 | b1;
634
635       return result;
636    }
637
638    public long getTdsInt64()
639       throws com.internetcds.jdbc.tds.TdsException, java.io.IOException JavaDoc
640    {
641       long b1 = ((long)getByte() & 0xff);
642       long b2 = ((long)getByte() & 0xff) << 8;
643       long b3 = ((long)getByte() & 0xff) << 16;
644       long b4 = ((long)getByte() & 0xff) << 24;
645       long b5 = ((long)getByte() & 0xff) << 32;
646       long b6 = ((long)getByte() & 0xff) << 40;
647       long b7 = ((long)getByte() & 0xff) << 48;
648       long b8 = ((long)getByte() & 0xff) << 56;
649       return b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8;
650    }
651
652
653    /**
654     * convert two bytes in a byte array into a Java short integer.
655     *
656     * @param buf array of data
657     * @param offset index into the buf array where the short integer
658     * is stored.
659     */

660    private static int ntohs(byte buf[], int offset)
661    {
662       int lo = ((int)buf[offset+1] & 0xff);
663       int hi = (((int)buf[offset] & 0xff) << 8);
664
665       return hi | lo; // return an int since we really want an _unsigned_
666
}
667
668    /**
669     * Read a physical packet.
670     * <p>
671     * <B>Warning</B> This method will block until it gets all of the input.
672     */

673    private void getPhysicalPacket()
674       throws TdsException, java.io.IOException JavaDoc
675    {
676       byte tmpBuf[] = new byte[8];
677
678
679       // read the header
680
for (int nread = 0; nread < 8; )
681       {
682          nread += in.read(tmpBuf, nread, 8 - nread);
683       }
684       if (Logger.isActive())
685       {
686          String JavaDoc dump = com.internetcds.util.HexDump.hexDump(tmpBuf, 8);
687          String JavaDoc t = (new Timestamp JavaDoc(
688             System.currentTimeMillis())).toString();
689
690          Logger.println("Instance " + id + " @ " + t
691                         + " recevied header #" + (packetsReceived+1)
692                         + "\n" + dump);
693       }
694       byte packetType = tmpBuf[0];
695       if (packetType!=LOGON
696           && packetType!=QUERY
697           && packetType!=REPLY)
698       {
699          throw new TdsUnknownPacketType(packetType, tmpBuf);
700       }
701       // figure out how many bytes are remaining in this packet.
702
int len = ntohs(tmpBuf, 2) - 8;
703       // Added 2000-06-05
704
if (len >= inBuffer.length)
705       {
706           inBuffer = new byte[len];
707       }
708       if (len < 0)
709       {
710          throw new TdsException("Confused by a length of " + len);
711       }
712
713       // now get the data
714
for (int nread = 0; nread < len; )
715       {
716             //Dusan1
717

718          nread += in.read(inBuffer, nread, len - nread);
719       }
720       packetsReceived++;
721
722
723       // adjust the bookkeeping info about the incoming buffer
724
inBufferLen = len;
725       inBufferIndex = 0;
726
727       if (Logger.isActive())
728       {
729          String JavaDoc dump = com.internetcds.util.HexDump.hexDump(inBuffer, len);
730          String JavaDoc t = (new Timestamp JavaDoc(
731             System.currentTimeMillis())).toString();
732
733          Logger.println("Instance " + id + " @ " + t
734                         + " recevied data #" + (packetsReceived)
735                         + "\n" + dump);
736       }
737    }
738 }
739
740
Popular Tags