001 /**
002 * Copyright (C) 2009-2013 Barchart, Inc. <http://www.barchart.com/>
003 *
004 * All rights reserved. Licensed under the OSI BSD License.
005 *
006 * http://www.opensource.org/licenses/bsd-license.php
007 */
008 package com.barchart.udt.net;
009
010 import java.io.IOException;
011 import java.io.InputStream;
012 import java.nio.channels.IllegalBlockingModeException;
013
014 import com.barchart.udt.ErrorUDT;
015 import com.barchart.udt.SocketUDT;
016
017 /**
018 * {@link InputStream} implementation for UDT sockets.
019 */
020 public class NetInputStreamUDT extends InputStream {
021
022 protected final SocketUDT socketUDT;
023
024 /**
025 *
026 * @param socketUDT
027 * The UDT socket.
028 */
029 public NetInputStreamUDT(final SocketUDT socketUDT) {
030
031 if (!socketUDT.isBlocking()) {
032 throw new IllegalBlockingModeException();
033 }
034
035 this.socketUDT = socketUDT;
036
037 }
038
039 @Override
040 public int read() throws IOException {
041
042 /*
043 * Here's the contract from the JavaDoc on this for SocketChannel:
044 *
045 * A read operation might not fill the buffer, and in fact it might not
046 * read any bytes at all. Whether or not it does so depends upon the
047 * nature and state of the channel. A socket channel in non-blocking
048 * mode, for example, cannot read any more bytes than are immediately
049 * available from the socket's input buffer; similarly, a file channel
050 * cannot read any more bytes than remain in the file. It is guaranteed,
051 * however, that if a channel is in blocking mode and there is at least
052 * one byte remaining in the buffer then this method will block until at
053 * least one byte is read.
054 *
055 * Long story short: This UDT InputStream should only ever be created
056 * when the SocketChannel's in blocking mode, and when it's in blocking
057 * mode the SocketChannel read call below will block just like we need
058 * it too.
059 */
060
061 final byte[] data = new byte[1];
062
063 final int count = read(data);
064
065 assert count == 1;
066
067 return data[0];
068
069 }
070
071 @Override
072 public int read(final byte[] bytes) throws IOException {
073
074 return read(bytes, 0, bytes.length);
075
076 }
077
078 @SuppressWarnings("serial")
079 @Override
080 public int read(final byte[] bytes, final int off, final int len)
081 throws IOException {
082
083 final int count = socketUDT.receive(bytes, off, off + len);
084
085 if (count > 0) {
086 assert count <= len;
087 return count;
088 }
089
090 if (count == 0) {
091 throw new ExceptionReceiveUDT(socketUDT.id(),
092 ErrorUDT.USER_DEFINED_MESSAGE, "UDT receive time out") {
093 };
094 }
095
096 throw new IllegalStateException("should not happen");
097
098 }
099
100 @Override
101 public void close() throws IOException {
102 socketUDT.close();
103 }
104
105 @Override
106 public int available() throws IOException {
107 // This is the default InputStream return value.
108 // The java/net/SocketInputStream.java implementation delegates to
109 // the native implementation, which returns 0 on at least some OSes.
110 return 0;
111 }
112
113 @Override
114 public long skip(final long numbytes) throws IOException {
115 if (numbytes <= 0) {
116 return 0;
117 }
118 long n = numbytes;
119 final int buflen = (int) Math.min(1024, n);
120 final byte data[] = new byte[buflen];
121 while (n > 0) {
122 final int r = read(data, 0, (int) Math.min(buflen, n));
123 if (r < 0) {
124 break;
125 }
126 n -= r;
127 }
128 return numbytes - n;
129 }
130
131 @Override
132 public void mark(final int readlimit) {
133 throw new UnsupportedOperationException("mark not supported");
134 }
135
136 @Override
137 public void reset() throws IOException {
138 throw new UnsupportedOperationException("reset not supported");
139 }
140
141 @Override
142 public boolean markSupported() {
143 return false;
144 }
145
146 }