package net.i2p.client.streaming.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.client.streaming.I2PSocketOptions;
/**
* Bridge to I2PSocket.
*
* This extends Socket to make porting apps easier.
* Methods throw IOExceptions like Sockets do, rather than returning
* null for some methods.
*
* StandardSockets are always bound, and always start out connected
* (unless connectDelay is > 0).
* You may not create an unbound StandardSocket.
* Create this through the SocketManager.
*
* Todo: Make public and add getPeerDestination() ?
*
* @author zzz
* @since 0.8.4
*/
class StandardSocket extends Socket {
private final I2PSocket _socket;
StandardSocket(I2PSocket socket) {
_socket = socket;
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public void bind(SocketAddress bindpoint) {
throw new UnsupportedOperationException();
}
@Override
public void close() throws IOException {
if (_socket.isClosed())
throw new IOException("Already closed");
_socket.close();
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public void connect(SocketAddress endpoint) {
throw new UnsupportedOperationException();
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public void connect(SocketAddress endpoint, int timeout) {
throw new UnsupportedOperationException();
}
/**
* @return null always, unimplemented
*/
@Override
public SocketChannel getChannel() {
//return _socket.getChannel();
return null;
}
/**
* @return null always
*/
@Override
public InetAddress getInetAddress() {
return null;
}
@Override
public InputStream getInputStream() throws IOException {
InputStream rv = _socket.getInputStream();
if (rv != null)
return rv;
throw new IOException("No stream");
}
@Override
public boolean getKeepAlive() {
ConnectionOptions opts = (ConnectionOptions) _socket.getOptions();
if (opts == null)
return false;
return opts.getInactivityAction() == ConnectionOptions.INACTIVITY_ACTION_SEND;
}
/**
* @return null always
*/
@Override
public InetAddress getLocalAddress() {
return null;
}
/**
* @return the port or 0 if unknown
*/
@Override
public int getLocalPort() {
return _socket.getLocalPort();
}
/**
* @return an I2PSocketAddress as of 0.9.26; prior to that, returned null
* @since implemented in 0.9.26
*/
@Override
public SocketAddress getLocalSocketAddress() {
return new I2PSocketAddress(_socket.getThisDestination(), _socket.getLocalPort());
}
/**
* @return false always
*/
@Override
public boolean getOOBInline() {
return false;
}
@Override
public OutputStream getOutputStream() throws IOException {
OutputStream rv = _socket.getOutputStream();
if (rv != null)
return rv;
throw new IOException("No stream");
}
/**
* @return the port or 0 if unknown
*/
@Override
public int getPort() {
return _socket.getPort();
}
@Override
public int getReceiveBufferSize() {
ConnectionOptions opts = (ConnectionOptions) _socket.getOptions();
if (opts == null)
return 64*1024;
return opts.getInboundBufferSize();
}
/**
* @return an I2PSocketAddress as of 0.9.26; prior to that, threw UnsupportedOperationException
* @since implemented in 0.9.26
*/
@Override
public SocketAddress getRemoteSocketAddress() {
return new I2PSocketAddress(_socket.getPeerDestination(), _socket.getPort());
}
/**
* @return false always
*/
@Override
public boolean getReuseAddress() {
return false;
}
@Override
public int getSendBufferSize() {
ConnectionOptions opts = (ConnectionOptions) _socket.getOptions();
if (opts == null)
return 64*1024;
return opts.getInboundBufferSize();
}
@Override
public int getSoLinger() {
I2PSocketOptions opts = _socket.getOptions();
if (opts == null)
return -1;
return -1; // fixme really?
}
@Override
public int getSoTimeout() {
I2PSocketOptions opts = _socket.getOptions();
if (opts == null)
return 0;
long rv = opts.getReadTimeout();
// Java Socket: 0 is forever, and we don't exactly have nonblocking
if (rv > Integer.MAX_VALUE)
rv = Integer.MAX_VALUE;
else if (rv < 0)
rv = 0;
else if (rv == 0)
rv = 1;
return (int) rv;
}
/**
* @return false always
*/
@Override
public boolean getTcpNoDelay() {
// No option yet. See ConnectionDataReceiver
return false;
}
/**
* @return 0 always
*/
@Override
public int getTrafficClass() {
return 0;
}
/**
* @return true always
*/
@Override
public boolean isBound() {
return true;
}
@Override
public boolean isClosed() {
return _socket.isClosed();
}
@Override
public boolean isConnected() {
return !_socket.isClosed();
}
@Override
public boolean isInputShutdown() {
return _socket.isClosed();
}
@Override
public boolean isOutputShutdown() {
return _socket.isClosed();
}
/**
* @throws UnsupportedOperationException always
*/
@Override
public void sendUrgentData(int data) {
throw new UnsupportedOperationException();
}
@Override
public void setKeepAlive(boolean on) {
ConnectionOptions opts = (ConnectionOptions) _socket.getOptions();
if (opts == null)
return;
if (on)
opts.setInactivityAction(ConnectionOptions.INACTIVITY_ACTION_SEND);
else
opts.setInactivityAction(ConnectionOptions.INACTIVITY_ACTION_NOOP); // DISCONNECT?
}
/**
* @throws UnsupportedOperationException if on is true
*/
@Override
public void setOOBInline(boolean on) {
if (on)
throw new UnsupportedOperationException();
}
/**
* Does nothing.
*/
@Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
}
/**
* Does nothing.
*/
@Override
public void setReceiveBufferSize(int size) {
}
/**
* Does nothing.
*/
@Override
public void setReuseAddress(boolean on) {
}
/**
* Does nothing.
*/
@Override
public void setSendBufferSize(int size) {
}
/**
* Does nothing.
*/
@Override
public void setSoLinger(boolean on, int linger) {
}
@Override
public void setSoTimeout(int timeout) throws SocketException {
I2PSocketOptions opts = _socket.getOptions();
if (opts == null)
throw new SocketException("No options");
// Java Socket: 0 is forever
if (timeout == 0)
timeout = -1;
opts.setReadTimeout(timeout);
}
/**
* Does nothing.
*/
@Override
public void setTcpNoDelay(boolean on) {
}
/**
* Does nothing.
*/
@Override
public void setTrafficClass(int tc) {
}
@Override
public void shutdownInput() throws IOException {
close();
}
@Override
public void shutdownOutput() throws IOException {
close();
}
@Override
public String toString() {
return _socket.toString();
}
}