Prev |  | Next

## 6. Driver/server socket protocol

Here’s a brief explanation of the text-based protocol which is used between the drivers and server.

The drivers may send things on the socket at any time. They will send out changes to their local storage immediately, without any sort of prompting from the server. As a result, the server must always check on any driver sockets for activity.

In terms of communications, each driver is a server on the Unix socket (or Windows named pipe) which it creates, and the data server `upsd` is a client which knows where to find such sockets, how they are named, and connects to all of them to send commands and receive data updates.

During development, it is possible to use tools like `socat` to connect to the socket (you may want to enable `NOBROADCAST` mode soon), e.g.

    socat - UNIX-CONNECT:/var/state/ups/dummy-ups-UPS1

For more insight, NUT provides an optional tool of its own (not built by default): the `sockdebug` which is built when `configure --with-dev` is in effect, or can be requested from the root directory of the build workspace:

    make sockdebug && \
    ./server/sockdebug dummy-ups-UPS1

### 6.1. Formatting

All parsing on either side of the socket is done by parseconf, so the same rules about escaping characters and "quoting multi-word elements" apply here. Values which may contain odd characters are typically sent through pconf_encode to apply \ characters where necessary.

The "" construct is used throughout to force a multi-word value to stay together on its way to the other end.

### 6.2. Commands used by the drivers

These commands (or semantically responses to server commands in some cases) can be sent by drivers to the data server over the socket protocol.

#### SETINFO

    SETINFO <varname> "<value>"

    SETINFO ups.status "OB LB"

There is no "ADDINFO" — if a given variable does not exist, it is created upon receiving the first SETINFO command.

#### DELINFO

    DELINFO <varname>

    DELINFO ups.temperature

#### ADDENUM

    ADDENUM <varname> "<value>"

    ADDENUM input.transfer.low "95"

#### DELENUM

    DELENUM <varname> "<value>"

    DELENUM input.transfer.low "98"

#### ADDRANGE

    ADDRANGE <varname> <minvalue> <maxvalue>

    ADDRANGE input.transfer.low 95 100

#### DELRANGE

    DELRANGE <varname> <minvalue> <maxvalue>

    DELRANGE input.transfer.low 95 100

#### SETAUX

    SETAUX <varname> <numeric value>

    SETAUX ups.id 8

This overrides any previous value. The auxiliary value is presently used as a length byte for read-write variables that are strings.

#### SETFLAGS

    SETFLAGS <varname> <flag>...

    SETFLAGS ups.id RW STRING

Note that this command takes a variable number of arguments, as multiple flags are supported. Also note that they are not crammed together in "" quotes, since "RW STRING" would mean something completely different.

This also replaces any previous flags for a given variable.

Currently supported flags include `RW`, `STRING` and `NUMBER` (detailed in the NUT Network Protocol documentation); unrecognized values are quietly ignored.

#### ADDCMD

    ADDCMD <cmdname>

    ADDCMD load.off

#### DELCMD

    DELCMD <cmdname>

    DELCMD load.on

#### PID

    PID <id>

    PID 12345

    PID "StrangeOS process identifier"

Response to `GETPID` query, where we serve platform-specific process identifier. On POSIX and many other platforms this would be a numeric value, but most generally it should be treated as an opaque string.

#### DUMPDONE

    DUMPDONE

This is only used to tell the server that every possible item has been transmitted in response to its DUMPALL request. Once this has been received by the server, it can be sure that it knows everything that the driver does.

#### PONG

    PONG

This is sent in response to a PING from the server. It is only used as a sanity check to make sure that the driver has not gotten stuck somewhere.

#### OK

    OK Goodbye

This is sent in response to a LOGOUT from the server (or more likely from a sibling driver or `upsdrvctl` program).

#### DATAOK

    DATAOK

This means that the driver is able to communicate with the UPS, and the data should be treated as usable. It is always sent at the end of the dump if the data is not stale. It may also be sent at other times.

#### DATASTALE

    DATASTALE

This is sent by the driver to inform any listeners that the data is no longer usable. This usually means that the driver is unable to get any sort of meaningful response from the UPS. You must not rely on any status information once this has been sent.

This will be sent in the beginning of a dump if the data is stale, and may be repeated. It is cleared by DATAOK.

#### TRACKING

    TRACKING <id> <value>

This is sent in response to an INSTCMD or SET VAR that includes a TRACKING, upon completion of request execution by the driver. <value> is the integer return value from the driver handlers instcmd and setvar (see drivers/upshandler.h). The server is in charge of translating these codes into strings, as per docs/net-protocol.txt GET TRACKING.

