forked from KNEMC/KLALB
290 lines
7.7 KiB
Java
290 lines
7.7 KiB
Java
package org.kne.cloud.network.klalb;
|
|
|
|
import java.io.IOException;
|
|
import java.net.BindException;
|
|
import java.net.DatagramPacket;
|
|
import java.net.Inet4Address;
|
|
import java.net.Inet6Address;
|
|
import java.net.InetAddress;
|
|
import java.net.NetworkInterface;
|
|
import java.net.SocketException;
|
|
import java.net.UnknownHostException;
|
|
import java.nio.BufferOverflowException;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Queue;
|
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.locks.LockSupport;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Supplier;
|
|
|
|
import org.kne.cloud.network.VirtualRawSocketImpl;
|
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
|
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6DefaultPayload;
|
|
import org.kne.cloud.network.ipv6.IPv6ProtocolRegister;
|
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
|
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
|
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
|
import org.kne.cloud.network.ipv6.LoopbackIPv6NetworkLink;
|
|
import org.kne.io.KNEChannels;
|
|
|
|
public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements IPv6ProtocolRegister{
|
|
|
|
private boolean ipHeaderInclude=false;
|
|
|
|
private LoopbackIPv6NetworkLink link;
|
|
|
|
|
|
protected volatile Inet6Address remoteaddr;
|
|
protected volatile Inet6Address localaddr;
|
|
|
|
private int bindProtocolNumber;
|
|
|
|
private volatile int inputchachesize = 1024*1024;
|
|
|
|
protected LoopbackIPv6NetworkLink getLoopbackLink() {
|
|
return link;
|
|
}
|
|
|
|
public KLALBVirtualRawSocketImpl(LoopbackIPv6NetworkLink link) {
|
|
super();
|
|
this.link = link;
|
|
}
|
|
|
|
@Override
|
|
public void setOption(int optID, Object value) throws SocketException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
public Object getOption(int optID) throws SocketException {
|
|
// TODO 自动生成的方法存根
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void create() throws IOException {
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void setIPHeaderInclude(boolean ipHeaderInclude) throws IOException {
|
|
this.ipHeaderInclude=ipHeaderInclude;
|
|
}
|
|
|
|
@Override
|
|
protected boolean getIPHeaderInclude() throws IOException {
|
|
return ipHeaderInclude;
|
|
}
|
|
|
|
@Override
|
|
protected void setUseSelectTimeout(boolean useSelect) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected boolean getUseSelectTimeout() throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected void setSendTimeout(int timeout) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected int getSendTimeout() throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
protected void setReceiveTimeout(int timeout) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected int getReceiveTimeout() throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
protected void close() {
|
|
link.getProtocolNumberRegister()[bindProtocolNumber]=null;
|
|
}
|
|
|
|
@Override
|
|
protected void bind(InetAddress address,int protocolNumber) throws SocketException{
|
|
if(protocolNumber<0) {
|
|
throw new UnsupportedOperationException("unsupprted bind all protocols");
|
|
}
|
|
try {
|
|
if (address.equals(Inet4Address.getByName("0.0.0.0"))) {
|
|
address = Inet6Address.getByName("::0");
|
|
}
|
|
} catch (UnknownHostException e) {
|
|
e.printStackTrace();
|
|
}
|
|
if (!(address instanceof Inet6Address)) {
|
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
|
}
|
|
if (!address.isAnyLocalAddress() ) {
|
|
boolean contains=false;
|
|
for(IPv6AddressGroup adg:link.getAddressGroups()) {
|
|
if(adg.checkMatch(IPv6Address.valueOf( address))) {
|
|
contains=true;
|
|
break;
|
|
}
|
|
}
|
|
if(!contains) {
|
|
throw new BindException("must bind to self");
|
|
}
|
|
}
|
|
|
|
localaddr=(Inet6Address) address;
|
|
this.bindProtocolNumber=protocolNumber;
|
|
if(link.getProtocolNumberRegister()[protocolNumber]!=null) {
|
|
throw new BindException("protocol number already bind");
|
|
}else {
|
|
link.getProtocolNumberRegister()[protocolNumber]=this;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void join(InetAddress inetaddr) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void leave(InetAddress inetaddr) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void joinGroup(InetAddress mcastaddr, NetworkInterface netIf) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void leaveGroup(InetAddress mcastaddr, NetworkInterface netIf) throws IOException {
|
|
// TODO 自动生成的方法存根
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void send(DatagramPacket p) throws IOException {
|
|
ByteBuffer buf= ByteBuffer.wrap(p.getData(), p.getOffset(), p.getLength());
|
|
if(ipHeaderInclude) {
|
|
|
|
}else {
|
|
IPv6DefaultPayload pl=new IPv6DefaultPayload(bindProtocolNumber);
|
|
pl.getData().put(buf);
|
|
pl.getData().flip();
|
|
BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>>cons=link.getReceiveConsumer();
|
|
if(cons!=null) {
|
|
cons.accept(link,() -> {
|
|
IPv6Packet ipv=new IPv6Packet();
|
|
ipv.setVersion(6);
|
|
ipv.setTrafficClass(0);
|
|
ipv.setFlowLabel(0);
|
|
ipv.setHopLimit(255);
|
|
if(!localaddr.isAnyLocalAddress()) {
|
|
ipv.setSourceAddress2(localaddr);
|
|
}else {
|
|
ipv.setSourceAddress(link.getRouter().getLocator().getAddress());
|
|
}
|
|
InetAddress address= p.getAddress();
|
|
if (!(address instanceof Inet6Address)) {
|
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
|
}
|
|
ipv.setDestinationAddress2((Inet6Address)address);
|
|
//ipv.enableECN();
|
|
ipv.setPayload(pl);
|
|
return ipv;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected InetAddress peek() throws IOException {
|
|
return peekNextPacket().getSourceAddress2();
|
|
}
|
|
|
|
@Override
|
|
protected void peekData(DatagramPacket p) throws IOException {
|
|
IPv6Packet pack=peekNextPacket();
|
|
copyTo(pack, p);
|
|
}
|
|
|
|
private void copyTo(IPv6Packet pack, DatagramPacket p) throws IOException {
|
|
p.setAddress(pack.getSourceAddress2());
|
|
ByteBuffer buffer= ByteBuffer.wrap(p.getData(),p.getOffset(),p.getLength());
|
|
if(ipHeaderInclude) {
|
|
|
|
}else {
|
|
try {
|
|
pack.getPayload().writeToChannel(KNEChannels.newWritableChannel(buffer));
|
|
}catch(BufferOverflowException e) {
|
|
|
|
}
|
|
}
|
|
buffer.flip();
|
|
p.setLength(buffer.limit());
|
|
}
|
|
|
|
@Override
|
|
protected void receive(DatagramPacket p) throws IOException {
|
|
IPv6Packet pack=pollNextPacket();
|
|
copyTo(pack, p);
|
|
}
|
|
private volatile Thread parkThread;
|
|
private IPv6Packet peekNextPacket() {
|
|
IPv6Packet pol=null;
|
|
while(true) {
|
|
pol=recvQueue.peek();
|
|
if(pol!=null) {
|
|
recvQueueUsed.addAndGet((int) -pol.getPayload().getTotalLength());
|
|
return pol;
|
|
}
|
|
parkThread=Thread.currentThread();
|
|
LockSupport.parkNanos(1000000L);
|
|
}
|
|
}
|
|
private IPv6Packet pollNextPacket() {
|
|
IPv6Packet pol=null;
|
|
while(true) {
|
|
pol=recvQueue.poll();
|
|
if(pol!=null) {
|
|
recvQueueUsed.addAndGet((int) -pol.getPayload().getTotalLength());
|
|
return pol;
|
|
}
|
|
parkThread=Thread.currentThread();
|
|
LockSupport.parkNanos(1000000L);
|
|
}
|
|
}
|
|
private Queue<IPv6Packet> recvQueue = new ConcurrentLinkedQueue<IPv6Packet>();
|
|
private AtomicInteger recvQueueUsed=new AtomicInteger(0);
|
|
|
|
@Override
|
|
public boolean onaccept(IPv6Packet packx) throws IOException {
|
|
if(recvQueueUsed.get()<=inputchachesize) {
|
|
if(recvQueue.offer(packx)) {
|
|
recvQueueUsed.addAndGet((int) packx.getPayload().getTotalLength());
|
|
LockSupport.unpark(parkThread);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|