Spice protocol format file ========================== Copyright (C) 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). Basic ----- The spice protocol format file defines the network protocol used by spice. It resemble the C format. file ::= ; definitions ::= | ; definition ::= ||||| ; protocol ::= "protocol" "{" "}" ";" ; protocol_channels ::= | ; protocol_channel ::= [ "=" ] ";" ; integer ::= | ; 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. 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 */ 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; 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 ::= "{" [ ] "}" ";" ; flag ::= "{" [ ] "}" ";" ; enum_type ::= "enum8"|"enum16"|"enum32" ; flag_type ::= "flag8"|"flag16"|"flag32" ; enumflag_items ::= | enumflag_item ::= [ "=" ] [ "," ] ; enum_name ::= [a-z0-9_]* ; Example: enum16 Level { LOW = 0x100, MEDIUM, HIGH = 0x1000 }; Variables --------- As you should already have noted variables are similar to C syntax but there are some differences. variable ::= [ "*" ] [ "[" "]" ] ; 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. 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 ::= ||""||| ; array_size_image ::= "image_size" "(" "," ")" ; array_size_bytes ::= "bytes" "(" "," ")" ; 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. 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" "{" [ ] "}" ";" ; fields ::= | ; field ::= | Example: struct Point { int32 x; int32 y; }; Messages -------- Messages have the same syntax of structure (beside `message`) with the different that they can be used directly inside channels. message ::= "message" "{" [ ] "}" ";" ; Switches -------- TODO Type definitions ---------------- Like C type definition allow to short types defining new ones. typedef ::= "typedef" ; note that unlike C name came before the type. Example: typedef XCoord int32; Channels -------- channel ::= "channel" [ ":" ] "{" "}" ";" ; channel_messages ::= | ; channel_message ::= "server:" | "client:" | "message" [ "=" ] ; 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. Protocol -------- protocol ::= "protocol" "{" "}" ";" ; protocol_channels ::= | ; protocol_channel ::= [ "=" ] ";" ; 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. 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 ::= ""|| ; attribute ::= [ "(" ")" ] ; attribute_values ::= "," | attribute_value ::= | 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. 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; }; 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). 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). to_ptr ~~~~~~ TODO nocopy ~~~~~~ TODO as_ptr ~~~~~~ TODO 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; }; 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. marshall ~~~~~~~~ TODO 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. 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. ptr_array ~~~~~~~~~ TODO outvar ~~~~~~ TODO anon ~~~~ TODO chunk ~~~~~ TODO ifdef ~~~~~ TODO zero ~~~~ TODO minor ~~~~~ TODO bytes_count ~~~~~~~~~~~ TODO virtual ~~~~~~~ TODO fixedsize ~~~~~~~~~ TODO