+Release 1.7 (2010-08-13)
+========================
+- Always wake up readers after writing
+- Get rid of PATH_MAX and MAXPATHLEN
+- Add ~ operator support in code generator
+- xcb_open: Improve protocol/host parsing
+- xcb_connect_to_display_with_auth_info: Fix memory leak
+- Report which extensions are being built
+
+Release 1.6 (2010-04-09)
+========================
+- darwin: xnu doesn't support poll on ttys on the master side
+- Fix descriptor leak on memory error path
+- Support xcb_discard_reply
+- Open the X11 socket with close-on-exec flag
+- Fix authentication on hpux and Hurd
+
Release 1.5 (2009-12-03)
========================
- setsockopt(SO_KEEPALIVE) on TCP display connections
AC_PREREQ(2.57)
AC_INIT([libxcb],
- 1.5,
+ 1.7,
[xcb@lists.freedesktop.org])
AC_CONFIG_SRCDIR([xcb.pc.in])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AC_ARG_WITH(launchd, AS_HELP_STRING([--with-launchd], [Build with support for Apple's launchd (default: auto)]), [LAUNCHD=$withval], [LAUNCHD=auto])
if test "x$LAUNCHD" = xauto; then
unset LAUNCHD
- AC_CHECK_PROG(LAUNCHD, [launchd], [yes], [no])
+ AC_CHECK_PROG(LAUNCHD, [launchd], [yes], [no], [$PATH$PATH_SEPARATOR/sbin])
fi
if test "x$LAUNCHD" = xyes ; then
echo " Build unit tests....: ${HAVE_CHECK}"
echo " XCB buffer size.....: ${xcb_queue_buffer_size}"
echo ""
+echo " X11 extensions"
+echo " Composite...........: ${BUILD_COMPOSITE}"
+echo " Damage..............: ${BUILD_DAMAGE}"
+echo " Dpms................: ${BUILD_DPMS}"
+echo " Dri2................: ${BUILD_DRI2}"
+echo " Glx.................: ${BUILD_GLX}"
+echo " Randr...............: ${BUILD_RANDR}"
+echo " Record..............: ${BUILD_RECORD}"
+echo " Render..............: ${BUILD_RENDER}"
+echo " Resource............: ${BUILD_RESOURCE}"
+echo " Screensaver.........: ${BUILD_SCREENSAVER}"
+echo " selinux.............: ${BUILD_SELINUX}"
+echo " Shape...............: ${BUILD_SHAPE}"
+echo " Shm.................: ${BUILD_SHM}"
+echo " Sync................: ${BUILD_SYNC}"
+echo " Xevie...............: ${BUILD_XEVIE}"
+echo " Xfixes..............: ${BUILD_XFIXES}"
+echo " Xfree86-dri.........: ${BUILD_XFREE86_DRI}"
+echo " xinerama............: ${BUILD_XINERAMA}"
+echo " xinput..............: ${BUILD_XINPUT}"
+echo " xprint..............: ${BUILD_XPRINT}"
+echo " xtest...............: ${BUILD_XTEST}"
+echo " xv..................: ${BUILD_XV}"
+echo " xvmc................: ${BUILD_XVMC}"
+echo ""
echo " Used CFLAGS:"
echo " CPPFLAGS............: ${CPPFLAGS}"
echo " CFLAGS..............: ${CFLAGS}"
</pre>
<p>
If the window has already been created, we can use the
- <span class="code">xcb_configure_window()</span> function to set
+ <span class="code">xcb_change_window_attributes()</span> function to set
the events that the window will receive. The subsection
<a href="#winconf">Configuring a window</a> shows its
prototype. As an example, here is a piece of code that
/* The connection c and the window win are supposed to be defined */
-xcb_configure_window (c, win, XCB_CW_EVENT_MASK, values);
+xcb_change_window_attributes (c, win, XCB_CW_EVENT_MASK, values);
</pre>
<div class="emph">
<p>
'''
lenexp = _c_accessor_get_length(expr, prefix)
- if expr.op != None:
+ if expr.op == '~':
+ return '(' + '~' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
+ elif expr.op != None:
return '(' + _c_accessor_get_expr(expr.lhs, prefix) + ' ' + expr.op + ' ' + _c_accessor_get_expr(expr.rhs, prefix) + ')'
elif expr.bitfield:
return 'xcb_popcount(' + lenexp + ')'
#define SIN6_ADDR(s) (&((struct sockaddr_in6 *)s)->sin6_addr)
-static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen,
- int display)
+static Xauth *get_authptr(struct sockaddr *sockname, int display)
{
char *addr = 0;
int addrlen = 0;
return 0; /* Unknown authorization type */
}
+/* `sockaddr_un.sun_path' typical size usually ranges between 92 and 108 */
+#define INITIAL_SOCKNAME_SLACK 108
+
+/* Return a dynamically allocated socket address structure according
+ to the value returned by either getpeername() or getsockname()
+ (according to POSIX, applications should not assume a particular
+ length for `sockaddr_un.sun_path') */
+static struct sockaddr *get_peer_sock_name(int (*socket_func)(int,
+ struct sockaddr *,
+ socklen_t *),
+ int fd)
+{
+ socklen_t socknamelen = sizeof(struct sockaddr) + INITIAL_SOCKNAME_SLACK;
+ socklen_t actual_socknamelen = socknamelen;
+ struct sockaddr *sockname = malloc(socknamelen), *new_sockname = NULL;
+
+ if (sockname == NULL)
+ return NULL;
+
+ /* Both getpeername() and getsockname() truncates sockname if
+ there is not enough space and set the required length in
+ actual_socknamelen */
+ if (socket_func(fd, sockname, &actual_socknamelen) == -1)
+ goto sock_or_realloc_error;
+
+ if (actual_socknamelen > socknamelen)
+ {
+ socknamelen = actual_socknamelen;
+
+ if ((new_sockname = realloc(sockname, actual_socknamelen)) == NULL ||
+ socket_func(fd, new_sockname, &actual_socknamelen) == -1 ||
+ actual_socknamelen > socknamelen)
+ goto sock_or_realloc_error;
+
+ sockname = new_sockname;
+ }
+
+ return sockname;
+
+ sock_or_realloc_error:
+ free(sockname);
+ return NULL;
+}
+
int _xcb_get_auth_info(int fd, xcb_auth_info_t *info, int display)
{
/* code adapted from Xlib/ConnDis.c, xtrans/Xtranssocket.c,
xtrans/Xtransutils.c */
- char sockbuf[sizeof(struct sockaddr) + MAXPATHLEN];
- unsigned int socknamelen = sizeof(sockbuf); /* need extra space */
- struct sockaddr *sockname = (struct sockaddr *) &sockbuf;
+ struct sockaddr *sockname = NULL;
int gotsockname = 0;
Xauth *authptr = 0;
int ret = 1;
* for UNIX Domain Sockets, but this is irrelevant,
* since compute_auth() ignores the peer name in this
* case anyway.*/
- if (getpeername(fd, sockname, &socknamelen) == -1)
+ if ((sockname = get_peer_sock_name(getpeername, fd)) == NULL)
{
+ if ((sockname = get_peer_sock_name(getsockname, fd)) == NULL)
+ return 0; /* can only authenticate sockets */
if (sockname->sa_family != AF_UNIX)
+ {
+ free(sockname);
return 0; /* except for AF_UNIX, sockets should have peernames */
- if (getsockname(fd, sockname, &socknamelen) == -1)
- return 0; /* can only authenticate sockets */
+ }
gotsockname = 1;
}
- authptr = get_authptr(sockname, socknamelen, display);
+ authptr = get_authptr(sockname, display);
if (authptr == 0)
+ {
+ free(sockname);
return 0; /* cannot find good auth data */
+ }
info->namelen = memdup(&info->name, authptr->name, authptr->name_length);
if (!info->namelen)
goto no_auth; /* out of memory */
- if (!gotsockname && getsockname(fd, sockname, &socknamelen) == -1)
+ if (!gotsockname && (sockname = get_peer_sock_name(getsockname, fd)) == NULL)
{
free(info->name);
goto no_auth; /* can only authenticate sockets */
goto no_auth; /* cannot build auth record */
}
+ free(sockname);
+ sockname = NULL;
+
XauDisposeAuth(authptr);
return ret;
no_auth:
+ free(sockname);
+
info->name = 0;
info->namelen = 0;
XauDisposeAuth(authptr);
#include <netinet/in.h>
#endif /* _WIN32 */
+/* SHUT_RDWR is fairly recent and is not available on all platforms */
+#if !defined(SHUT_RDWR)
+#define SHUT_RDWR 2
+#endif
+
typedef struct {
uint8_t status;
uint8_t pad0[5];
assert(count <= (int) (sizeof(parts) / sizeof(*parts)));
pthread_mutex_lock(&c->iolock);
- {
- struct iovec *parts_ptr = parts;
- ret = _xcb_out_send(c, &parts_ptr, &count);
- }
+ ret = _xcb_out_send(c, parts, count);
pthread_mutex_unlock(&c->iolock);
return ret;
}
{
xcb_connection_t* c;
+#ifndef USE_POLL
+ if(fd >= FD_SETSIZE) /* would overflow in FD_SET */
+ {
+ close(fd);
+ return (xcb_connection_t *) &error_connection;
+ }
+#endif
+
c = calloc(1, sizeof(xcb_connection_t));
if(!c) {
close(fd);
return;
free(c->setup);
+
+ /* disallow further sends and receives */
+ shutdown(c->fd, SHUT_RDWR);
close(c->fd);
pthread_mutex_destroy(&c->iolock);
pthread_mutex_unlock(&c->iolock);
do {
#if USE_POLL
- ret = poll(&fd, 1, -1);
+ ret = poll(&fd, 1, -1);
#else
- ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
+ ret = select(c->fd + 1, &rfds, &wfds, 0, 0);
#endif
} while (ret == -1 && errno == EINTR);
- if (ret < 0)
+ if(ret < 0)
{
_xcb_conn_shutdown(c);
- ret = 0;
+ ret = 0;
}
pthread_mutex_lock(&c->iolock);
#include "xcbint.h"
#if USE_POLL
#include <poll.h>
-#elif !defined _WIN32
+#endif
+#ifndef _WIN32
#include <sys/select.h>
#include <sys/socket.h>
#endif
struct reader_list *next;
} reader_list;
-static void wake_up_next_reader(xcb_connection_t *c)
-{
- int pthreadret;
- if(c->in.readers)
- pthreadret = pthread_cond_signal(c->in.readers->data);
- else
- pthreadret = pthread_cond_signal(&c->in.event_cond);
- assert(pthreadret == 0);
-}
-
static int read_packet(xcb_connection_t *c)
{
xcb_generic_reply_t genrep;
/* XGE events may have sizes > 32 */
if (genrep.response_type == XCB_XGE_EVENT)
- {
- eventlength = ((xcb_ge_event_t*)&genrep)->length * 4;
- }
+ eventlength = genrep.length * 4;
buf = malloc(length + eventlength +
(genrep.response_type == XCB_REPLY ? 0 : sizeof(uint32_t)));
pthread_cond_destroy(&cond);
}
- wake_up_next_reader(c);
+ _xcb_in_wake_up_next_reader(c);
pthread_mutex_unlock(&c->iolock);
return ret;
}
if(!_xcb_conn_wait(c, &c->in.event_cond, 0, 0))
break;
- wake_up_next_reader(c);
+ _xcb_in_wake_up_next_reader(c);
pthread_mutex_unlock(&c->iolock);
return ret;
}
void *reply;
if(c->has_error)
return 0;
- if(XCB_SEQUENCE_COMPARE_32(cookie.sequence,>,c->in.request_expected)
+ if(XCB_SEQUENCE_COMPARE_32(cookie.sequence,>=,c->in.request_expected)
&& XCB_SEQUENCE_COMPARE_32(cookie.sequence,>,c->in.request_completed))
{
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), &ret));
}
}
+void _xcb_in_wake_up_next_reader(xcb_connection_t *c)
+{
+ int pthreadret;
+ if(c->in.readers)
+ pthreadret = pthread_cond_signal(c->in.readers->data);
+ else
+ pthreadret = pthread_cond_signal(&c->in.event_cond);
+ assert(pthreadret == 0);
+}
+
int _xcb_in_expect_reply(xcb_connection_t *c, uint64_t request, enum workarounds workaround, int flags)
{
pending_reply *pend = malloc(sizeof(pending_reply));
vector[0].iov_base = c->out.queue;
vector[0].iov_len = c->out.queue_len;
c->out.queue_len = 0;
- return _xcb_out_send(c, &vector, &count);
+ return _xcb_out_send(c, vector, count);
}
static void get_socket_back(xcb_connection_t *c)
return 0;
pthread_mutex_lock(&c->iolock);
c->out.request += requests;
- ret = _xcb_out_send(c, &vector, &count);
+ ret = _xcb_out_send(c, vector, count);
pthread_mutex_unlock(&c->iolock);
return ret;
}
pthread_mutex_destroy(&out->reqlenlock);
}
-int _xcb_out_send(xcb_connection_t *c, struct iovec **vector, int *count)
+int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count)
{
int ret = 1;
- while(ret && *count)
- ret = _xcb_conn_wait(c, &c->out.cond, vector, count);
+ while(ret && count)
+ ret = _xcb_conn_wait(c, &c->out.cond, &vector, &count);
c->out.request_written = c->out.request;
pthread_cond_broadcast(&c->out.cond);
+ _xcb_in_wake_up_next_reader(c);
return ret;
}
return 1;
if(c->out.queue_len)
{
- struct iovec vec, *vec_ptr = &vec;
- int count = 1;
+ struct iovec vec;
vec.iov_base = c->out.queue;
vec.iov_len = c->out.queue_len;
c->out.queue_len = 0;
- return _xcb_out_send(c, &vec_ptr, &count);
+ return _xcb_out_send(c, &vec, 1);
}
while(c->out.writing)
pthread_cond_wait(&c->out.cond, &c->iolock);
#include <assert.h>
#include <sys/types.h>
+#include <limits.h>
#ifdef DNETCONN
#include <netdnet/dnetdb.h>
#include <netdnet/dn.h>
{
int len, display, screen;
char *slash, *colon, *dot, *end;
+
if(!name || !*name)
name = getenv("DISPLAY");
if(!name)
return 0;
+
+#ifdef HAVE_LAUNCHD
+ if(strncmp(name, "/tmp/launch", 11) == 0)
+ slash = NULL;
+ else
+#endif
slash = strrchr(name, '/');
+
if (slash) {
len = slash - name;
if (protocol) {
colon = strrchr(name, ':');
if(!colon)
- return 0;
+ goto error_out;
len = colon - name;
++colon;
display = strtoul(colon, &dot, 10);
if(dot == colon)
- return 0;
+ goto error_out;
if(*dot == '\0')
screen = 0;
else
{
if(*dot != '.')
- return 0;
+ goto error_out;
++dot;
screen = strtoul(dot, &end, 10);
if(end == dot || *end != '\0')
- return 0;
+ goto error_out;
}
/* At this point, the display string is fully parsed and valid, but
* the caller's memory is untouched. */
*host = malloc(len + 1);
if(!*host)
- return 0;
+ goto error_out;
memcpy(*host, name, len);
(*host)[len] = '\0';
*displayp = display;
if(screenp)
*screenp = screen;
return 1;
+
+error_out:
+ if (protocol) {
+ free(*protocol);
+ *protocol = NULL;
+ }
+
+ return 0;
}
int xcb_parse_display(const char *name, char **host, int *displayp,
return _xcb_parse_display(name, host, NULL, displayp, screenp);
}
-static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port);
+static int _xcb_open_tcp(const char *host, char *protocol, const unsigned short port);
#ifndef _WIN32
static int _xcb_open_unix(char *protocol, const char *file);
#endif /* !WIN32 */
static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen);
#endif
-static int _xcb_open(char *host, char *protocol, const int display)
+static int _xcb_open(const char *host, char *protocol, const int display)
{
-#ifdef HAVE_ABSTRACT_SOCKETS
int fd;
+ static const char unix_base[] = "/tmp/.X11-unix/X";
+ const char *base = unix_base;
+ size_t filelen;
+ char *file = NULL;
+ int actual_filelen;
+
+#ifdef HAVE_LAUNCHD
+ if(strncmp(host, "/tmp/launch", 11) == 0) {
+ base = host;
+ host = "";
+ protocol = NULL;
+ }
#endif
- static const char base[] = "/tmp/.X11-unix/X";
- char file[sizeof(base) + 20];
- int filelen;
- if(*host)
+ if(*host || protocol)
{
#ifdef DNETCONN
/* DECnet displays have two colons, so _xcb_parse_display will have
return _xcb_open_tcp(host, protocol, port);
}
}
+
#ifndef _WIN32
+ filelen = strlen(base) + 1 + sizeof(display) * 3 + 1;
+ file = malloc(filelen);
+ if(file == NULL)
+ return -1;
+
/* display specifies Unix socket */
- filelen = snprintf(file, sizeof(file), "%s%d", base, display);
- if(filelen < 0)
+#ifdef HAVE_LAUNCHD
+ if(strncmp(base, "/tmp/launch", 11) == 0)
+ actual_filelen = snprintf(file, filelen, "%s:%d", base, display);
+ else
+#endif
+ actual_filelen = snprintf(file, filelen, "%s%d", base, display);
+ if(actual_filelen < 0)
+ {
+ free(file);
return -1;
+ }
/* snprintf may truncate the file */
- filelen = MIN(filelen, sizeof(file) - 1);
+ filelen = MIN(actual_filelen, filelen - 1);
#ifdef HAVE_ABSTRACT_SOCKETS
fd = _xcb_open_abstract(protocol, file, filelen);
if (fd >= 0 || (errno != ENOENT && errno != ECONNREFUSED))
+ {
+ free(file);
return fd;
+ }
+
#endif
- return _xcb_open_unix(protocol, file);
+ fd = _xcb_open_unix(protocol, file);
+ free(file);
+
+ return fd;
#endif /* !_WIN32 */
return -1; /* if control reaches here then something has gone wrong */
}
}
#endif
-static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port)
+static int _xcb_open_tcp(const char *host, char *protocol, const unsigned short port)
{
int fd = -1;
struct addrinfo hints;
struct addrinfo *results, *addr;
char *bracket;
- if (protocol && strcmp("tcp",protocol))
+ if (protocol && strcmp("tcp",protocol) && strcmp("inet",protocol)
+#ifdef AF_INET6
+ && strcmp("inet6",protocol)
+#endif
+ )
return -1;
+
+ if (*host == '\0')
+ host = "localhost";
memset(&hints, 0, sizeof(hints));
#ifdef AI_ADDRCONFIG
xcb_connection_t *xcb_connect_to_display_with_auth_info(const char *displayname, xcb_auth_info_t *auth, int *screenp)
{
int fd, display = 0;
- char *host;
- char *protocol;
+ char *host = NULL;
+ char *protocol = NULL;
xcb_auth_info_t ourauth;
xcb_connection_t *c;
int parsed = _xcb_parse_display(displayname, &host, &protocol, &display, screenp);
-#ifdef HAVE_LAUNCHD
- if(!displayname)
- displayname = getenv("DISPLAY");
- if(displayname && strlen(displayname)>11 && !strncmp(displayname, "/tmp/launch", 11))
- fd = _xcb_open_unix(NULL, displayname);
- else
-#endif
- if(!parsed)
- return (xcb_connection_t *) &error_connection;
- else
+ if(!parsed) {
+ c = (xcb_connection_t *) &error_connection;
+ goto out;
+ } else
fd = _xcb_open(host, protocol, display);
- free(host);
- if(fd == -1)
- return (xcb_connection_t *) &error_connection;
+ if(fd == -1) {
+ c = (xcb_connection_t *) &error_connection;
+ goto out;
+ }
- if(auth)
- return xcb_connect_to_fd(fd, auth);
+ if(auth) {
+ c = xcb_connect_to_fd(fd, auth);
+ goto out;
+ }
if(_xcb_get_auth_info(fd, &ourauth, display))
{
else
c = xcb_connect_to_fd(fd, 0);
+out:
+ free(host);
+ free(protocol);
return c;
}
int _xcb_out_init(_xcb_out *out);
void _xcb_out_destroy(_xcb_out *out);
-int _xcb_out_send(xcb_connection_t *c, struct iovec **vector, int *count);
+int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count);
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request);
int _xcb_in_init(_xcb_in *in);
void _xcb_in_destroy(_xcb_in *in);
+void _xcb_in_wake_up_next_reader(xcb_connection_t *c);
+
int _xcb_in_expect_reply(xcb_connection_t *c, uint64_t request, enum workarounds workaround, int flags);
void _xcb_in_replies_done(xcb_connection_t *c);