KLALB3.2
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
|
||||
package org.kne.cloud.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketOptions;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.kne.cloud.network.klalb.KLALBVirtualRawSocketImpl;
|
||||
|
||||
|
||||
public class RawSocket {
|
||||
|
||||
|
||||
public static final ProtocolFamily PF_INET=StandardProtocolFamily.INET;
|
||||
|
||||
|
||||
public static final ProtocolFamily PF_INET6=StandardProtocolFamily.INET6;
|
||||
|
||||
private static final VarHandle STATE ;
|
||||
static {
|
||||
try {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
STATE = l.findVarHandle(RawSocket.class, "state", int.class);
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
//the underlying SocketImpl, may be null, may be swapped when connecting
|
||||
private RawSocketImpl impl;
|
||||
|
||||
// state bits
|
||||
private static final int SOCKET_CREATED = 1 << 0; // impl.create(boolean) called
|
||||
private static final int BOUND = 1 << 1;
|
||||
private static final int CONNECTED = 1 << 2;
|
||||
private static final int CLOSED = 1 << 3;
|
||||
private static final int SHUT_IN = 1 << 9;
|
||||
private static final int SHUT_OUT = 1 << 10;
|
||||
private volatile int state;
|
||||
|
||||
// used to coordinate creating and closing underlying socket
|
||||
private final Object socketLock = new Object();
|
||||
|
||||
|
||||
InetAddress connectedAddress = null;
|
||||
|
||||
private boolean explicitFilter = false;
|
||||
private int bytesLeftToFilter;
|
||||
/**
|
||||
* Atomically sets state to the result of a bitwise OR of the current value
|
||||
* and the given mask.
|
||||
* @return the previous state value
|
||||
*/
|
||||
private int getAndBitwiseOrState(int mask) {
|
||||
return (int) STATE.getAndBitwiseOr(this, mask);
|
||||
}
|
||||
|
||||
private static boolean isBound(int s) {
|
||||
return (s & BOUND) != 0;
|
||||
}
|
||||
|
||||
private static boolean isConnected(int s) {
|
||||
return (s & CONNECTED) != 0;
|
||||
}
|
||||
|
||||
private static boolean isClosed(int s) {
|
||||
return (s & CLOSED) != 0;
|
||||
}
|
||||
|
||||
private static boolean isInputShutdown(int s) {
|
||||
return (s & SHUT_IN) != 0;
|
||||
}
|
||||
|
||||
private static boolean isOutputShutdown(int s) {
|
||||
return (s & SHUT_OUT) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected RawSocket(RawSocketImpl impl) {
|
||||
this.impl=impl;
|
||||
}
|
||||
|
||||
public RawSocket(RawSocketImpl impl, Inet6Address bindAddress) throws SocketException {
|
||||
this.impl=impl;
|
||||
bind(bindAddress);
|
||||
}
|
||||
|
||||
public RawSocket(KLALBVirtualRawSocketImpl impl, Inet6Address bindAddress, int bindProtocol) throws SocketException {
|
||||
this.impl=impl;
|
||||
bind(bindAddress,bindProtocol);
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return isConnected(state);
|
||||
}
|
||||
public boolean isBound() {
|
||||
return isBound(state);
|
||||
}
|
||||
public boolean isOpen() {
|
||||
return !isClosed(state);
|
||||
}
|
||||
public boolean isClosed() {
|
||||
return isClosed(state);
|
||||
}
|
||||
private void checkAddress(InetAddress addr, String op) {
|
||||
if (addr == null) {
|
||||
return;
|
||||
}
|
||||
if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
|
||||
throw new IllegalArgumentException(op + ": invalid address type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private RawSocketImpl getImpl() throws SocketException {
|
||||
if ((state & SOCKET_CREATED) == 0) {
|
||||
synchronized (socketLock) {
|
||||
int s = state; // re-read state
|
||||
if ((s & SOCKET_CREATED) == 0) {
|
||||
if (isClosed(s)) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
RawSocketImpl impl = this.impl;
|
||||
if (impl == null) {
|
||||
this.impl = impl = createImpl();
|
||||
}
|
||||
try {
|
||||
impl.create();
|
||||
} catch (SocketException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new SocketException(e.getMessage(), e);
|
||||
}
|
||||
getAndBitwiseOrState(SOCKET_CREATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
private static RawSocketImpl createImpl() {
|
||||
RawSocketImplFactory factory = RawSocket.factory;
|
||||
if (factory != null) {
|
||||
return factory.createRawSocketImpl();
|
||||
} else {
|
||||
return null;
|
||||
// RawSocketImpl delegate = RawSocketImpl.createPlatformSocketImpl(false);
|
||||
// return new SocksSocketImpl(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static volatile RawSocketImplFactory factory;
|
||||
|
||||
static RawSocketImplFactory socketImplFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(since = "17")
|
||||
public static synchronized void setSocketImplFactory(RawSocketImplFactory fac)
|
||||
throws IOException
|
||||
{
|
||||
if (factory != null) {
|
||||
throw new SocketException("factory already defined");
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkSetFactory();
|
||||
}
|
||||
factory = fac;
|
||||
}
|
||||
public void bind(InetAddress address) throws SocketException {
|
||||
bind(address,-1);
|
||||
}
|
||||
public void bind(InetAddress address,int protocolNumber)
|
||||
throws SocketException
|
||||
{
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (isBound(s))
|
||||
throw new SocketException("Already bound");
|
||||
|
||||
|
||||
|
||||
if (address == null) {
|
||||
try {
|
||||
address = Inet6Address.getByName("::0");
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
checkAddress (address, "bind");
|
||||
getImpl().bind(address,protocolNumber);
|
||||
getAndBitwiseOrState(BOUND);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void bindDevice(String device)
|
||||
throws UnsupportedOperationException, IllegalStateException, IOException
|
||||
{
|
||||
if(!isOpen())
|
||||
throw new IllegalStateException();
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
public InetAddress getLocalAddress() {
|
||||
if (isClosed())
|
||||
return null;
|
||||
InetAddress in;
|
||||
try {
|
||||
in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
|
||||
if (in.isAnyLocalAddress()) {
|
||||
in = InetAddress.getByName("::0");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
in = InetAddress.getByName("::0");
|
||||
} catch (UnknownHostException e1) {
|
||||
e1.printStackTrace();
|
||||
in=null;
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
synchronized (socketLock) {
|
||||
if ((state & CLOSED) == 0) {
|
||||
int s = getAndBitwiseOrState(CLOSED);
|
||||
if ((s & (SOCKET_CREATED | CLOSED)) == SOCKET_CREATED) {
|
||||
// close underlying socket if created
|
||||
impl.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIPHeaderInclude(boolean on) throws IOException {
|
||||
impl.setIPHeaderInclude(on);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean getIPHeaderInclude() throws IOException {
|
||||
return impl.getIPHeaderInclude();
|
||||
}
|
||||
|
||||
public void setSendBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("negative send size");
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_SNDBUF, size);
|
||||
}
|
||||
|
||||
public int getSendBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
|
||||
if (o instanceof Integer i) {
|
||||
result = i.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("invalid receive size");
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_RCVBUF, size);
|
||||
}
|
||||
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
|
||||
if (o instanceof Integer i) {
|
||||
result = i.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setUseSelectTimeout(boolean useSelect) throws IOException {
|
||||
impl.setUseSelectTimeout(useSelect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean getUseSelectTimeout() throws IOException {
|
||||
return impl.getUseSelectTimeout();
|
||||
}
|
||||
|
||||
|
||||
/* public void setSendTimeout(int timeout) throws SocketException {
|
||||
impl.setSendTimeout( timeout);
|
||||
}
|
||||
|
||||
|
||||
public int getSendTimeout() throws SocketException {
|
||||
return impl.getSendTimeout();
|
||||
}*/
|
||||
|
||||
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("timeout can't be negative");
|
||||
getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
|
||||
}
|
||||
|
||||
|
||||
public int getSoTimeout() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
|
||||
/* extra type safety */
|
||||
if (o instanceof Integer i) {
|
||||
return i.intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void send(DatagramPacket p) throws IOException {
|
||||
synchronized (p) {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
InetAddress packetAddress = p.getAddress();
|
||||
checkAddress(packetAddress, "send");
|
||||
if (isConnected()) {
|
||||
// we're connected
|
||||
if (packetAddress == null) {
|
||||
p.setAddress(connectedAddress);
|
||||
} else if ((!packetAddress.equals(connectedAddress)) ) {
|
||||
throw new IllegalArgumentException("connected address " +
|
||||
"and packet address" +
|
||||
" differ");
|
||||
}
|
||||
|
||||
} else {
|
||||
if (packetAddress == null) {
|
||||
throw new IllegalArgumentException("Address not set");
|
||||
}
|
||||
}
|
||||
// Check whether the socket is bound
|
||||
if (!isBound())
|
||||
bind(InetAddress.getByName("::0"));
|
||||
// call the method to send
|
||||
getImpl().send(p);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void receive(DatagramPacket p) throws IOException {
|
||||
synchronized (p) {
|
||||
if (!isBound())
|
||||
bind(InetAddress.getByName("::0"));
|
||||
DatagramPacket tmp = null;
|
||||
if (explicitFilter) {
|
||||
// We have to do the filtering the old fashioned way since
|
||||
// the native impl doesn't support connect or the connect
|
||||
// via the impl failed, or .. "explicitFilter" may be set when
|
||||
// a socket is connected via the impl, for a period of time
|
||||
// when packets from other sources might be queued on socket.
|
||||
boolean stop = false;
|
||||
while (!stop) {
|
||||
// peek at the packet to see who it is from.
|
||||
DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
|
||||
getImpl().peekData(peekPacket);
|
||||
InetAddress peekAddress = peekPacket.getAddress();
|
||||
if ((!connectedAddress.equals(peekAddress)) ) {
|
||||
// throw the packet away and silently continue
|
||||
tmp = new DatagramPacket(
|
||||
new byte[1024], 1024);
|
||||
getImpl().receive(tmp);
|
||||
if (explicitFilter) {
|
||||
if (checkFiltering(tmp)) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the security check succeeds, or the datagram is
|
||||
// connected then receive the packet
|
||||
getImpl().receive(p);
|
||||
if (explicitFilter && tmp == null) {
|
||||
// packet was not filtered, account for it here
|
||||
checkFiltering(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
private boolean checkFiltering(DatagramPacket p) throws SocketException {
|
||||
bytesLeftToFilter -= p.getLength();
|
||||
if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) {
|
||||
explicitFilter = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user