diff options
Diffstat (limited to '')
-rw-r--r-- | LIBAXL_REQUEST_CREATE_WINDOW.3 | 60 | ||||
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | common.h | 26 | ||||
-rw-r--r-- | libaxl-consts.h | 17 | ||||
-rw-r--r-- | libaxl-display-info.h | 301 | ||||
-rw-r--r-- | libaxl-replies.h | 4 | ||||
-rw-r--r-- | libaxl-requests.h | 4 | ||||
-rw-r--r-- | libaxl-types.h | 2 | ||||
-rw-r--r-- | libaxl.h | 282 | ||||
-rw-r--r-- | libaxl_fileno.c | 8 | ||||
-rw-r--r-- | libaxl_generate_id.c | 20 | ||||
-rw-r--r-- | libaxl_get_decnet_object.c | 8 | ||||
-rw-r--r-- | libaxl_get_tcp_port.c | 4 | ||||
-rw-r--r-- | libaxl_info.c | 9 | ||||
-rw-r--r-- | libaxl_next_depth.c | 4 | ||||
-rw-r--r-- | libaxl_next_screen.c | 4 | ||||
-rw-r--r-- | libaxl_protocol_version.c | 8 | ||||
-rw-r--r-- | libaxl_protocol_version_major.c | 8 | ||||
-rw-r--r-- | libaxl_protocol_version_minor.c | 8 | ||||
-rw-r--r-- | libaxl_receive_handshake.c | 211 | ||||
-rw-r--r-- | libaxl_send_handshake.c | 115 |
21 files changed, 1054 insertions, 64 deletions
diff --git a/LIBAXL_REQUEST_CREATE_WINDOW.3 b/LIBAXL_REQUEST_CREATE_WINDOW.3 index e5d64ff..210b5c3 100644 --- a/LIBAXL_REQUEST_CREATE_WINDOW.3 +++ b/LIBAXL_REQUEST_CREATE_WINDOW.3 @@ -23,37 +23,37 @@ LIBAXL_REQUEST_CREATE_WINDOW - Create an unmapped window #define LIBAXL_REQUEST_CREATE_WINDOW 1 struct libaxl_request_create_window { - uint8_t \fIopcode\fP; - uint8_t \fIdepth\fP; - uint16_t \fI_request_length\fP; - libaxl_window_t \fIwid\fP; - libaxl_window_t \fIparent\fP; - int16_t \fIx\fP; - int16_t \fIy\fP; - uint16_t \fIwidth\fP; - uint16_t \fIheight\fP; - uint16_t \fIborder_width\fP; - uint16_t \fIclass\fP; - libaxl_visual_id_t \fIvisual\fP; - uint32_t \fIvalue_mask\fP; + uint8_t \fIopcode\fP; + uint8_t \fIdepth\fP; + uint16_t \fI_request_length\fP; + libaxl_window_t \fIwid\fP; + libaxl_window_t \fIparent\fP; + int16_t \fIx\fP; + int16_t \fIy\fP; + uint16_t \fIwidth\fP; + uint16_t \fIheight\fP; + uint16_t \fIborder_width\fP; + uint16_t \fIclass\fP; + libaxl_visual_t \fIvisual\fP; + uint32_t \fIvalue_mask\fP; - libaxl_pixmap_t \fIbackground_pixmap\fP; - uint32_t \fIbackground_pixel\fP; - libaxl_pixmap_t \fIborder_pixmap\fP; - uint32_t \fIborder_pixel\fP; - uint8_t \fIbit_gravity\fP; - uint8_t \fIwin_gravity\fP; - uint8_t \fIbacking_store\fP; - uint8_t \fI__omitted1\fP; - uint32_t \fIbacking_planes\fP; - uint32_t \fIbacking_pixel\fP; - libaxl_bool_t \fIoverride_redirect\fP; - libaxl_bool_t \fIsave_under\fP; - uint16_t \fI__omitted2\fP; - uint32_t \fIevent_mask\fP; - uint32_t \fIdo_not_propagate_mask\fP; - libaxl_colormap_t \fIcolormap\fP; - libaxl_cursor_t \fIcursor\fP; + libaxl_pixmap_t \fIbackground_pixmap\fP; + uint32_t \fIbackground_pixel\fP; + libaxl_pixmap_t \fIborder_pixmap\fP; + uint32_t \fIborder_pixel\fP; + uint8_t \fIbit_gravity\fP; + uint8_t \fIwin_gravity\fP; + uint8_t \fIbacking_store\fP; + uint8_t \fI__omitted1\fP; + uint32_t \fIbacking_planes\fP; + uint32_t \fIbacking_pixel\fP; + libaxl_bool_t \fIoverride_redirect\fP; + libaxl_bool_t \fIsave_under\fP; + uint16_t \fI__omitted2\fP; + uint32_t \fIevent_mask\fP; + uint32_t \fIdo_not_propagate_mask\fP; + libaxl_colormap_t \fIcolormap\fP; + libaxl_cursor_t \fIcursor\fP; }; .fi .SH DESCRIPTION @@ -13,9 +13,21 @@ include $(OSCONFIGFILE) OBJ =\ libaxl_context_create.o\ libaxl_context_free.o\ + libaxl_fileno.o\ libaxl_flush.o\ + libaxl_generate_id.o\ + libaxl_get_decnet_object.o\ + libaxl_get_tcp_port.o\ + libaxl_info.o\ + libaxl_next_depth.o\ + libaxl_next_screen.o\ libaxl_parse_display.o\ + libaxl_protocol_version_major.o\ + libaxl_protocol_version_minor.o\ + libaxl_protocol_version.o\ libaxl_receive.o\ + libaxl_receive_handshake.o\ + libaxl_send_handshake.o\ libaxl_send_request.o LIB_HDR =\ @@ -31,7 +43,8 @@ LIB_HDR =\ libaxl-requests.h\ libaxl-requests-ptr-structs.h\ libaxl-requests-structs.h\ - libaxl-types.h + libaxl-types.h\ + libaxl-display-info.h HDR =\ common.h\ @@ -9,6 +9,7 @@ #include <fcntl.h> #include <limits.h> #include <stdatomic.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -54,18 +55,21 @@ DEFINE_CHECKED(ssize_t, __checked_ssize_t) #define X_TCP_PORT 6000 -struct libaxl_connection { - int fd; - uint16_t last_seqnum; +struct libaxl_connection { /* TODO add serialisation functions, add close and detach functions */ + int fd; + uint16_t last_seqnum; LIBAXL_CONNECTION_RWLOCK; /* INIT_LIBAXL_CONNECTION_RWLOCK(&.) */ - LIBAXL_CONTEXT *pending_out; - size_t in_progress; - size_t in_buf_size; - char *in_buf; - uint32_t xid_base; /* TODO information for these are send by server when connecting { */ - uint32_t xid_bits; - uint32_t xid_shift; /* } */ - uint8_t request_map[1UL << 16]; + LIBAXL_CONTEXT *pending_out; + size_t in_progress; + size_t in_buf_size; + char *in_buf; + uint32_t xid_base; + uint32_t xid_max; + uint32_t xid_shift; + volatile _Atomic uint32_t xid_last; /* atomic_init(&.xid_last, 0) */ + uint8_t request_map[1UL << 16]; + struct libaxl_display_info info; + char *info_buf; }; struct libaxl_context { diff --git a/libaxl-consts.h b/libaxl-consts.h index 26c1933..cf6a119 100644 --- a/libaxl-consts.h +++ b/libaxl-consts.h @@ -79,6 +79,14 @@ #define LIBAXL_KEYBOARD 1 #define LIBAXL_POINTER 2 +/* struct libaxl_visual_type.class */ +#define LIBAXL_STATIC_GRAY 0 +#define LIBAXL_GRAY_SCALE 1 +#define LIBAXL_STATIC_COLOR 2 +#define LIBAXL_PSEUDO_COLOR 3 +#define LIBAXL_TRUE_COLOR 4 +#define LIBAXL_DIRECT_COLOR 5 + /* circatulation place */ #define LIBAXL_TOP 0 #define LIBAXL_BOTTOM 1 @@ -208,7 +216,8 @@ #define LIBAXL_INCLUDE_INFERIORS 1 /* backing store */ -#define LIBAXL_NOT_USEFUL 0 +#define LIBAXL_NOT_USEFUL 0 /* Not used in `struct libaxl_screen.backing_stores` */ +#define LIBAXL_NEVER 0 /* Used in `struct libaxl_screen.backing_stores` */ #define LIBAXL_WHEN_MAPPED 1 #define LIBAXL_ALWAYS 2 @@ -230,9 +239,9 @@ #define LIBAXL_NONLINEAR 3 #define LIBAXL_NONLINEAR_VIRTUAL 4 /* window focus details */ -#define LIBAXL_FOCUS_POINTER 5 /* Just called Pointer in the specification*/ -#define LIBAXL_FOCUS_POINTER_ROOT 6 /* Just called PointerRoot in the specification*/ -#define LIBAXL_FOCUS_NONE 7 /* Just called None in the specification*/ +#define LIBAXL_FOCUS_POINTER 5 /* Just called Pointer in the specification */ +#define LIBAXL_FOCUS_POINTER_ROOT 6 /* Just called PointerRoot in the specification */ +#define LIBAXL_FOCUS_NONE 7 /* Just called None in the specification */ /* misc. */ #define LIBAXL_ANY_PROPERTY_TYPE 0 diff --git a/libaxl-display-info.h b/libaxl-display-info.h new file mode 100644 index 0000000..71cf80f --- /dev/null +++ b/libaxl-display-info.h @@ -0,0 +1,301 @@ +/* See LICENSE file for copyright and license details. */ + +/** + * The highest number of the `struct_version` field in + * `struct libaxl_display_info` that this header file + * supports + */ +#define LIBAXL_DISPLAY_INFO_VERSION 0 + +/** + * Standard byte orders + */ +enum libaxl_byte_order { + /** + * Least significant byte first + */ + LIBAXL_LSB_FIRST, + + /** + * Most significant byte first + */ + LIBAXL_MSB_FIRST +}; + +/** + * Standard bit orders + */ +enum libaxl_bit_order { + /** + * Least significant bit leftmost + */ + LIBAXL_LSB_LEFTMOST, + + /** + * Most significant bit leftmost + */ + LIBAXL_MSB_LEFTMOST +}; + +struct libaxl_format { + uint8_t depth; + uint8_t bits_per_pixel; + uint8_t scanline_pad; + uint8_t __unused[5]; +}; + +struct libaxl_visual_type { + libaxl_visual_t visual_id; + uint8_t class; /* LIBAXL_STATIC_GRAY, LIBAXL_GRAY_SCALE, LIBAXL_STATIC_COLOR, + * LIBAXL_PSEUDO_COLOR, LIBAXL_TRUE_COLOR, LIBAXL_DIRECT_COLOR */ + uint8_t bits_per_rgb_value; + uint16_t colormap_entries; + uint32_t red_mask; + uint32_t green_mask; + uint32_t blue_mask; + uint32_t __unused; +}; + +struct libaxl_depth { + uint8_t depth; + uint8_t __pad; + uint16_t number_of_visuals; + uint32_t __unused; + struct libaxl_visual_type visuals[]; +}; + +/** + * Screen information + */ +struct libaxl_screen { + /** + * The root window of the screen + * + * This is always an LIBAXL_INPUT_OUTPUT window + */ + libaxl_window_t root; + + /** + * The map initially associated with the root window + * + * Windows with minimal colour requires may want to + * use this colormap if they use the same depth as + * the root window. + */ + libaxl_colormap_t default_colormap; + + /** + * Bright colour usable for implementing monochrome + * applications using `.default_colormap` + * + * This colour is permanently allocated + * + * May be set to a dark colour on some screens + * (that what the colours to be inverted); the + * actual RGB value is unspecified and may any + * colour and not necessarily black or white + */ + uint32_t white_pixel; + + /** + * Dark colour usable for implementing monochrome + * applications using `.default_colormap` + * + * This colour is permanently allocated + * + * May be set to a bright colour on some screens + * (that what the colours to be inverted); the + * actual RGB value is unspecified and may any + * colour and not necessarily black or white + */ + uint32_t black_pixel; + + uint32_t current_input_masks; /* TODO SETofEVENTS */ + + /** + * The width, in pixels, of the root window; + * which cannot be changed in the core protocol + * + * This value will not update when root window + * is resized, but new connections may get an + * update value + */ + uint16_t width_in_pixels; + + /** + * The height, in pixels, of the root window; + * which cannot be changed in the core protocol + * + * This value will not update when root window + * is resized, but new connections may get an + * update value + */ + uint16_t height_in_pixels; + + /** + * The width, in millimeters, of the root window; + * which cannot be changed in the core protocol + * + * This value will not update when root window + * is resized or the monitor is changed + * + * Note that the horizontal and vertical DPI + * (dots per inch) of a monitor are not + * necessarily equal to each other + */ + uint16_t width_in_millimeters; + + /** + * The height, in millimeters, of the root window; + * which cannot be changed in the core protocol + * + * This value will not update when root window + * is resized or the monitor is changed + * + * Note that the horizontal and vertical DPI + * (dots per inch) of a monitor are not + * necessarily equal to each other + */ + uint16_t height_in_millimeters; + + uint16_t min_installed_maps; + uint16_t max_installed_maps; + libaxl_visual_t root_visual; + uint8_t backing_stores; + libaxl_bool_t save_under; + uint8_t root_depth; + uint8_t number_of_allowed_depths; + struct libaxl_depth allowed_depths[]; +}; + +/** + * Information about the display, display server, and connection + */ +struct libaxl_display_info { + /** + * The version number of this structure that this library uses. + * When using dynamic linking, is important use the version that + * is the lowest of the number stored in this field and the + * number stored in the LIBAXL_DISPLAY_INFO_VERSION constant. + */ + int struct_version; /* TODO set when creating LIBAXL_CONNECTION */ + + /* SINCE STRUCT VERSION 0: */ + + /** + * The major number of version of the protocol negotiated + * between the client and the server. This is not necessarily + * the same number as returned in the second parameter of + * the libaxl_receive_handshake() function. + */ + int protocol_version_major; + + /** + * The minor number of version of the protocol negotiated + * between the client and the server. This is not necessarily + * the same number as returned in the third parameter of + * the libaxl_receive_handshake() function. + */ + int protocol_version_minor; + + /** + * The version of the protocol negotiated between the client + * and the server, encoded as the sum of the major number + * multipled by 10000 and the minor number. + */ + int protocol_version; + + /** + * The byte order generally used in communication with the + * display server + */ + enum libaxl_byte_order protocol_byte_order; + + /** + * The byte order used in images + */ + enum libaxl_byte_order image_byte_order; + + /** + * The smallest keycode transmitted by the server + * + * Will never be less than 8 + */ + unsigned int min_keycode; + + /** + * The greatest keycode transmitted by the server + * + * This field has the `unsigned int` type rather than the + * `libaxl_keycode_t` type because the latter is restricted + * to 8-bits, and a future version of the protocol could + * theoretically use a larger value + */ + unsigned int max_keycode; + + /** + * Some identification of the owner of the server implementation + */ + const char *vendor; + + /** + * Release number for the implementation. The vendor controls + * the semantics of this number. + */ + uint32_t vendor_release; + + /** + * The bit order used in the units in the scanlines of bitmaps + */ + enum libaxl_bit_order bitmap_format_bit_order; + + /** + * Number of bits (will be a multiple of 8) that the scanlines + * in bitmaps are quantised into units of + * + * Will never greater than `bitmap_format_scanline_pad` + */ + size_t bitmap_format_scanline_unit; + + /** + * Number of bits (will be a multiple of 8), that scanlines in + * bitmaps are padded to + */ + size_t bitmap_format_scanline_pad; + + /** + * The server may retain recent pointer motion history with + * finer granularity than is reported by LIBAXL_EVENT_MOTION_NOTIFY + * events, and which may be requested with + * LIBAXL_REQUEST_GET_MOTION_EVENTS requests + */ + size_t motion_buffer_size; + + /** + * The maximum value that can may appear in the length field + * in requests (that field is filled in by the library). Any + * requests larger than this (it is in byte-quads, meaning + * that it is multipled by 4 to get limit in bytes) generate + * a LIBAXL_ERROR_LENGTH error and the request is discarded. + * + * This field will always be at least 4096 (meaning 16384 bytes) + */ + size_t maximum_request_length; + + /** + * The number of elements in `.formats` + */ + size_t nformats; + + const struct libaxl_format *formats; /* TODO doc */ + + /** + * The number of elements in `.screens` + */ + size_t nscreens; + + /** + * List of all screens in the display + */ + const struct libaxl_format *screens; +}; diff --git a/libaxl-replies.h b/libaxl-replies.h index 7b30ee1..30e02a1 100644 --- a/libaxl-replies.h +++ b/libaxl-replies.h @@ -7,7 +7,7 @@ struct libaxl_reply_get_window_attributes { uint8_t backing_store; /* LIBAXL_NOT_USEFUL, LIBAXL_WHEN_MAPPED, or LIBAXL_ALWAYS */ uint16_t sequence_number; uint32_t _reply_length; /* = 3 */ - libaxl_visual_id_t visual; + libaxl_visual_t visual; uint16_t class; /* LIBAXL_INPUT_OUTPUT (= 1) or LIBAXL_INPUT_ONLY (= 2) */ uint8_t bit_gravity; uint8_t win_gravity; @@ -264,7 +264,7 @@ struct libaxl_reply_get_image { uint8_t depth; uint16_t sequence_number; uint32_t _reply_length; - libaxl_visual_id_t visual; /* Can be LIBAXL_NONE */ + libaxl_visual_t visual; /* Can be LIBAXL_NONE */ uint8_t __unused[20]; size_t size_of_data; uint8_t *data; diff --git a/libaxl-requests.h b/libaxl-requests.h index 21984f2..f0a6279 100644 --- a/libaxl-requests.h +++ b/libaxl-requests.h @@ -13,7 +13,7 @@ struct libaxl_request_create_window { uint16_t height; uint16_t border_width; uint16_t class; /* LIBAXL_COPY_FROM_PARENT, LIBAXL_INPUT_OUTPUT, or LIBAXL_INPUT_ONLY */ - libaxl_visual_id_t visual; /* Can be LIBAXL_COPY_FROM_PARENT */ + libaxl_visual_t visual; /* Can be LIBAXL_COPY_FROM_PARENT */ uint32_t value_mask; /* Determines which below are included, all are encoded as uint32_t */ #define LIBAXL_REQUEST_CREATE_WINDOW_BACKGROUND_PIXMAP 0x00000001UL #define LIBAXL_REQUEST_CREATE_WINDOW_BACKGROUND_PIXEL 0x00000002UL @@ -1008,7 +1008,7 @@ struct libaxl_request_create_colormap { uint16_t _request_length; /* = 4 */ libaxl_colormap_t mid; libaxl_window_t window; - libaxl_visual_id_t visual; + libaxl_visual_t visual; }; struct libaxl_request_free_colormap { diff --git a/libaxl-types.h b/libaxl-types.h index 1826430..c55a319 100644 --- a/libaxl-types.h +++ b/libaxl-types.h @@ -13,7 +13,7 @@ typedef libaxl_id_t libaxl_colormap_t; typedef libaxl_id_t libaxl_drawable_t; /* libaxl_window_t or libaxl_pixmap_t */ typedef libaxl_id_t libaxl_fontable_t; /* libaxl_font_t or libaxl_gcontext_t */ typedef libaxl_id_t libaxl_atom_t; -typedef libaxl_id_t libaxl_visual_id_t; +typedef libaxl_id_t libaxl_visual_t; typedef uint32_t libaxl_timestamp_t; typedef uint32_t libaxl_keysym_t; typedef uint8_t libaxl_keycode_t; @@ -2,6 +2,9 @@ #ifndef LIBAXL_H #define LIBAXL_H +#include <stddef.h> +#include <stdint.h> + #if defined(__GNUC__) # define _LIBAXL_GCC_ONLY(...) __VA_ARGS__ #else @@ -15,6 +18,32 @@ #include "libaxl-errors.h" #include "libaxl-requests.h" #include "libaxl-replies.h" +#include "libaxl-display-info.h" + +/** + * The major version number of the highest version of X protocol + * of the library supports (the lowest version is 11.0). If you + * are using dynamic linking, you make also want to use the + * libaxl_protocol_major() function. + */ +#define LIBAXL_PROTOCOL_MAJOR 11 + +/** + * The minor version number of the highest version of X protocol + * of the library supports (the lowest version is 11.0). If you + * are using dynamic linking, you make also want to use the + * libaxl_protocol_minor() function. + */ +#define LIBAXL_PROTOCOL_MINOR 0 + +/** + * The version number of the highest version of X protocol of + * the library supports, as one integer where the major number + * is multiped by 100000, (the lowest version is 11.0, which is + * encoded as 1100000). If you are using dynamic linking, you + * make also want to use the libaxl_protocol_version() function. + */ +#define LIBAXL_PROTOCOL_VERSION ((LIBAXL_PROTOCOL_MAJOR) * 100000 + (LIBAXL_PROTOCOL_MINOR)) /* libaxl error codes */ #define LIBAXL_ERROR_SYSTEM -1 /* use `errno` */ @@ -28,8 +57,20 @@ #define LIBAXL_ERROR_MALFORMATTED_REQUEST -9 #define LIBAXL_ERROR_CONNECTION_CLOSED -10 #define LIBAXL_ERROR_INVALID_REPLY_OPCODE -11 +#define LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE -12 +#define LIBAXL_ERROR_OUT_OF_RESOURCE_IDS -13 -union libaxl_input { /* TODO man */ +#define LIBAXL_HANDSHAKE_FAILED 0 +#define LIBAXL_HANDSHAKE_SUCCESS 1 +#define LIBAXL_HANDSHAKE_AUTHENTICATE 2 + +/* + * The largest possible return of the libaxl_get_decnet_object() + * function, plus 1 for the terminal NUL byte + */ +#define LIBAXL_DECNET_OBJECT_MAX (5 + 3 * sizeof(int) - sizeof(int) / 2) + +union libaxl_input { /* TODO doc, man */ uint8_t type; union libaxl_error error; /* if .type = LIBAXL_ERROR */ union libaxl_reply reply; /* if .type = LIBAXL_REPLY */ @@ -50,6 +91,118 @@ typedef struct libaxl_connection LIBAXL_CONNECTION; typedef struct libaxl_context LIBAXL_CONTEXT; /** + * Returns the major version number of the highest version of + * X protocol of the library supports (the lowest version is + * 11.0). If you are using static linking, you make also want + * to use the LIBAXL_PROTOCOL_MAJOR constant. + * + * @return The major version number of highest support version of the protocol + */ +int libaxl_protocol_version_major(void); + +/** + * Returns the minor version number of the highest version of + * X protocol of the library supports (the lowest version is + * 11.0). If you are using static linking, you make also want + * to use the LIBAXL_PROTOCOL_MINOR constant. + * + * @return The minor version number of highest support version of the protocol + */ +int libaxl_protocol_version_minor(void); + +/** + * Returns the minor version number of the highest version of + * X protocol of the library supports (the lowest version is 11.0, + * which is encoded as 1100000). If you are using static linking, + * you make also want to use the LIBAXL_PROTOCOL_VERSION constant. + * + * @return The version number of highest support version of the protocol, + * encoded as a sum of the major number multipled by 100000 (1e5) + * and the minor number, e.g. 1100000 for 11.0 (X11) + */ +int libaxl_protocol_version(void); + +/** + * Get the file description used for a connection to + * the X display server + * + * @param conn The connection to the display server + * @return The number of the file descriptor that holds + * the connection to the display server + */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) +int libaxl_fileno(LIBAXL_CONNECTION *); /* TODO man */ + +/** + * Get information about a connection and the display + * and display server it is connected to + * + * This information is sent to the client during the + * connection handshake, and is never updated hence + * + * @param conn The connection to the display server + * @param version Should be `LIBAXL_DISPLAY_INFO_VERSION`; used to + * identify if old fields that have been replaces + * must allocated and filled in with information + * from the new fields that the application does + ' not know about + * @return Information about the display, the display + * server, and the connection; `NULL` on error + * + * On failure, no error is returned, but the error + * is always LIBAXL_ERROR_SYSTEM + */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) +const struct libaxl_display_info *libaxl_info(LIBAXL_CONNECTION *, int); /* TODO man */ + +/** + * Get the next element in a `struct libaxl_depth *` + * + * Usage example for iterating of all elements in + * `screen->allowed_depths` where `screen` is a + * `struct libaxl_screen *`: + * + * struct libaxl_depth *depth; + * size_t i = 0; + * for (depth = screen->allowed_depths; i < screen->number_of_allowed_depths; depth = libaxl_next_depth(depth)) { + * ... do something with `depth` or `break` if `i` is of a desired value (index) ... + * } + * + * @param depth The element before the element to return + * @return The element after `depth` + */ +inline const struct libaxl_depth * +libaxl_next_depth(const struct libaxl_depth *depth) /* TODO man */ +{ + return (const struct libaxl_depth *)(uintptr_t)&depth->visuals[depth->number_of_visuals]; +} + +/** + * Get the next element in a `struct libaxl_screen *` + * + * Usage example for iterating of all elements in `info->screens` + * where `info` is a `struct libaxl_display_info *`: + * + * struct libaxl_screen *screen; + * size_t i = 0; + * for (screen = info->screens; i < info->nscreens; screen = libaxl_next_screen(screen)) { + * ... do something with `screen` or `break` if `i` is of a desired value (index) ... + * } + * + * @param screen The element before the element to return + * @return The element after `screen` + */ +inline const struct libaxl_screen * +libaxl_next_screen(const struct libaxl_screen *screen) /* TODO man */ +{ + uint8_t n = screen->number_of_allowed_depths; + const struct libaxl_depth *depth = screen->allowed_depths; + while (n--) + depth = libaxl_next_depth(depth); + return (const struct libaxl_screen *)(uintptr_t)depth; +} + +/** * Create context, for a thread, to use when accessing * the display server * @@ -70,20 +223,26 @@ void libaxl_context_free(LIBAXL_CONTEXT *); /* TODO man */ * Generate a resource ID * * The generated resource ID can be deallocated - * with the `libaxl_deallocate_id` function + * with the libaxl_deallocate_id() function * * @param ctx The thread's context for the connection * @return The generated resource ID, 0 on failure + * + * On failure, no error is returned, but the error + * is always LIBAXL_ERROR_OUT_OF_RESOURCE_IDS */ -libaxl_id_t libaxl_generate_id(LIBAXL_CONTEXT *); /* TODO man, implement */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))) +libaxl_id_t libaxl_generate_id(LIBAXL_CONTEXT *); /* TODO man */ /** * Deallocate a resource ID so that it can be reused later * - * @param ctx The thread's context for the connection - * @param id The generated resource ID to deallocate + * @param ctx The thread's context for the connection + * @param id The generated resource ID to deallocate + * @return 0 on success, a negative libaxl error code on failure */ -void libaxl_deallocate_id(LIBAXL_CONTEXT *, libaxl_id_t); /* TODO man, implement */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) +int libaxl_deallocate_id(LIBAXL_CONTEXT *, libaxl_id_t); /* TODO man, implement */ /** * Parse a display name string @@ -96,7 +255,7 @@ void libaxl_deallocate_id(LIBAXL_CONTEXT *, libaxl_id_t); /* TODO man, implement * * <path>[.<screen>] * - * @param name The display name string, $DISPLAY will be used if `NULL` or empty + * @param name The display name string, $DISPLAY will be used if NULL or empty * @param hostp Output parameter for the host of or (if the protocol is "unix") path * to the display, remember to free after successful completion * @param protocolp Output parameter for the network protocol used to access the display, @@ -109,6 +268,62 @@ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__(2, 3, 4, 5)))) int libaxl_parse_display(const char *, char **, char **, int *, int *); /* TODO man */ /** + * Get the TCP port that is used for a display + * + * @param display The display's number, the function will assume that it is a valid number + * @return The TCP port used for the display + */ +_LIBAXL_GCC_ONLY(__attribute__((__warn_unused_result__))) +inline uint16_t libaxl_get_tcp_port(int display) /* TODO man */ +{ + return (uint16_t)(display + 6000); +} + +/** + * Get the DECnet object name that is used for a display + * + * @param buf Buffer that the object name shall be written to, it is recommended + * that is size, if static, is LIBAXL_DECNET_OBJECT_MAX (which is + * always sufficient), otherwise it should be at least the return value + * of this function (for the same last argument but with NULL and 0 + * as the first two arguments) plus 1 + * @param size The size of the buffer in the `buf` argument + * @param display The display's number + * @return The length of the object name, will not exceed LIBAXL_DECNET_OBJECT_MAX + * less 1; an additional uncounted NUL byte will be written to the buffer + * if it is large enough; or -1 on failure (specifically snprintf(3), which + * the function calls, by fail with EOVERFLOW if the `size` argument is + * greater than {INT_MAX}) + */ +int libaxl_get_decnet_object(char *, size_t, int); /* TODO man */ + +/** + * This function is to be called once and only once, excluding any + * failure that does not set `errno` to EINPROGRESS and excluding + * any call for which the display server respond that the handshake + * failed or requires authentication, immediately after connecting + * to the socket for the display + * + * The libaxl_receive_handshake() shall be called immediately after + * calling this function + * + * @param ctx The thread's context for the connection to the display to send the handshake over + * @param auth_name The protocol name of the authorisation the client expects the server to use; + * valid authorisation mechanisms are not part of the core X protocol + * @param auth_name_len The length of `auth_name`, 0 if `auth_name` is NULL + * @param auth_data The authorisation data, which is specific to the choosen authorisation mechanism + * @param auth_data_len The length of `auth_data`, 0 if `auth_data` is NULL + * @param flags Flags to use for the 4th parameter when calling send(3) + * @return 0 on success, a negative libaxl error code on failure + * + * If the function returns LIBAXL_ERROR_SYSTEM and sets `errno` + * to EINPROGRESS, the message has been saved (possibly partially + * sent) and pending to be sent by calling libaxl_flush(). + */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__(1)))) +int libaxl_send_handshake(LIBAXL_CONTEXT *restrict, const char *, size_t, const char *, size_t, int); /* TODO man */ + +/** * Send a request to the display server * * May deadlock if called from an asynchronously called signal handler @@ -150,14 +365,55 @@ _LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) int libaxl_flush(LIBAXL_CONNECTION *restrict, int); /* TODO man */ /** + * Receive the server's part of the handshake, this function + * shall be called once immediately after each successful call + * to the libaxl_send_handshake() function or successful call + * to the libaxl_flush() function due to EINPROGRESS failure + * of call to the libaxl_send_handshake() function + * + * @param ctx The thread's context for the connection to the display server + * @param majorp Output parameter for the major version number for a version + * of the X protocol that the display server supports, which is + * not necessarily the version that the library uses. Will only + * be set if the function returns LIBAXL_HANDSHAKE_FAILED or + * LIBAXL_HANDSHAKE_SUCCESS. + * @param minorp Output parameter for the minor version number for a version + * of the X protocol that the display server supports, which is + * not necessarily the version that the library uses. Will only + * be set if the function returns LIBAXL_HANDSHAKE_FAILED or + * LIBAXL_HANDSHAKE_SUCCESS. + * @param reasonp Output parameter for the reason the handshake or authorisation + * failed. Will be set to NULL unless the function returns + * LIBAXL_HANDSHAKE_FAILED or LIBAXL_HANDSHAKE_AUTHENTICATE. + * Remember to free after successful completion (non-negative return) + * @param flags Flags to use for the 4th parameter when calling recv(3) + * @return 0 on success, a negative libaxl error code on failure + * + * Behaviour is unspecified if SO_PEEK_OFF is active on the + * connection to the display server or if the MSG_PEEK flag + * is used + */ +_LIBAXL_GCC_ONLY(__attribute__((__nonnull__(1)))) +int libaxl_receive_handshake(LIBAXL_CONTEXT *restrict, int *restrict, int *restrict, char **restrict, int); /* TODO man */ + +/** * Receive the next pending message from the display server * - * @param ctx The thread's context for the connection to the display server - * @param msgp Output parameter for the received message; the message will - * be vaild until the next time this function is called with the - * same `ctx` parameter or until the libaxl_context_free() function - * is called with the same `ctx` paramter (whichever comes first) - * @param flags Flags to use for the 4th parameter when calling recv(3) + * Be aware: order of replies and events is not guaranteed, + * and events caused by a request are sent before replies + * and errors, however when multiple events are generated, + * by some action, they are send in an uninterrupted sequence + * (no other event, error, or reply is send between those event). + * This means that it is important to check the returned + * sequence number. + * + * @param ctx The thread's context for the connection to the display server + * @param msgp Output parameter for the received message; the message will + * be vaild until the next time this function is called with the + * same `ctx` parameter or until the libaxl_context_free() function + * is called with the same `ctx` paramter (whichever comes first) + * @param flags Flags to use for the 4th parameter when calling recv(3) + * @return 0 on success, a negative libaxl error code on failure * * Behaviour is unspecified if SO_PEEK_OFF is active on the * connection to the display server or if the MSG_PEEK flag diff --git a/libaxl_fileno.c b/libaxl_fileno.c new file mode 100644 index 0000000..14bf978 --- /dev/null +++ b/libaxl_fileno.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_fileno(LIBAXL_CONNECTION *conn) +{ + return conn->fd; +} diff --git a/libaxl_generate_id.c b/libaxl_generate_id.c new file mode 100644 index 0000000..232ef4d --- /dev/null +++ b/libaxl_generate_id.c @@ -0,0 +1,20 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +libaxl_id_t +libaxl_generate_id(LIBAXL_CONTEXT *ctx) +{ + LIBAXL_CONNECTION *conn = ctx->conn; + uint32_t id; + + id = atomic_fetch_add(&conn->xid_last, 1); + if (id <= conn->xid_max) + return (id << conn->xid_shift) | conn->xid_base; + + atomic_fetch_sub(&conn->xid_last, 1); + + liberror_save_backtrace(NULL); + liberror_set_error("Request has been buffered and is ready to be sent", + "libaxl_generate_id", "libaxl", LIBAXL_ERROR_OUT_OF_RESOURCE_IDS); + return 0; +} diff --git a/libaxl_get_decnet_object.c b/libaxl_get_decnet_object.c new file mode 100644 index 0000000..a744fd2 --- /dev/null +++ b/libaxl_get_decnet_object.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_get_decnet_object(char *buf, size_t size, int display) +{ + return snprintf(buf, size, "X$X%i", display); +} diff --git a/libaxl_get_tcp_port.c b/libaxl_get_tcp_port.c new file mode 100644 index 0000000..2fd3eca --- /dev/null +++ b/libaxl_get_tcp_port.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline uint16_t libaxl_get_tcp_port(int display); diff --git a/libaxl_info.c b/libaxl_info.c new file mode 100644 index 0000000..585f2f1 --- /dev/null +++ b/libaxl_info.c @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +const struct libaxl_display_info * +libaxl_info(LIBAXL_CONNECTION *conn, int version) +{ + (void) version; + return &conn->info; +} diff --git a/libaxl_next_depth.c b/libaxl_next_depth.c new file mode 100644 index 0000000..c14c977 --- /dev/null +++ b/libaxl_next_depth.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline const struct libaxl_depth *libaxl_next_depth(const struct libaxl_depth *depth); diff --git a/libaxl_next_screen.c b/libaxl_next_screen.c new file mode 100644 index 0000000..3c129c3 --- /dev/null +++ b/libaxl_next_screen.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +extern inline const struct libaxl_screen *libaxl_next_screen(const struct libaxl_screen *screen); diff --git a/libaxl_protocol_version.c b/libaxl_protocol_version.c new file mode 100644 index 0000000..feaa953 --- /dev/null +++ b/libaxl_protocol_version.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_protocol_version(void) +{ + return LIBAXL_PROTOCOL_VERSION; +} diff --git a/libaxl_protocol_version_major.c b/libaxl_protocol_version_major.c new file mode 100644 index 0000000..7dc00da --- /dev/null +++ b/libaxl_protocol_version_major.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_protocol_version_major(void) +{ + return LIBAXL_PROTOCOL_MAJOR; +} diff --git a/libaxl_protocol_version_minor.c b/libaxl_protocol_version_minor.c new file mode 100644 index 0000000..de1e688 --- /dev/null +++ b/libaxl_protocol_version_minor.c @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int +libaxl_protocol_version_minor(void) +{ + return LIBAXL_PROTOCOL_MINOR; +} diff --git a/libaxl_receive_handshake.c b/libaxl_receive_handshake.c new file mode 100644 index 0000000..5e193e2 --- /dev/null +++ b/libaxl_receive_handshake.c @@ -0,0 +1,211 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +struct response { + uint8_t status; + uint8_t length_of_reason; /* Only used in Failed, and not in Authenticate */ + uint16_t protocol_major_version; /* Not in Authenticate */ + uint16_t protocol_minor_version; /* Not in Authenticate */ + union { + struct { + uint16_t length_of_addition_data; + char additional_data[]; + }; + struct { + uint16_t __length_of_addition_data__1; + char reason[]; + }; + struct { + uint16_t __length_of_addition_data__2; + uint32_t release_number; + uint32_t resource_id_base; + uint32_t resource_id_mask; + uint32_t motion_buffer_size; + uint16_t length_of_vendor; + uint16_t maximum_request_length; + uint8_t number_of_roots; + uint8_t number_of_pixmap_formats; + uint8_t image_byte_order; + uint8_t bitmap_format_bit_order; + uint8_t bitmap_format_scanline_unit; + uint8_t bitmap_format_scanline_pad; + uint8_t min_keycode; + uint8_t max_keycode; + uint32_t __unused; + char vendor[]; + }; + }; +}; + +int +libaxl_receive_handshake(LIBAXL_CONTEXT *restrict ctx, int *restrict majorp, int *restrict minorp, char **restrict reasonp, int flags) +{ + LIBAXL_CONNECTION *conn = ctx->conn; + char *restrict inbuf, *new; + size_t n, t, len, vendor_len, out_off, in_off; + ssize_t r; + int read_stage = 0, saved_errno; + struct response *resp; +#ifdef MSG_TRUNC + int flag_trunc; +#endif + +#ifdef MSG_TRUNC + flags ^= flag_trunc = flags & MSG_TRUNC; +#endif + + WLOCK_CONNECTION_RECV(conn); + + inbuf = conn->in_buf; + n = offsetof(struct response, additional_data); + + if (conn->in_buf_size < n) { + inbuf = liberror_realloc(inbuf, n); + if (!inbuf) { + WUNLOCK_CONNECTION_RECV(conn); + return LIBAXL_ERROR_SYSTEM; + } + conn->in_buf = inbuf; + conn->in_buf_size = n; + } + +continue_read: + while (conn->in_progress < n) { + r = recv(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags); + if (r <= 0) { + WUNLOCK_CONNECTION_RECV(conn); + liberror_save_backtrace(NULL); + if (!r) { + liberror_set_error("The connection to the display server has been closed", + "libaxl_receive_handshake", "libaxl", LIBAXL_ERROR_CONNECTION_CLOSED); + return LIBAXL_ERROR_CONNECTION_CLOSED; + } + liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, "<display server>"); + return LIBAXL_ERROR_SYSTEM; + } + conn->in_progress += (size_t)r; + } + + if (read_stage == 0) { + n += (size_t)((struct response *)inbuf)->length_of_addition_data * 4; + read_stage = 1; + goto continue_read; + } + + conn->in_progress = 0; + +#ifdef MSG_TRUNC + if (flag_trunc) { + WUNLOCK_CONNECTION_RECV(conn); + return 0; + } +#endif + + t = conn->in_buf_size; + conn->in_buf_size = ctx->in_buf_size; + ctx->in_buf_size = t; + + conn->in_buf = ctx->in_buf; + ctx->in_buf = inbuf; + + WUNLOCK_CONNECTION_RECV(conn); + + resp = (struct response *)inbuf; + + if (majorp) + *majorp = (int)resp->protocol_major_version; + if (minorp) + *minorp = (int)resp->protocol_minor_version; + if (reasonp) + *reasonp = NULL; + + switch (resp->status) { + case LIBAXL_HANDSHAKE_FAILED: + len = (size_t)resp->length_of_reason; + if (n < len + offsetof(struct response, reason)) + goto invalid; + goto return_reason; + + case LIBAXL_HANDSHAKE_AUTHENTICATE: + len = n - offsetof(struct response, reason); + return_reason: + if (reasonp) { + *reasonp = liberror_malloc(len + 1); + if (!*reasonp) + return LIBAXL_ERROR_SYSTEM; + memcpy(*reasonp, resp->reason, len); + (*reasonp)[len] = '\0'; + } + break; + + case LIBAXL_HANDSHAKE_SUCCESS: + if (resp->resource_id_base & resp->resource_id_mask || + (resp->resource_id_base | resp->resource_id_mask) >> 29) + goto invalid; + + conn->xid_base = resp->resource_id_base; + for (conn->xid_shift = 0; !(resp->resource_id_mask & 1); conn->xid_shift += 1) + resp->resource_id_mask >>= 1; + conn->xid_max = resp->resource_id_mask; + conn->info.vendor_release = resp->release_number; + conn->info.min_keycode = resp->min_keycode; + conn->info.max_keycode = resp->max_keycode; + conn->info.image_byte_order = resp->image_byte_order; + conn->info.motion_buffer_size = resp->motion_buffer_size; + conn->info.maximum_request_length = resp->maximum_request_length; + conn->info.bitmap_format_bit_order = resp->bitmap_format_bit_order; + conn->info.bitmap_format_scanline_unit = resp->bitmap_format_scanline_unit; + conn->info.bitmap_format_scanline_pad = resp->bitmap_format_scanline_pad; + + /* These restricts are less restrictive than the protocol specifices, + * in case the they are modified later on */ + if (resp->resource_id_mask || + conn->xid_max + 1 < UINT16_C(1) << 18 || + (conn->xid_max & (conn->xid_max + 1)) || + resp->min_keycode < 8 || + resp->image_byte_order > 1 || + resp->maximum_request_length < 4096 || + resp->bitmap_format_bit_order > 1 || + resp->bitmap_format_scanline_unit % 8 || + resp->bitmap_format_scanline_pad % 8 || + resp->bitmap_format_scanline_unit > resp->bitmap_format_scanline_pad) + goto invalid; + + vendor_len = resp->length_of_vendor; + conn->info.nscreens = resp->number_of_roots; + conn->info.nformats = resp->number_of_pixmap_formats; + + memmove(inbuf, resp->vendor, out_off = in_off = vendor_len); + inbuf[out_off++] = '\0'; + out_off += (4 - out_off % 4) % 4; + in_off += (4 - in_off % 4) % 4; + in_off += offsetof(struct response, vendor); + t = out_off; + memmove(&inbuf[out_off], &inbuf[in_off], n - in_off); + out_off += n - in_off; + + saved_errno = errno; + new = realloc(inbuf, out_off); + errno = saved_errno; + if (new) + inbuf = new; + + conn->info_buf = inbuf; + conn->info.vendor = inbuf; + conn->info.formats = (void *)&inbuf[t]; + conn->info.screens = (void *)&inbuf[t + conn->info.nformats * 8]; + + ctx->in_buf_size = 0; + ctx->in_buf = NULL; + break; + + default: + invalid: + liberror_set_error("Invalid handshake response received from the display server", + "libaxl_receive_handshake", "libaxl", LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE); + errno = EBADMSG; + return LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE; + } + + return (int)resp->status; +} diff --git a/libaxl_send_handshake.c b/libaxl_send_handshake.c new file mode 100644 index 0000000..80d48aa --- /dev/null +++ b/libaxl_send_handshake.c @@ -0,0 +1,115 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +static int +send_all(int fd, void *restrict data, size_t n, int flags, size_t *restrict progressp) +{ + char *bs = data; + ssize_t r; + + while (n) { + r = liberror_send(fd, bs, n, flags, "<display server>"); + if (r < 0) + return -1; + bs += r, n -= (size_t)r; + *progressp += (size_t)r; + } + + return 0; +} + +int +libaxl_send_handshake(LIBAXL_CONTEXT *restrict ctx, const char *auth_name, size_t auth_name_len, + const char *auth_data, size_t auth_data_len, int flags) +{ + LIBAXL_CONNECTION *conn = ctx->conn; + LIBAXL_CONTEXT *pending, **pendingp; + size_t len, o = 0; + char *buf; + + RLOCK_CONNECTION_SEND(conn); + pending = conn->pending_out; + conn->info.protocol_version_major = LIBAXL_PROTOCOL_MAJOR; + conn->info.protocol_version_minor = LIBAXL_PROTOCOL_MINOR; + conn->info.protocol_version = LIBAXL_PROTOCOL_VERSION; + conn->info.protocol_byte_order = LIBAXL_MSB_FIRST; /* TODO Use LIBAXL_LSB_FIRST if preferable */ + RUNLOCK_CONNECTION_SEND(conn); + if (pending) { + liberror_save_backtrace(NULL); + liberror_set_error(pending == ctx + ? "Request from the previous call is pending to be flush" + : "A request from another thread is pending to be flushed", + "libaxl_send_handshake", "errno", EALREADY); + errno = EALREADY; + return LIBAXL_ERROR_SYSTEM; + } + + if (auth_name_len > UINT16_MAX) { + liberror_save_backtrace(NULL); + liberror_set_error("Authorisation protocol name is too long", "libaxl_send_handshake", "errno", EINVAL); + errno = EINVAL; + return LIBAXL_ERROR_SYSTEM; + } + + if (auth_data_len > UINT16_MAX) { + liberror_save_backtrace(NULL); + liberror_set_error("Authorisation data is too long", "libaxl_send_handshake", "errno", EINVAL); + errno = EINVAL; + return LIBAXL_ERROR_SYSTEM; + } + + buf = ctx->out_buf; + len = 12 + (auth_name_len + 3) / 4 * 4 + (auth_data_len + 3) / 4 * 4; + if (len > ctx->out_buf_size) { + buf = liberror_realloc(buf, len); + if (!buf) + return LIBAXL_ERROR_SYSTEM; + ctx->out_buf = buf; + ctx->out_buf_size = len; + } + + buf[o++] = 'B'; /* TODO Use 'l' (LSB first) if preferable */ + buf[o++] = 0; + *(uint16_t *)&buf[o] = htons(LIBAXL_PROTOCOL_MAJOR); + o += 2; + *(uint16_t *)&buf[o] = htons(LIBAXL_PROTOCOL_MINOR); + o += 2; + *(uint16_t *)&buf[o] = htons((uint16_t)auth_name_len); + o += 2; + *(uint16_t *)&buf[o] = htons((uint16_t)auth_data_len); + o += 2; + buf[o++] = 0; + buf[o++] = 0; + memcpy(&buf[o], auth_name, auth_name_len); + for (o += auth_name_len; o % 4; o++) + buf[o] = 0; + memcpy(&buf[o], auth_data, auth_data_len); + for (o += auth_data_len; o % 4; o++) + buf[o] = 0; + + ctx->out_length = o; + ctx->out_progress = 0; + + WLOCK_CONNECTION_SEND(conn); + + if (send_all(conn->fd, ctx->out_buf, ctx->out_length, flags, &ctx->out_progress)) { + ctx->next_pending_out = NULL; + pendingp = &conn->pending_out; + while (*pendingp) + pendingp = &(*pendingp)->next_pending_out; + *pendingp = ctx; + ctx->refcount += 1; + + WUNLOCK_CONNECTION_SEND(conn); + + liberror_save_backtrace(NULL); + liberror_set_error("Handshake has been buffered and is ready to be sent", + "libaxl_send_request", "errno", EINPROGRESS); + errno = EINPROGRESS; + return LIBAXL_ERROR_SYSTEM; + } + + WUNLOCK_CONNECTION_SEND(conn); + + return 0; +} |