/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel.epoll;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.unix.IovArray;
import io.netty.util.concurrent.FastThreadLocal;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;

import static io.netty.channel.unix.Limits.UIO_MAX_IOV;
import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;

Support sendmmsg(...) on linux with GLIBC 2.14+
/** * Support <a href="http://linux.die.net/man/2/sendmmsg">sendmmsg(...)</a> on linux with GLIBC 2.14+ */
final class NativeDatagramPacketArray implements ChannelOutboundBuffer.MessageProcessor { private static final FastThreadLocal<NativeDatagramPacketArray> ARRAY = new FastThreadLocal<NativeDatagramPacketArray>() { @Override protected NativeDatagramPacketArray initialValue() throws Exception { return new NativeDatagramPacketArray(); } @Override protected void onRemoval(NativeDatagramPacketArray value) throws Exception { NativeDatagramPacket[] packetsArray = value.packets; // Release all packets for (NativeDatagramPacket datagramPacket : packetsArray) { datagramPacket.release(); } } }; // Use UIO_MAX_IOV as this is the maximum number we can write with one sendmmsg(...) call. private final NativeDatagramPacket[] packets = new NativeDatagramPacket[UIO_MAX_IOV]; private int count; private NativeDatagramPacketArray() { for (int i = 0; i < packets.length; i++) { packets[i] = new NativeDatagramPacket(); } }
Try to add the given DatagramPacket. Returns true on success, false otherwise.
/** * Try to add the given {@link DatagramPacket}. Returns {@code true} on success, * {@code false} otherwise. */
boolean add(DatagramPacket packet) { if (count == packets.length) { return false; } ByteBuf content = packet.content(); int len = content.readableBytes(); if (len == 0) { return true; } NativeDatagramPacket p = packets[count]; InetSocketAddress recipient = packet.recipient(); if (!p.init(content, recipient)) { return false; } count++; return true; } @Override public boolean processMessage(Object msg) throws Exception { return msg instanceof DatagramPacket && add((DatagramPacket) msg); }
Returns the count
/** * Returns the count */
int count() { return count; }
Returns an array with count() NativeDatagramPackets filled.
/** * Returns an array with {@link #count()} {@link NativeDatagramPacket}s filled. */
NativeDatagramPacket[] packets() { return packets; }
Returns a NativeDatagramPacketArray which is filled with the flushed messages of ChannelOutboundBuffer.
/** * Returns a {@link NativeDatagramPacketArray} which is filled with the flushed messages of * {@link ChannelOutboundBuffer}. */
static NativeDatagramPacketArray getInstance(ChannelOutboundBuffer buffer) throws Exception { NativeDatagramPacketArray array = ARRAY.get(); array.count = 0; buffer.forEachFlushedMessage(array); return array; }
Used to pass needed data to JNI.
/** * Used to pass needed data to JNI. */
@SuppressWarnings("unused") static final class NativeDatagramPacket { // Each NativeDatagramPackets holds a IovArray which is used for gathering writes. // This is ok as NativeDatagramPacketArray is always obtained via a FastThreadLocal and // so the memory needed is quite small anyway. private final IovArray array = new IovArray(); // This is the actual struct iovec* private long memoryAddress; private int count; private byte[] addr; private int scopeId; private int port; private void release() { array.release(); }
Init this instance and return true if the init was successful.
/** * Init this instance and return {@code true} if the init was successful. */
private boolean init(ByteBuf buf, InetSocketAddress recipient) { array.clear(); if (!array.add(buf)) { return false; } // always start from offset 0 memoryAddress = array.memoryAddress(0); count = array.count(); InetAddress address = recipient.getAddress(); if (address instanceof Inet6Address) { addr = address.getAddress(); scopeId = ((Inet6Address) address).getScopeId(); } else { addr = ipv4MappedIpv6Address(address.getAddress()); scopeId = 0; } port = recipient.getPort(); return true; } } }