File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\value\Transfer.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.value;
8
9 import java.io.BufferedInputStream;
10 import java.io.BufferedOutputStream;
11 import java.io.DataInputStream;
12 import java.io.DataOutputStream;
13 import java.io.IOException;
14 import java.io.Reader;
15 import java.math.BigDecimal;
16 import java.net.InetAddress;
17 import java.net.Socket;
18 import java.sql.Date;
19 import java.sql.ResultSet;
20 import java.sql.ResultSetMetaData;
21 import java.sql.SQLException;
22 import java.sql.Time;
23 import java.sql.Timestamp;
24 import org.h2.constant.ErrorCode;
25 import org.h2.engine.Constants;
26 import org.h2.engine.SessionInterface;
27 import org.h2.message.DbException;
28 import org.h2.message.TraceSystem;
29 import org.h2.security.SHA256;
30 import org.h2.store.Data;
31 import org.h2.store.DataReader;
32 import org.h2.tools.SimpleResultSet;
33 import org.h2.util.DateTimeUtils;
34 import org.h2.util.IOUtils;
35 import org.h2.util.MathUtils;
36 import org.h2.util.NetUtils;
37 import org.h2.util.StringUtils;
38 import org.h2.util.Utils;
39
40 /**
41 * The transfer class is used to send and receive Value objects.
42 * It is used on both the client side, and on the server side.
43 */
44 public class Transfer {
45
46 private static final int BUFFER_SIZE = 16 * 1024;
47 private static final int LOB_MAGIC = 0x1234;
48 private static final int LOB_MAC_SALT_LENGTH = 16;
49
50 private Socket socket;
51 private DataInputStream in;
52 private DataOutputStream out;
53 private SessionInterface session;
54 private boolean ssl;
55 private int version;
56 private byte[] lobMacSalt;
57
58 /**
59 * Create a new transfer object for the specified session.
60 *
61 * @param session the session
62 */
63 public Transfer(SessionInterface session) {
64 this.session = session;
65 }
66
67 /**
68 * Set the socket this object uses.
69 *
70 * @param s the socket
71 */
72 public void setSocket(Socket s) {
73 socket = s;
74 }
75
76 /**
77 * Initialize the transfer object. This method will try to open an input and
78 * output stream.
79 */
80 public synchronized void init() throws IOException {
81 if (socket != null) {
82 in = new DataInputStream(new BufferedInputStream(socket.getInputStream(), Transfer.BUFFER_SIZE));
83 out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), Transfer.BUFFER_SIZE));
84 }
85 }
86
87 /**
88 * Write pending changes.
89 */
90 public void flush() throws IOException {
91 out.flush();
92 }
93
94 /**
95 * Write a boolean.
96 *
97 * @param x the value
98 * @return itself
99 */
100 public Transfer writeBoolean(boolean x) throws IOException {
101 out.writeByte((byte) (x ? 1 : 0));
102 return this;
103 }
104
105 /**
106 * Read a boolean.
107 *
108 * @return the value
109 */
110 public boolean readBoolean() throws IOException {
111 return in.readByte() == 1;
112 }
113
114 /**
115 * Write a byte.
116 *
117 * @param x the value
118 * @return itself
119 */
120 private Transfer writeByte(byte x) throws IOException {
121 out.writeByte(x);
122 return this;
123 }
124
125 /**
126 * Read a byte.
127 *
128 * @return the value
129 */
130 private byte readByte() throws IOException {
131 return in.readByte();
132 }
133
134 /**
135 * Write an int.
136 *
137 * @param x the value
138 * @return itself
139 */
140 public Transfer writeInt(int x) throws IOException {
141 out.writeInt(x);
142 return this;
143 }
144
145 /**
146 * Read an int.
147 *
148 * @return the value
149 */
150 public int readInt() throws IOException {
151 return in.readInt();
152 }
153
154 /**
155 * Write a long.
156 *
157 * @param x the value
158 * @return itself
159 */
160 public Transfer writeLong(long x) throws IOException {
161 out.writeLong(x);
162 return this;
163 }
164
165 /**
166 * Read a long.
167 *
168 * @return the value
169 */
170 public long readLong() throws IOException {
171 return in.readLong();
172 }
173
174 /**
175 * Write a double.
176 *
177 * @param i the value
178 * @return itself
179 */
180 private Transfer writeDouble(double i) throws IOException {
181 out.writeDouble(i);
182 return this;
183 }
184
185 /**
186 * Write a float.
187 *
188 * @param i the value
189 * @return itself
190 */
191 private Transfer writeFloat(float i) throws IOException {
192 out.writeFloat(i);
193 return this;
194 }
195
196 /**
197 * Read a double.
198 *
199 * @return the value
200 */
201 private double readDouble() throws IOException {
202 return in.readDouble();
203 }
204
205 /**
206 * Read a float.
207 *
208 * @return the value
209 */
210 private float readFloat() throws IOException {
211 return in.readFloat();
212 }
213
214 /**
215 * Write a string. The maximum string length is Integer.MAX_VALUE.
216 *
217 * @param s the value
218 * @return itself
219 */
220 public Transfer writeString(String s) throws IOException {
221 if (s == null) {
222 out.writeInt(-1);
223 } else {
224 int len = s.length();
225 out.writeInt(len);
226 for (int i = 0; i < len; i++) {
227 out.writeChar(s.charAt(i));
228 }
229 }
230 return this;
231 }
232
233 /**
234 * Read a string.
235 *
236 * @return the value
237 */
238 public String readString() throws IOException {
239 int len = in.readInt();
240 if (len == -1) {
241 return null;
242 }
243 StringBuilder buff = new StringBuilder(len);
244 for (int i = 0; i < len; i++) {
245 buff.append(in.readChar());
246 }
247 String s = buff.toString();
248 s = StringUtils.cache(s);
249 return s;
250 }
251
252 /**
253 * Write a byte array.
254 *
255 * @param data the value
256 * @return itself
257 */
258 public Transfer writeBytes(byte[] data) throws IOException {
259 if (data == null) {
260 writeInt(-1);
261 } else {
262 writeInt(data.length);
263 out.write(data);
264 }
265 return this;
266 }
267
268 /**
269 * Write a number of bytes.
270 *
271 * @param buff the value
272 * @param off the offset
273 * @param len the length
274 * @return itself
275 */
276 public Transfer writeBytes(byte[] buff, int off, int len) throws IOException {
277 out.write(buff, off, len);
278 return this;
279 }
280
281 /**
282 * Read a byte array.
283 *
284 * @return the value
285 */
286 public byte[] readBytes() throws IOException {
287 int len = readInt();
288 if (len == -1) {
289 return null;
290 }
291 byte[] b = Utils.newBytes(len);
292 in.readFully(b);
293 return b;
294 }
295
296 /**
297 * Read a number of bytes.
298 *
299 * @param buff the target buffer
300 * @param off the offset
301 * @param len the number of bytes to read
302 */
303 public void readBytes(byte[] buff, int off, int len) throws IOException {
304 in.readFully(buff, off, len);
305 }
306
307 /**
308 * Close the transfer object and the socket.
309 */
310 public synchronized void close() {
311 if (socket != null) {
312 try {
313 if (out != null) {
314 out.flush();
315 }
316 if (socket != null) {
317 socket.close();
318 }
319 } catch (IOException e) {
320 TraceSystem.traceThrowable(e);
321 } finally {
322 socket = null;
323 }
324 }
325 }
326
327 /**
328 * Write a value.
329 *
330 * @param v the value
331 */
332 public void writeValue(Value v) throws IOException {
333 int type = v.getType();
334 writeInt(type);
335 switch (type) {
336 case Value.NULL:
337 break;
338 case Value.BYTES:
339 case Value.JAVA_OBJECT:
340 writeBytes(v.getBytesNoCopy());
341 break;
342 case Value.UUID: {
343 ValueUuid uuid = (ValueUuid) v;
344 writeLong(uuid.getHigh());
345 writeLong(uuid.getLow());
346 break;
347 }
348 case Value.BOOLEAN:
349 writeBoolean(v.getBoolean().booleanValue());
350 break;
351 case Value.BYTE:
352 writeByte(v.getByte());
353 break;
354 case Value.TIME:
355 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
356 writeLong(((ValueTime) v).getNanos());
357 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
358 writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
359 } else {
360 writeLong(v.getTime().getTime());
361 }
362 break;
363 case Value.DATE:
364 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
365 writeLong(((ValueDate) v).getDateValue());
366 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
367 writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getDate()));
368 } else {
369 writeLong(v.getDate().getTime());
370 }
371 break;
372 case Value.TIMESTAMP: {
373 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
374 ValueTimestamp ts = (ValueTimestamp) v;
375 writeLong(ts.getDateValue());
376 writeLong(ts.getNanos());
377 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
378 Timestamp ts = v.getTimestamp();
379 writeLong(DateTimeUtils.getTimeLocalWithoutDst(ts));
380 writeInt(ts.getNanos());
381 } else {
382 Timestamp ts = v.getTimestamp();
383 writeLong(ts.getTime());
384 writeInt(ts.getNanos());
385 }
386 break;
387 }
388 case Value.DECIMAL:
389 writeString(v.getString());
390 break;
391 case Value.DOUBLE:
392 writeDouble(v.getDouble());
393 break;
394 case Value.FLOAT:
395 writeFloat(v.getFloat());
396 break;
397 case Value.INT:
398 writeInt(v.getInt());
399 break;
400 case Value.LONG:
401 writeLong(v.getLong());
402 break;
403 case Value.SHORT:
404 writeInt(v.getShort());
405 break;
406 case Value.STRING:
407 case Value.STRING_IGNORECASE:
408 case Value.STRING_FIXED:
409 writeString(v.getString());
410 break;
411 case Value.BLOB: {
412 if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
413 if (v instanceof ValueLobDb) {
414 ValueLobDb lob = (ValueLobDb) v;
415 if (lob.isStored()) {
416 writeLong(-1);
417 writeInt(lob.getTableId());
418 writeLong(lob.getLobId());
419 if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
420 writeBytes(calculateLobMac(lob.getLobId()));
421 }
422 writeLong(lob.getPrecision());
423 break;
424 }
425 }
426 }
427 long length = v.getPrecision();
428 if (length < 0) {
429 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "length=" + length);
430 }
431 writeLong(length);
432 long written = IOUtils.copyAndCloseInput(v.getInputStream(), out);
433 if (written != length) {
434 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "length:" + length + " written:" + written);
435 }
436 writeInt(LOB_MAGIC);
437 break;
438 }
439 case Value.CLOB: {
440 if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
441 if (v instanceof ValueLobDb) {
442 ValueLobDb lob = (ValueLobDb) v;
443 if (lob.isStored()) {
444 writeLong(-1);
445 writeInt(lob.getTableId());
446 writeLong(lob.getLobId());
447 if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
448 writeBytes(calculateLobMac(lob.getLobId()));
449 }
450 writeLong(lob.getPrecision());
451 break;
452 }
453 }
454 }
455 long length = v.getPrecision();
456 if (length < 0) {
457 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "length=" + length);
458 }
459 writeLong(length);
460 Reader reader = v.getReader();
461 Data.copyString(reader, out);
462 writeInt(LOB_MAGIC);
463 break;
464 }
465 case Value.ARRAY: {
466 ValueArray va = (ValueArray) v;
467 Value[] list = va.getList();
468 int len = list.length;
469 Class<?> componentType = va.getComponentType();
470 if (componentType == Object.class) {
471 writeInt(len);
472 } else {
473 writeInt(-(len + 1));
474 writeString(componentType.getName());
475 }
476 for (Value value : list) {
477 writeValue(value);
478 }
479 break;
480 }
481 case Value.RESULT_SET: {
482 try {
483 ResultSet rs = ((ValueResultSet) v).getResultSet();
484 rs.beforeFirst();
485 ResultSetMetaData meta = rs.getMetaData();
486 int columnCount = meta.getColumnCount();
487 writeInt(columnCount);
488 for (int i = 0; i < columnCount; i++) {
489 writeString(meta.getColumnName(i + 1));
490 writeInt(meta.getColumnType(i + 1));
491 writeInt(meta.getPrecision(i + 1));
492 writeInt(meta.getScale(i + 1));
493 }
494 while (rs.next()) {
495 writeBoolean(true);
496 for (int i = 0; i < columnCount; i++) {
497 int t = DataType.convertSQLTypeToValueType(meta.getColumnType(i + 1));
498 Value val = DataType.readValue(session, rs, i + 1, t);
499 writeValue(val);
500 }
501 }
502 writeBoolean(false);
503 rs.beforeFirst();
504 } catch (SQLException e) {
505 throw DbException.convertToIOException(e);
506 }
507 break;
508 }
509 default:
510 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "type=" + type);
511 }
512 }
513
514 /**
515 * Read a value.
516 *
517 * @return the value
518 */
519 public Value readValue() throws IOException {
520 int type = readInt();
521 switch(type) {
522 case Value.NULL:
523 return ValueNull.INSTANCE;
524 case Value.BYTES:
525 return ValueBytes.getNoCopy(readBytes());
526 case Value.UUID:
527 return ValueUuid.get(readLong(), readLong());
528 case Value.JAVA_OBJECT:
529 return ValueJavaObject.getNoCopy(null, readBytes());
530 case Value.BOOLEAN:
531 return ValueBoolean.get(readBoolean());
532 case Value.BYTE:
533 return ValueByte.get(readByte());
534 case Value.DATE:
535 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
536 return ValueDate.fromDateValue(readLong());
537 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
538 return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
539 }
540 return ValueDate.get(new Date(readLong()));
541 case Value.TIME:
542 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
543 return ValueTime.fromNanos(readLong());
544 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
545 return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
546 }
547 return ValueTime.get(new Time(readLong()));
548 case Value.TIMESTAMP: {
549 if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
550 return ValueTimestamp.fromDateValueAndNanos(readLong(), readLong());
551 } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
552 Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readLong()));
553 ts.setNanos(readInt());
554 return ValueTimestamp.get(ts);
555 }
556 Timestamp ts = new Timestamp(readLong());
557 ts.setNanos(readInt());
558 return ValueTimestamp.get(ts);
559 }
560 case Value.DECIMAL:
561 return ValueDecimal.get(new BigDecimal(readString()));
562 case Value.DOUBLE:
563 return ValueDouble.get(readDouble());
564 case Value.FLOAT:
565 return ValueFloat.get(readFloat());
566 case Value.INT:
567 return ValueInt.get(readInt());
568 case Value.LONG:
569 return ValueLong.get(readLong());
570 case Value.SHORT:
571 return ValueShort.get((short) readInt());
572 case Value.STRING:
573 return ValueString.get(readString());
574 case Value.STRING_IGNORECASE:
575 return ValueStringIgnoreCase.get(readString());
576 case Value.STRING_FIXED:
577 return ValueStringFixed.get(readString());
578 case Value.BLOB: {
579 long length = readLong();
580 if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
581 if (length == -1) {
582 int tableId = readInt();
583 long id = readLong();
584 byte[] hmac;
585 if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
586 hmac = readBytes();
587 } else {
588 hmac = null;
589 }
590 long precision = readLong();
591 return ValueLobDb.create(Value.BLOB, session.getDataHandler().getLobStorage(), tableId, id, hmac, precision);
592 }
593 int len = (int) length;
594 byte[] small = new byte[len];
595 IOUtils.readFully(in, small, 0, len);
596 int magic = readInt();
597 if (magic != LOB_MAGIC) {
598 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
599 }
600 return ValueLobDb.createSmallLob(Value.BLOB, small, length);
601 }
602 Value v = session.getDataHandler().getLobStorage().createBlob(in, length);
603 int magic = readInt();
604 if (magic != LOB_MAGIC) {
605 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
606 }
607 return v;
608 }
609 case Value.CLOB: {
610 long length = readLong();
611 if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
612 if (length == -1) {
613 int tableId = readInt();
614 long id = readLong();
615 byte[] hmac;
616 if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
617 hmac = readBytes();
618 } else {
619 hmac = null;
620 }
621 long precision = readLong();
622 return ValueLobDb.create(Value.CLOB, session.getDataHandler().getLobStorage(), tableId, id, hmac, precision);
623 }
624 DataReader reader = new DataReader(in);
625 int len = (int) length;
626 char[] buff = new char[len];
627 IOUtils.readFully(reader, buff, len);
628 int magic = readInt();
629 if (magic != LOB_MAGIC) {
630 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
631 }
632 byte[] small = new String(buff).getBytes("UTF-8");
633 return ValueLobDb.createSmallLob(Value.CLOB, small, length);
634 }
635 Value v = session.getDataHandler().getLobStorage().createClob(new DataReader(in), length);
636 int magic = readInt();
637 if (magic != LOB_MAGIC) {
638 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
639 }
640 return v;
641 }
642 case Value.ARRAY: {
643 int len = readInt();
644 Class<?> componentType = Object.class;
645 if (len < 0) {
646 len = -(len + 1);
647 componentType = Utils.loadUserClass(readString());
648 }
649 Value[] list = new Value[len];
650 for (int i = 0; i < len; i++) {
651 list[i] = readValue();
652 }
653 return ValueArray.get(componentType, list);
654 }
655 case Value.RESULT_SET: {
656 SimpleResultSet rs = new SimpleResultSet();
657 int columns = readInt();
658 for (int i = 0; i < columns; i++) {
659 rs.addColumn(readString(), readInt(), readInt(), readInt());
660 }
661 while (true) {
662 if (!readBoolean()) {
663 break;
664 }
665 Object[] o = new Object[columns];
666 for (int i = 0; i < columns; i++) {
667 o[i] = readValue().getObject();
668 }
669 rs.addRow(o);
670 }
671 return ValueResultSet.get(rs);
672 }
673 default:
674 throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "type=" + type);
675 }
676 }
677
678 /**
679 * Get the socket.
680 *
681 * @return the socket
682 */
683 public Socket getSocket() {
684 return socket;
685 }
686
687 /**
688 * Set the session.
689 *
690 * @param session the session
691 */
692 public void setSession(SessionInterface session) {
693 this.session = session;
694 }
695
696 /**
697 * Enable or disable SSL.
698 *
699 * @param ssl the new value
700 */
701 public void setSSL(boolean ssl) {
702 this.ssl = ssl;
703 }
704
705 /**
706 * Open a new new connection to the same address and port as this one.
707 *
708 * @return the new transfer object
709 */
710 public Transfer openNewConnection() throws IOException {
711 InetAddress address = socket.getInetAddress();
712 int port = socket.getPort();
713 Socket s2 = NetUtils.createSocket(address, port, ssl);
714 Transfer trans = new Transfer(null);
715 trans.setSocket(s2);
716 trans.setSSL(ssl);
717 return trans;
718 }
719
720 public void setVersion(int version) {
721 this.version = version;
722 }
723
724 public synchronized boolean isClosed() {
725 return socket == null || socket.isClosed();
726 }
727
728 /**
729 * Verify the HMAC.
730 *
731 * @param hmac the message authentication code
732 * @param lobId the lobId
733 * @throws DbException if the HMAC does not match
734 */
735 public void verifyLobMac(byte[] hmac, long lobId) {
736 byte[] result = calculateLobMac(lobId);
737 if (!Utils.compareSecure(hmac, result)) {
738 throw DbException.get(ErrorCode.REMOTE_CONNECTION_NOT_ALLOWED);
739 }
740 }
741
742 private byte[] calculateLobMac(long lobId) {
743 if (lobMacSalt == null) {
744 lobMacSalt = MathUtils.secureRandomBytes(LOB_MAC_SALT_LENGTH);
745 }
746 byte[] data = new byte[8];
747 Utils.writeLong(data, 0, lobId);
748 byte[] hmacData = SHA256.getHashWithSalt(data, lobMacSalt);
749 return hmacData;
750 }
751
752 }
753