Sample 3 - Who-Has/I-Have Counter

This sample application is very similar to the second sample. It has the same basic structure and initialization, it counts the number of Who-Has and I-Have messages it receives, and prints out a summary after the application has been signaled to terminate, such as a KeyboardInterrupt raised.

Processing Service Requests

The beginning is going to be standard boiler plate function header:

def do_WhoHasRequest(self, apdu):
    """Respond to a Who-Has request."""
    if _debug: SampleApplication._debug("do_WhoHasRequest %r", apdu)

Unlike the Who-Is request, Who-Has can come in two different flavors, one checking for an object by its identifier and one checking by its name. Both cannot appear in the APDU at the same time:

key = (str(apdu.pduSource),)
if apdu.object.objectIdentifier is not None:
    key += (str(apdu.object.objectIdentifier),)
elif apdu.object.objectName is not None:
    key += (apdu.object.objectName,)
else:
    print "(rejected APDU:"
    apdu.debug_contents()
    print ")"
    return

# count the times this has been received
whoHasCounter[key] += 1

When an optional parameter is not specified in a PDU then the corrisponding attribute will be None. With this particular APDU the object parameter is required, but only one of its child attributes objectIdentifier or objectName will be not None. If both are None then the request is not properly formed.

Note

The encoding and decoding layer will not completely understand all of the combinations of required and optional parameters in an APDU, so verify the validity of the reuest is the responsibility of the application.

The application can rely on the fact that the APDU is well-formed, which is to say it has teh appropriate opening and closing tags and the data types of the parameters are correct. Watch out for Any!

The I-Am function is much simpler because all of the parameters are required:

key = (
    str(apdu.pduSource),
    str(apdu.deviceIdentifier),
    str(apdu.objectIdentifier),
    apdu.objectName
    )

# count the times this has been received
iHaveCounter[key] += 1

Dumping the contents of the counters is simple.

Just like Who-Is and I-Am, pairing up the requests and responses can be a useful excersize, but in most cases the I-Am response from a device will be a unicast message directly back to the requestor, so relying on broadcast traffic to analyze object binding is not as useful as it used to be.

The Who-Has and I-Have services are not widely used.