PongMsg.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
phex.msg |
![]() |
![]() |
Phex |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* PHEX - The pure-java Gnutella-servent.
* Copyright (C) 2001 - 2008 Phex Development Group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* --- SVN Information ---
* $Id: PongMsg.java 4231 2008-07-15 16:01:10Z gregork $
*/
package phex.msg;
import java.util.HashSet;
import java.util.Set;
import phex.common.address.DefaultDestAddress;
import phex.common.address.DestAddress;
import phex.common.address.MalformedDestAddressException;
import phex.common.log.NLogger;
import phex.io.buffer.ByteBuffer;
import phex.net.repres.PresentationManager;
import phex.security.AccessType;
import phex.security.PhexSecurityManager;
import phex.udp.hostcache.UdpHostCache;
import phex.utils.HexConverter;
import phex.utils.IOUtil;
/**
* <p>A pong response.</p>
*
* <p>This encapsulates a Gnutella message that informs this servent of the
* vital statistics of a Gnutella host. Pongs should only ever be received
* in response to pings.</p>
*
* <p>This implementation handles GGEP extension blocks.</p>
*/
public class PongMsg extends Message
{
protected static final int MIN_PONG_DATA_LEN = 14;
/**
* <p>The un-parsed body of the message.</p>
*/
private byte[] body;
/**
* The address this pong is carrying.
*/
private DestAddress pongAddress;
private long fileCount;
private long fileSizeInKB;
private String vendor;
private int vendorVersionMajor = -1;
private int vendorVersionMinor = -1;
private int avgDailyUptime;
private boolean isUltrapeer;
private GGEPBlock ggepBlock;
/**
* holds the information that can appear in udp pongs
*/
private Set<DestAddress> ippDestAddresses;
private Set<UdpHostCache> udpHostCaches;
private UdpHostCache udpHostCache;
public PongMsg( MsgHeader aHeader, byte[] payload, PhexSecurityManager securityService )
{
super( aHeader );
getHeader().setPayloadType( MsgHeader.PONG_PAYLOAD );
body = payload;
getHeader().setDataLength( body.length );
avgDailyUptime = -1;
// parse the body
parseBody( securityService );
}
/**
* <p>Create a new MsgInitResponse.</p>
*
* <p>The header will be modified so that its function property becomes
* MsgHeader.sInitResponse. The header argument is owned by this object.</p>
*
* @param header the MsgHeader to associate with the new message
*/
protected PongMsg( MsgHeader header, DestAddress pongAddress, int fileCount,
int fileSizeInKB, boolean isUltrapeer, GGEPBlock ggepBlock )
{
super( header );
getHeader().setPayloadType( MsgHeader.PONG_PAYLOAD );
this.pongAddress = pongAddress;
this.fileCount = fileCount;
this.isUltrapeer = isUltrapeer;
this.ggepBlock = ggepBlock;
if ( isUltrapeer )
{
this.fileSizeInKB = createUltrapeerMarking( fileSizeInKB );
}
else
{
this.fileSizeInKB = fileSizeInKB;
}
buildBody();
getHeader().setDataLength( body.length );
}
/**
* Get the address this pong is carrying.
* @return the address of this pong message.
*/
public DestAddress getPongAddress()
{
return pongAddress;
}
/**
* Get the number of files served from this servent.
*
* @return a zero or positive integer giving the number of files served
*/
public long getFileCount()
{
return fileCount;
}
/**
* Get the number of bytes served by this servent.
*
* @return the number of bytes served
*/
public long getFileSizeInKB()
{
return fileSizeInKB;
}
/**
* @return the vendor
*/
public String getVendor()
{
return vendor;
}
/**
* @return the vendorVersionMajor
*/
public int getVendorVersionMajor()
{
return vendorVersionMajor;
}
/**
* @return the vendorVersionMinor
*/
public int getVendorVersionMinor()
{
return vendorVersionMinor;
}
/**
* @return the avgDailyUptime
*/
public int getDailyUptime()
{
return avgDailyUptime;
}
public boolean hasFreeLeafSlots()
{
if ( ggepBlock == null ||
!ggepBlock.isExtensionAvailable( GGEPBlock.ULTRAPEER_ID ) )
{
return false;
}
byte[] data = ggepBlock.getExtensionData( GGEPBlock.ULTRAPEER_ID );
if ( data != null )
{
if( data.length >= 3 )
{
if( data[1] > 0 )
{
return true;
}
}
}
return false;
}
public boolean hasFreeUPSlots()
{
if ( ggepBlock == null ||
!ggepBlock.isExtensionAvailable( GGEPBlock.ULTRAPEER_ID ) )
{
return false;
}
byte[] data = ggepBlock.getExtensionData( GGEPBlock.ULTRAPEER_ID );
if ( data != null )
{
if( data.length >= 3 )
{
if( data[2] > 0 )
{
return true;
}
}
}
return false;
}
public Set<DestAddress> getIPPDestAddresses()
{
return ippDestAddresses;
}
public Set<UdpHostCache> getUdpHostCaches()
{
return udpHostCaches;
}
public UdpHostCache getUdpHostCache()
{
return udpHostCache;
}
public byte[] getBody()
{
return body;
}
/**
* {@inheritDoc}
*/
@Override
public ByteBuffer createMessageBuffer()
{
return ByteBuffer.wrap( body );
}
public byte[] getbytes()
{
byte[] data = new byte[ MsgHeader.DATA_LENGTH + body.length ];
byte[] hdr = getHeader().getBytes();
System.arraycopy( hdr, 0, data, 0, MsgHeader.DATA_LENGTH );
System.arraycopy( body, 0, data, MsgHeader.DATA_LENGTH , body.length );
return data;
}
public String getDebugString()
{
return "Pong[ Addr=" + pongAddress +
", FileCount=" + fileCount +
", FileSize=" + fileSizeInKB +
", AvgUptime=" + avgDailyUptime +
", HEX=[" + HexConverter.toHexString( body ) +
"] ]";
}
private void buildBody()
{
byte[] ggepExtension;
int extensionLength;
if ( ggepBlock != null )
{
// we only build from the first GGEP block our body
ggepExtension = ggepBlock.getBytes();
extensionLength = ggepExtension.length;
}
else
{
ggepExtension = null;
extensionLength = 0;
}
body = new byte[ 14 + extensionLength ];
IOUtil.serializeShortLE( (short)pongAddress.getPort(), body, 0 );
System.arraycopy( pongAddress.getIpAddress().getHostIP(), 0, body, 2, 4 );
IOUtil.serializeIntLE( (int)fileCount, body, 6);
IOUtil.serializeIntLE( (int)fileSizeInKB, body, 10);
if ( ggepExtension != null )
{
System.arraycopy( ggepExtension, 0, body, 14, extensionLength );
}
}
private void parseBody( PhexSecurityManager securityService )
{
int port = IOUtil.unsignedShort2Int(IOUtil.deserializeShortLE( body, 0 ));
byte[] ip = new byte[4];
ip[0] = body[2];
ip[1] = body[3];
ip[2] = body[4];
ip[3] = body[5];
pongAddress = new DefaultDestAddress( ip, port );
fileCount = IOUtil.unsignedInt2Long( IOUtil.deserializeIntLE( body, 6 ) );
fileSizeInKB = IOUtil.unsignedInt2Long( IOUtil.deserializeIntLE( body, 10 ) );
// parse possible GGEP data
if ( body.length <= 14 )
{
return;
}
parseGGEPBlocks( securityService );
}
private void parseGGEPBlocks( PhexSecurityManager securityService )
{
ggepBlock = GGEPBlock.mergeGGEPBlocks( GGEPBlock.parseGGEPBlocks( body, 14 ) );
if ( ggepBlock.isExtensionAvailable( GGEPBlock.VENDOR_CODE_ID ) )
{
byte[] data = ggepBlock.getExtensionData( GGEPBlock.VENDOR_CODE_ID );
if ( data.length >= 4 )
{
vendor = new String( data, 0, 4 ).intern();
if ( data.length > 4 )
{
vendorVersionMajor = data[4] >> 4;
vendorVersionMinor = data[4] & 0x0F;
}
}
}
if ( ggepBlock.isExtensionAvailable( GGEPBlock.AVARAGE_DAILY_UPTIME ) )
{
byte[] data = ggepBlock.getExtensionData( GGEPBlock.AVARAGE_DAILY_UPTIME );
if ( data != null )
{
if ( data.length >= 1 && data.length <= 4)
{
avgDailyUptime = IOUtil.deserializeIntLE( data, 0, data.length );
if ( avgDailyUptime <= 0 )
{
NLogger.warn( PongMsg.class, "Negative average uptime GGEP extension data: " +
avgDailyUptime + " - " + HexConverter.toHexString( data ) );
avgDailyUptime = -1;
}
}
else
{
NLogger.warn( PongMsg.class, "Invalid average uptime GGEP extension data: " +
HexConverter.toHexString( data ) );
avgDailyUptime = -1;
}
}
}
// checks for the UP ggep extension
// if its present and the host has free slots its added to the respective free slots container
// in NetworkHostContainer ....as of now we ignore the actual count of the slots available
if ( ggepBlock.isExtensionAvailable( GGEPBlock.UDP_HOST_CACHE_IPP ) )
{
byte[] data = ggepBlock.getExtensionData( GGEPBlock.UDP_HOST_CACHE_IPP );
if ( data != null )
{
ippDestAddresses = unpackIpPortData( data, securityService );
}
}
// try to get any packed udp host cache list which may be present in udp pongs
if( ggepBlock.isExtensionAvailable( GGEPBlock.UDP_HOST_CACHE_PHC))
{
byte[] data = ggepBlock.getExtensionData( GGEPBlock.UDP_HOST_CACHE_PHC );
if ( data != null )
{
String packedData = new String( data );
udpHostCaches = parsePackedHostCache( packedData, securityService );
}
}
//check if the sending host is a udp host cache n add to
//the functional udp host cache container
if( ggepBlock.isExtensionAvailable( GGEPBlock.UDP_HOST_CACHE_UDPHC))
{
byte[] data = ggepBlock.getExtensionData( GGEPBlock.UDP_HOST_CACHE_UDPHC );
try
{
DestAddress address;
if ( data != null && data.length > 0)
{
address = new DefaultDestAddress( new String( data ), pongAddress.getPort() );
}
else
{
address = pongAddress;
}
//add to the container
AccessType access = securityService.controlHostAddressAccess(
address );
if ( access == AccessType.ACCESS_GRANTED )
{
udpHostCache = new UdpHostCache( address );
}
}
catch( IllegalArgumentException e)
{
NLogger.warn( PongMsg.class, "INVALID Udp Host Cache found " +
"and ignored " + e);
}
}
}
/**
* gets the list of udp host cache addresses from the
* packed host cache ggep extension
* @param packedHostCaches
*/
private Set<UdpHostCache> parsePackedHostCache( String packedHostCaches, PhexSecurityManager securityMgr )
{
PresentationManager netPresMgr = PresentationManager.getInstance();
String[] hostCaches = packedHostCaches.split( "\n" );
Set<UdpHostCache> packedUdpHostCaches = new HashSet<UdpHostCache>( hostCaches.length );
for( int i=0; i < hostCaches.length; i++ )
{
//find the position of the first key/value pair if any
int pos = hostCaches[i].indexOf( "&" );
try
{
DestAddress address;
//no key/value pair found
if( pos == -1)
{
address = netPresMgr.createHostAddress(hostCaches[i], DefaultDestAddress.DEFAULT_PORT);
}
else
{
//key/value pair found, but just ignore as of now
String temp = hostCaches[i].substring( 0, pos );
address = netPresMgr.createHostAddress(temp, DefaultDestAddress.DEFAULT_PORT);
}
AccessType access = securityMgr.controlHostAddressAccess( address );
if ( access == AccessType.ACCESS_GRANTED )
{
UdpHostCache cache = new UdpHostCache( address );
packedUdpHostCaches.add( cache );
}
}
catch ( MalformedDestAddressException e )
{
// just ignore and continue with next string
NLogger.warn( PongMsg.class, " Ignored " +
"One Host Cache address in a packed host cache list "
+ e );
continue;
}
}
return packedUdpHostCaches;
}
private static Set<DestAddress> unpackIpPortData( byte[] data, PhexSecurityManager securityMgr )
{
Set<DestAddress> ipPortPairs = null;
try
{
final int FIELD_SIZE = 6;
if (data.length % FIELD_SIZE != 0)
{
throw new InvalidGGEPBlockException("invalid IPPORT EXTENSION DATA IN PONG");
}
int size = data.length/FIELD_SIZE;
ipPortPairs = new HashSet<DestAddress>();
int index;
for (int i=0; i<size; i++)
{
index = i*FIELD_SIZE;
byte[] ip = new byte[4];
System.arraycopy(data, index, ip, 0, 4);
int port = IOUtil.unsignedShort2Int(
IOUtil.deserializeShortLE( data, index + 4 ) );
AccessType access = securityMgr.controlHostIPAccess( ip );
if ( access == AccessType.ACCESS_GRANTED )
{
DestAddress current = new DefaultDestAddress( ip, port );
ipPortPairs.add( current );
}
}
}
catch ( InvalidGGEPBlockException exp )
{
//ignore and continue parsing...
NLogger.warn( PongMsg.class, exp );
}
return ipPortPairs;
}
/**
* Returns true if this pong is marking a ultrapeer. This is the case when
* fileSizeInKB is a power of two but at least 8.
* @return true if this pong is marking a ultrapeer.
*/
public boolean isUltrapeerMarked()
{
if ( fileSizeInKB < 8 )
{
return false;
}
return ( fileSizeInKB & (fileSizeInKB - 1 ) ) == 0;
}
/**
* Sets the ultrapeer kbytes field for ultrapeers.
* This is done by returning the nearest power of two of the kbytes field.
* A kbytes value of 1536 would return 1024.
* 1535 512.
*/
private static int createUltrapeerMarking( int kbytes )
{
if ( kbytes < 12 )
{
return 8;
}
// first get the bit count of the value and substract 1...
int bitCount = IOUtil.determineBitCount( kbytes );
// calculate the power of two...
int power = (int)Math.pow( 2, bitCount );
// now determine the border value of the exponent...
int minBorder = power - (power / 4);
if ( kbytes < minBorder )
{
power = (int)Math.pow( 2, bitCount-1 );
}
return power;
}
}
The table below shows all metrics for PongMsg.java.




