Design
A typical nuggets user will run
both a client and server program. Whether or not these are run in two threads
or two processes shouldn't
matter.
Server
The server first registers the nuggets
service with the underlying bluetooth implementation. This step actually happens
in the same function call that accepts a connection, but it becomes important
in the client. Next the server attempts to read the first 16 bytes (this should
be the hash) of a file that would contain this client's nugget if we already
had it.
Once a connection is accepted, the
server receives a length, a hash, and a nugget. The length is a 4 byte big-endian
representation of the nugget length. The hash is an MD5 hash of the nugget.
The nugget... well, nobody knows what they put in nuggets - that's why we have
to get the length.
Upon receiving the fixed-length
quantities, the server compares the hash sent by the client with the hash read
from the file. If they are identical, the server closes the connection immediately.
If the nugget were something large (multimedia), this would save you the work
of receiving all packets after the first one if you didn't need to.
If the server does choose to receive
the nugget, it does so. It then writes to a file (uniquely named for that client)
the recently received hash followed by the actual nugget. The server signals
receipt of the nugget by sending an empty packet to the client. If the client
doesn't wait for this empty packet, it frequently closes the connection before
the server can receive the entire nugget.
Client
Ideally, the client program registers
to be called back whenever a new bluetooth device is discovered and then sleeps
indefinitely. On device discovery, the client creates a new thread which searches
that device for nuggets and, upon finding the nuggets service, exchanges
nuggets with it.
In reality, the Impronto SDK's implementation
of device discovery eventually
decides that it has found all the devices it's going to find. It also
caches previously-found devices so that it can return them immediately upon
later discovery requests. To account for this, the client keeps a
5
element list of recently discovered devices and doesn't service-search
them when the discovery reports their existance. To account for the immediate
termination of discoveries due to the caches, the client sleeps for 5
seconds after any discovery finishes.
The client first reads it's nugget
from a file and calculates the hash and the nugget length. This
is done per-connection. The client first sends a 4 byte nugget-length,
then a 16 byte hash of it's nugget, then sends the actual nugget. After sending,
the client waits for a single packet from the server indicating it has received
the entire nugget.
This design minimizes power consumption. Note that the client and server both
sleep for the majority of their runtime. Also, when handling large nuggets, only one packet is transmitted unless the
server actually needs the nugget. Overhead for control traffic is only one empty packet. These optimizations also conserve power
by minimizing the use of the bluetooth transmitter.