diff options
author | Mattias Andrée <maandree@operamail.com> | 2015-08-28 17:53:10 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@operamail.com> | 2015-08-28 17:53:10 +0200 |
commit | 5cf79f84396fe1f496c53a2ee8903fed8759d28f (patch) | |
tree | 358a768adbcfc7e7a314fef3ad242bd00a27b73d | |
parent | typo (diff) | |
download | mds-5cf79f84396fe1f496c53a2ee8903fed8759d28f.tar.gz mds-5cf79f84396fe1f496c53a2ee8903fed8759d28f.tar.bz2 mds-5cf79f84396fe1f496c53a2ee8903fed8759d28f.tar.xz |
doc proto-util
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r-- | doc/info/mds.texinfo | 323 | ||||
-rw-r--r-- | src/libmdsclient/proto-util.c | 3 |
2 files changed, 326 insertions, 0 deletions
diff --git a/doc/info/mds.texinfo b/doc/info/mds.texinfo index 18a85b1..a090f7b 100644 --- a/doc/info/mds.texinfo +++ b/doc/info/mds.texinfo @@ -8703,6 +8703,329 @@ macros, but function-like macros and lvalue-macros use shorter. Inclusion-guards are formatted @code{MDS_LIBMDSCLIENT_*_H}. +@menu +* Protocol Utilties:: Low-level functions for implementing protocols. +@end menu + + + +@node Protocol Utilties +@section Protocol Utilties + +@cpindex Implementing protocols +@cpindex Protocols, implementing +The header file @file{<libmdsclient/proto-util.h>} +provides functions that can be used in implementing +protocols. Using these functions will make it easy +to implement the protocol, the implementing may +however be more efficient if you implement everything +by hand. In particular, protocols that are expected +to be used very often with similar data may be faster +if implemented using caching techniques. + +The header file provides a function for retrieving +header files of interest: + +@table @asis +@item @code{libmds_headers_cherrypick} [(@code{char** restrict headers, size_t header_count, size_t* restrict found, libmds_cherrypick_optimisation_t optimisation, ...}) @arrow{} @code{int}] +@fnindex @code{libmds_headers_cherrypick} +@cpindex Headers, cherrypicking +@cpindex Cherrypicking headers +@cpindex Headers, reading +@cpindex Reading headers +This function takes an list of headers as input. The +headers are provided by the parameter @code{headers}, +and the number of headers is specified by the parameter +@code{header_count}. These headers must include both +the names and values. For example: +@example +headers = (char[][]) @{ + "Client ID: 0:1", + "Message ID: 12", + @}; +@end example + +The function will store the number headers it found +to @code{*found}, unless @code{found} is @code{NULL}. +Only requested headers are counted. + +The function can use optimisations based on the input +The parameter @code{optimisation} is used to provide +hints required for optimal optimisation. + +@tpindex @code{libmds_cherrypick_optimisation_t} +@tpindex @code{enum libmds_cherrypick_optimisation} +@code{optimisation} is defined with the type +@code{libmds_cherrypick_optimisation_t} @{also known as +@code{enum libmds_cherrypick_optimisation}@}. Values of +@code{optimisation} should combine, using bit-wise OR, +two values defined in @code{libmds_cherrypick_optimisation_t}. +One of the values should be from the header input +optimisation group: + +@table @code +@item DO_NOT_SORT = 0 +@code{headers} is neither sorted nor may it its +elements be reordered. However, the function may +choose to create a copy of @code{headers} and +sort that copy, if it sees it as beneficial. +@item SORT +@code{headers} is not sorted, but the function +may sort it without copying it, if it sees it as +beneficial. +@item SORTED +@code{headers} is already sorted in ascending +order. This means that the function will not +reorder its elements. +@end table + +The other value should be from the header request +optimisation group: + +@table @code +@item ARGS_UNSORTED = 0 +The header request list is not sorted. +@item ARGS_SORTED +The header request list is sorted in ascending order. +@end table + +Note that @code{DO_NOT_SORT} and @code{ARGS_UNSORTED} +are both guaranteed to have the value 0. The other +definitions do not have a guaranteed value, but they +are guaranteed to be unique and only consist of one +set bit. + +The variadic arguments are used for the header request +list. The first argument in the variadic argument list +should be a @code{const char*} that names a requested +header. It should only contain the name of the header. +The follow argument should be of the type @code{char**}. +The first element in this argument will be set the +the value of the header named by the previous argument, +or @code{NULL} if not found. This, pair of arguments, +is repeated once for every requested header. The end +of the variadic argument list must be marked with a +@code{NULL}. For example: + +@example +char* recv_client_id; +char* recv_message_id; +char* recv_command_id; +r = libmds_headers_cherrypick(headers, n, NULL, 0, + /* Header request starts here */ + "Client ID", &recv_client_id, + "Message ID", &recv_message_id, + "Command", &recv_command, + NULL); +@end example + +The functions behaviour is undefined for if a header +is requested more than once, or in an order contrary +to the specifications provided by @code{optimisation}. +The functions behaviour is also undefined if the input +headers are in an order contrary to the specifications +provided by @code{optimisation}. + +Upon successful completion, even if no requested headers +are found, this function returned zero. On error, @code{-1} +is returned and @code{errno} is set to indicate the error. + +This function can fail with errno set to @code{ENOMEM}, +if the process cannot allocate required memory. + +The call must not free returned header values. They are +freed automatically when corresponding element in the +header input list is freed. The input headers are returned +with an offset. This also means that the returned values +will be modified if the value part of the input headers are +modified. +@end table + +The header file also provides four pre-optimised version +of @code{libmds_headers_cherrypick}. These functionf behaves +like @code{libmds_headers_cherrypick}, except they does not +have the optimisation parameter, and return the number of +found headers rather than storing it using a pointer. +Additionally these function cannot fail. + +@table @asis +@item @code{libmds_headers_cherrypick_linear_unsorted} [(@code{char** restrict headers, size_t header_count, ...}) @arrow{} @code{size_t}] +@fnindex @code{libmds_headers_cherrypick_linear_unsorted} +This function is not optimised. Because of its low overhead +it can still be the fastest choice. +@item @code{libmds_headers_cherrypick_linear_sorted} [(@code{char** restrict headers, size_t header_count, ...}) @arrow{} @code{size_t}] +@fnindex @code{libmds_headers_cherrypick_linear_sorted} +This function uses linear search, but uses an optimised based +on the assumption that both the input header list and the +header request list are sorted in ascending order. Because of +its low overhead it can still be faster than +@code{libmds_headers_cherrypick_binary_sorted}. +@item @code{libmds_headers_cherrypick_binary_unsorted} [(@code{char** restrict headers, size_t header_count, ...}) @arrow{} @code{size_t}] +@fnindex @code{libmds_headers_cherrypick_binary_unsorted} +This function uses binary search. It assumes that the +header input list sorted in ascending order, header request +list is unsorted. +@item @code{libmds_headers_cherrypick_binary_sorted} [(@code{char** restrict headers, size_t header_count, ...}) @arrow{} @code{size_t}] +@fnindex @code{libmds_headers_cherrypick_binary_sorted} +This function uses binary search. It assumes that the +both the header input list and header request list are +sorted in ascending order. It seeks for the headers in +the order the are provided in the header request list, +and adjusts the lower bound on the binary search each +time it founds a header. +@end table + +Currently it is assumed that these are the only useful +optimisations. This may however change in the future, +and some optimisations may even be removed. Therefore +the user of the library can check at compile time weather +the functions are still available. This is done by checking +that a macro with exactly the same name as the function +is defined. + +@cpindex Sorting headers +@cpindex Headers, sorting +If you want to sort a list of headers. You need to be +aware that the header should treated as ending at the +first occurrence of a colon followed by a blank space. +Because of this, @file{<libmdsclient/proto-util.h>} +provides a function for sorting a list of headers. + +@table @asis +@item @code{libmds_headers_sort} [(@code{char** restrict headers, size_t header_count}) @arrow{} @code{void}] +@fnindex @code{libmds_headers_sort} +This function takes the list of headers in the parameter +@code{headers} and the number of headers in the parameter +@code{header_count}. It cannot fail, and thus does not +return a value. + +This function sorts the headers in ascending order, +and is used internally by @code{libmds_headers_cherrypick} +if it chooses to sort headers. +@end table + +@file{<libmdsclient/proto-util.h>} also provides a function +for composing messages: + +@table @asis +@item @code{libmds_compose} [(@code{char** restrict buffer, size_t* restrict buffer_size, size_t* restrict length, const char* restrict payload, const size_t* restrict payload_length, ...}) @arrow{} @code{int}] +@fnindex @code{libmds_compose} +@cpindex Messages, composing +@cpindex Composing messages +@cpindex Messages, writting +@cpindex Writting messages +This function provides a simple way for writting message +that can be send to the display server. The function writes +the message on a buffer provides by the caller. This buffer +is reallocationed by the function if necessary. + +The buffer is provided by a pointer, @code{buffer} to the +buffer. @code{*buffer} is changed to the new buffer pointer +if it is reallocated. The current size of @code{*buffer} +should be stored @code{*buffer_size}. @code{*buffer_size} +will be updated with the new allocation size if the buffer +is reallocated. Neither if these pointers may be @code{NULL}. +However, @code{*buffer} should be @code{NULL} if +@code{*buffer_size} is zero, and vice versa. + +The length of the written message will be saved to +@code{length}. @code{length} must not be @code{NULL}. + +If the message should include a payload. It should be +provided using the parameter @code{payload}. If the message +should not have a payload @code{payload} should be @code{NULL}. +The argument @code{payload_length} should point to a value +with the length of the message, or be @code{NULL} if the +function should measure the @code{payload} by searching for +a NUL bytes which must exists in such a cass. If +@code{payload_length} is not @code{NULL}, there is not +requirement for a NUL byte. If @code{payload} is @code{NULL}, +@code{payload_length} is unused and may have any value. + +The function uses variadic arguments for header input. +The first argument in the variadic argument list should +be an @code{printf}-formatted format-string that describes +a header line (header name, colon, blank space, header value.) +The following arguments are the formatting-arguments for that +format string. At the end of the list of formatting-arguments, +this is begin anew for the next header, and so on. After the +last header, a @code{NULL} should be used to mark the end of +the list. The header formatting string, may include any +extensions provided by your C library. Nut is has one additional +extension: if the formatting-string begins with a question mark, +the first formatting-argument is if type @code{int} and the +header is only included if that argument is non-zero. +This is no way to escape a question mark at the beginning of +the formatting-string, because headers should never begin +with a question mark. + +Upon successful completion, this function returns zero. +On error, this function returns @code{-1} and sets @code{errno} +to indicate the error. + +This function may fail with @code{errno} set to @code{ENOMEM} +if the process cannot allocate more memory. + +The functions behaviour is undefined if a header is longer than +@iftex +2@sup{15} +@end iftex +@ifnottex +2 to the power of 15 +@end ifnottex +bytes. + +This function shall not be used if there must be a guarantee +that the written data can be securely erased. +@end table + +The header file also provides a function for finding the +next unused message ID: + +@table @asis +@item @code{libmds_next_message_id} [(@code{uint32_t* restrict message_id, int (*test)(uint32_t message_id, void* data), void* data}) @arrow{} @code{int}] +The parameter @code{message_id} is a pointer to the message +ID counter. It should contain the ID of the previous +message,@footnote{For the first message, it is preferred +that this value is @code{UINT32_MAX}, so the first message +is the ID 0, but it is not a requirement, it should however +be initialised.} it will be updated with the message ID +for the new message upon successful completion. +@code{message_id} must not be @code{NULL}. + +The parameter @code{test} can either point to a function +that is used to test if a message ID is unused, or be +@code{NULL} if no testing should be done. @code{*test} +tests whether the message ID provided as the first +argument is free to be used. The second argument in +@code{*test} will be the value of the parameter @code{data} +in the call to the function @code{libmds_next_message_id}. +@code{data} can e used to deal with threading or any other issues. +@code{data} may be @code{NULL}. @code{data} is unused if +@code{test} is @code{NULL}. + +Upon successful completion zero is returned. On error +@code{-1} is returned and @code{errno} is set the indicate +the error. + +This function can fail with errno set to any error thrown +by @code{*test}, as well as @code{EAGAIN}. @code{EAGAIN} +is thrown if the function cannot find any free message ID +to use. It is advisable to make @code{*test} throw this +immediately if there are no free message ID:s. +The function cannot fail if @code{test} is @code{NULL}. +@end table + +@fnindex @code{libmds_headers_cherrypick_v} +@fnindex @code{libmds_headers_cherrypick_linear_unsorted_v} +@fnindex @code{libmds_headers_cherrypick_linear_sorted_v} +@fnindex @code{libmds_headers_cherrypick_binary_unsorted_v} +@fnindex @code{libmds_headers_cherrypick_binary_sorted_v} +@fnindex @code{libmds_compose_v} +All functions that uses variadic arguments, have a variant +that uses @code{va_list} instead. These functions are suffixed +@code{_v}. + @node libmdslltk diff --git a/src/libmdsclient/proto-util.c b/src/libmdsclient/proto-util.c index a2b24f6..c0f0c3b 100644 --- a/src/libmdsclient/proto-util.c +++ b/src/libmdsclient/proto-util.c @@ -709,6 +709,9 @@ int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_ # pragma GCC diagnostic ignored "-Wformat-nonliteral" # pragma GCC diagnostic ignored "-Wsuggest-attribute=format" part_len = vasprintf(&part_msg, format, args); + /* TODO we need a version of vasprintf that can + * write to a buffer with an offset, but + * reallocate the buffer on will. */ # pragma GCC diagnostic pop if (include == 0) |