aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LIBAXL_REQUEST_OPEN_FONT.32
-rw-r--r--Makefile6
-rw-r--r--README2
-rw-r--r--TODO2
-rw-r--r--common.h7
-rw-r--r--internal-linux.h4
-rw-r--r--internal-llmutex.h2
-rw-r--r--libaxl.h7
-rw-r--r--libaxl/advanced.h6
-rw-r--r--libaxl/consts.h4
-rw-r--r--libaxl/display-info.h7
-rw-r--r--libaxl/events.h6
-rw-r--r--libaxl/low-level.h8
-rw-r--r--libaxl_close.346
-rw-r--r--libaxl_close.c2
-rw-r--r--libaxl_connect.c263
-rw-r--r--libaxl_connect_without_handshake.c94
-rw-r--r--libaxl_context_create.33
-rw-r--r--libaxl_create.34
-rw-r--r--libaxl_create.c1
-rw-r--r--libaxl_deallocate_id.38
-rw-r--r--libaxl_detach.34
-rw-r--r--libaxl_parse_display.c2
-rw-r--r--libaxl_receive.c10
-rw-r--r--libaxl_receive_handshake.367
-rw-r--r--libaxl_receive_handshake.c68
-rw-r--r--libaxl_send_handshake.384
-rw-r--r--libaxl_send_request.c2
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
diff --git a/Makefile b/Makefile
index 720bf58..24cefb9 100644
--- a/Makefile
+++ b/Makefile
@@ -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)"
diff --git a/README b/README
index 6f1d0d5..ef90287 100644
--- a/README
+++ b/README
@@ -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)
diff --git a/TODO b/TODO
index bf1008c..f847558 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/common.h b/common.h
index c54d000..ee68661 100644
--- a/common.h
+++ b/common.h
@@ -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 {\
diff --git a/libaxl.h b/libaxl.h
index fd0c9c1..40b0df3 100644
--- a/libaxl.h
+++ b/libaxl.h
@@ -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 '?':