package com.limegroup.gnutella.messages.vendor; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.List; import com.limegroup.gnutella.ErrorService; import com.limegroup.gnutella.ManagedConnection; import com.limegroup.gnutella.RouterService; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.statistics.BandwidthStat; public class StatisticVendorMessage extends VendorMessage { public static final int VERSION = 1; private static final String DELIMITER = " | "; private static final String DELIMITER2 = " ^ "; /** * Constructor for a StatisticVendorMessage read off the network, meaing it * was received in respose to a GiveStatsVendorMessage sent by this node. */ public StatisticVendorMessage(byte[] guid, byte ttl, byte hops, int version, byte[] payload) throws BadPacketException { super(guid, ttl, hops, F_LIME_VENDOR_ID, F_STATISTICS, version, payload); } /** * Constructor to make a StatisticVendorMessage in response to a * GiveStatisticsVendorMessage. This is an outgoing StatisticVendorMessage */ public StatisticVendorMessage(GiveStatsVendorMessage giveStatVM) { super(F_LIME_VENDOR_ID, F_STATISTICS, VERSION, derivePayload(giveStatVM)); } /** * Determines whether or not we know how to respond to the GiveStats msg. */ public static boolean isSupported(GiveStatsVendorMessage vm) { switch(vm.getStatType()) { case GiveStatsVendorMessage.GNUTELLA_INCOMING_TRAFFIC: case GiveStatsVendorMessage.GNUTELLA_OUTGOING_TRAFFIC: switch(vm.getStatControl()) { case GiveStatsVendorMessage.PER_CONNECTION_STATS: case GiveStatsVendorMessage.ALL_CONNECTIONS_STATS: case GiveStatsVendorMessage.UP_CONNECTIONS_STATS: case GiveStatsVendorMessage.LEAF_CONNECTIONS_STATS: return true; default: return false; } case GiveStatsVendorMessage.HTTP_DOWNLOAD_TRAFFIC_STATS: case GiveStatsVendorMessage.HTTP_UPLOAD_TRAFFIC_STATS: return true; default: return false; } } private static byte[] derivePayload(GiveStatsVendorMessage giveStatsVM) { byte control = giveStatsVM.getStatControl(); byte type = giveStatsVM.getStatType(); byte[] part1 = {control, type}; //write the type of stats we are writing out ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { baos.write(part1); } catch(IOException iox) { ErrorService.error(iox); // impossible. } byte[] part2; StringBuffer buff; switch(type) { case GiveStatsVendorMessage.GNUTELLA_INCOMING_TRAFFIC: case GiveStatsVendorMessage.GNUTELLA_OUTGOING_TRAFFIC: boolean incoming = type==GiveStatsVendorMessage.GNUTELLA_INCOMING_TRAFFIC; part2 = getGnutellaStats(control,incoming); break; case GiveStatsVendorMessage.HTTP_DOWNLOAD_TRAFFIC_STATS: //NOTE: in this case we ignore the granularity control, since //HTTP traffic is not connection specific buff = new StringBuffer(); buff.append( BandwidthStat.HTTP_HEADER_DOWNSTREAM_BANDWIDTH.getTotal()); buff.append(DELIMITER2); buff.append( BandwidthStat.HTTP_BODY_DOWNSTREAM_BANDWIDTH.getTotal()); part2 = buff.toString().getBytes(); break; case GiveStatsVendorMessage.HTTP_UPLOAD_TRAFFIC_STATS: //NOTE: in this case we ignore the granularity control, since //HTTP traffic is not connection specific buff = new StringBuffer(); buff.append( BandwidthStat.HTTP_HEADER_UPSTREAM_BANDWIDTH.getTotal()); buff.append(DELIMITER2); buff.append(BandwidthStat.HTTP_BODY_UPSTREAM_BANDWIDTH.getTotal()); part2 = buff.toString().getBytes(); break; default: throw new IllegalArgumentException("unknown type: " + type); } try { baos.write(part2); } catch (IOException iox) { ErrorService.error(iox); // impossible. } return baos.toByteArray(); } private static byte[] getGnutellaStats(byte control, boolean incoming) { List conns = RouterService.getConnectionManager().getConnections(); StringBuffer buff = new StringBuffer(); switch(control) { case GiveStatsVendorMessage.PER_CONNECTION_STATS: for(Iterator iter = conns.iterator(); iter.hasNext() ; ) { ManagedConnection c = (ManagedConnection)iter.next(); buff.append(c.toString()); buff.append(DELIMITER2); if(incoming) { buff.append(c.getNumMessagesReceived()); buff.append(DELIMITER); buff.append(c.getNumReceivedMessagesDropped()); } else { buff.append(c.getNumMessagesSent()); buff.append(DELIMITER); buff.append(c.getNumSentMessagesDropped()); } buff.append(DELIMITER2); } return buff.toString().getBytes(); case GiveStatsVendorMessage.ALL_CONNECTIONS_STATS: int messages = -1; int dropped = -1; for(Iterator iter = conns.iterator(); iter.hasNext() ; ) { ManagedConnection c = (ManagedConnection)iter.next(); messages += incoming ? c.getNumMessagesReceived() : c.getNumMessagesSent(); dropped += incoming ? c.getNumReceivedMessagesDropped() : c.getNumSentMessagesDropped(); } buff.append(messages); buff.append(DELIMITER); buff.append(dropped); return buff.toString().getBytes(); case GiveStatsVendorMessage.UP_CONNECTIONS_STATS: for(Iterator iter = conns.iterator(); iter.hasNext() ; ) { ManagedConnection c = (ManagedConnection)iter.next(); if(!c.isSupernodeConnection()) continue; buff.append(c.toString()); buff.append(DELIMITER2); if(incoming) { buff.append(c.getNumMessagesReceived()); buff.append(DELIMITER); buff.append(c.getNumReceivedMessagesDropped()); } else { buff.append(c.getNumMessagesSent()); buff.append(DELIMITER); buff.append(c.getNumSentMessagesDropped()); } buff.append(DELIMITER2); } return buff.toString().getBytes(); case GiveStatsVendorMessage.LEAF_CONNECTIONS_STATS: for(Iterator iter = conns.iterator(); iter.hasNext() ; ) { ManagedConnection c = (ManagedConnection)iter.next(); if(!c.isLeafConnection()) continue; buff.append(c.toString()); buff.append(DELIMITER2); if(incoming) { buff.append(c.getNumMessagesReceived()); buff.append(DELIMITER); buff.append(c.getNumReceivedMessagesDropped()); } else { buff.append(c.getNumMessagesSent()); buff.append(DELIMITER); buff.append(c.getNumSentMessagesDropped()); } buff.append(DELIMITER2); } return buff.toString().getBytes(); default: throw new IllegalArgumentException("unknown control: " + control); } } public String getReportedStats() { return new String(getPayload()); } }