1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.unix;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.ChannelOutboundBuffer.MessageProcessor;
21 import io.netty.util.internal.PlatformDependent;
22
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25
26 import static io.netty.channel.unix.Limits.IOV_MAX;
27 import static io.netty.channel.unix.Limits.SSIZE_MAX;
28 import static io.netty.util.internal.ObjectUtil.checkPositive;
29 import static java.lang.Math.min;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public final class IovArray implements MessageProcessor {
49
50
51 private static final int ADDRESS_SIZE = Buffer.addressSize();
52
53
54
55
56
57 public static final int IOV_SIZE = 2 * ADDRESS_SIZE;
58
59
60
61
62
63 private static final int MAX_CAPACITY = IOV_MAX * IOV_SIZE;
64
65 private final long memoryAddress;
66 private final ByteBuf memory;
67 private int count;
68 private long size;
69 private long maxBytes = SSIZE_MAX;
70
71 public IovArray() {
72 this(Unpooled.wrappedBuffer(Buffer.allocateDirectWithNativeOrder(MAX_CAPACITY)).setIndex(0, 0));
73 }
74
75 @SuppressWarnings("deprecation")
76 public IovArray(ByteBuf memory) {
77 assert memory.writerIndex() == 0;
78 assert memory.readerIndex() == 0;
79 this.memory = PlatformDependent.hasUnsafe() ? memory : memory.order(
80 PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
81 if (memory.hasMemoryAddress()) {
82 memoryAddress = memory.memoryAddress();
83 } else {
84
85 memoryAddress = Buffer.memoryAddress(memory.internalNioBuffer(0, memory.capacity()));
86 }
87 }
88
89 public void clear() {
90 count = 0;
91 size = 0;
92 }
93
94
95
96
97 @Deprecated
98 public boolean add(ByteBuf buf) {
99 return add(buf, buf.readerIndex(), buf.readableBytes());
100 }
101
102 public boolean add(ByteBuf buf, int offset, int len) {
103 if (count == IOV_MAX) {
104
105 return false;
106 }
107 if (buf.nioBufferCount() == 1) {
108 if (len == 0) {
109 return true;
110 }
111 if (buf.hasMemoryAddress()) {
112 return add(memoryAddress, buf.memoryAddress() + offset, len);
113 } else {
114 ByteBuffer nioBuffer = buf.internalNioBuffer(offset, len);
115 return add(memoryAddress, Buffer.memoryAddress(nioBuffer) + nioBuffer.position(), len);
116 }
117 } else {
118 ByteBuffer[] buffers = buf.nioBuffers(offset, len);
119 for (ByteBuffer nioBuffer : buffers) {
120 final int remaining = nioBuffer.remaining();
121 if (remaining != 0 &&
122 (!add(memoryAddress, Buffer.memoryAddress(nioBuffer) + nioBuffer.position(), remaining)
123 || count == IOV_MAX)) {
124 return false;
125 }
126 }
127 return true;
128 }
129 }
130
131
132
133
134
135
136 public boolean isFull() {
137 return memory.capacity() < (count + 1) * IOV_SIZE || size >= maxBytes;
138 }
139
140 private boolean add(long memoryAddress, long addr, int len) {
141 assert addr != 0;
142
143
144
145 if ((maxBytes - len < size && count > 0) ||
146
147 memory.capacity() < (count + 1) * IOV_SIZE) {
148
149
150
151
152
153
154 return false;
155 }
156 final int baseOffset = idx(count);
157 final int lengthOffset = baseOffset + ADDRESS_SIZE;
158
159 size += len;
160 ++count;
161
162 if (ADDRESS_SIZE == 8) {
163
164 if (PlatformDependent.hasUnsafe()) {
165 PlatformDependent.putLong(baseOffset + memoryAddress, addr);
166 PlatformDependent.putLong(lengthOffset + memoryAddress, len);
167 } else {
168 memory.setLong(baseOffset, addr);
169 memory.setLong(lengthOffset, len);
170 }
171 } else {
172 assert ADDRESS_SIZE == 4;
173 if (PlatformDependent.hasUnsafe()) {
174 PlatformDependent.putInt(baseOffset + memoryAddress, (int) addr);
175 PlatformDependent.putInt(lengthOffset + memoryAddress, len);
176 } else {
177 memory.setInt(baseOffset, (int) addr);
178 memory.setInt(lengthOffset, len);
179 }
180 }
181 return true;
182 }
183
184
185
186
187 public int count() {
188 return count;
189 }
190
191
192
193
194 public long size() {
195 return size;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 public void maxBytes(long maxBytes) {
209 this.maxBytes = min(SSIZE_MAX, checkPositive(maxBytes, "maxBytes"));
210 }
211
212
213
214
215
216 public long maxBytes() {
217 return maxBytes;
218 }
219
220
221
222
223 public long memoryAddress(int offset) {
224 return memoryAddress + idx(offset);
225 }
226
227
228
229
230 public void release() {
231 memory.release();
232 }
233
234 @Override
235 public boolean processMessage(Object msg) throws Exception {
236 if (msg instanceof ByteBuf) {
237 ByteBuf buffer = (ByteBuf) msg;
238 return add(buffer, buffer.readerIndex(), buffer.readableBytes());
239 }
240 return false;
241 }
242
243 private static int idx(int index) {
244 return IOV_SIZE * index;
245 }
246 }