View Javadoc
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; 41 42 /*** 43 * Handle the communications for a Tds instance. 44 * 45 * @version $Id: TdsComm.java,v 1.1 2003/04/29 18:07:53 sinisa Exp $ 46 * @author Craig Spannring 47 * @author Igor Petrovski 48 */ 49 public class TdsComm implements TdsDefinitions 50 { 51 public static final String cvsVersion = "$Id: TdsComm.java,v 1.1 2003/04/29 18:07:53 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 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 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 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 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 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 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 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 value) 274 throws java.io.IOException 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 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 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 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 s) throws java.io.IOException { 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 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 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 dump = HexDump.hexDump(outBuffer, nextOutBufferIndex); 470 String t = (new Timestamp( 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 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 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 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 getString(int len) 580 throws com.internetcds.jdbc.tds.TdsException, 581 java.io.IOException 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(chars); 591 } 592 else 593 return new String(getBytes(len)); 594 } 595 596 public void skip(int i) 597 throws com.internetcds.jdbc.tds.TdsException, 598 java.io.IOException 599 { 600 for(; i>0; i--) 601 { 602 getByte(); 603 } 604 } // skip() 605 606 public int getNetShort() 607 throws TdsException, java.io.IOException 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 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 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 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 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 dump = com.internetcds.util.HexDump.hexDump(tmpBuf, 8); 687 String t = (new Timestamp( 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 dump = com.internetcds.util.HexDump.hexDump(inBuffer, len); 730 String t = (new Timestamp( 731 System.currentTimeMillis())).toString(); 732 733 Logger.println("Instance " + id + " @ " + t 734 + " recevied data #" + (packetsReceived) 735 + "\n" + dump); 736 } 737 } 738 } 739

This page was automatically generated by Maven