package freenet.clients.fcp; import freenet.node.FSParseException; import freenet.node.Node; import freenet.node.probe.Error; import freenet.node.probe.Listener; import freenet.node.probe.Probe; import freenet.node.probe.Type; import freenet.support.SimpleFieldSet; /** * FCP Message which is received from a client and requests a network probe of a specific type. * <ul> * <li>Identifier: Optional; identifier to match probe request with results.</li> * <li>type: Mandatory; denotes the desired response type. Valid values are: * <ul> * <li>BANDWIDTH - returns outgoing bandwidth limit in KiB per second.</li> * <li>BUILD - returns Freenet build / main version.</li> * <li>IDENTIFIER - returns identifier and integer 7-day uptime percentage.</li> * <li>LINK_LENGTHS - returns link lengths between the endpoint and its connected peers.</li> * <li>LOCATION - returns the endpoint's location.</li> * <li>REJECT_STATS - returns CHK and SSK reject percentage for bulk inserts and bulk requests.</li> * <li>STORE_SIZE - returns store size in GiB.</li> * <li>UPTIME_48H - returns 48-hour uptime percentage.</li> * <li>UPTIME_7D - returns 7-day uptime percentage.</li> * </ul></li> * <li>hopsToLive: Optional; approximately how many hops the probe will take before possibly returning a result. * Valid values are [1, Probe.MAX_HTL]. If omitted Probe.MAX_HTL is used.</li> * </ul> */ public class ProbeRequest extends FCPMessage { public static final String NAME = "ProbeRequest"; private final String identifier; private final Type type; private final byte htl; public ProbeRequest(SimpleFieldSet fs) throws MessageInvalidException { /* If not defined in the field set Identifier will be null. As adding a null value to the field set does * not actually add something under the key, it will also be omitted in the response messages. */ this.identifier = fs.get(IDENTIFIER); try { this.type = Type.valueOf(fs.get(TYPE)); //If HTL is not specified default to MAX_HTL. this.htl = fs.get(HTL) == null ? Probe.MAX_HTL : fs.getByte(HTL); if (this.htl < 0) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "hopsToLive cannot be negative.", null, false); } } catch (IllegalArgumentException e) { throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "Unrecognized parse probe type \"" + fs.get(TYPE) + "\": " + e, null, false); } catch (FSParseException e) { //Getting a String from a SimpleFieldSet does not throw - it can at worst return null. throw new MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "Unable to parse hopsToLive \"" + fs.get(HTL) + "\": " + e, null, false); } } @Override public SimpleFieldSet getFieldSet() { return new SimpleFieldSet(true); } @Override public String getName() { return NAME; } @Override public void run(final FCPConnectionHandler handler, Node node) throws MessageInvalidException { if(!handler.hasFullAccess()) { throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Probe requires full access.", identifier, false); } Listener listener = new Listener() { @Override public void onError(Error error, Byte code, boolean local) { handler.outputHandler.queue(new ProbeError(identifier, error, code, local)); } @Override public void onRefused() { handler.outputHandler.queue(new ProbeRefused(identifier)); } @Override public void onOutputBandwidth(float outputBandwidth) { handler.outputHandler.queue(new ProbeBandwidth(identifier, outputBandwidth)); } @Override public void onBuild(int build) { handler.outputHandler.queue(new ProbeBuild(identifier, build)); } @Override public void onIdentifier(long probeIdentifier, byte percentageUptime) { handler.outputHandler.queue(new ProbeIdentifier(identifier, probeIdentifier, percentageUptime)); } @Override public void onLinkLengths(float[] linkLengths) { handler.outputHandler.queue(new ProbeLinkLengths(identifier, linkLengths)); } @Override public void onLocation(float location) { handler.outputHandler.queue(new ProbeLocation(identifier, location)); } @Override public void onStoreSize(float storeSize) { handler.outputHandler.queue(new ProbeStoreSize(identifier, storeSize)); } @Override public void onUptime(float uptimePercent) { handler.outputHandler.queue(new ProbeUptime(identifier, uptimePercent)); } @Override public void onRejectStats(byte[] stats) { handler.outputHandler.queue(new ProbeRejectStats(identifier, stats)); } @Override public void onOverallBulkOutputCapacity( byte bandwidthClassForCapacityUsage, float capacityUsage) { handler.outputHandler.queue(new ProbeOverallBulkOutputCapacityUsage(identifier, bandwidthClassForCapacityUsage, capacityUsage)); } }; node.startProbe(htl, node.random.nextLong(), type, listener); } }