SANE Network Documentation

The SANE Standard documents a network protocol, but unfortunately low-level information is missing. As I'm trying to learn the protocol I am at the same time going to write this document.

The standard itself is available at http://www.sane-project.org/html/.

This page tries to document the code that is currently present in the saned frontend and the sanei_* functions. It is not meant as a replacement for the standard.

transport

Currently TCP seems to be the only available transport in the net backend, optionally over IPv6. The port used by sane is 6566, it is registered with the IANA:

sane-port       6566/tcp   SANE Control Port
sane-port       6566/udp   SANE Control Port
#                          Henning Meier-Geinitz <henning@meier-geinitz.de> October 2002

protocol

The protocol uses procedure numbers to do calls into the saned server. Currently the following numbers are assigned:

SANE_NET_INIT 0
SANE_NET_GET_DEVICES 1
SANE_NET_OPEN 2
SANE_NET_CLOSE 3
SANE_NET_GET_OPTION_DESCRIPTORS 4
SANE_NET_CONTROL_OPTION 5
SANE_NET_GET_PARAMETERS 6
SANE_NET_START 7
SANE_NET_CANCEL 8
SANE_NET_AUTHORIZE 9
SANE_NET_EXIT 10

network packets

I've already covered valid protocol numbers, here's what is transferred.

Each packet consists of the procedure number, and a number of other things that are procedure-dependent. Everything is transferred in network byte order (except on the data connection).

The extra things are described below (for each procedure). For what the function actually does, please see the SANE API documentation, the network access is only a thin layer above it.

A note on authorization: Authorization can occur only during SANE_NET_OPEN, SANE_NET_START and SANE_NET_CONTROL_OPTION. You have to send authorization whenever a response to one of the above commands has only the resource_to_authorize field set (all others 0). See the description of the commands for more information. If you fail to authorize in this case, the scanning process may terminate.

In the sane network protocol, an array is represented by the length of the array followed by the items.

A pointer is represented by a single word that is 0 if the pointer is NULL, or non-zero otherwise. Then follow the items the struct that the pointer points to contains.

A string is transferred as an array of its SANE_CHARs, unless the wire is in ASCII mode [which can never happen]. The transferred data includes the trailing 0.

A description of the various procedure calls follows:

SANE_NET_INIT

This message is used to negotiate the version and initialise network scanning. If it fails, you cannot talk to the server at all.

request

  • client version code (word)
  • username string

reply

  • status code (word)
  • server version code (word)

SANE_NET_AUTHORIZE

This message is used to send authorization tokens for a given resource.

request

  • resource (string)
  • username (string)
  • password (string)

reply

  • a single 0 word if no protocol errors occurred

SANE_NET_GET_DEVICES

This message causes the network daemon to enumerate all devices it can access.

request

nothing but the procedure code

reply

A pointer to an array of SANE_Device pointers. In C, this reads

*((* SANE_Device)[])

SANE_NET_OPEN

request

  • the device name (may not be NULL)

reply

  • status (word)
  • handle (word)
  • resource to authorize (string)

Here, if you give an empty device name, the two following things are possible:

  1. handle is 0 and the resource is NULL, then status contains an error code from sane_get_devices
  2. no devices exist, and the status is SANE_STATUS_INVAL
  3. authorization is needed for the first device (or more exactly, the backend of that device) and so status 0 and resource = backend name is returned
  4. No authorization is needed and the handle of the first device is returned (SANE_NET_OPEN succeeded).

After these replies or if you do not give an empty device name, the protocol proceeds with authorization to the given resource (see SANE_NET_AUTHORIZE). If authorization fails, the reply's status is set to SANE_STATUS_ACCESS_DENIED, otherwise the device is opened and the result of that is sent in the status field. An additional status is possible, SANE_STATUS_NO_MEM, if a handle could not be allocated, otherwise the handle field is set to the device handle, which is needed in further operations.

SANE_NET_CLOSE

request

  • handle (word)

reply

  • a zero word

SANE_NET_GET_OPTION_DESCRIPTORS

request

  • handle (word)

reply

an array of pointers to a SANE_Option_Descriptor struct which contains (in the given order):

  • name (string)
  • title (string)
  • description (string)
  • type (value type)
  • size (word)
  • cap (word)
  • the constraint type (constraint_type)
  • depending on the constraint type:
    • SANE_CONSTRAINT_NONE: nothing
    • SANE_CONSTRAINT_RANGE: a pointer to a SANE_Range struct
    • SANE_CONSTRAINT_WORD_LIST: an array of words
    • SANE_CONSTRAINT_STRING_LIST: an array of strings including the terminating NULL string

SANE_NET_CONTROL_OPTION

request

  • handle (word)
  • option (word)
  • action (word)
  • if action != SANE_ACTION_SET_AUTO (or the wire protocol version is < 3) then the following fields follow:
    • value_type (word)
    • value_size (word)
    • value

reply

  • status (word)
  • info (word)
  • value_type (word)
  • value_size (word)
  • value (data)
  • resource to authorize (string)

Authentication may need to occurr, in that case all fields but the resource to authorize are set to 0. Otherwise, the reply contains the result of sane_control_option.

SANE_NET_GET_PARAMETERS

request

  • handle (word)

reply

  • status
  • parameters (SANE_Parameters) containing:
    • format (frame = word)
    • last_frame (boolean = word, 1 True, 0 False)
    • bytes_per_line (word)
    • pixels_per_line (word)
    • lines (word)
    • depth (word)

The returned data is from the sane_get_parameters API call.

SANE_NET_START

request

  • handle

reply

  • status (word)
  • port (word)
  • byte order (word, 0x1234 for little, 0x4321 for big endian)
  • resource to authorize

Again, authorization may be required in which case everything but the resource to authorize is set to 0.

After the status returned is SANE_STATUS_GOOD, the server starts listening on the port given in the port field. The client must then connect to that port like in active FTP (the server blocks until that has happened). The client must not send any data to the data connection, that connection is only for receiving data. If you do not connect within one hour of opening the connection, the server process exits.

The server now starts scanning, sending all data over the data connection, while still processing requests on the control connection. The data on the data connection is sent in the server's byte order, thus the client needs to translate if it is using a different byte order.

When the scan is finished, the server closes the data connection.

SANE_NET_CANCEL

As with the SANE API, this is not just used to cancel a scan but also to clean up after a successful scan (since it is the only place sane_cancel is called in the server)

request

  • handle (word)

reply

  • a simple 0 word

SANE_NET_EXIT

request

nothing but the procedure code

reply

nothing, the server terminates and closes the connection upon receipt of this procedure code.