DRM Protocol version 1

Introduction

This document describes only the lowest layer of the architecture. This means of course that compatibility at this level does not mean compatibility at higher levels, if the semantics of the data that is transmitted changes. The semantics is described in the API documentation of the java classes that are mentioned here. The API and this low level protocol have therefore a different versioning.

The protocol is based on java object serialization streams using the serialization stream format of JDKTM 1.2. This document does not define the object serialization protocol. The reader should refer to http://java.sun.com/j2se/1.3/docs/guide/serialization/index.html. Accordingly, in the description of the protocol java types will be used as primitives. These types should be written and read using the above mentioned java serialization streams through a socket connection. The objects in the stream must not be null except when it is explicitly allowed.

A session always starts with an initiation when the protocol versions understood by the peers and the group names are exchanged and the type of the session is identified by the initiator. This is followed by the actual data exchange. In the following the initiation will be described followed by the detailed description of the different types of sessions.

The following table contains definitions of terms used throughout the document.

Client The initiator of the communication. Only temporary role, the same application can be server too.
Server The passive party that accepts communication requests. Only temporary role, the same application can be client too.

This document contains strictly technical information, further documentation of the classes mentioned here can be found elsewhere. All constants are given in unsigned decimal format.

Initiation

The connection starts with establishing a socket connection between the peers (initiated by the client). This means that an IP address and a port identifies a peer. The default port we use is 10101, but any other port is allowed. Typically if this number is not available the sequential ports can be tried, e.g. 10102, 10103, etc. The following table shows the communication steps.

Client int VERSION String GROUP byte TYPE -
Server - - - int ANSWER

For this version the VERSION value is 1. If ANSWER equals GROUP_MISMATCH(=-1) then the peer is from a different group and the communication will be closed. Otherwise ANSWER equals the protocol version spoken by the peer. The following table gives the values of the known session types:

TYPE meaning
0 MESSAGE (message sending)
1 AGENT (agent sending)
123 ISALIVE (are you alive?)

ISALIVE

Let's start with the simplest session, the ISALIVE request.

Client -
Server java.lang.String BASE-NAME

In words: the server simply replies by sending a String object. This string contains the name of the server.

MESSAGE

When the message has no reply, the communication looks like this:

Client Server
String RECIPIENT -
- byte STATUS_1
drm.agentbase.Message MESSAGE -
- byte STATUS_2

When the message has a reply, it looks like this:

Client Server
String RECIPIENT -
- byte STATUS_1
drm.agentbase.Message MESSAGE -
- byte STATUS_2=0
- Object REPLY

The interpretation of the status info is the following:

STATUS_1 meaning
101 OK: The recipient is here, send message.
102 NOT_OK: The recipient is not here, don't send message. The connection is interrupted by the server.

STATUS_2 meaning
101 OK: The message was delivered to the recipient successfully, and the recipient does not send a reply.
102 NOT_OK: There was a problem with delivering or handling the message.
0 REPLY: The message was handled and a reply is on the way.

drm.agentbase.Message is a class with serial version uid

static final long serialVersionUID = 49323201182294530L;
Its serialized fields are
drm.agentbase.Address sender;
drm.agentbase.Address recipient;
java.lang.String type;
byte[] contbin;
The serial version of drm.agentbase.Address is
static final long serialVersionUID = 2145788465305611890L;
Its serialized fields are
java.net.InetAddress host
int port
java.lang.String name
It is also part of the low level protocol that the host field of the sender address in the message must be set to the client side IP of the socket after deserialization. The reason for this is that the sender entity is not required to know its own IP address. For this reason the sender IP must be determined on the recipient side.

AGENT

The agent has its own class type that must implement drm.agentbase.IAgent and it may need several other classes to run. For the API of drm.agentbase.IAgent please refer to version 2 of the DRM (see http://sourceforge.net/projects/dr-ea-m/). The agent also belongs to a job that has a name. When loading the agent the server checks if it has the class files for running the agent using the job name. Thus the job name identifies the resources used by the agent.

Here we can have two scenarios. In the first case the class files needed to run the agent are already at the node. In the second case they are not. The first table shows the communication in the first case.

Client Server
java.lang.String JOBNAME -
- byte STATUS=101
drm.agentbase.IAgent AGENT -
drm.agentbase.Address SENDER_BASE -
- byte STATUS

JOBNAME is the name of the job the agent is a part of. It can be used by the server to check if the resources for the agent are accessible locally. This is why it is important that every job must have a unique name (at least with a high probability) that is suitable to identify the presence of specific optional classes.

AGENT can be of any type but it must implement the drm.agentbase.IAgent interface from DRM. The agentbase will communicate with the agent trough this interface.

Just like in the case of MESSAGE the IP address in the addr field of SENDER-BASE must be set to the client side IP of the socket by the server.

The second table shows the communication if the class files of the agent are not at the server.

Client Server
java.lang.String JOBNAME -
- byte STATUS=100
int SIZE -
DATA -
- byte ACK
drm.agentbase.IAgent AGENT -
drm.agentbase.Address SENDER_BASE -
- byte STATUS

Everything is the same only here we also have an uploading phase inserted. If SIZE is positive than DATA contains a jar file of SIZE bytes. These bytes are simply written to the stream sequentially. If SIZE is negative then DATA is an object of type java.util.File describing an absolute directory name. The resources of the job must be in that directory on the server.

ACK can have any value. It indicates that the jar file has been read.

The interpretation of the closing status report of the server is the following:

STATUS meaning
101 OK. The agent was successfully installed.
102 NOT_OK. There was a problem with installing the agent.

Evolvability

Finally some notes on the evolvability of the protocol. Even though the possibility of extension of the protocol is not strictly part of the protocol definition (it is mostly an implementation issue), we would like to give some ideas.

The most problems come from the fact that we are dealing with mobile code (agents). There are two sides of this question: the DRM-agent and the agent-DRM interface. In other words the agent should be able to talk to the system and the way round. And the versions of the agent and the DRM may not match. (see drm.agentbase.IAgent.version() and Base.RELEASE_VERSION in the DRM release).

The system talks to the agent through the drm.agentbase.IAgent interface. If methods are deleted from it then the old system version will not be able to call these methods, and if methods are added then the new system version will miss them when talking to an old agent. (Changing a method signature is equivalent to an addition and a removal.) Removing methods is unlikely and also unnecessary (since they can be given an empty implementation). The case when we add methods can be solved by wrapping the lower version agent into an object that propagates the old method calls to the agent and gives default implementations to the new ones. When sending such an agent on of course only the original wrapped object should be sent.

The agent can use any publicly accessible part of the DRM. The problems come when an agent of a newer version goes to a base which implements an old DRM version. The agent will miss the methods that are present only in its version. There is no real solution to this beside the clear documentation of new methods and avoiding deleting old ones just like it is done in the standard java packages. Indicating that a field or method is present only from a given version will allow the developer of the agent to decide whether the agent should remain compatible. Another possibility is reflection, i.e. the agent can first check if a given method is implemented before calling it.

Of course the compatibility of the system classes w.r.t. serialization can also be maintained without great difficulties: if we only add new fields to the classes they remain compatible: this is guaranteed by the serialization stream specification.

Changes in the protocol can also be handled by later versions as the protocol itself is versioned too (see the initiation section).