669 lines
22 KiB
Java
669 lines
22 KiB
Java
/*
|
||
* Copyright (c)2013-2021 ZeroTier, Inc.
|
||
*
|
||
* Use of this software is governed by the Business Source License included
|
||
* in the LICENSE.TXT file in the project's root directory.
|
||
*
|
||
* Change Date: 2026-01-01
|
||
*
|
||
* On the date above, in accordance with the Business Source License, use
|
||
* of this software will be governed by version 2.0 of the Apache License.
|
||
*/
|
||
/****/
|
||
|
||
package com.zerotier.sockets;
|
||
|
||
import com.zerotier.sockets.*;
|
||
import java.io.*;
|
||
import java.net.*;
|
||
|
||
/**
|
||
* Implements Socket-like behavior over ZeroTier
|
||
*
|
||
* @author ZeroTier, Inc.
|
||
*/
|
||
public class ZeroTierSocket {
|
||
// File descriptor from lower native layer
|
||
private int _zfd = -1;
|
||
private int _family = -1;
|
||
private int _type = -1;
|
||
private int _protocol = -1;
|
||
|
||
// State flags
|
||
private boolean _isClosed = false;
|
||
private boolean _isConnected = false;
|
||
private boolean _isBound = false;
|
||
private boolean _inputHasBeenShutdown = false;
|
||
private boolean _outputHasBeenShutdown = false;
|
||
|
||
// Input and Output streams
|
||
private ZeroTierInputStream _inputStream = new ZeroTierInputStream();
|
||
private ZeroTierOutputStream _outputStream = new ZeroTierOutputStream();
|
||
|
||
// The remote address to which the ZeroTierSocket is connected
|
||
private InetAddress _remoteAddr;
|
||
private int _remotePort;
|
||
private InetAddress _localAddr;
|
||
private int _localPort;
|
||
|
||
private void setNativeFileDescriptor(int fd)
|
||
{
|
||
_zfd = fd;
|
||
_inputStream.zfd = fd;
|
||
_outputStream.zfd = fd;
|
||
}
|
||
|
||
public int getNativeFileDescriptor()
|
||
{
|
||
return _zfd;
|
||
}
|
||
|
||
private ZeroTierSocket(int family, int type, int protocol, int zfd)
|
||
{
|
||
_family = family;
|
||
_type = type;
|
||
_protocol = protocol;
|
||
setNativeFileDescriptor(zfd);
|
||
// Since we only call this from accept() we will mark it as connected
|
||
_isConnected = true;
|
||
}
|
||
|
||
public ZeroTierSocket(String remoteAddr, int remotePort) throws IOException
|
||
{
|
||
_protocol = 0;
|
||
_type = ZeroTierNative.ZTS_SOCK_STREAM;
|
||
|
||
InetAddress address = InetAddress.getByName(remoteAddr);
|
||
if (address instanceof Inet6Address) {
|
||
_family = ZeroTierNative.ZTS_AF_INET6;
|
||
}
|
||
else if (address instanceof Inet4Address) {
|
||
_family = ZeroTierNative.ZTS_AF_INET;
|
||
}
|
||
|
||
_zfd = ZeroTierNative.zts_bsd_socket(_family, _type, _protocol);
|
||
setNativeFileDescriptor(_zfd);
|
||
int err;
|
||
if ((err = ZeroTierNative.zts_connect(_zfd, remoteAddr, remotePort, 0)) < 0) {
|
||
throw new IOException("Error while connecting to remote host (" + err + ")");
|
||
}
|
||
_isConnected = true;
|
||
}
|
||
|
||
/**
|
||
* Create a new ZeroTierSocket with the given attributes
|
||
* @param family The socket family
|
||
* @param type The socket type
|
||
* @param protocol Supported protocol
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public ZeroTierSocket(int family, int type, int protocol) throws IOException
|
||
{
|
||
if (_zfd > -1) {
|
||
throw new IOException("This socket has already been created (fd=" + _zfd + ")");
|
||
}
|
||
_zfd = ZeroTierNative.zts_bsd_socket(family, type, protocol);
|
||
if (_zfd < 0) {
|
||
throw new IOException("Error while creating socket (" + _zfd + ")");
|
||
}
|
||
_family = family;
|
||
_type = type;
|
||
_protocol = protocol;
|
||
setNativeFileDescriptor(_zfd);
|
||
}
|
||
|
||
/**
|
||
* Connect to a remote host
|
||
* @param remoteAddr Remote address to which this socket should connect
|
||
* @param remotePort Remote port to which this socket should connect
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void connect(InetAddress remoteAddr, int remotePort) throws IOException
|
||
{
|
||
if (_zfd < 0) {
|
||
throw new IOException("Invalid socket (fd < 0)");
|
||
}
|
||
if ((remoteAddr instanceof Inet4Address) && _family != ZeroTierNative.ZTS_AF_INET) {
|
||
throw new IOException("Invalid address type. Socket is of type AF_INET");
|
||
}
|
||
if ((remoteAddr instanceof Inet6Address) && _family != ZeroTierNative.ZTS_AF_INET6) {
|
||
throw new IOException("Invalid address type. Socket is of type AF_INET6");
|
||
}
|
||
int err;
|
||
if ((err = ZeroTierNative.zts_connect(_zfd, remoteAddr.getHostAddress(), remotePort, 0)) < 0) {
|
||
throw new IOException("Error while connecting to remote host (" + err + ")");
|
||
}
|
||
_isConnected = true;
|
||
}
|
||
|
||
/**
|
||
* Connect to a remote host
|
||
* @param remoteAddr Remote address to which this socket should connect
|
||
* @param remotePort Remote port to which this socket should connect
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void connect(String remoteAddr, int remotePort) throws IOException
|
||
{
|
||
InetAddress remoteInetAddr = InetAddress.getByName(remoteAddr);
|
||
connect(remoteInetAddr, remotePort);
|
||
}
|
||
|
||
/**
|
||
* Connect to a remote host
|
||
* @param remoteAddr Remote address to which this socket should connect
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void connect(SocketAddress remoteAddr) throws IOException
|
||
{
|
||
int remotePort = ((InetSocketAddress)remoteAddr).getPort();
|
||
connect(((InetSocketAddress)remoteAddr).getHostString(), remotePort);
|
||
}
|
||
|
||
/**
|
||
* Bind to a local address
|
||
* @param localAddr Local address to which this socket should bind
|
||
* @param localPort Local port to which this socket should bind
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void bind(InetAddress localAddr, int localPort) throws IOException
|
||
{
|
||
if (_zfd < 0) {
|
||
throw new IOException("Invalid socket (fd < 0)");
|
||
}
|
||
if ((localAddr instanceof Inet4Address) && _family != ZeroTierNative.ZTS_AF_INET) {
|
||
throw new IOException("Invalid address type. Socket is of type AF_INET");
|
||
}
|
||
if ((localAddr instanceof Inet6Address) && _family != ZeroTierNative.ZTS_AF_INET6) {
|
||
throw new IOException("Invalid address type. Socket is of type AF_INET6");
|
||
}
|
||
int err;
|
||
if ((err = ZeroTierNative.zts_bind(_zfd, localAddr.getHostAddress(), localPort)) < 0) {
|
||
throw new IOException("Error while connecting to remote host (" + err + ")");
|
||
}
|
||
_localPort = localPort;
|
||
_isBound = true;
|
||
}
|
||
|
||
/**
|
||
* Bind to a local address
|
||
* @param localAddr Local address to which this socket should bind
|
||
* @param localPort Local port to which this socket should bind
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void bind(String localAddr, int localPort) throws IOException
|
||
{
|
||
InetAddress localInetAddr = InetAddress.getByName(localAddr);
|
||
bind(localInetAddr, localPort);
|
||
}
|
||
|
||
/**
|
||
* Put the ZeroTierSocket into a listening state
|
||
* @param backlog Size of connection backlog
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void listen(int backlog) throws IOException
|
||
{
|
||
if (_zfd < 0) {
|
||
throw new IOException("Invalid socket (fd < 0)");
|
||
}
|
||
if (backlog < 0) {
|
||
throw new IOException("Invalid backlog value");
|
||
}
|
||
int err;
|
||
if ((err = ZeroTierNative.zts_bsd_listen(_zfd, backlog)) < 0) {
|
||
throw new IOException("Error while putting socket into listening state (" + err + ")");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Accept incoming connections on this ZeroTierSocket
|
||
* @return New ZeroTierSocket representing the accepted connection
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public ZeroTierSocket accept() throws IOException
|
||
{
|
||
if (_zfd < 0) {
|
||
throw new IOException("Invalid socket (fd < 0)");
|
||
}
|
||
int accetpedFd = -1;
|
||
ZeroTierSocketAddress addr = new ZeroTierSocketAddress();
|
||
if ((accetpedFd = ZeroTierNative.zts_bsd_accept(_zfd, addr)) < 0) {
|
||
throw new IOException("Error while accepting connection (" + accetpedFd + ")");
|
||
}
|
||
return new ZeroTierSocket(_family, _type, _protocol, accetpedFd);
|
||
}
|
||
|
||
/**
|
||
* Close the ZeroTierSocket.
|
||
*
|
||
* @exception IOException when an I/O error occurs
|
||
*/
|
||
public void close() throws IOException
|
||
{
|
||
if (_zfd < 0) {
|
||
throw new IOException("Invalid socket (fd < 0)");
|
||
}
|
||
ZeroTierNative.zts_bsd_close(_zfd);
|
||
_isClosed = true;
|
||
}
|
||
|
||
/**
|
||
* Return whether keepalive is enabled.
|
||
* @return true or false
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public boolean getKeepAlive() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_keepalive(_zfd) == 1;
|
||
}
|
||
|
||
/**
|
||
* Get the local port to which this ZeroTierSocket is bound
|
||
* @return Local port
|
||
*/
|
||
public int getLocalPort()
|
||
{
|
||
if (! _isBound) {
|
||
return -1;
|
||
}
|
||
return _localPort;
|
||
}
|
||
|
||
/**
|
||
* Get the local address to which this ZeroTierSocket is bound
|
||
* @return Local address
|
||
*/
|
||
public InetAddress getLocalAddress()
|
||
{
|
||
if (! _isBound) {
|
||
return null;
|
||
}
|
||
return _localAddr;
|
||
}
|
||
|
||
/**
|
||
* Get the remote port to which this ZeroTierSocket is connected
|
||
* @return Remote port
|
||
*/
|
||
public int getRemotePort()
|
||
{
|
||
if (! _isConnected) {
|
||
return -1;
|
||
}
|
||
return _remotePort;
|
||
}
|
||
|
||
/**
|
||
* Get the remote address to which this ZeroTierSocket is connected
|
||
* @return Remote address
|
||
*/
|
||
public InetAddress getRemoteAddress()
|
||
{
|
||
if (! _isConnected) {
|
||
return null;
|
||
}
|
||
return _remoteAddr;
|
||
}
|
||
|
||
/**
|
||
* Get the remote address to which this ZeroTierSocket is connected. Same as getRemoteAddress()
|
||
* @return Remote address
|
||
*/
|
||
public InetAddress getInetAddress()
|
||
{
|
||
if (! _isConnected) {
|
||
return null;
|
||
}
|
||
return _remoteAddr;
|
||
}
|
||
|
||
/**
|
||
* Get the local endpoint address to which this socket is bound to
|
||
* @return Local endpoint address
|
||
*/
|
||
public SocketAddress getLocalSocketAddress()
|
||
{
|
||
if (! _isConnected) {
|
||
return null;
|
||
}
|
||
return new InetSocketAddress(_remoteAddr, _remotePort);
|
||
}
|
||
|
||
/**
|
||
* Return the size of the receive buffer for the ZeroTierSocket's ZeroTierInputStream (SO_RCVBUF)
|
||
* @return Size of the receive buffer
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public int getReceiveBufferSize() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_recv_buf_size(_zfd);
|
||
}
|
||
|
||
/**
|
||
* Return the size of the send buffer for the ZeroTierSocket's ZeroTierOutputStream (SO_SNDBUF)
|
||
* @return Size of the send buffer
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public int getSendBufferSize() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_send_buf_size(_zfd);
|
||
}
|
||
|
||
/**
|
||
* Return whether address reuse is enabled on this ZeroTierSocket (SO_REUSEADDR)
|
||
* @return true or false
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public boolean getReuseAddress() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_reuse_addr(_zfd) == 1;
|
||
}
|
||
|
||
/**
|
||
* Return the amount of time that a ZeroTierSocket will linger after closure (SO_LINGER)
|
||
* @return Nothing.
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public int getSoLingerTime() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_linger_value(_zfd);
|
||
}
|
||
|
||
/**
|
||
* Get the ZeroTierSocket's timeout value (SO_RCVTIMEO)
|
||
* @return Nothing.
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public int getSoTimeout() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_recv_timeout(_zfd);
|
||
}
|
||
|
||
/**
|
||
* Return whether TCP no-delay is enabled (TCP_NODELAY)
|
||
* @return true or false
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public boolean tcpNoDelayEnabled() throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
return ZeroTierNative.zts_get_no_delay(_zfd) == 1;
|
||
}
|
||
|
||
/**
|
||
* Return whether this ZeroTierSocket is bound to a local address
|
||
* @return true or false
|
||
*/
|
||
public boolean isBound()
|
||
{
|
||
return _isBound;
|
||
}
|
||
|
||
/**
|
||
* Return whether this ZeroTierSocket has been closed
|
||
* @return true or false
|
||
*/
|
||
public boolean isClosed()
|
||
{
|
||
return _isClosed;
|
||
}
|
||
|
||
/**
|
||
* Return whether this ZeroTierSocket is connected to a remote address
|
||
* @return true or false
|
||
*/
|
||
public boolean isConnected()
|
||
{
|
||
return _isConnected;
|
||
}
|
||
|
||
/**
|
||
* Disable the input-aspect of the ZeroTierSocket.
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void shutdownInput() throws SocketException
|
||
{
|
||
if (! _isConnected) {
|
||
throw new SocketException("Error: ZeroTierSocket is not connected");
|
||
}
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (_inputHasBeenShutdown) {
|
||
throw new SocketException("Error: ZeroTierSocket input has been shut down");
|
||
}
|
||
ZeroTierNative.zts_bsd_shutdown(_zfd, ZeroTierNative.ZTS_SHUT_RD);
|
||
_inputHasBeenShutdown = true;
|
||
}
|
||
|
||
/**
|
||
* Disable the output-aspect of the ZeroTierSocket.
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void shutdownOutput() throws SocketException
|
||
{
|
||
if (! _isConnected) {
|
||
throw new SocketException("Error: ZeroTierSocket is not connected");
|
||
}
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (_outputHasBeenShutdown) {
|
||
throw new SocketException("Error: ZeroTierSocket output has been shut down");
|
||
}
|
||
ZeroTierNative.zts_bsd_shutdown(_zfd, ZeroTierNative.ZTS_SHUT_WR);
|
||
_outputHasBeenShutdown = true;
|
||
}
|
||
|
||
/**
|
||
* Return a reference to the ZeroTierInputStream used by this ZeroTierSocket
|
||
* @return A reference to the ZeroTierInputStream
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public ZeroTierInputStream getInputStream() throws SocketException
|
||
{
|
||
if (! _isConnected) {
|
||
throw new SocketException("Error: ZeroTierSocket is not connected");
|
||
}
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (_inputHasBeenShutdown) {
|
||
throw new SocketException("Error: ZeroTierSocket input has been shut down");
|
||
}
|
||
return _inputStream;
|
||
}
|
||
|
||
/**
|
||
* Return a reference to the ZeroTierOutputStream used by this ZeroTierSocket
|
||
* @return A reference to the ZeroTierOutputStream
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public ZeroTierOutputStream getOutputStream() throws SocketException
|
||
{
|
||
if (! _isConnected) {
|
||
throw new SocketException("Error: ZeroTierSocket is not connected");
|
||
}
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (_outputHasBeenShutdown) {
|
||
throw new SocketException("Error: ZeroTierSocket output has been shut down");
|
||
}
|
||
return _outputStream;
|
||
}
|
||
|
||
/**
|
||
* Return whether the input-aspect of the ZeroTierSocket has been disabled.
|
||
* @return true or false
|
||
*/
|
||
public boolean inputStreamHasBeenShutdown()
|
||
{
|
||
return _inputHasBeenShutdown;
|
||
}
|
||
|
||
/**
|
||
* Return whether the output-aspect of the ZeroTierSocket has been disabled.
|
||
* @return true or false
|
||
*/
|
||
public boolean outputStreamHasBeenShutdown()
|
||
{
|
||
return _outputHasBeenShutdown;
|
||
}
|
||
|
||
/**
|
||
* Enable or disable the keepalive setting (SO_KEEPALIVE)
|
||
* @param enabled Whether SO_KEEPALIVE is enabled.
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setKeepAliveEnabled(boolean enabled) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (ZeroTierNative.zts_set_keepalive(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set SO_KEEPALIVE");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set the size of the receive buffer for the ZeroTierSocket's ZeroTierInputStream.
|
||
* @param bufferSize Size of receive buffer
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setReceiveBufferSize(int bufferSize) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (bufferSize <= 0) {
|
||
throw new IllegalArgumentException("Error: bufferSize <= 0");
|
||
}
|
||
if (ZeroTierNative.zts_set_recv_buf_size(_zfd, bufferSize) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set receive buffer size");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Enable or disable the re-use of addresses (SO_REUSEADDR)
|
||
* @param enabled Whether SO_REUSEADDR is enabled
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setReuseAddress(boolean enabled) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (ZeroTierNative.zts_set_reuse_addr(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set SO_REUSEADDR");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set the size of the send buffer for the ZeroTierSocket's ZeroTierOutputStream (SO_SNDBUF)
|
||
* @param bufferSize Size of send buffer
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setSendBufferSize(int bufferSize) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (bufferSize <= 0) {
|
||
throw new IllegalArgumentException("Error: bufferSize <= 0");
|
||
}
|
||
if (ZeroTierNative.zts_set_send_buf_size(_zfd, bufferSize) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set SO_SNDBUF");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set the amount of time that a ZeroTierSocket will linger after closure (SO_LINGER)
|
||
* @param enabled Whether SO_LINGER is enabled
|
||
* @param lingerTime SO_LINGER time
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setSoLinger(boolean enabled, int lingerTime) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (lingerTime < 0) {
|
||
throw new IllegalArgumentException("Error: lingerTime < 0");
|
||
}
|
||
if (ZeroTierNative.zts_set_linger(_zfd, (enabled ? 1 : 0), lingerTime) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set ZTS_SO_LINGER");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set the timeout value for SO_RCVTIMEO
|
||
* @param timeout Socket receive timeout value.
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setSoTimeout(int timeout) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (timeout < 0) {
|
||
throw new IllegalArgumentException("Error: SO_TIMEOUT < 0");
|
||
}
|
||
// TODO: This is incorrect
|
||
if (ZeroTierNative.zts_set_recv_timeout(_zfd, timeout, timeout) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set SO_RCVTIMEO");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Enable or disable TCP_NODELAY
|
||
* @param enabled Whether TCP_NODELAY is enabled
|
||
*
|
||
* @exception SocketException when an error occurs in the native socket layer
|
||
*/
|
||
public void setTcpNoDelayEnabled(boolean enabled) throws SocketException
|
||
{
|
||
if (_isClosed) {
|
||
throw new SocketException("Error: ZeroTierSocket is closed");
|
||
}
|
||
if (ZeroTierNative.zts_set_no_delay(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
|
||
throw new SocketException("Error: Could not set TCP_NODELAY");
|
||
}
|
||
}
|
||
}
|