/*
* Copyright (c) 2006-2007 Graz University of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names "Graz University of Technology" and "IAIK of Graz University of
* Technology" must not be used to endorse or promote products derived from
* this software without prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package ejip.jtcpip;
/**
* Provides methods to manipulate a Payload instance as if it is a UDP packet
*
* @see ejip2.jtcpip.Payload
*
* @author Tobias Kellner
* @author Ulrich Feichter
* @author Christof Rath
* @version $Rev: 938 $ $Date: 2007/01/24 19:37:07 $
*/
public class UDPPacket
{
/**
* Get the sending port. The value is read from the UDP header.
*
* @param pay
* The Payload
* @return The source port
*/
public static short getSourcePort(Payload pay)
{
return (short) ((pay.payload[0] >>> 16) & 0xFFFF);
}
/**
* Set the sending port. The value is set in the UDP header.
*
* @param pay
* The Payload
* @param port
* The source port
*/
public static void setSourcePort(Payload pay, short port)
{
int i = pay.payload[0] & 0x0000FFFF;
pay.payload[0] = i | (port << 16);
}
/**
* Get the receiving port. The value is read from the UDP header.
*
* @param pay
* The Payload
* @return The destination port
*/
public static short getDestPort(Payload pay)
{
return (short) (pay.payload[0] & 0x0000FFFF);
}
/**
* Set the receiving port. The value is set in the UDP header.
*
* @param pay
* The Payload
* @param port
* The destination port
*/
public static void setDestPort(Payload pay, short port)
{
int i = pay.payload[0] & 0xFFFF0000;
pay.payload[0] = i | port;
}
/**
* Get the length in bytes of the entire datagram. This includes header and
* data. (min. 8 - max. 65527) The value is read from the UDP header.
*
* @param pay
* The Payload
* @return The UDP Packet lenght
*/
public static short getLength(Payload pay)
{
return (short) ((pay.payload[1] >>> 16) & 0xFFFF);
}
/**
* Set the length in bytes of the entire datagram. This includes header and
* data. (min. 8 - max. 65527) The value is set in the UDP header.
*
* @param pay
* The Payload
* @param len
* The UDP Packet lenght
*/
public static void setLength(Payload pay, short len)
{
int i = pay.payload[1] & 0x0000FFFF;
pay.payload[1] = i | (len << 16);
}
/**
* Get the Header Checksum. The checksum is calculated over the UDP header
* (+IP Pseudoheader) and the data. The value is read from the UDP header.
*
* @param pay
* The Payload
* @return The Header Checksum
*/
public static short getChecksum(Payload pay)
{
return (short) ((pay.payload[1] >>> 16) & 0xFFFF);
}
/**
* Set the Header Checksum to the correct value. The checksum is calculated
* over the UDP header (+IP Pseudoheader) and the data (with the checksum
* field set to zero). The calculation is done in
* {@link UDPPacket#calculateChecksum}. The value is set in the UDP header.
*
* @param pay
* The Payload
*/
public static void setChecksum(Payload pay)
{
pay.payload[1] = pay.payload[1] & 0xFFFF0000;
pay.payload[1] = pay.payload[1] | (calculateChecksum(pay) & 0xFFFF);
}
/**
* Calculate the correct Checksum. The checksum is calculated over the UDP
* header (+IP Pseudoheader) and the data (with the checksum field assumed
* to be zero).
*
* @param pay
* The Payload
* @return The Checksum
*/
public static short calculateChecksum(Payload pay)
{
// compute over UDP Header and Payload, except the last bytes which
// don't
// fall on an int boundary
int udpPacketLength = pay.length;
int cnt = udpPacketLength / 4;
int i = 0;
int sum = 0;
int ofs = 0;
while (cnt != 0)
{
try
{
i = pay.payload[ofs];
} catch (Exception e)
{
System.out.println("Offset: " + ofs);
e.printStackTrace();
System.exit(1);
}
sum += i & 0xFFFF;
sum += i >>> 16;
++ofs;
--cnt;
}
int modulo = udpPacketLength % 4;
if (modulo != 0)
{
i = pay.payload[ofs];
// compute over the last int of the payload
switch (modulo)
{
case 1:
sum += (i >>> 16) & 0xFF00;
break;
case 2:
sum += (i >>> 16) & 0xFFFF;
break;
case 3:
sum += i & 0xFF00;
sum += (i >>> 16) & 0xFFFF;
}
}
// compute over the pseudo header
sum += (IPPacket.getDestAddr(pay) & 0xFFFF) + (IPPacket.getDestAddr(pay) >>> 16);
sum += (IPPacket.getSrcAddr(pay) & 0xFFFF) + (IPPacket.getSrcAddr(pay) >>> 16);
sum += IPPacket.getProtocol(pay) & 0x00FF;
sum += udpPacketLength & 0xFFFF;
while ((sum >> 16) != 0)
sum = (sum & 0xffff) + (sum >> 16);
sum = (~sum) & 0xffff;
return (short) sum;
}
/**
* Check whether the checksum is valid.
*
* @param pay
* The Payload
* @return Whether the checksum is valid.
*/
public static boolean isChecksumValid(Payload pay)
{
return calculateChecksum(pay) == 0;
}
/**
* Get the Data offset. This is the size of the UDP header in 32-bit words.
*
* @param pay
* The Payload
* @return The Data offset
*/
public static byte getDataOffset(Payload pay)
{
return 2;
}
/**
* Returns the length of the payload in octets. This is the size of the IP
* packet minus the size of the IP and the UDP headers.
*
* @param pay
* The Payload
* @return The number of payload octets
*/
public static int getDataLength(Payload pay)
{
return pay.length - getDataOffset(pay) * 4;
}
/**
* Fills the payload buffer with a given byte array.
*
* @param pay
* The Payload to write to
* @param buffer
* The data to write
* @throws JtcpipException
* Data too large
*/
public static void setData(Payload pay, byte[] buffer) throws JtcpipException
{
if (buffer != null)
setData(pay, buffer, 0, buffer.length);
else
setData(pay, buffer, 0, 0);
}
/**
* Fills the payload buffer with a given area of a byte array.
*
* @param pay
* The Payload to write to
* @param buffer
* The data to write
* @param firstByte
* The start of the data to write
* @param count
* The length of the data to write
* @throws JtcpipException
* Data too large
*/
public static void setData(Payload pay, byte[] buffer, int firstByte, int count)
throws JtcpipException
{
pay.setData(getDataOffset(pay), buffer, firstByte, count);
}
}