1
17 package org.apache.tomcat.util.net;
18
19 import java.nio.BufferOverflowException;
20 import java.nio.ByteBuffer;
21
22 import org.apache.tomcat.util.buf.ByteBufferUtils;
23
24 public class SocketBufferHandler {
25
26 static SocketBufferHandler EMPTY = new SocketBufferHandler(0, 0, false) {
27 @Override
28 public void expand(int newSize) {
29 }
30 };
31
32 private volatile boolean readBufferConfiguredForWrite = true;
33 private volatile ByteBuffer readBuffer;
34
35 private volatile boolean writeBufferConfiguredForWrite = true;
36 private volatile ByteBuffer writeBuffer;
37
38 private final boolean direct;
39
40 public SocketBufferHandler(int readBufferSize, int writeBufferSize,
41 boolean direct) {
42 this.direct = direct;
43 if (direct) {
44 readBuffer = ByteBuffer.allocateDirect(readBufferSize);
45 writeBuffer = ByteBuffer.allocateDirect(writeBufferSize);
46 } else {
47 readBuffer = ByteBuffer.allocate(readBufferSize);
48 writeBuffer = ByteBuffer.allocate(writeBufferSize);
49 }
50 }
51
52
53 public void configureReadBufferForWrite() {
54 setReadBufferConfiguredForWrite(true);
55 }
56
57
58 public void configureReadBufferForRead() {
59 setReadBufferConfiguredForWrite(false);
60 }
61
62
63 private void setReadBufferConfiguredForWrite(boolean readBufferConFiguredForWrite) {
64
65 if (this.readBufferConfiguredForWrite != readBufferConFiguredForWrite) {
66 if (readBufferConFiguredForWrite) {
67
68 int remaining = readBuffer.remaining();
69 if (remaining == 0) {
70 readBuffer.clear();
71 } else {
72 readBuffer.compact();
73 }
74 } else {
75
76 readBuffer.flip();
77 }
78 this.readBufferConfiguredForWrite = readBufferConFiguredForWrite;
79 }
80 }
81
82
83 public ByteBuffer getReadBuffer() {
84 return readBuffer;
85 }
86
87
88 public boolean isReadBufferEmpty() {
89 if (readBufferConfiguredForWrite) {
90 return readBuffer.position() == 0;
91 } else {
92 return readBuffer.remaining() == 0;
93 }
94 }
95
96
97 public void unReadReadBuffer(ByteBuffer returnedData) {
98 if (isReadBufferEmpty()) {
99 configureReadBufferForWrite();
100 readBuffer.put(returnedData);
101 } else {
102 int bytesReturned = returnedData.remaining();
103 if (readBufferConfiguredForWrite) {
104
105 if ((readBuffer.position() + bytesReturned) > readBuffer.capacity()) {
106 throw new BufferOverflowException();
107 } else {
108
109 for (int i = 0; i < readBuffer.position(); i++) {
110 readBuffer.put(i + bytesReturned, readBuffer.get(i));
111 }
112
113 for (int i = 0; i < bytesReturned; i++) {
114 readBuffer.put(i, returnedData.get());
115 }
116
117 readBuffer.position(readBuffer.position() + bytesReturned);
118 }
119 } else {
120
121 int shiftRequired = bytesReturned - readBuffer.position();
122 if (shiftRequired > 0) {
123 if ((readBuffer.capacity() - readBuffer.limit()) < shiftRequired) {
124 throw new BufferOverflowException();
125 }
126
127 int oldLimit = readBuffer.limit();
128 readBuffer.limit(oldLimit + shiftRequired);
129 for (int i = readBuffer.position(); i < oldLimit; i++) {
130 readBuffer.put(i + shiftRequired, readBuffer.get(i));
131 }
132 } else {
133 shiftRequired = 0;
134 }
135
136 int insertOffset = readBuffer.position() + shiftRequired - bytesReturned;
137 for (int i = insertOffset; i < bytesReturned + insertOffset; i++) {
138 readBuffer.put(i, returnedData.get());
139 }
140 readBuffer.position(insertOffset);
141 }
142 }
143 }
144
145
146 public void configureWriteBufferForWrite() {
147 setWriteBufferConfiguredForWrite(true);
148 }
149
150
151 public void configureWriteBufferForRead() {
152 setWriteBufferConfiguredForWrite(false);
153 }
154
155
156 private void setWriteBufferConfiguredForWrite(boolean writeBufferConfiguredForWrite) {
157
158 if (this.writeBufferConfiguredForWrite != writeBufferConfiguredForWrite) {
159 if (writeBufferConfiguredForWrite) {
160
161 int remaining = writeBuffer.remaining();
162 if (remaining == 0) {
163 writeBuffer.clear();
164 } else {
165 writeBuffer.compact();
166 writeBuffer.position(remaining);
167 writeBuffer.limit(writeBuffer.capacity());
168 }
169 } else {
170
171 writeBuffer.flip();
172 }
173 this.writeBufferConfiguredForWrite = writeBufferConfiguredForWrite;
174 }
175 }
176
177
178 public boolean isWriteBufferWritable() {
179 if (writeBufferConfiguredForWrite) {
180 return writeBuffer.hasRemaining();
181 } else {
182 return writeBuffer.remaining() == 0;
183 }
184 }
185
186
187 public ByteBuffer getWriteBuffer() {
188 return writeBuffer;
189 }
190
191
192 public boolean isWriteBufferEmpty() {
193 if (writeBufferConfiguredForWrite) {
194 return writeBuffer.position() == 0;
195 } else {
196 return writeBuffer.remaining() == 0;
197 }
198 }
199
200
201 public void reset() {
202 readBuffer.clear();
203 readBufferConfiguredForWrite = true;
204 writeBuffer.clear();
205 writeBufferConfiguredForWrite = true;
206 }
207
208
209 public void expand(int newSize) {
210 configureReadBufferForWrite();
211 readBuffer = ByteBufferUtils.expand(readBuffer, newSize);
212 configureWriteBufferForWrite();
213 writeBuffer = ByteBufferUtils.expand(writeBuffer, newSize);
214 }
215
216 public void free() {
217 if (direct) {
218 ByteBufferUtils.cleanDirectBuffer(readBuffer);
219 ByteBufferUtils.cleanDirectBuffer(writeBuffer);
220 }
221 }
222
223 }
224