001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.luni.net;
019:
020: import java.io.UnsupportedEncodingException;
021:
022: import org.apache.harmony.luni.util.Msg;
023:
024: class Socks4Message {
025: static final int COMMAND_CONNECT = 1;
026:
027: static final int COMMAND_BIND = 2;
028:
029: static final int RETURN_SUCCESS = 90;
030:
031: static final int RETURN_FAILURE = 91;
032:
033: static final int RETURN_CANNOT_CONNECT_TO_IDENTD = 92;
034:
035: static final int RETURN_DIFFERENT_USER_IDS = 93;
036:
037: static final int REPLY_LENGTH = 8;
038:
039: static final int INDEX_VERSION = 0;
040:
041: private static final int SOCKS_VERSION = 4;
042:
043: private static final int INDEX_COMMAND = 1;
044:
045: private static final int INDEX_PORT = 2;
046:
047: private static final int INDEX_IP = 4;
048:
049: private static final int INDEX_USER_ID = 8;
050:
051: private static final int BUFFER_LENGTH = 256;
052:
053: private static final int MAX_USER_ID_LENGTH = BUFFER_LENGTH
054: - INDEX_USER_ID;
055:
056: protected byte[] buffer;
057:
058: public Socks4Message() {
059: super ();
060: buffer = new byte[BUFFER_LENGTH];
061: setVersionNumber(SOCKS_VERSION);
062: }
063:
064: /**
065: * Get the request's command or result.
066: */
067: public int getCommandOrResult() {
068: return buffer[INDEX_COMMAND];
069: }
070:
071: /**
072: * Set the request's command or result.
073: */
074: public void setCommandOrResult(int command) {
075: buffer[INDEX_COMMAND] = (byte) command;
076: }
077:
078: /**
079: * Answer the request's port number.
080: */
081: public int getPort() {
082: return getInt16(INDEX_PORT);
083: }
084:
085: /**
086: * Set the request's port number.
087: */
088: public void setPort(int port) {
089: setInt16(INDEX_PORT, port);
090: }
091:
092: /*
093: * Answer the IP address of the request as an integer.
094: */
095: public int getIP() {
096: return getInt32(INDEX_IP);
097: }
098:
099: /**
100: * Set the IP address. This expects an array of four bytes in host order.
101: */
102: public void setIP(byte[] ip) {
103: buffer[INDEX_IP] = ip[0];
104: buffer[INDEX_IP + 1] = ip[1];
105: buffer[INDEX_IP + 2] = ip[2];
106: buffer[INDEX_IP + 3] = ip[3];
107: }
108:
109: /**
110: * Answer the user id for authentication.
111: */
112: public String getUserId() {
113: return getString(INDEX_USER_ID, MAX_USER_ID_LENGTH);
114: }
115:
116: /**
117: * Set the user id for authentication.
118: */
119: public void setUserId(String id) {
120: setString(INDEX_USER_ID, MAX_USER_ID_LENGTH, id);
121: }
122:
123: @Override
124: public String toString() {
125: StringBuilder buf = new StringBuilder(50);
126: buf.append("Version: ");
127: buf.append(Integer.toHexString(getVersionNumber()));
128: buf.append(" Command: ");
129: buf.append(Integer.toHexString(getCommandOrResult()));
130: buf.append(" Port: ");
131: buf.append(getPort());
132: buf.append(" IP: ");
133: buf.append(Integer.toHexString(getIP()));
134: buf.append(" User ID: ");
135: buf.append(getUserId());
136: return buf.toString();
137: }
138:
139: /**
140: * Answer the total number of bytes used for the request. This method
141: * searches for the end of the user id, then searches for the end of the
142: * password and returns the final index as the requests length.
143: */
144: public int getLength() {
145: int index = 0;
146:
147: // Look for the end of the user id.
148: for (index = INDEX_USER_ID; buffer[index] != 0; index++) {
149: /*
150: * Finds the end of the user id by searching for the null
151: * termination of the user id string.
152: */
153: }
154:
155: // Increment the index to include the NULL character in the length;
156: index++;
157: return index;
158: }
159:
160: /**
161: * Answer an error string corresponding to the given error value.
162: */
163: public String getErrorString(int error) {
164: switch (error) {
165: case RETURN_FAILURE:
166: return Msg.getString("K00cd"); //$NON-NLS-1$
167: case RETURN_CANNOT_CONNECT_TO_IDENTD:
168: return Msg.getString("K00ce"); //$NON-NLS-1$
169: case RETURN_DIFFERENT_USER_IDS:
170: return Msg.getString("K00cf"); //$NON-NLS-1$
171: default:
172: return Msg.getString("K00d0"); //$NON-NLS-1$
173: }
174: }
175:
176: /**
177: * Answer the message's byte buffer.
178: */
179: public byte[] getBytes() {
180: return buffer;
181: }
182:
183: /**
184: * Get a 16 bit integer from the buffer at the offset given.
185: */
186: private int getInt16(int offset) {
187: return (((buffer[offset] & 0xFF) << 8) + (buffer[offset + 1] & 0xFF));
188: }
189:
190: /**
191: * Get a 32 bit integer from the buffer at the offset given.
192: */
193: private int getInt32(int offset) {
194: return ((buffer[offset + 3] & 0xFF)
195: + ((buffer[offset + 2] & 0xFF) << 8)
196: + ((buffer[offset + 1] & 0xFF) << 16) + ((buffer[offset + 0] & 0xFF) << 24));
197: }
198:
199: /**
200: * Get a String from the buffer at the offset given. The method reads until
201: * it encounters a null value or reaches the maxLength given.
202: */
203: private String getString(int offset, int maxLength) {
204: int index = offset;
205: int lastIndex = index + maxLength;
206: String result;
207:
208: while (index < lastIndex && (buffer[index] != 0)) {
209: index++;
210: }
211: try {
212: result = new String(buffer, offset, index - offset,
213: "ISO8859_1"); //$NON-NLS-1$
214: } catch (UnsupportedEncodingException e) {
215: throw new RuntimeException(e.toString());
216: }
217: return result;
218: }
219:
220: /**
221: * Answer the SOCKS version number. Should always be 4.
222: */
223: private int getVersionNumber() {
224: return buffer[INDEX_VERSION];
225: }
226:
227: /**
228: * Put a 16 bit integer into the buffer at the offset given.
229: */
230: private void setInt16(int offset, int value) {
231: buffer[offset] = (byte) (value >>> 8 & 0xFF);
232: buffer[offset + 1] = (byte) (value & 0xFF);
233: }
234:
235: /**
236: * Put a string into the buffer at the offset given.
237: */
238: private void setString(int offset, int maxLength, String theString) {
239: byte[] stringBytes;
240: try {
241: stringBytes = theString.getBytes("ISO8859_1"); //$NON-NLS-1$
242: } catch (UnsupportedEncodingException e) {
243: throw new RuntimeException(e.toString());
244: }
245: int length = Math.min(stringBytes.length, maxLength);
246: System.arraycopy(stringBytes, 0, buffer, offset, length);
247: buffer[offset + length] = 0;
248: }
249:
250: /**
251: * Set the SOCKS version number. This should always be 4.
252: */
253: private void setVersionNumber(int number) {
254: buffer[INDEX_VERSION] = (byte) number;
255: }
256: }
|