-
Notifications
You must be signed in to change notification settings - Fork 4
Protocol Description
The labrad protocol uses a centralized arbiter called the manager to handle communication between clients. All communication goes through this manager, with clients and servers each maintaining a single TCP connection to the manager. In TCP language, both LabRAD servers and clients are TCP clients, with the manager being the only TCP server. What distinguishes LabRAD servers from clients is that servers advertise 'settings' -- remotely invokable methods that clients can use. Labrad servers can also act as clients themselves, and they often do: for instance, the oscilloscope server acts as a client for the GPIB bus server.
Every client/server has an ID number, a positive integer. The manager itself is always ID 1. The registry is usually 2 and all other client and servers are assigned as they connect. Each connection also has a name set when connecting. For clients these are usually generic names like "python-client (rotm)", but for servers they are the server name, and must be unique. Two servers with the same name cannot connect to the same manager. The manager will 'keep the slot open' for servers that disconnect. If the server later reconnects with the same name it will get the same ID. This is not done for clients.
Labrad communication is divided into packets (not related to TCP/IP packets or ethernet frames). Each packet contains the following information: (src/dest, context, request ID, list of records), and they have the following meaning:
- src/dest: this is the connection ID that this message is from/to. For packets going from a client to the manger, this is the ID of the server that should receive it. For packets going from the manager to a server, this is the ID of the client that send the request.
- context: This is a pair of 32-bit numbers, written like (4,2). They repesent a context which servers may use to keep track of data for each client (such as current working directory, or selected GPIB device).
- request ID: This is like a packet serial number, used to match responses with the request that generated them. "requests" (i.e., setting invocations) always have a positive request ID. The response uses the negative of the request ID. Messages/signals always use request ID 0 (since they neither generate responses nor are in response to a request)
- list of records: In a request, contains the setting ID and data for a sequence of settings to be invoked. In a reply, contains the returned data. For efficiency, a single packet may contain many setting invocations. This reduces the impact of network latency.
As described above, requests are labrad messages with positive message ID. The response comes with message ID that is the negative of the request. Responses are required to have the same record format as the request. That is, it must contain the same number of records, and they must be for the same setting IDs. The record data of a response corresponds to the return value of the settings it maps to.
There are a couple of exceptions to the above requirement that the response must contain the same record structure as the request. The very first packet that is part of the login sequence does not follow this convention. Also, in some cases, if a server encounters an exception while processing a request it may return an incomplete response (This needs to be verified). If a server aborts while processing a request, the response will never come and the client should timeout. If a client attempts to send a message to a server that is not present or has disconnected or disconnects before the request is fully transmitted, the manager will provide the appropriate error response. However, if the server receives the entire request and then drops the connection, the manager will not be able to provide the error message.
Contexts are handled in a very specific way. Contexts are represented as a tuple of two numbers (x,y). The first number, x, is generally the client ID. If a client sends a request with x=0, the manager will automatically replace the zero with the client ID. It is however possible to 'forge' the context ID and send requests on behalf of another client's context. The second number can be anything you want.
Contexts can also expire. This most often happens when a client disconnects, the manager will automatically expire all of its contexts. A client can also request (to the manager) to expire a specific context, or even only a specific context on a specific server. Servers will be notified of this, and can use it to clean up (for instance, freeing any data structures to avoid memory leaks).
The LabRAD protocol is a binary communication protocol. The supported data types each have a defined binary representation. An important consideration of binary protocols is byte order or endianness. When sending values larger than a single byte there are two possible ways to send the individual bytes: Most Significant Byte First (MSB) or Least Significant Byte First (LSB), aka big endian and little endian. The labrad manager detects each clients byte order and automatically changes byte order as necessary. This allows clients to be written in whichever byte order is convenient (generally, whatever byte order their CPU uses). Java and recent pylabrad clients use big endian which is known as "Network byte order" and is generally preferred for network communication. Delphi and older pylabrad clients use little endian, the native byte order on intel x86 CPUs. WARNING future protocol versions will require big endian communication. If you have a choice, please use big endian.