diff options
Diffstat (limited to '')
-rw-r--r-- | LIBAXL_REQUEST_OPEN_FONT.3 | 2 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | common.h | 7 | ||||
-rw-r--r-- | internal-linux.h | 4 | ||||
-rw-r--r-- | internal-llmutex.h | 2 | ||||
-rw-r--r-- | libaxl.h | 7 | ||||
-rw-r--r-- | libaxl/advanced.h | 6 | ||||
-rw-r--r-- | libaxl/consts.h | 4 | ||||
-rw-r--r-- | libaxl/display-info.h | 7 | ||||
-rw-r--r-- | libaxl/events.h | 6 | ||||
-rw-r--r-- | libaxl/low-level.h | 8 | ||||
-rw-r--r-- | libaxl_close.3 | 46 | ||||
-rw-r--r-- | libaxl_close.c | 2 | ||||
-rw-r--r-- | libaxl_connect.c | 263 | ||||
-rw-r--r-- | libaxl_connect_without_handshake.c | 94 | ||||
-rw-r--r-- | libaxl_context_create.3 | 3 | ||||
-rw-r--r-- | libaxl_create.3 | 4 | ||||
-rw-r--r-- | libaxl_create.c | 1 | ||||
-rw-r--r-- | libaxl_deallocate_id.3 | 8 | ||||
-rw-r--r-- | libaxl_detach.3 | 4 | ||||
-rw-r--r-- | libaxl_parse_display.c | 2 | ||||
-rw-r--r-- | libaxl_receive.c | 10 | ||||
-rw-r--r-- | libaxl_receive_handshake.3 | 67 | ||||
-rw-r--r-- | libaxl_receive_handshake.c | 68 | ||||
-rw-r--r-- | libaxl_send_handshake.3 | 84 | ||||
-rw-r--r-- | libaxl_send_request.c | 2 |
28 files changed, 672 insertions, 49 deletions
diff --git a/LIBAXL_REQUEST_OPEN_FONT.3 b/LIBAXL_REQUEST_OPEN_FONT.3 index c5a097d..f8dbf3a 100644 --- a/LIBAXL_REQUEST_OPEN_FONT.3 +++ b/LIBAXL_REQUEST_OPEN_FONT.3 @@ -207,7 +207,7 @@ if the font is scalable font. .I Spacing The escapement class of the font: .B P -for proportional (variable pitch), +for proportional (variable pitch), .B M for monospace (fixed pitch), or .B C @@ -13,6 +13,8 @@ include $(OSCONFIGFILE) OBJ =\ libaxl_attach.o\ libaxl_close.o\ + libaxl_connect.o\ + libaxl_connect_without_handshake.o\ libaxl_context_create.o\ libaxl_context_free.o\ libaxl_create.o\ @@ -280,6 +282,7 @@ MAN3 =\ LIBAXL_REQUEST_UNMAP_WINDOW.3\ LIBAXL_REQUEST_WARP_POINTER.3\ libaxl_attach.3\ + libaxl_close.3\ libaxl_context_create.3\ libaxl_context_free.3\ libaxl_create.3\ @@ -293,6 +296,8 @@ MAN3 =\ libaxl_protocol_version.3\ libaxl_protocol_version_major.3\ libaxl_protocol_version_minor.3\ + libaxl_receive_handshake.3\ + libaxl_send_handshake.3\ struct_libaxl_error_access.3\ struct_libaxl_error_alloc.3\ struct_libaxl_error_atom.3\ @@ -525,6 +530,7 @@ install: libaxl.a libaxl.$(LIBEXT) uninstall: -cd -- "$(DESTDIR)$(PREFIX)/include/" && rm -f -- $(LIB_HDR) + -rmdir -- "$(DESTDIR)$(PREFIX)/include/libaxl" -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libaxl.a" -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libaxl.$(LIBMINOREXT)" -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libaxl.$(LIBMAJOREXT)" @@ -2,7 +2,7 @@ libaxl is a currently under develop X library, and is not in a usable state (please help write man pages if you want it ready sooner). -The goals of libaxl is: +The goals of libaxl are: * Use asynchronous communication model (unlike libX11) @@ -1,5 +1,5 @@ Man pages: check italic–bold consistency Man pages: check values of constants -Add libaxl_connect Add libaxl_marshal Add libaxl_unmarshal +libaxl_close: guarantee that the file is closed @@ -2,8 +2,10 @@ #include "libaxl.h" #include <arpa/inet.h> +#include <netinet/tcp.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> @@ -12,6 +14,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <unistd.h> #if defined(__linux__) @@ -21,10 +24,14 @@ #if !defined(NO_LIBERROR) # include <liberror.h> #else +struct liberror_state {int err;}; +# define liberror_start(STATEP) ((STATEP)->err = errno) +# define liberror_end(STATEP) (errno = (STATEP)->err) # define liberror_save_backtrace(...) ((void) 0) # define liberror_set_error(...) ((void) 0) # define liberror_set_error_errno(...) ((void) 0) # define liberror_reset_error() ((void) 0) +# define liberror_pop_error() ((void) 0) #endif #if !defined(NO_LIBERROR) && !defined(NO_LIBERROR_LIBC) diff --git a/internal-linux.h b/internal-linux.h index 553a783..6a4103f 100644 --- a/internal-linux.h +++ b/internal-linux.h @@ -11,7 +11,7 @@ _Static_assert(sizeof(MUTEX) == sizeof(uint32_t)); #define INIT_MUTEX(MUTEX)\ - ((void)0) /* TODO atomic_init(&(MUTEX), 0) */ + atomic_init(&(MUTEX), 0) #define _TRYLOCK(MUTEX)\ !atomic_exchange(&(MUTEX), 1) @@ -27,6 +27,7 @@ _Static_assert(sizeof(MUTEX) == sizeof(uint32_t)); atomic_store(&(MUTEX), 0);\ if (syscall(SYS_futex, &(MUTEX), FUTEX_PRIVATE_FLAG | FUTEX_WAKE, INT_MAX, NULL, 0, 0) < 0) {\ /* TODO handle of error in _UNLOCK */\ + abort();\ }\ } while (0) @@ -34,5 +35,6 @@ _Static_assert(sizeof(MUTEX) == sizeof(uint32_t)); do {\ if (syscall(SYS_futex, &(MUTEX), FUTEX_PRIVATE_FLAG | FUTEX_WAIT, 1, NULL, 0, 0) < 0) {\ /* TODO handle of error in _WAIT */\ + abort();\ }\ } while (0) diff --git a/internal-llmutex.h b/internal-llmutex.h index b75a449..a6a3e78 100644 --- a/internal-llmutex.h +++ b/internal-llmutex.h @@ -26,7 +26,7 @@ #define WTRYLOCK_CONNECTION_(CONN, SUFFIX) _TRYLOCK((CONN)->exguard_##SUFFIX) #define WUNLOCK_CONNECTION_(CONN, SUFFIX) _UNLOCK((CONN)->exguard_##SUFFIX) -#define RLOCK_CONNECTION_(CONN, SUFFIX)\ +#define RLOCK_CONNECTION_(CONN, SUFFIX)\ do {\ char old_val__;\ do {\ @@ -49,6 +49,7 @@ typedef struct libaxl_context LIBAXL_CONTEXT; /* TODO man */ #define LIBAXL_ERROR_INVALID_REPLY_OPCODE -11 #define LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE -12 #define LIBAXL_ERROR_OUT_OF_RESOURCE_IDS -13 +#define LIBAXL_ERROR_PROTOCOL_NOT_SUPPORTED -14 union libaxl_input { /* TODO doc, man */ uint8_t type; @@ -57,14 +58,16 @@ union libaxl_input { /* TODO doc, man */ union libaxl_event event; /* otherwise (.type = event type) */ }; +_LIBAXL_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__))) +LIBAXL_CONNECTION *libaxl_connect(const char *restrict, char **restrict); /* TODO man doc */ + /** * Deallocation and close a connection * * @param conn The connection to the display server * @return 0 on success, -1 of there was an asynchronous error */ -_LIBAXL_GCC_ONLY(__attribute__((__nonnull__))) -int libaxl_close(LIBAXL_CONNECTION *); /* TODO man */ +int libaxl_close(LIBAXL_CONNECTION *); /** * Get the file description used for a connection to diff --git a/libaxl/advanced.h b/libaxl/advanced.h index 3164a36..13775e8 100644 --- a/libaxl/advanced.h +++ b/libaxl/advanced.h @@ -38,7 +38,7 @@ * @return The major version number of highest support version of the protocol */ _LIBAXL_GCC_ONLY(__attribute__((__warn_unused_result__))) -int libaxl_protocol_version_major(void); +int libaxl_protocol_version_major(void); /* TODO should be an `extern const int` */ /** * Returns the minor version number of the highest version of @@ -49,7 +49,7 @@ int libaxl_protocol_version_major(void); * @return The minor version number of highest support version of the protocol */ _LIBAXL_GCC_ONLY(__attribute__((__warn_unused_result__))) -int libaxl_protocol_version_minor(void); +int libaxl_protocol_version_minor(void); /* TODO should be an `extern const int` */ /** * Returns the minor version number of the highest version of @@ -62,7 +62,7 @@ int libaxl_protocol_version_minor(void); * the minor number, e.g. 11000 for 11.0 (X11) */ _LIBAXL_GCC_ONLY(__attribute__((__warn_unused_result__))) -int libaxl_protocol_version(void); +int libaxl_protocol_version(void); /* TODO should be an `extern const int` */ /** * Deallocations a connection object without diff --git a/libaxl/consts.h b/libaxl/consts.h index a57a9de..686de2b 100644 --- a/libaxl/consts.h +++ b/libaxl/consts.h @@ -247,6 +247,10 @@ #define LIBAXL_FOCUS_POINTER_ROOT 6 /* Just called PointerRoot in the specification */ #define LIBAXL_FOCUS_NONE 7 /* Just called None in the specification */ +/* focus flags */ +#define LIBAXL_FOCUS 0x01 +#define LIBAXL_SAME_SCREEN 0x02 + /* misc. */ #define LIBAXL_ANY_PROPERTY_TYPE 0 #define LIBAXL_ALL_TEMPORARY 0 diff --git a/libaxl/display-info.h b/libaxl/display-info.h index 91ceac2..966614c 100644 --- a/libaxl/display-info.h +++ b/libaxl/display-info.h @@ -182,7 +182,7 @@ struct libaxl_display_info { * 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 */ + int struct_version; /* SINCE STRUCT VERSION 0: */ @@ -309,4 +309,9 @@ struct libaxl_display_info { * `NULL` if the specified default screen does not exist */ const struct libaxl_screen *default_screen; + + /** + * The default screen + */ + int default_screen_number; }; diff --git a/libaxl/events.h b/libaxl/events.h index 9191a92..d6be648 100644 --- a/libaxl/events.h +++ b/libaxl/events.h @@ -163,7 +163,7 @@ struct libaxl_event_enter_notify { int16_t event_y; libaxl_keybutmask_t state; uint8_t mode; /* LIBAXL_NORMAL, LIBAXL_GRAB, or LIBAXL_UNGRAB */ - uint8_t flags; /* TODO #x01 = Focus, #x02 = Same-screen */ + uint8_t flags; /* Bitmask: LIBAXL_FOCUS, LIBAXL_SAME_SCREEN */ }; struct libaxl_event_leave_notify { @@ -181,7 +181,7 @@ struct libaxl_event_leave_notify { int16_t event_y; libaxl_keybutmask_t state; uint8_t mode; /* LIBAXL_NORMAL, LIBAXL_GRAB, or LIBAXL_UNGRAB */ - uint8_t flags; /* TODO #x01 = Focus, #x02 = Same-screen */ + uint8_t flags; /* Bitmask: LIBAXL_FOCUS, LIBAXL_SAME_SCREEN */ }; struct libaxl_event_pointer_window_event { @@ -199,7 +199,7 @@ struct libaxl_event_pointer_window_event { int16_t event_y; libaxl_keybutmask_t state; uint8_t mode; /* LIBAXL_NORMAL, LIBAXL_GRAB, or LIBAXL_UNGRAB */ - uint8_t flags; /* TODO #x01 = Focus, #x02 = Same-screen */ + uint8_t flags; /* Bitmask: LIBAXL_FOCUS, LIBAXL_SAME_SCREEN */ }; struct libaxl_event_focus_in { diff --git a/libaxl/low-level.h b/libaxl/low-level.h index d7413b8..70b87a7 100644 --- a/libaxl/low-level.h +++ b/libaxl/low-level.h @@ -27,6 +27,9 @@ _LIBAXL_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__))) LIBAXL_CONNECTION *libaxl_create(int); +_LIBAXL_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__))) +LIBAXL_CONNECTION *libaxl_connect_without_handshake(const char *host, const char *protocol, int display, int screen); /* TODO man doc */ + /** * Parse a display name string * @@ -129,7 +132,10 @@ int libaxl_send_handshake(LIBAXL_CONTEXT *restrict, const char *, size_t, const * 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 + * @return LIBAXL_HANDSHAKE_SUCCESS (NB! this value is not 0) on + * success, LIBAXL_HANDSHAKE_FAILED on handshake failure, + * LIBAXL_HANDSHAKE_AUTHENTICATE 2, or 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_close.3 b/libaxl_close.3 new file mode 100644 index 0000000..f3e5642 --- /dev/null +++ b/libaxl_close.3 @@ -0,0 +1,46 @@ +.TH libaxl_close 3 libaxl +.SH NAME +libaxl_close - Deallocate and close connection +.SH SYNOPSIS +.nf +#include <libaxl.h> + +int libaxl_close(LIBAXL_CONNECTION *\fIconn\fP); +.fi +.SH DESCRIPTION +The +.BR libaxl_close () +function deallocates the connection record +specified in the +.I conn +parameter, and closes the file descriptor of +the connection (without first shutting down +the connection). +.PP +If +.I conn +is +.IR NULL , +the function will return 0 without doing +anything. +.SH RETURN VALUE +The +.BR libaxl_close () +function returns 0 upon completion except if there +the file descriptor could not be closed or if there +was an asynchronous failure. +.SH ERRORS +The +.BR libaxl_close () +function can fail if for any reason specified +for the +.BR close (3) +function, and will in these cases return +.IR LIBAXL_ERROR_SYSTEM . +.SH NOTES +None. +.SH SEE ALSO +.BR libaxl_marshal (3), +.BR libaxl_fileno (3), +.BR libaxl_detach (3), +.BR libaxl_attach (3) diff --git a/libaxl_close.c b/libaxl_close.c index 8964f95..b636166 100644 --- a/libaxl_close.c +++ b/libaxl_close.c @@ -4,5 +4,7 @@ int libaxl_close(LIBAXL_CONNECTION *conn) { + if (!conn) + return 0; return liberror_close(libaxl_detach(conn)); } diff --git a/libaxl_connect.c b/libaxl_connect.c new file mode 100644 index 0000000..ee4edd8 --- /dev/null +++ b/libaxl_connect.c @@ -0,0 +1,263 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +enum { + FamilyInternet = 0, + FamilyDECnet = 1, + FamilyChaos = 2, + FamilyInternet6 = 6, + FamilyLocal = 256 +}; + +static char * +path_in_home(const char *filename) +{ + const char *home; + char *ret; + + home = getenv("HOME"); + if (!home || !*home) { /* TODO */ + abort(); + } + + ret = liberror_malloc(strlen(home) + strlen(filename) + 2); + if (!ret) + return NULL; + + stpcpy(stpcpy(stpcpy(ret, home), "/"), filename); + + return ret; +} + +static char * +get_auth_file(int *freep) +{ + char *xauthfile = getenv("XAUTHORITY"); + if (!xauthfile || !*xauthfile) { + xauthfile = path_in_home(".Xauthority"); + *freep = 1; + } else { + *freep = 0; + } + return xauthfile; +} + +static int +next_auth(int authfd, char **authbufp, size_t *bufsizep, size_t *lenp, size_t *havep) +{ + ssize_t r; + size_t got = *havep, need = 4; + int stage; + void *new; + + *lenp = 0; + + for (stage = 0; stage < 4; stage++) { + while (got < need) { + if (need > *bufsizep) { + new = liberror_realloc(*authbufp, need); + if (!new) + return -1; + *authbufp = new; + *bufsizep = need; + } + r = read(authfd, &(*authbufp)[got], *bufsizep - got); + if (r < 0) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "read", errno); + return -1; + } else if (!r) { + return 0; + } + got += (size_t)r; + } + need += (size_t)ntohs(*(uint16_t *)&(*authbufp)[need - 2]) + (stage < 3 ? 2 : 0); + } + + *lenp = need; + if (*havep > need) + *havep -= need; + else + *havep = got - need; + + return 0; +} + +static int +get_auth(const char *xauthfile, int sockfd, const char *host, const char *protocol, int display, + char **authnamep, size_t *authnamelenp, char **authdatap, size_t *authdatalenp, char **authbufp) +{ + int authfd, family, saved_errno; + char hostname[HOST_NAME_MAX + 1], number[2 + 3 * sizeof(int)]; + struct sockaddr_storage sockaddr; + socklen_t sockaddrlen = (socklen_t)sizeof(sockaddr); + size_t bufsize = 128, len, have = 0, off, numberlen, hostnamelen; + uint16_t partlen; + + (void) host; + (void) protocol; + + *authnamep = *authdatap = *authbufp = NULL; + *authnamelenp = *authdatalenp = 0; + + numberlen = (size_t)sprintf(number, "%i", display); + + if (gethostname(hostname, HOST_NAME_MAX)) + stpcpy(hostname, "localhost"); + hostnamelen = strlen(hostname); + + if (getpeername(sockfd, (void *)&sockaddr, &sockaddrlen)) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "getsockname", errno); + return -1; + } + + switch (sockaddr.ss_family) { + case AF_LOCAL: + family = FamilyLocal; + break; + case AF_INET: + family = FamilyInternet; /* TODO */ + return 0; + case AF_INET6: + family = FamilyInternet6; /* TODO */ + return 0; + default: + return 0; + } + + *authbufp = liberror_malloc(bufsize); + if (!*authbufp) + return -1; + + authfd = open(xauthfile, O_RDONLY); + if (authfd < 0 && errno != ENOENT) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "open", errno); + return -1; + } else if (authfd < 0) { + return 0; + } + + for (;; memmove(*authbufp, &(*authbufp)[len], have)) { + if (next_auth(authfd, authbufp, &bufsize, &len, &have)) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "read", errno); + saved_errno = errno; + close(authfd); + errno = saved_errno; + return -1; + } else if (!len) { + break; + } + + if (*(uint16_t *)&(*authbufp)[0] != htons(family)) + continue; + if (*(uint16_t *)&(*authbufp)[2] != htons((uint16_t)hostnamelen)) + continue; + if (memcmp(&(*authbufp)[4], hostname, hostnamelen)) + continue; + off = 4 + (size_t)hostnamelen; + partlen = ntohs(*(uint16_t *)&(*authbufp)[off]); + off += 2; + if (partlen != numberlen) + continue; + if (memcmp(&(*authbufp)[off], number, numberlen)) + continue; + off += numberlen; + + *authnamelenp = (size_t)ntohs(*(uint16_t *)&(*authbufp)[off]); + off += 2; + *authnamep = &(*authbufp)[off]; + off += *authnamelenp; + *authdatalenp = (size_t)ntohs(*(uint16_t *)&(*authbufp)[off]); + off += 2; + *authdatap = &(*authbufp)[off]; + + break; + } + + close(authfd); + return 0; +} + +LIBAXL_CONNECTION * +libaxl_connect(const char *restrict display, char **restrict reasonp) +{ + struct liberror_state error_state; + LIBAXL_CONNECTION *conn = NULL; + LIBAXL_CONTEXT *ctx = NULL; + int xauthfile_free = 0, dispnum, screen, major, minor, r; + char *xauthfile = NULL, *host = NULL, *protocol = NULL; + char *authname = NULL, *authdata = NULL, *authbuf = NULL; + size_t authnamelen, authdatalen; + int saved_errno = errno; + + if (reasonp) + *reasonp = NULL; + + r = libaxl_parse_display(display, &host, &protocol, &dispnum, &screen); + if (r) + goto fail; + + xauthfile = get_auth_file(&xauthfile_free); + if (!xauthfile) + goto fail; + + conn = libaxl_connect_without_handshake(host, protocol, dispnum, screen); + if (!conn) + goto fail; + + ctx = libaxl_context_create(conn); + if (!ctx) + goto fail; + + if (get_auth(xauthfile, conn->fd, host, protocol, dispnum, &authname, &authnamelen, &authdata, &authdatalen, &authbuf)) + goto fail; + + r = libaxl_send_handshake(ctx, authname, authnamelen, authdata, authdatalen, MSG_NOSIGNAL); + if (r) { + if (r == LIBAXL_ERROR_SYSTEM && errno == EINPROGRESS) { + for (;;) { + r = libaxl_flush(conn, MSG_NOSIGNAL); + if (r != LIBAXL_ERROR_SYSTEM || errno != EINPROGRESS) + break; + liberror_pop_error(); + } + } + if (r) + goto fail; + liberror_pop_error(); + } + + errno = saved_errno; + + r = libaxl_receive_handshake(ctx, &major, &minor, reasonp, MSG_NOSIGNAL); + switch (r) { + case LIBAXL_HANDSHAKE_FAILED: /* TODO */ + case LIBAXL_HANDSHAKE_AUTHENTICATE: /* TODO */ + abort(); + break; + + case LIBAXL_HANDSHAKE_SUCCESS: + break; + + default: + goto fail; + } + + libaxl_context_free(ctx); + return conn; + +fail: + liberror_start(&error_state); + if (xauthfile_free) + free(xauthfile); + free(authbuf); + free(host); + free(protocol); + libaxl_context_free(ctx); + libaxl_close(conn); + liberror_end(&error_state); + return NULL; +} diff --git a/libaxl_connect_without_handshake.c b/libaxl_connect_without_handshake.c new file mode 100644 index 0000000..181cdb2 --- /dev/null +++ b/libaxl_connect_without_handshake.c @@ -0,0 +1,94 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +static int +connect_tcp_ip(const char *host, int display) +{ + uint16_t port = libaxl_get_tcp_port(display); + int fd; + + abort(); /* TODO */ + + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &(int){1}, sizeof(int)); + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int)); + + return -1; +} + +static int +connect_unix(const char *path) +{ + struct sockaddr_un addr; + int fd; + + fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "socket", errno); + return -1; + } + + if (strlen(path) >= sizeof(addr.sun_path)) { + liberror_save_backtrace(NULL); + /* We could fix this with an O_PATH fd to the file, + * but we will not as other libraries probably do + * not do that, and there is something very wrong + * with your setup if the name is too long for + * `struct sockaddr_un`. */ + close(fd); + errno = ENAMETOOLONG; + liberror_set_error_errno("Path to X display socket is too long", "libaxl_connect_without_handshake", ENAMETOOLONG); + return -1; + } + + addr.sun_family = AF_LOCAL; + stpcpy(addr.sun_path, path); + if (connect(fd, (void *)&addr, (socklen_t)sizeof(addr))) { + liberror_save_backtrace(NULL); + liberror_set_error_errno(strerror(errno), "connect", errno); + return -1; + } + + return fd; +} + +LIBAXL_CONNECTION * +libaxl_connect_without_handshake(const char *host, const char *protocol, int display, int screen) +{ + LIBAXL_CONNECTION *conn; + char path[sizeof("/tmp/.X11-unix/X-") + 3 * sizeof(int)]; + int fd; + + if ((!protocol || !*protocol) && (!host || !*host)) { + sprintf(path, "/tmp/.X11-unix/X%i", display); + fd = connect_unix(path); + if (fd < 0) { + fd = connect_tcp_ip("localhost", display); + if (fd >= 0) + liberror_pop_error(); + } + + } else if (!protocol || !*protocol || + !strcasecmp(protocol, "tcp") || !strcasecmp(protocol, "inet") || + !strcasecmp(protocol, "tcp6") || !strcasecmp(protocol, "inet6")) { + fd = connect_tcp_ip(host, display); + + } else if (!strcmp(protocol, "unix")) { + fd = connect_unix(host); + + } else { + liberror_save_backtrace(NULL); + liberror_set_error("Display server uses unsupported underlaying protocol", + "libaxl_connect_without_handshake", "libaxl", LIBAXL_ERROR_PROTOCOL_NOT_SUPPORTED); + return NULL; + } + + if (fd < 0) + return NULL; + + conn = libaxl_create(fd); + if (conn) + conn->info.default_screen_number = screen; + + return conn; +} diff --git a/libaxl_context_create.3 b/libaxl_context_create.3 index 05c9f20..f764dca 100644 --- a/libaxl_context_create.3 +++ b/libaxl_context_create.3 @@ -18,7 +18,8 @@ parameter. .SH RETURN VALUE The .BR libaxl_context_create () -returns the context on success completion, or +function returns the context on success +completion, or .I NULL on failure. .SH ERRORS diff --git a/libaxl_create.3 b/libaxl_create.3 index 00417dc..d29c32e 100644 --- a/libaxl_create.3 +++ b/libaxl_create.3 @@ -20,8 +20,8 @@ parameter. .SH RETURN VALUE The .BR libaxl_create () -returns the connection record on success -completion, or +function returns the connection record on +success completion, or .I NULL on failure. .SH ERRORS diff --git a/libaxl_create.c b/libaxl_create.c index 3d6d7b6..a25566f 100644 --- a/libaxl_create.c +++ b/libaxl_create.c @@ -8,6 +8,7 @@ libaxl_create(int fd) conn = liberror_calloc(1, sizeof(*conn)); if (conn) { conn->fd = fd; + conn->info.struct_version = LIBAXL_DISPLAY_INFO_VERSION; atomic_init(&conn->xid_last, 0); INIT_LIBAXL_CONNECTION_RWLOCK(conn); } diff --git a/libaxl_deallocate_id.3 b/libaxl_deallocate_id.3 index f475bee..a7e7dde 100644 --- a/libaxl_deallocate_id.3 +++ b/libaxl_deallocate_id.3 @@ -27,7 +27,13 @@ The function returns 0 on successful completion and a negative libaxl error code on failure. .SH ERRORS -TODO \" errors for libaxl_deallocate_id +The +.BR libaxl_deallocate_id () +function may fail if +.TP +.IR LIBAXL_ERROR_SYSTEM " with " ENOMEM +Enough memory could not be allocated to add the +resource ID to the pool of reusable resource IDs. .SH NOTES None. .SH SEE ALSO diff --git a/libaxl_detach.3 b/libaxl_detach.3 index 8d1fb54..39dfefb 100644 --- a/libaxl_detach.3 +++ b/libaxl_detach.3 @@ -20,7 +20,8 @@ instead of closing it. .SH RETURN VALUE The .BR libaxl_detach () -returns the file descriptor of the connection. +function returns the file descriptor of the +connection. .SH ERRORS The .BR libaxl_detach () @@ -31,5 +32,4 @@ None. .BR libaxl_marshal (3), .BR libaxl_fileno (3), .BR libaxl_close (3), -.BR libaxl_detach (3), .BR libaxl_attach (3) diff --git a/libaxl_parse_display.c b/libaxl_parse_display.c index 037f49b..ab44083 100644 --- a/libaxl_parse_display.c +++ b/libaxl_parse_display.c @@ -110,7 +110,7 @@ normal: errno = saved_errno; /* Get screen */ - if (*name) + if (!*name) goto done; if (!isdigit(*name)) { liberror_save_backtrace(NULL); diff --git a/libaxl_receive.c b/libaxl_receive.c index bb4af68..11ca644 100644 --- a/libaxl_receive.c +++ b/libaxl_receive.c @@ -230,14 +230,15 @@ libaxl_receive(LIBAXL_CONTEXT *restrict ctx, union libaxl_input *restrict msgp, 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", "libaxl", LIBAXL_ERROR_CONNECTION_CLOSED); + WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_CONNECTION_CLOSED; } liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, "<display server>"); + WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_SYSTEM; } conn->in_progress += (size_t)r; @@ -268,15 +269,16 @@ libaxl_receive(LIBAXL_CONTEXT *restrict ctx, union libaxl_input *restrict msgp, 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", "libaxl", LIBAXL_ERROR_CONNECTION_CLOSED); + WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_CONNECTION_CLOSED; } liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, "<display server>"); + WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_SYSTEM; } conn->in_progress += (size_t)r; @@ -575,9 +577,13 @@ received_reply: *(void **)&msg[o] = data = &inbuf[i]; count = counts[oc++]; /* TODO */ + fprintf(stderr, "libaxl_receive: function not fully implemented: '*' case\n"); + abort(); break; case '&': /* TODO */ + fprintf(stderr, "libaxl_receive: function not fully implemented: '&' case\n"); + abort(); /* LIBAXL_REQUEST_LIST_FONTS LIBAXL_REQUEST_GET_FONT_PATH diff --git a/libaxl_receive_handshake.3 b/libaxl_receive_handshake.3 new file mode 100644 index 0000000..e0e2e0a --- /dev/null +++ b/libaxl_receive_handshake.3 @@ -0,0 +1,67 @@ +.TH libaxl_receive_handshake 3 libaxl +.SH NAME +libaxl_receive_handshake - Finish connection handshake +.SH SYNOPSIS +.nf +#include <libaxl.h> + +#define LIBAXL_HANDSHAKE_FAILED 0 +#define LIBAXL_HANDSHAKE_SUCCESS 1 +#define LIBAXL_HANDSHAKE_AUTHENTICATE 2 + +int libaxl_receive_handshake(LIBAXL_CONTEXT *\fIctx\fP, int *\fImajorp\fP, int *\fIminorp\fP, char **\fIreasonp\fP, int \fIflags\fP); +.fi +.SH DESCRIPTION +The +.BR libaxl_receive_handshake () +function receives the display server's part of +the handshake, which is sent in response to the +client's handshake message which is sent with the +.BR libaxl_send_handshake () +function. +.PP +The value of the +.I ctx +parameter shall be the thread's state for the +connection to the display server. +.PP +TODO majorp, minorp, reasonp +.PP +Flags to used in the fourth argument when the +.BR libaxl_receive_handshake () +function calls the +.BR recv (3) +function shall be specified in the +.I flags +parameter. +.SH RETURN VALUE +The +.BR libaxl_receive_handshake () +function return +.B LIBAXL_HANDSHAKE_SUCCESS +upon successful completion with successful handshake +(beaware, this value is not 0), +.B LIBAXL_HANDSHAKE_FAILURE +upon successful completion with handshake failure, +.B LIBAXL_HANDSHAKE_AUTHENTICATE +upon successful completion handshake rejection +due to insufficient or incorrect authentication, +or a negative libaxl error code on failure. +.SH ERRORS +The +.BR libaxl_receive_handshake () +function can only fail if: +.TP +TODO errors +.SH NOTES +The +.BR libaxl_receive_handshake () +function's behaviour is unspecified if the +.I SO_PEEK_OFF +socket option is active or the +.I MSG_PEEK +flag is used. +.SH SEE ALSO +.BR libaxl_connect (3), +.BR libaxl_send_handshake (3), +.BR libaxl_send (3) diff --git a/libaxl_receive_handshake.c b/libaxl_receive_handshake.c index 5323344..d26a5d4 100644 --- a/libaxl_receive_handshake.c +++ b/libaxl_receive_handshake.c @@ -2,20 +2,28 @@ #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 { + 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 */ uint16_t length_of_addition_data; char additional_data[]; }; struct { + uint8_t __status__1; + uint8_t __length_of_reason__1; + uint16_t __protocol_major_version__1; + uint16_t __protocol_minor_version__1; uint16_t __length_of_addition_data__1; char reason[]; }; struct { + uint8_t __status__2; + uint8_t __length_of_reason__2; + uint16_t __protocol_major_version__2; + uint16_t __protocol_minor_version__2; uint16_t __length_of_addition_data__2; uint32_t release_number; uint32_t resource_id_base; @@ -42,10 +50,11 @@ libaxl_receive_handshake(LIBAXL_CONTEXT *restrict ctx, int *restrict majorp, int { LIBAXL_CONNECTION *conn = ctx->conn; char *restrict inbuf, *new; - size_t n, t, len, vendor_len, out_off, in_off; + size_t i, n, t, len, vendor_len, out_off, in_off; ssize_t r; - int read_stage = 0, saved_errno; + int read_stage = 0, saved_errno, status; struct response *resp; + uint32_t xid_base, xid_mask; #ifdef MSG_TRUNC int flag_trunc; #endif @@ -59,6 +68,7 @@ libaxl_receive_handshake(LIBAXL_CONTEXT *restrict ctx, int *restrict majorp, int inbuf = conn->in_buf; n = offsetof(struct response, additional_data); +continue_read: if (conn->in_buf_size < n) { inbuf = liberror_realloc(inbuf, n); if (!inbuf) { @@ -69,25 +79,25 @@ libaxl_receive_handshake(LIBAXL_CONTEXT *restrict ctx, int *restrict majorp, int 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); + WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_CONNECTION_CLOSED; } liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, "<display server>"); + WUNLOCK_CONNECTION_RECV(conn); 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; + n += (size_t)ntohs(((struct response *)inbuf)->length_of_addition_data) * 4; read_stage = 1; goto continue_read; } @@ -113,15 +123,16 @@ continue_read: resp = (struct response *)inbuf; if (majorp) - *majorp = (int)resp->protocol_major_version; + *majorp = (int)ntohs(resp->protocol_major_version); if (minorp) - *minorp = (int)resp->protocol_minor_version; + *minorp = (int)ntohs(resp->protocol_minor_version); if (reasonp) *reasonp = NULL; + status = (int)resp->status; switch (resp->status) { case LIBAXL_HANDSHAKE_FAILED: - len = (size_t)resp->length_of_reason; + len = (size_t)ntohs(resp->length_of_reason); if (n < len + offsetof(struct response, reason)) goto invalid; goto return_reason; @@ -139,27 +150,28 @@ continue_read: break; case LIBAXL_HANDSHAKE_SUCCESS: - if (resp->resource_id_base & resp->resource_id_mask || - (resp->resource_id_base | resp->resource_id_mask) >> 29) + xid_base = ntohl(resp->resource_id_base); + xid_mask = ntohl(resp->resource_id_mask); + if (xid_base & xid_mask || (xid_base | xid_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->xid_base = xid_base; + for (conn->xid_shift = 0; !(xid_mask & 1); conn->xid_shift += 1) + xid_mask >>= 1; + conn->xid_max = xid_mask; + conn->info.vendor_release = ntohl(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.motion_buffer_size = ntohl(resp->motion_buffer_size); + conn->info.maximum_request_length = resp->maximum_request_length = ntohs(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 || + if (!xid_mask || conn->xid_max + 1 < UINT16_C(1) << 18 || (conn->xid_max & (conn->xid_max + 1)) || resp->min_keycode < 8 || @@ -171,7 +183,7 @@ continue_read: resp->bitmap_format_scanline_unit > resp->bitmap_format_scanline_pad) goto invalid; - vendor_len = resp->length_of_vendor; + vendor_len = ntohs(resp->length_of_vendor); conn->info.nscreens = resp->number_of_roots; conn->info.nformats = resp->number_of_pixmap_formats; @@ -194,7 +206,13 @@ continue_read: conn->info.vendor = inbuf; conn->info.formats = (void *)&inbuf[t]; conn->info.screens = (void *)&inbuf[t + conn->info.nformats * 8]; - conn->info.default_screen = conn->info.screens; + if ((size_t)conn->info.default_screen_number < conn->info.nscreens) { + conn->info.default_screen = conn->info.screens; + for (i = 0; i < (size_t)conn->info.default_screen_number; i++) + conn->info.default_screen = libaxl_next_screen(conn->info.default_screen); + } else { + conn->info.default_screen = NULL; + } ctx->in_buf_size = 0; ctx->in_buf = NULL; @@ -208,5 +226,5 @@ continue_read: return LIBAXL_ERROR_INVALID_HANDSHAKE_RESPONSE; } - return (int)resp->status; + return status; } diff --git a/libaxl_send_handshake.3 b/libaxl_send_handshake.3 new file mode 100644 index 0000000..c4b91ab --- /dev/null +++ b/libaxl_send_handshake.3 @@ -0,0 +1,84 @@ +.TH libaxl_send_handshake 3 libaxl +.SH NAME +libaxl_send_handshake - Initiate connection handshake +.SH SYNOPSIS +.nf +#include <libaxl.h> + +int libaxl_send_handshake(LIBAXL_CONTEXT *\fIctx\fP, const char *\fIauth_name\fP, size_t \fIauth_name_len\fP, + const char *\fIauth_data\fP, size_t \fIauth_data_len\fP, int \fIflags\fP); +.fi +.SH DESCRIPTION +The +.BR libaxl_send_handshake () +function sends the clients part of the handshake +to the display server. +.PP +The value of the +.I ctx +parameter shall be the thread's state for the +connection to the display server. +.PP +The value of the +.I auth_name +shall be the protocol name of the authorisation +the client expects the server to use, and the +value of the +.I auth_name_len +shall be the length of the name, or 0 if +.I auth_name +is +.IR NULL . +The value of the +.I auth_data +shall be the authorisation data, which is specific +to the choosen authorisation mechanism, and the +value of the +.I auth_data_len +shall be the length of the authorisation data, +or 0 if +.I auth_data +is +.IR NULL . +.PP +This function is called immediately after connecting +to the socket for the display, and shall not be called +again except of the authorisation failed, in which +case a new authorisation mechanism can be tried. +.SH RETURN VALUE +The +.BR libaxl_send_handshake () +function return 0 upon successful completion, or a +negative libaxl error code on failure. +.SH ERRORS +The +.BR libaxl_send_handshake () +function can only fail if: +.TP +.IR LIBAXL_ERROR_SYSTEM " with " EINVAL +.I auth_name_len +or +.I auth_data_len +is greater than 65535. +.TP +.IR LIBAXL_ERROR_SYSTEM " with " EALREADY +There is an incompleted send pending, that must +be flushed with the +.BR libaxl_flush (3) +function first. +.TP +.IR LIBAXL_ERROR_SYSTEM " with " EINPROGRESS +The message could not be fully sent (why +.BR send (3) +failed can be found in the causal of the error) +and must be completed by flushing it with the +.BR libaxl_flush (3) +function. +.SH NOTES +Valid authorisation mechanisms are not part of +the core X protocol. +.SH SEE ALSO +.BR libaxl_connect (3), +.BR libaxl_create (3), +.BR libaxl_parse_display (3), +.BR libaxl_receive_handshake (3) diff --git a/libaxl_send_request.c b/libaxl_send_request.c index 0c77252..471da0b 100644 --- a/libaxl_send_request.c +++ b/libaxl_send_request.c @@ -341,6 +341,8 @@ again: case 'e': /* TODO event */ ALIGN(&i, union libaxl_event); + fprintf(stderr, "libaxl_send_request: function not fully implemented: 'e' case\n"); + abort(); break; case '?': |