Copyright © 2016 Red Hat, Inc. Licensed under a Creative Commons Attribution-Share Alike 3.0 United States License (see http://creativecommons.org/licenses/by-sa/3.0/us/legalcode).

1. Basic

The spice protocol format file defines the network protocol used by spice. It resemble the C format.

file ::= <definitions> <protocol> ;
definitions ::= <definition>|<definitions><definition> ;
definition ::= <typedef>|<structure>|<enum>|<flag>|<message>|<channel> ;
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
integer ::= <hex>|<dec> ;
dec ::= [+-][0-9]+ ;
hex ::= "0x" [0-9a-f]+ ;
identifier ::= [a-z][a-z0-9_]* ;

(here BNF with some regular expression is used).

It’s used to generate automatically code to marshall/demarshall the network data.

Example:

channel ExampleChannel {
   message {
      uint32 dummy;
   } Dummy;
};
protocol Example {
    ExampleChannel first = 1001;
};

As you can see brackets like C are used and structures looks like C but you can also see that keyworks like channel, protocol, message or some predefined types like uint32 are proper of the protocol.

2. Comments

Both C and C++ style comments are supported

// this is a comment
/* this is a comment too
   but can be split in multiple lines */

3. Base types

All int from 8 to 64 bit (8, 16, 32 and 64) are supported either signed or unsigned. Also you can pass one unix descriptor.

base_type ::= "int8"|"uint8"|"int16"|"uint16"|"int32"|"uint32"|"int64"|"uint64"|"unix_fd" ;

Example:

int16 x;

4. Enumerations and flags

It’s possible to specify enumerations and flags. The difference is that flags are defined as 2 power values and can combined. Enumerations and flags must have a size (8, 16 or 32) specified.

enum ::= <enum_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
flag ::= <flag_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
enum_type ::= "enum8"|"enum16"|"enum32" ;
flag_type ::= "flag8"|"flag16"|"flag32" ;
enumflag_items ::= <enumflag_item>|<enumflag_items><enumflag_item>
enumflag_item ::= <enum_name> [ "=" <integer> ] [ "," ] ;
enum_name ::= [a-z0-9_]* ;

Example:

enum16 Level {
    LOW = 0x100,
    MEDIUM,
    HIGH = 0x1000
};

5. Variables

As you should already have noted variables are similar to C syntax but there are some differences.

variable ::= <type> [ "*" ] <identifier> [ "[" <array_size> "]" ] <attributes>;

The * specify a pointer. This is quite different from C. For the protocol it specifies that in the protocol stream a relative offset is put that points to that variable usually after all defined fields. This happens even on arrays, so for instance

int32 *n;

containing a 0x12345678 n value could ended up coded as

04 00 00 00 // 4 as offset
78 56 34 12 // `n`

(little endian). While an array of 2 items defined as

int32 *n[2];

and containing 0x12345678 and 0x9abcdef could end up with

04 00 00 00 // 4 as offset
78 56 34 12 // `n`[0]
ef cd ab 09 // `n`[1]

note that int32 *n[2] defined a pointer to an array of 2 items and not an array of pointers as C.

WARNING: You should avoid using pointers on protocol if not necessary as they are complicated to handle not using autogenerated code and also use more space on the network.

6. Arrays

As seen above the easiest way to define an array size is specifiying a constant value. However there are multiple way to specify the size

array_size ::= <integer>|<identifier>|""|<array_size_image>|<array_size_bytes>|<array_size_cstring> ;
array_size_image ::= "image_size" "(" <integer> "," <identifier> ")" ;
array_size_bytes ::= "bytes" "(" <identifier> "," <identifier> ")" ;
array_size_cstring ::= "cstring()" ;

We already seen integer. Specifying an identifier name instead (should be variable) indicate that the length is specified in another field, for instance

uint8 name_len;
int8 name[name_len];

allows to put a name of name_len len. The empty value tell that the array will end when the containing message end so if we have

int8 name[];

and the message is

66 6f 6f

possibly the name we want is foo (66 6f 6f is the ASCII encoding for foo).

TODO: what happen with two [] in the structure ?? TODO: can a [] array not be the last and what happens ??

image_size allow to specify an array holding an image, for instance

uint16 width;
uint16 heigth;
uin18 raw_image[image_size(8, width, height)];

could contain row data in raw_image. The constant 8 is the bit size of the image.

TODO bytes

cstring allows to specify NUL-terminated sequence so having

int8 name[cstring()];

and the message as

66 6f 6f 00

we’ll have the foo name. Note that the field does not need to end the message as in int8 name[] example.

7. Structures

The simpler coumpound type is the structure. As in C is defined as a list of fields (any variable or swicth). But as a protocol definition there are no alignment or padding and every field (beside pointer values) follow each other.

struct ::= "struct" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
fields ::= <field>|<fields><field> ;
field ::= <variable>|<switch>

Example:

struct Point {
    int32 x;
    int32 y;
};

8. Messages

Messages have the same syntax of structure (beside message) with the different that they can be used directly inside channels.

message ::= "message" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;

9. Switches

TODO

10. Type definitions

Like C type definition allow to short types defining new ones.

typedef ::= "typedef" <identifier> <type> <attributes> ;

note that unlike C name came before the type.

Example:

typedef XCoord int32;

11. Channels

channel ::= "channel" <identifier> [ ":" <identifier> ] "{" <channel_messages> "}" <attributes> ";" ;
channel_messages ::= <channel_message>|<channel_messages><channel_message> ;
channel_message ::= "server:" | "client:" | "message" <identifier> [ "=" <integer> ] ;

Example:

channel ExampleChannel {
server:
   message {
      uint32 dummy;
   } Dummy;
};

Note that every message is associated with a number which is used in the protocol. The assignment work in a similar way to enumeration in C beside first message is assigned 1 value and not 0. So first message (if no integer is specified) is assigned 1, second 2 and so on.

server: or client: specify the direction of messages following, server specify messages from server while client from client. If not specified is assumed from server.

For each channel you can specify a parent channel. Derived channel inherite all messages specified in the parent. Note that messages from parent can be overrided by derived channels.

12. Protocol

protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;

Example:

protocol Example {
    ExampleChannel first = 1001;
};

Protocol specify the list of channel supported. Channel have an associated number assigned in a similar way of channels (incremented from one to the next with first starting from 0 if not specified).

NOTE: Due to the way currently code is generate you should use small numbers.

13. Attributes

As you probably noted attributed can be specified for lot of definitions. They allow to change code generated or specific contraints to the protocol.

attributes ::= ""|<attributes><attribute>|<attribute> ;
attribute ::= <attribute_name> [ "(" <attribute_values> ")" ] ;
attribute_values ::= <attribute_values> "," <attribute_value> | <attribute_value>
attribute_value ::= <integer> | <identifier>
attribute_name ::= @[a-z][a-z0-9_]* ;

Mostly of the attributes have no arguments, other currently have only one argument.

NOTE: Some comments are also written in spice-common python_modules/ptypes.py source file.

13.1. ctype

Specify the structure type name that the generated marshaller/demarshaller code will use. By default the name will be converted to CamelCase and prefixed by Spice so for example a structure like

struct Point {
    int32 x;
    int32 y;
} @ctype(MyPoint);

will be marshalled into a C structure like

struct MyPoint {
    int32_t x;
    int32_t y;
};

13.2. prefix

This attribute allow to specify the prefix used for generated enumerations (both protocol enumerations and flags generate C enumerations). By default the enumeration will use upper case of the enum/flag name prefixed with SPICE_ and followed by item so

enum32 level {
    LOW,
    HIGH,
};

will generate

typedef enum SpiceLevel {
    SPICE_LEVEL_LOW,
    SPICE_LEVEL_HIGH,
    SPICE_LEVEL_ENUM_END
} SpiceLevel;

while

enum32 level {
    LOW,
    HIGH,
} @prefix(LVL_);

will generate

typedef enum SpiceLevel {
    LVL_LOW,
    LVL_HIGH,
    SPICE_LEVEL_ENUM_END
} SpiceLevel;

(note that an automatic END enumeration is generated and name is not affected).

13.3. end

This attribute specify that the data will be appended/embedded in the final C structure.

Example:

struct test {
    uint16 len;
    uint16 array[len] @end;
};

Output C structure:

struct test {
    uint16_t len;
    uint16_t array[0];
};

The generated code will allocate the C structure to allow space for extracted array.

WARNING: This option is usually confused with with empty size protocol. The empty protocol array size specify array that extend on the network data while the @end attribute specify to extend the C structure (for instance in the example the attribute was attached to a len-sized array).

13.4. to_ptr

TODO

13.5. nocopy

TODO

13.6. as_ptr

TODO

13.7. nomarshal

Do not generate code for marshalling this variable. Usually used on last array element to make possible to manually feed data.

Example: struct Data { uint32 data_size; uint8 data[data_size] @nomarshal; };

13.8. zero_terminated

The field should terminated by zero. Actually it’s not used by python code so it’s not enforced and no code is generated.

13.9. marshall

TODO

13.10. nonnull

This pointer field cannot be NULL. This means that marshaller assume C structure contain not NULL pointer and demarshaller will fail to demarshall message if offset is 0.

13.11. unique_flag

This flag field should contain just a single flag. Actually it’s not used by python code so it’s not enforced and no code is generated.

13.12. ptr_array

TODO

13.13. outvar

TODO

13.14. anon

TODO

13.15. chunk

TODO

13.16. ifdef

TODO

13.17. zero

TODO

13.18. minor

TODO

13.19. bytes_count

TODO

13.20. virtual

TODO

13.21. fixedsize

TODO