Source code: com/act365/net/SocketUtils.java
1 /*
2 * JSocket Wrench
3 *
4 * Copyright (C) act365.com October 2003
5 *
6 * Web site: http://www.act365.com/wrench
7 * E-mail: developers@act365.com
8 *
9 * The JSocket Wrench library adds support for low-level Internet protocols
10 * to the Java programming language.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
20 * Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 package com.act365.net;
28
29 import com.act365.net.tcp.*;
30
31 import java.io.*;
32 import java.net.*;
33
34 /**
35 *
36 * SocketUtils provides various utility functions e.g. checksum calculations,
37 * functions to read and write numbers from bytestreams and a bytestream
38 * dump printer.
39 */
40
41 public class SocketUtils {
42
43 /**
44 * The protocol in use in the current session.
45 */
46
47 static int protocol = 0 ;
48
49 static boolean includeheader = false ;
50
51 /**
52 * Sets the <code>DatagramSocket</code> factory to be used in the program.
53 * The TCP, TCP/J, UDP and ICMP protocols are supported. TCP/J is a clone
54 * of TCP that uses the IP protocol code 152. The addition of the Raw
55 * prefix to the protocol name indicates that the user wishes to write his
56 * own IP headers for the socket. (The option is not supported on Windows).
57 * The <code>Socket</code> and <code>ServerSocket</code> factory objects
58 * will be set for TCP-based protocols.
59 *
60 * @param protocol protocol to be used by <code>DatagramSocket</code> objects in the app
61 */
62
63 public static void setProtocol( String protocollabel ) throws IOException {
64 if( protocollabel.equals("") ){
65 } else if( protocollabel.equalsIgnoreCase("ICMP") ){
66 protocol = SocketConstants.IPPROTO_ICMP ;
67 includeheader = false ;
68 DatagramSocket.setDatagramSocketImplFactory( new ICMPDatagramSocketImplFactory() );
69 } else if( protocollabel.equalsIgnoreCase("RawTCP") ){
70 protocol = SocketConstants.IPPROTO_TCP ;
71 includeheader = true ;
72 DatagramSocket.setDatagramSocketImplFactory( new RawTCPDatagramSocketImplFactory() );
73 Socket.setSocketImplFactory( new TCPSocketImplFactory() );
74 ServerSocket.setSocketFactory( new TCPSocketImplFactory() );
75 } else if( protocollabel.equalsIgnoreCase("RawTCPJ") ){
76 protocol = SocketConstants.IPPROTO_TCPJ ;
77 includeheader = true ;
78 DatagramSocket.setDatagramSocketImplFactory( new RawTCPJDatagramSocketImplFactory() );
79 Socket.setSocketImplFactory( new TCPJSocketImplFactory() );
80 ServerSocket.setSocketFactory( new TCPJSocketImplFactory() );
81 } else if( protocollabel.equalsIgnoreCase("RawUDP") ){
82 protocol = SocketConstants.IPPROTO_UDP ;
83 includeheader = true ;
84 DatagramSocket.setDatagramSocketImplFactory( new RawUDPDatagramSocketImplFactory() );
85 } else if( protocollabel.equalsIgnoreCase("RawICMP") ){
86 protocol = SocketConstants.IPPROTO_ICMP ;
87 includeheader = true ;
88 DatagramSocket.setDatagramSocketImplFactory( new RawICMPDatagramSocketImplFactory() );
89 } else if( protocollabel.equalsIgnoreCase("TCP") ){
90 protocol = SocketConstants.IPPROTO_TCP ;
91 includeheader = false ;
92 DatagramSocket.setDatagramSocketImplFactory( new TCPDatagramSocketImplFactory() );
93 Socket.setSocketImplFactory( new TCPSocketImplFactory() );
94 ServerSocket.setSocketFactory( new TCPSocketImplFactory() );
95 } else if( protocollabel.equalsIgnoreCase("TCPJ") ){
96 protocol = SocketConstants.IPPROTO_TCPJ ;
97 includeheader = false ;
98 DatagramSocket.setDatagramSocketImplFactory( new TCPJDatagramSocketImplFactory() );
99 Socket.setSocketImplFactory( new TCPJSocketImplFactory() );
100 ServerSocket.setSocketFactory( new TCPJSocketImplFactory() );
101 } else if( protocollabel.equalsIgnoreCase("UDP") ){
102 protocol = SocketConstants.IPPROTO_TCP ;
103 includeheader = false ;
104 DatagramSocket.setDatagramSocketImplFactory( new UDPDatagramSocketImplFactory() );
105 } else {
106 throw new IOException("Protocol" + protocollabel + " is not supported");
107 }
108 }
109
110 /**
111 Returns the protocol associated with the current <code>DatagramSocketImpl</code>.
112 */
113
114 public static int getProtocol() {
115
116 return protocol ;
117 }
118
119 /**
120 Indicates whether the chosen protocol requires the user to include the IP header.
121 */
122
123 public static boolean includeHeader() {
124
125 return includeheader ;
126 }
127
128 /**
129 Standard internet checksum algorithm shared by IP, ICMP, UDP and TCP.
130 */
131
132 public static short checksum( byte[] message , int length , int offset ) {
133
134 // Sum consecutive 16-bit words.
135
136 int sum = 0 ;
137
138 while( offset < length - 1 ){
139
140 sum += (int) integralFromBytes( message , offset , 2 );
141
142 offset += 2 ;
143 }
144
145 if( offset == length - 1 ){
146
147 sum += ( message[offset] >= 0 ? message[offset] : message[offset] ^ 0xffffff00 ) << 8 ;
148 }
149
150 // Add upper 16 bits to lower 16 bits.
151
152 sum = ( sum >>> 16 ) + ( sum & 0xffff );
153
154 // Add carry
155
156 sum += sum >>> 16 ;
157
158 // Ones complement and truncate.
159
160 return (short) ~sum ;
161 }
162
163 /**
164 Specific checksum calculation used for the UDP and TCP pseudo-header.
165 */
166
167 public static short checksum( byte[] source ,
168 byte[] destination ,
169 byte protocol ,
170 short length ,
171 byte[] message ,
172 int offset ) {
173
174 int bufferlength = length + 12 ;
175
176 boolean odd = length % 2 == 1 ;
177
178 if( odd ){
179 ++ bufferlength ;
180 }
181
182 byte[] buffer = new byte[ bufferlength ];
183
184 buffer[0] = source[0];
185 buffer[1] = source[1];
186 buffer[2] = source[2];
187 buffer[3] = source[3];
188
189 buffer[4] = destination[0];
190 buffer[5] = destination[1];
191 buffer[6] = destination[2];
192 buffer[7] = destination[3];
193
194 buffer[8] = (byte) 0 ;
195 buffer[9] = protocol ;
196
197 shortToBytes( length , buffer , 10 );
198
199 int i = 11 ;
200
201 while( ++ i < length + 12 ){
202 buffer[ i ] = message[ i + offset - 12 ] ;
203 }
204
205 if( odd ){
206 buffer[ i ] = (byte) 0 ;
207 }
208
209 return checksum( buffer , buffer.length , 0 );
210 }
211
212 /**
213 Forms an integral type from consecutive bytes in a buffer
214 */
215
216 static long integralFromBytes( byte[] buffer , int offset , int length ){
217
218 long answer = 0 ;
219
220 while( -- length >= 0 ) {
221 answer = answer << 8 ;
222 answer |= buffer[offset] >= 0 ? buffer[offset] : 0xffffff00 ^ buffer[offset] ;
223 ++ offset ;
224 }
225
226 return answer ;
227 }
228
229 /**
230 Converts consecutive bytes from a buffer into a short.
231 */
232
233 public static short shortFromBytes( byte[] buffer , int offset ) {
234 return (short) integralFromBytes( buffer , offset , 2 );
235 }
236
237 /**
238 Converts consecutive bytes from a buffer into an int.
239 */
240
241 public static int intFromBytes( byte[] buffer , int offset ) {
242 return (int) integralFromBytes( buffer , offset , 4 );
243 }
244
245 /**
246 Converts consecutive bytes from a buffer into a long.
247 */
248
249 public static long longFromBytes( byte[] buffer , int offset ) {
250 return integralFromBytes( buffer , offset , 8 );
251 }
252
253 /**
254 Writes a long into a buffer.
255 */
256
257 public static void longToBytes( long value , byte[] buffer , int offset ) {
258 buffer[ offset + 7 ] = (byte)( value & 0xff );
259 value = value >>> 8 ;
260 buffer[ offset + 6 ] = (byte)( value & 0xff );
261 value = value >>> 8 ;
262 buffer[ offset + 5 ] = (byte)( value & 0xff );
263 value = value >>> 8 ;
264 buffer[ offset + 4 ] = (byte)( value & 0xff );
265 value = value >>> 8 ;
266 buffer[ offset + 3 ] = (byte)( value & 0xff );
267 value = value >>> 8 ;
268 buffer[ offset + 2 ] = (byte)( value & 0xff );
269 value = value >>> 8 ;
270 buffer[ offset + 1 ] = (byte)( value & 0xff );
271 value = value >>> 8 ;
272 buffer[ offset ] = (byte)( value );
273 }
274
275 /**
276 Writes an int into a buffer.
277 */
278
279 public static void intToBytes( int value , byte[] buffer , int offset ){
280 buffer[ offset + 3 ] = (byte)( value & 0xff );
281 value = value >> 8 ;
282 buffer[ offset + 2 ] = (byte)( value & 0xff );
283 value = value >> 8 ;
284 buffer[ offset + 1 ] = (byte)( value & 0xff );
285 value = value >> 8 ;
286 buffer[ offset ] = (byte)( value );
287 }
288
289 /**
290 Writes a short into a buffer.
291 */
292
293 public static void shortToBytes( short value , byte[] buffer , int offset ){
294 buffer[ offset + 1 ] = (byte)( value & 0xff );
295 value = (short)( value >> 8 );
296 buffer[ offset ] = (byte)( value );
297 }
298
299 /**
300 Dumps a buffer in printable form.
301 */
302
303 public static void dump( PrintStream printer , byte[] buffer , int offset , int count ){
304
305 final int upper_bound = offset + ( count / 8 + 1 )* 8 ;
306
307 int i = offset ;
308
309 StringBuffer str = new StringBuffer();
310
311 while( i <= upper_bound ){
312
313 int j ;
314
315 String tmpstr ;
316
317 if( ( i - offset ) % 8 == 0 ){
318
319 if( i > 0 ){
320
321 str.append(' ');
322
323 j = i - 9 ;
324
325 while( ++ j < i ){
326
327 if( j < offset + count ){
328 if( buffer[ j ] >= 32 ){
329 try {
330 tmpstr = new String( buffer , j , 1 , "UTF8" );
331 } catch ( UnsupportedEncodingException e ){
332 tmpstr = null ;
333 }
334 } else {
335 tmpstr = null ;
336 }
337 } else {
338 tmpstr = " ";
339 }
340
341 if( tmpstr != null ){
342 str.append( tmpstr );
343 } else {
344 str.append('.');
345 }
346 }
347
348 printer.println( str.toString() );
349 }
350
351 str = new StringBuffer( 38 );
352
353 tmpstr = Integer.toHexString( i - offset );
354
355 j = -1 ;
356
357 while( ++ j < 4 - tmpstr.length() ){
358 str.append('0');
359 }
360
361 str.append( tmpstr );
362 }
363
364 str.append(' ');
365
366 if( i < offset + count ){
367
368 int unsigned = buffer[ i - offset ] >= 0 ? buffer[ i - offset ] : 0xffffff00 ^ buffer[ i - offset ] ;
369
370 if( unsigned < 16 ){
371 str.append('0');
372 }
373
374 str.append( Integer.toHexString( unsigned ) );
375 } else {
376 str.append(" ");
377 }
378
379 ++ i ;
380 }
381 }
382 }