February, 2012

The SAO MSG protocol

The MSG protocol was developed at SAO by John Roll and Jacob Mandel. It is an ASCII based protocol that allows distributed programming using the client/server model. The SAO MMT Instrument control software uses it, as does many other components of the MMT control software.

The MSG protocol is based on messages exchanged over TCP/IP sockets and can probably be implemented by virtually any modern programming language. The most widely used MSG library is the Tcl library, although a full featured C language library was developed by SAO.

An MSG server publishes variables and registers commands. Clients may execute commands, and set, get, or subscribe to variables. An "lst" command is provided to allow a client to ask a server to enumerate the full set of variables and commands it provides.

A unique part of the protocol is the subscription facility, which allows a client to subscribe to a server for a specific variable. Once this is done, the server will notify the client whenever the value of a variable changes. This kind of asynchronous notification can be tricky to program. A simple client can ignore this facility and simply set or get variables.

A message from a client looks like this:

num command args\n
The num value is non-zero if an ACK is requested, 0 if it should be suppressed. If an ACK is requested, the num value is sent with the ACK. A get command with num=0 is pointless as nothing will be returned. There are 4 builtin commands: set, get, lst, and subscribe All commands end with a newline character.
An example of requesting a value would be:
7 get flag
7 ack 99

Commands exist to setup a server, publish variables, register commands, and to restrict which clients can access a server, but are not discussed in detail here.

An MSG server

The following Tcl code will set up a simple msg server:

#package require  msg
source  msg.tcl

set local_state bogus

set server XYZ
set env($server)     .:3999

msg_server   $server
msg_allow	"*"

msg_publish  $server state    local_state

msg_up $server

vwait forever
Note first of all the little dance with the env array. You decide on a name for your server (by tradition with all capitals), then set the value of this name in the env array to be the host:port string you would like it to use. What a script could do is to check if this value was already set and if so leave it alone to be discovered by msg initialization. Or you can just ignore the env array entirely, and pass the host:port string as a second argument to msg_server like so:
msg_server $server .:3999

In any event, you pass your server name as the first argument to each and every msg routine you call.

Invisibly to you (hopefully) the msg library creates a global array with the same name as your server (XYZ in the example above) and uses this for working storage. You should never care about the following, but in one example I studied (with server name "TT") , the following 21 variables were defined in the "TT" global array:

sock --> sock3
count --> mycount
log,cache --> 
type --> 2
port --> 3999
P,log --> 
setting --> 
host --> LOCALHOST
server --> TT
connection --> Down
count,cache --> 2
reopen --> 1000
name --> LOCALHOST:3999
logfile --> NULL
log --> msg_logger
P,count --> 
up --> 0
hosts.allow --> *
N --> 2
timeout --> 5000
hosts.deny -->  * 
This server had two published variables: log and count. The variable "log" is built into the msg library, so you get it for free.

MSG and commands

Variables are easy to set up in a server, commands (implemented by a callback function) are a little more difficult.
msg_register $server halt
This would register a command that could be invoked via the msg command "halt". The callback function for this command would be named TT.halt or $server.halt and would receive 4 arguments:
proc XYZ.halt { s sock msgid cmd } {
}
Here the 4 arguments are: Here is a simple script that sets up a server that publishes an incrementing counter and a command to reset it. It also includes some code to do introspection on the array that msg sets up in the global namespace.