1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.epoll;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelOutboundBuffer;
20 import io.netty.channel.ChannelOutboundBuffer.MessageProcessor;
21 import io.netty.channel.socket.DatagramPacket;
22 import io.netty.channel.unix.IovArray;
23 import io.netty.channel.unix.Limits;
24 import io.netty.channel.unix.SegmentedDatagramPacket;
25 import io.netty.util.internal.UnstableApi;
26
27 import java.net.Inet6Address;
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.net.UnknownHostException;
31
32 import static io.netty.channel.unix.Limits.UIO_MAX_IOV;
33 import static io.netty.channel.unix.NativeInetAddress.copyIpv4MappedIpv6Address;
34
35
36
37
38 final class NativeDatagramPacketArray {
39
40
41 private final NativeDatagramPacket[] packets = new NativeDatagramPacket[UIO_MAX_IOV];
42
43
44
45 private final IovArray iovArray = new IovArray();
46
47
48 private final byte[] ipv4Bytes = new byte[4];
49 private final MyMessageProcessor processor = new MyMessageProcessor();
50
51 private int count;
52
53 NativeDatagramPacketArray() {
54 for (int i = 0; i < packets.length; i++) {
55 packets[i] = new NativeDatagramPacket();
56 }
57 }
58
59 boolean addWritable(ByteBuf buf, int index, int len) {
60 return add0(buf, index, len, 0, null);
61 }
62
63 private boolean add0(ByteBuf buf, int index, int len, int segmentLen, InetSocketAddress recipient) {
64 if (count == packets.length) {
65
66
67 return false;
68 }
69
70
71 int offset = iovArray.count();
72 if (offset == Limits.IOV_MAX || !iovArray.add(buf, index, len)) {
73
74 return false;
75 }
76 NativeDatagramPacket p = packets[count];
77 p.init(iovArray.memoryAddress(offset), iovArray.count() - offset, segmentLen, recipient);
78
79 count++;
80 return true;
81 }
82
83 void add(ChannelOutboundBuffer buffer, boolean connected, int maxMessagesPerWrite) throws Exception {
84 processor.connected = connected;
85 processor.maxMessagesPerWrite = maxMessagesPerWrite;
86 buffer.forEachFlushedMessage(processor);
87 }
88
89
90
91
92 int count() {
93 return count;
94 }
95
96
97
98
99 NativeDatagramPacket[] packets() {
100 return packets;
101 }
102
103 void clear() {
104 this.count = 0;
105 this.iovArray.clear();
106 }
107
108 void release() {
109 iovArray.release();
110 }
111
112 private final class MyMessageProcessor implements MessageProcessor {
113 private boolean connected;
114 private int maxMessagesPerWrite;
115
116 @Override
117 public boolean processMessage(Object msg) {
118 final boolean added;
119 if (msg instanceof DatagramPacket) {
120 DatagramPacket packet = (DatagramPacket) msg;
121 ByteBuf buf = packet.content();
122 int segmentSize = 0;
123 if (packet instanceof io.netty.channel.unix.SegmentedDatagramPacket) {
124 int seg = ((io.netty.channel.unix.SegmentedDatagramPacket) packet).segmentSize();
125
126
127 if (buf.readableBytes() > seg) {
128 segmentSize = seg;
129 }
130 }
131 added = add0(buf, buf.readerIndex(), buf.readableBytes(), segmentSize, packet.recipient());
132 } else if (msg instanceof ByteBuf && connected) {
133 ByteBuf buf = (ByteBuf) msg;
134 added = add0(buf, buf.readerIndex(), buf.readableBytes(), 0, null);
135 } else {
136 added = false;
137 }
138 if (added) {
139 maxMessagesPerWrite--;
140 return maxMessagesPerWrite > 0;
141 }
142 return false;
143 }
144 }
145
146 private static InetSocketAddress newAddress(byte[] addr, int addrLen, int port, int scopeId, byte[] ipv4Bytes)
147 throws UnknownHostException {
148 final InetAddress address;
149 if (addrLen == ipv4Bytes.length) {
150 System.arraycopy(addr, 0, ipv4Bytes, 0, addrLen);
151 address = InetAddress.getByAddress(ipv4Bytes);
152 } else {
153 address = Inet6Address.getByAddress(null, addr, scopeId);
154 }
155 return new InetSocketAddress(address, port);
156 }
157
158
159
160
161 @SuppressWarnings("unused")
162 @UnstableApi
163 public final class NativeDatagramPacket {
164
165
166
167
168
169 private long memoryAddress;
170 private int count;
171
172 private final byte[] senderAddr = new byte[16];
173 private int senderAddrLen;
174 private int senderScopeId;
175 private int senderPort;
176
177 private final byte[] recipientAddr = new byte[16];
178 private int recipientAddrLen;
179 private int recipientScopeId;
180 private int recipientPort;
181
182 private int segmentSize;
183
184 private void init(long memoryAddress, int count, int segmentSize, InetSocketAddress recipient) {
185 this.memoryAddress = memoryAddress;
186 this.count = count;
187 this.segmentSize = segmentSize;
188
189 this.senderScopeId = 0;
190 this.senderPort = -1;
191 this.senderAddrLen = 0;
192
193 if (recipient == null) {
194 this.recipientScopeId = 0;
195 this.recipientPort = 0;
196 this.recipientAddrLen = 0;
197 } else {
198 InetAddress address = recipient.getAddress();
199 if (address instanceof Inet6Address) {
200 System.arraycopy(address.getAddress(), 0, recipientAddr, 0, recipientAddr.length);
201 recipientScopeId = ((Inet6Address) address).getScopeId();
202 } else {
203 copyIpv4MappedIpv6Address(address.getAddress(), recipientAddr);
204 recipientScopeId = 0;
205 }
206 recipientAddrLen = recipientAddr.length;
207 recipientPort = recipient.getPort();
208 }
209 }
210
211 boolean hasSender() {
212 return senderPort >= 0;
213 }
214
215 DatagramPacket newDatagramPacket(ByteBuf buffer, InetSocketAddress recipient) throws UnknownHostException {
216 InetSocketAddress sender = newAddress(senderAddr, senderAddrLen, senderPort, senderScopeId, ipv4Bytes);
217 if (recipientAddrLen != 0) {
218 recipient = newAddress(recipientAddr, recipientAddrLen, recipientPort, recipientScopeId, ipv4Bytes);
219 }
220
221
222 ByteBuf slice = buffer.retainedSlice(buffer.readerIndex(), count);
223
224
225 if (segmentSize > 0) {
226 return new SegmentedDatagramPacket(slice, segmentSize, recipient, sender);
227 }
228 return new DatagramPacket(slice, recipient, sender);
229 }
230 }
231 }