### 6.3. Commands sent by the server

The data server `upsd` (or technically any client that connects to a Unix socket or Windows named pipe provided by each NUT driver) can send the following commands to the driver:

#### PING

    PING

This is sent to check on the health of a driver. The server should only send this when it hasn’t heard anything valid from a driver recently. Some drivers have very little to say in terms of updates, and this may be the only communications they have with the server on a normal basis.

If a driver does not respond with the PONG within a few seconds at the most, it should be treated as dead/unavailable. Data stored in the server must not be passed on to the clients when this happens.

### Note

For the `upsd` data server, the MAXAGE setting in upsd.conf controls how long since the last message from the driver it is considered stale. At 1/3 of this time the server sends a `PING` command to the driver, so there is some time for a `PONG` to arrive and reset the timer (any other message would serve that goal as well).

#### INSTCMD

    INSTCMD <cmdname> [<cmdparam>] [TRACKING <id>]

    INSTCMD panel.test.start
    INSTCMD load.off 10
    INSTCMD load.on 10 TRACKING 1bd31808-cb49-4aec-9d75-d056e6f018d2

NOTE:

- <cmdparam> is an additional and optional parameter for the command,
- "TRACKING <id>" can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING.

#### SET

    SET <varname> "<value>" [TRACKING <id>]

    SET ups.id "Data room"
    SET ups.id "Data room" TRACKING 2dedb58a-3b91-4fab-831f-c8af4b90760a

NOTE:

- "TRACKING <id>" can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING.

#### GETPID

The server (or sibling driver instances, or `upsdrvctl` tool) can use this to request the platform-specific process identifier of the driver process. On POSIX and many other platforms this would be a numeric value, but most generally it should be treated as an opaque string.

#### DUMPALL

    DUMPALL

The server uses this to request a complete copy of everything the driver knows. This is returned in the form of the same commands (SETINFO, etc.) that would be used if they were being updated normally. As a result, the same parsing happens either way.

The server can tell when it has a full copy of the data by waiting for DUMPDONE. That special response from the driver is sent once the entire set has been transmitted.

#### DUMPVALUE

    DUMPVALUE <varname>

    DUMPVALUE driver.version

Only request the value of specified variable name (and its additional metadata in other lines), same as when `DUMPALL` iterates all such names.

The NUT data server or other socket-protocol client should parse the response line by line, looking for the SETINFO line to get the value; if a DUMPDONE is seen first, the value was not available in the driver.

#### DUMPSTATUS

    DUMPSTATUS

Effectively an alias to `DUMPVALUE ups.status`.

#### NOBROADCAST

This connection does not want to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`). Default is to receive everything.

#### BROADCAST (NUM)

This connection specified whether it wants to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`), and by default enables that — unless disabled by providing an optional zero or negative numeric argument. Note that initial default is to receive everything, so this command may be useful for connections that disabled broadcasts at some point.

#### LOGOUT

Primarily used by communications between driver processes and/or `upsdrvctl`, this command allows clients to gracefully close connection to the NUT driver which acts as the server on the socket/pipe, avoiding noisy logs about sudden disconnection.

    LOGOUT
    OK Goodbye

### 6.4. Design notes

#### Requests

There is no way to request just one variable. This was done on purpose to limit the complexity of the drivers. Their job is to send out updates and handle a few simple requests. DUMPALL is provided to give the server a known foundation.

To track a limited set of variables, a server just needs to do DUMPALL, then only have handlers that remember values for the variables that matter. Anything else should be ignored.

#### Access/Security

There are no access controls in the drivers. Anything that can connect to their sockets can make requests, including SET and INSTCMD if supported by the driver and hardware. These sockets must be kept secure. If your operating system does not honor permissions or modes on sockets, then you must store them in a directory with suitable permissions to limit access.

#### Command limitations

As parseconf is used to handle decoding and chunking of the data, there are some limits on what may be used. These default to 32 arguments of 512 characters each, which should be more than enough for everything which is currently needed by the software.

These limits are strictly for sanity purposes, and may be raised if necessary. parseconf itself can handle vast numbers of arguments and characters, with some speed penalty as things get really big.

#### Re-establishing communications

If the server loses its connection to the driver and later reconnects, it must flush any local storage and start again with DUMPALL. The driver may have changed the internal state considerably during that time, and any other approach could leave old elements behind.

Prev |  | Next
| Home |