blob: f7a22b77421a233fe9764228e88d2eb3b853d963 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.luni.net;
import java.io.UnsupportedEncodingException;
import org.apache.harmony.luni.internal.nls.Messages;
class Socks4Message {
static final int COMMAND_CONNECT = 1;
static final int COMMAND_BIND = 2;
static final int RETURN_SUCCESS = 90;
static final int RETURN_FAILURE = 91;
static final int RETURN_CANNOT_CONNECT_TO_IDENTD = 92;
static final int RETURN_DIFFERENT_USER_IDS = 93;
static final int REPLY_LENGTH = 8;
static final int INDEX_VERSION = 0;
private static final int SOCKS_VERSION = 4;
private static final int INDEX_COMMAND = 1;
private static final int INDEX_PORT = 2;
private static final int INDEX_IP = 4;
private static final int INDEX_USER_ID = 8;
private static final int BUFFER_LENGTH = 256;
private static final int MAX_USER_ID_LENGTH = BUFFER_LENGTH - INDEX_USER_ID;
protected byte[] buffer;
public Socks4Message() {
super();
buffer = new byte[BUFFER_LENGTH];
setVersionNumber(SOCKS_VERSION);
}
/**
* Get the request's command or result.
*/
public int getCommandOrResult() {
return buffer[INDEX_COMMAND];
}
/**
* Set the request's command or result.
*/
public void setCommandOrResult(int command) {
buffer[INDEX_COMMAND] = (byte) command;
}
/**
* Answer the request's port number.
*/
public int getPort() {
return getInt16(INDEX_PORT);
}
/**
* Set the request's port number.
*/
public void setPort(int port) {
setInt16(INDEX_PORT, port);
}
/*
* Answer the IP address of the request as an integer.
*/
public int getIP() {
return getInt32(INDEX_IP);
}
/**
* Set the IP address. This expects an array of four bytes in host order.
*/
public void setIP(byte[] ip) {
buffer[INDEX_IP] = ip[0];
buffer[INDEX_IP + 1] = ip[1];
buffer[INDEX_IP + 2] = ip[2];
buffer[INDEX_IP + 3] = ip[3];
}
/**
* Answer the user id for authentication.
*/
public String getUserId() {
return getString(INDEX_USER_ID, MAX_USER_ID_LENGTH);
}
/**
* Set the user id for authentication.
*/
public void setUserId(String id) {
setString(INDEX_USER_ID, MAX_USER_ID_LENGTH, id);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(50);
buf.append("Version: ");
buf.append(Integer.toHexString(getVersionNumber()));
buf.append(" Command: ");
buf.append(Integer.toHexString(getCommandOrResult()));
buf.append(" Port: ");
buf.append(getPort());
buf.append(" IP: ");
buf.append(Integer.toHexString(getIP()));
buf.append(" User ID: ");
buf.append(getUserId());
return buf.toString();
}
/**
* Answer the total number of bytes used for the request. This method
* searches for the end of the user id, then searches for the end of the
* password and returns the final index as the requests length.
*/
public int getLength() {
int index = 0;
// Look for the end of the user id.
for (index = INDEX_USER_ID; buffer[index] != 0; index++) {
/*
* Finds the end of the user id by searching for the null
* termination of the user id string.
*/
}
// Increment the index to include the NULL character in the length;
index++;
return index;
}
/**
* Answer an error string corresponding to the given error value.
*/
public String getErrorString(int error) {
switch (error) {
case RETURN_FAILURE:
return Messages.getString("luni.14"); //$NON-NLS-1$
case RETURN_CANNOT_CONNECT_TO_IDENTD:
return Messages.getString("luni.15"); //$NON-NLS-1$
case RETURN_DIFFERENT_USER_IDS:
return Messages.getString("luni.16"); //$NON-NLS-1$
default:
return Messages.getString("luni.17"); //$NON-NLS-1$
}
}
/**
* Answer the message's byte buffer.
*/
public byte[] getBytes() {
return buffer;
}
/**
* Get a 16 bit integer from the buffer at the offset given.
*/
private int getInt16(int offset) {
return (((buffer[offset] & 0xFF) << 8) + (buffer[offset + 1] & 0xFF));
}
/**
* Get a 32 bit integer from the buffer at the offset given.
*/
private int getInt32(int offset) {
return ((buffer[offset + 3] & 0xFF)
+ ((buffer[offset + 2] & 0xFF) << 8)
+ ((buffer[offset + 1] & 0xFF) << 16) + ((buffer[offset + 0] & 0xFF) << 24));
}
/**
* Get a String from the buffer at the offset given. The method reads until
* it encounters a null value or reaches the maxLength given.
*/
private String getString(int offset, int maxLength) {
int index = offset;
int lastIndex = index + maxLength;
String result;
while (index < lastIndex && (buffer[index] != 0)) {
index++;
}
try {
result = new String(buffer, offset, index - offset, "ISO8859_1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
return result;
}
/**
* Answer the SOCKS version number. Should always be 4.
*/
private int getVersionNumber() {
return buffer[INDEX_VERSION];
}
/**
* Put a 16 bit integer into the buffer at the offset given.
*/
private void setInt16(int offset, int value) {
buffer[offset] = (byte) (value >>> 8 & 0xFF);
buffer[offset + 1] = (byte) (value & 0xFF);
}
/**
* Put a string into the buffer at the offset given.
*/
private void setString(int offset, int maxLength, String theString) {
byte[] stringBytes;
try {
stringBytes = theString.getBytes("ISO8859_1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
int length = Math.min(stringBytes.length, maxLength);
System.arraycopy(stringBytes, 0, buffer, offset, length);
buffer[offset + length] = 0;
}
/**
* Set the SOCKS version number. This should always be 4.
*/
private void setVersionNumber(int number) {
buffer[INDEX_VERSION] = (byte) number;
}
}