package org.simplejavamail.mailer.internal.socks.socks5server.msg;
import org.simplejavamail.mailer.internal.socks.common.SocksException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.simplejavamail.mailer.internal.socks.socks5server.msg.StreamUtil.checkEnd;
public class CommandMessage {
private static final Logger LOGGER = LoggerFactory.getLogger(CommandMessage.class);
private InetAddress inetAddress;
private int port;
private int command;
private SocksServerReplyException socksServerReplyException;
public void read(final InputStream inputStream)
throws IOException {
LOGGER.trace("CommandMessage.read");
checkEnd(inputStream.read()); // version, unused
command = checkEnd(inputStream.read());
checkEnd(inputStream.read());
final int addressType = checkEnd(inputStream.read());
if (!AddressType.isSupport(addressType) && socksServerReplyException == null) {
socksServerReplyException = new SocksServerReplyException(ServerReply.ADDRESS_TYPE_NOT_SUPPORTED);
}
// read address
switch (addressType) {
case AddressType.IPV4:
final byte[] addressBytes = read(inputStream, 4);
inetAddress = InetAddress.getByAddress(addressBytes);
break;
case AddressType.DOMAIN_NAME:
final int domainLength = checkEnd(inputStream.read());
if (domainLength < 1) {
throw new SocksException("Length of domain must great than 0");
}
final byte[] domainBytes = read(inputStream, domainLength);
final String host = new String(domainBytes, UTF_8);
try {
inetAddress = InetAddress.getByName(host);
} catch (final UnknownHostException e) {
if (socksServerReplyException == null) {
socksServerReplyException = new SocksServerReplyException(ServerReply.HOST_UNREACHABLE);
}
}
break;
default:
// TODO Implement later.
break;
}
port = bytesToInt(read(inputStream, 2));
}
private static int bytesToInt(final byte[] portBytes) {
if (portBytes.length != 2) {
throw new IllegalArgumentException("byte array size must be 2");
}
return ((portBytes[0] & 0xFF) << 8) | portBytes[1] & 0xFF;
}
private static byte[] read(final InputStream inputStream, final int length)
throws IOException {
final byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
bytes[i] = (byte) checkEnd(inputStream.read());
}
return bytes;
}
public boolean hasSocksException() {
return socksServerReplyException != null;
}
public InetAddress getInetAddress() {
return inetAddress;
}
public int getPort() {
return port;
}
public int getCommand() {
return command;
}
public SocksServerReplyException getSocksServerReplyException() {
return socksServerReplyException;
}
}