#include <assert.h>
#include <X11/Xauth.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/un.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
+ #ifdef _WIN32
+ #include "xcb_windefs.h"
+ #else
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <sys/un.h>
+ #endif /* _WIN32 */
+
#include "xcb.h"
#include "xcbint.h"
#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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
- #include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include "xcbint.h"
#if USE_POLL
#include <poll.h>
- #else
+ #elif !defined _WIN32
#include <sys/select.h>
#endif
+ #ifdef _WIN32
+ #include "xcb_windefs.h"
+ #else
+ #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];
static int set_fd_flags(const int fd)
{
+ /* Win32 doesn't have file descriptors and the fcntl function. This block sets the socket in non-blocking mode */
+
+ #ifdef _WIN32
+ u_long iMode = 1; /* non-zero puts it in non-blocking mode, 0 in blocking mode */
+ int ret = 0;
+
+ ret = ioctlsocket(fd, FIONBIO, &iMode);
+ if(ret != 0)
+ return 0;
+ return 1;
+ #else
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
return 0;
if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
return 0;
return 1;
+ #endif /* _WIN32 */
}
static int write_setup(xcb_connection_t *c, xcb_auth_info_t *auth_info)
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;
}
{
int n;
assert(!c->out.queue_len);
+
+ #ifdef _WIN32
+ int i = 0;
+ int ret = 0,err = 0;
+ struct iovec *vec;
+ n = 0;
+
+ /* Could use the WSASend win32 function for scatter/gather i/o but setting up the WSABUF struct from
+ an iovec would require more work and I'm not sure of the benefit....works for now */
+ vec = *vector;
+ while(i < *count)
+ {
+ ret = send(c->fd,vec->iov_base,vec->iov_len,0);
+ if(ret == SOCKET_ERROR)
+ {
+ err = WSAGetLastError();
+ if(err == WSAEWOULDBLOCK)
+ {
+ return 1;
+ }
+ }
+ n += ret;
+ *vec++;
+ i++;
+ }
+ #else
n = writev(c->fd, *vector, *count);
if(n < 0 && errno == EAGAIN)
return 1;
+ #endif /* _WIN32 */
+
if(n <= 0)
{
_xcb_conn_shutdown(c);
{
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>
- #else
-#elif !defined _WIN32
++#endif
++#ifndef _WIN32
#include <sys/select.h>
+ #include <sys/socket.h>
#endif
+ #ifdef _WIN32
+ #include "xcb_windefs.h"
+ #endif /* _WIN32 */
+
#define XCB_ERROR 0
#define XCB_REPLY 1
#define XCB_XGE_EVENT 35
+ /* required for compiling for Win32 using MinGW */
+ #ifndef MSG_WAITALL
+ #define MSG_WAITALL 0
+ #endif
+
struct event_list {
xcb_generic_event_t *event;
struct event_list *next;
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)));
int done = 0;
while(done < len)
{
- int ret = read(fd, ((char *) buf) + done, len - done);
+ int ret = recv(fd, ((char *) buf) + done, len - done,MSG_WAITALL);
if(ret > 0)
done += ret;
+ #ifndef _WIN32
if(ret < 0 && errno == EAGAIN)
+ #else
+ if(ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
+ #endif /* !_Win32 */
{
#if USE_POLL
struct pollfd pfd;
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
+
+ /* Initializing errno here makes sure that for Win32 this loop will execute only once */
+ errno = 0;
do {
ret = select(fd + 1, &fds, 0, 0, 0);
} while (ret == -1 && errno == EINTR);
- #endif
+ #endif /* USE_POLL */
}
if(ret <= 0)
return ret;
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));
int _xcb_in_read(xcb_connection_t *c)
{
- int n = read(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len);
+ int n = recv(c->fd, c->in.queue + c->in.queue_len, sizeof(c->in.queue) - c->in.queue_len,MSG_WAITALL);
if(n > 0)
c->in.queue_len += n;
while(read_packet(c))
/* empty */;
+ #ifndef _WIN32
if((n > 0) || (n < 0 && errno == EAGAIN))
+ #else
+ if((n > 0) || (n < 0 && WSAGetLastError() == WSAEWOULDBLOCK))
+ #endif /* !_WIN32 */
return 1;
_xcb_conn_shutdown(c);
return 0;
#include <assert.h>
#include <sys/types.h>
- #include <sys/socket.h>
+#include <limits.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
#ifdef DNETCONN
#include <netdnet/dnetdb.h>
#include <netdnet/dn.h>
#endif
- #include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
- #include <fcntl.h>
#include <string.h>
+ #ifdef _WIN32
+ #include "xcb_windefs.h"
+ #else
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>
+ #include <fcntl.h>
+ #include <netdb.h>
+ #endif /* _WIN32 */
+
#include "xcb.h"
#include "xcbext.h"
#include "xcbint.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 */
#ifdef DNETCONN
static int _xcb_open_decnet(const char *host, char *protocol, const unsigned short port);
#endif
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 */
}
static int _xcb_socket(int family, int type, int proto)
#endif
{
fd = socket(family, type, proto);
+ #ifndef _WIN32
if (fd >= 0)
fcntl(fd, F_SETFD, FD_CLOEXEC);
+ #endif
}
return fd;
}
}
#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
return fd;
}
+ #ifndef _WIN32
static int _xcb_open_unix(char *protocol, const char *file)
{
int fd;
}
return fd;
}
+ #endif /* !_WIN32 */
#ifdef HAVE_ABSTRACT_SOCKETS
static int _xcb_open_abstract(char *protocol, const char *file, size_t filelen)
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;
}