/* * $Id: UDPPacket.java 5347 2005-05-25 22:45:54Z dfs $ * * Copyright 2005 Daniel F. Savarese * Contact Information: http://www.savarese.org/contact.html * * Licensed 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.savarese.org/software/ApacheLicense-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.savarese.vserv.tcpip; /** * UDPPacket extends {@link IPPacket} to handle UDP packets. The UDP * packet structure is described in * <a href="http://www.ietf.org/rfc/rfc0768.txt?number=768">RFC 768</a>. * * @author <a href="http://www.savarese.org/">Daniel F. Savarese</a> */ public class UDPPacket extends IPPacket { /** Offset into the UDP packet of the source port header value. */ public static final int OFFSET_SOURCE_PORT = 0; /** Offset into the UDP packet of the destination port header value. */ public static final int OFFSET_DESTINATION_PORT = 2; /** Offset into the UDP packet of UDP total packet length header value. */ public static final int OFFSET_UDP_TOTAL_LENGTH = 4; /** Offset into the UDP packet of the UDP checksum. */ public static final int OFFSET_UDP_CHECKSUM = 6; /** Length of the UDP packet header in bytes. */ public static final int LENGTH_UDP_HEADER = 8; /** The byte offset into the IP packet where the UDP packet begins. */ private int __offset; /** * Creates a new UDP packet of a given size. * * @param size The number of bytes in the packet. */ public UDPPacket(int size) { super(size); __offset = 0; } /** * Creates a new UDP packet that is a copy of a given packet. * * @param packet The packet to replicate. */ public UDPPacket(UDPPacket packet) { super(packet.size()); copy(packet); __offset = packet.__offset; } /** * Copies the contents of a UDPPacket. If the current data array is * of insufficient length to store the contents, a new array is * allocated. * * @param packet The UDPPacket to copy. */ public final void copyData(UDPPacket packet) { if(_data_.length < packet._data_.length) { byte[] data = new byte[packet._data_.length]; System.arraycopy(_data_, 0, data, 0, getCombinedHeaderByteLength()); _data_ = data; } int length = packet.getUDPDataByteLength(); System.arraycopy(packet._data_, packet.getCombinedHeaderByteLength(), _data_, getCombinedHeaderByteLength(), length); setUDPDataByteLength(length); } public void setData(byte[] data) { super.setData(data); __offset = getIPHeaderByteLength(); } /** * Sets the source port. * * @param port The new source port. */ public final void setSourcePort(int port) { _data_[__offset + OFFSET_SOURCE_PORT] = (byte)((port >> 8) & 0xff); _data_[__offset + OFFSET_SOURCE_PORT + 1] = (byte)(port & 0xff); } /** * Sets the destination port. * * @param port The new destination port. */ public final void setDestinationPort(int port) { _data_[__offset + OFFSET_DESTINATION_PORT] = (byte)((port >> 8) & 0xff); _data_[__offset + OFFSET_DESTINATION_PORT + 1] = (byte)(port & 0xff); } /** * @return The source port. */ public final int getSourcePort() { return (((_data_[__offset + OFFSET_SOURCE_PORT] & 0xff) << 8) | (_data_[__offset + OFFSET_SOURCE_PORT + 1] & 0xff)); } /** * @return The destination port. */ public final int getDestinationPort() { return (((_data_[__offset + OFFSET_DESTINATION_PORT] & 0xff) << 8) | (_data_[__offset + OFFSET_DESTINATION_PORT + 1] & 0xff)); } public void setIPHeaderLength(int length) { super.setIPHeaderLength(length); __offset = getIPHeaderByteLength(); } /** * Sets the UDP total length header field. * * @param length The length of the UDP packet in bytes. */ public void setUDPPacketLength(int length) { _data_[__offset + OFFSET_UDP_TOTAL_LENGTH] = (byte)((length >> 8) & 0xff); _data_[__offset + OFFSET_UDP_TOTAL_LENGTH + 1] = (byte)(length & 0xff); } /** * @return The value of the UDP total length header field. */ public final int getUDPPacketLength() { return (((_data_[__offset + OFFSET_UDP_TOTAL_LENGTH] & 0xff) << 8) | (_data_[__offset + OFFSET_UDP_TOTAL_LENGTH + 1] & 0xff)); } /** * @return The UDP checksum. */ public final int getUDPChecksum() { return (((_data_[__offset + OFFSET_UDP_CHECKSUM] & 0xff) << 8) | (_data_[__offset + OFFSET_UDP_CHECKSUM + 1] & 0xff)); } /** * @return The UDP packet length in bytes. This is the size of the * IP packet minus the size of the IP header. Normally, you want * this to equal the length stored in the UDP header * (see {@link #getUDPPacketLength}). */ public final int getUDPPacketByteLength() { return getIPPacketLength() - __offset; } /** * @return The IP header length plus the UDP header length in bytes. */ public final int getCombinedHeaderByteLength() { return __offset + LENGTH_UDP_HEADER; } /** * Sets the length of the UDP data payload. * * @param length The length of the UDP data payload in bytes. */ public final void setUDPDataByteLength(int length) { if(length < 0) length = 0; setIPPacketLength(getCombinedHeaderByteLength() + length); } public final int getUDPDataByteLength() { return getIPPacketLength() - getCombinedHeaderByteLength(); } private final int __getVirtualHeaderTotal() { int s1 = ((_data_[OFFSET_SOURCE_ADDRESS] & 0xff) << 8) | (_data_[OFFSET_SOURCE_ADDRESS + 1] & 0xff); int s2 = ((_data_[OFFSET_SOURCE_ADDRESS + 2] & 0xff) << 8) | (_data_[OFFSET_SOURCE_ADDRESS + 3] & 0xff); int d1 = ((_data_[OFFSET_DESTINATION_ADDRESS] & 0xff) << 8) | (_data_[OFFSET_DESTINATION_ADDRESS + 1] & 0xff); int d2 = ((_data_[OFFSET_DESTINATION_ADDRESS + 2] & 0xff) << 8) | (_data_[OFFSET_DESTINATION_ADDRESS + 3] & 0xff); return s1 + s2 + d1 + d2 + getProtocol() + getUDPPacketByteLength(); } /** * Computes the UDP checksum, optionally updating the UDP checksum header. * * @param update Specifies whether or not to update the UDP checksum * header after computing the checksum. A value of true indicates * the header should be updated, a value of false indicates it * should not be updated. * @return The computed UDP checksum. */ public final int computeUDPChecksum(boolean update) { return _computeChecksum_(__offset, __offset + OFFSET_UDP_CHECKSUM, getIPPacketLength(), __getVirtualHeaderTotal(), update); } /** * Same as <code>computeUDPChecksum(true);</code> * * @return The computed UDP checksum value. */ public final int computeUDPChecksum() { return computeUDPChecksum(true); } }