summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Triplett <josh@freedesktop.org>2006-11-20 17:53:30 -0800
committerJosh Triplett <josh@freedesktop.org>2006-11-20 17:54:34 -0800
commit48776ce233bf77fbaddbe972d2356bca69094239 (patch)
tree5156c441070ba1e4aafd7e29f82c6805d7c0cd38
parent6c3a8db3f69aebf2b5c1330ec6c11b3138f9bdfe (diff)
Support displays with IPv6 addresses or hosts which resolve to IPv6 addresses
xcb_parse_display already correctly handled IPv6 displays. Now, _xcb_open_tcp uses getaddrinfo, and correctly connects to IPv6 displays. Displays can use bare IPv6 addresses, square-bracketed IPv6 addresses, or hostnames which resolve to IPv6 addresses. Since IPv6 addresses may include colons, including at the end, revise the DECnet display parsing code to avoid triggering on IPv6 addresses. Authorization may not work with IPv6 connections yet. This commit brought to you by the (display) number ::1:1.1, the letter X, the Gobby collaborative editor, Josh Triplett, and Jamey Sharp.
-rw-r--r--src/xcb_util.c61
1 files changed, 38 insertions, 23 deletions
diff --git a/src/xcb_util.c b/src/xcb_util.c
index 3eab06a..587cb3a 100644
--- a/src/xcb_util.c
+++ b/src/xcb_util.c
@@ -96,28 +96,28 @@ int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp
return 1;
}
-static int _xcb_open_tcp(const char *host, const unsigned short port);
+static int _xcb_open_tcp(char *host, const unsigned short port);
static int _xcb_open_unix(const char *file);
#ifdef DNETCONN
static int _xcb_open_decnet(const char *host, const unsigned short port);
#endif
-static int _xcb_open(const char *host, const int display)
+static int _xcb_open(char *host, const int display)
{
int fd;
if(*host)
{
#ifdef DNETCONN
- if (strchr(host, ':'))
+ /* DECnet displays have two colons, so xcb_parse_display will have left
+ one at the end. However, an IPv6 address can end with *two* colons,
+ so only treat this as a DECnet display if host ends with exactly one
+ colon. */
+ char *colon = strchr(host, ':');
+ if(colon && *(colon+1) == '\0')
{
- /* DECnet displays have two colons, so the parser will have left
- one at the end */
- char *dnethost = strdup(host);
-
- dnethost[strlen(dnethost)-1] = '\0';
- fd = _xcb_open_decnet(dnethost, display);
- free(dnethost);
+ *colon = '\0';
+ fd = _xcb_open_decnet(host, display);
}
else
#endif
@@ -173,22 +173,37 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
}
#endif
-static int _xcb_open_tcp(const char *host, const unsigned short port)
+static int _xcb_open_tcp(char *host, const unsigned short port)
{
- int fd;
- struct sockaddr_in addr;
- struct hostent *hostaddr = gethostbyname(host);
- if(!hostaddr)
- return -1;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- memcpy(&addr.sin_addr, hostaddr->h_addr_list[0], sizeof(addr.sin_addr));
+ int fd = -1;
+ struct addrinfo hints = { AI_ADDRCONFIG | AI_NUMERICSERV, AF_UNSPEC,
+ SOCK_STREAM };
+ char service[6]; /* "65535" with the trailing '\0' */
+ struct addrinfo *results, *addr;
+ char *bracket;
+
+ /* Allow IPv6 addresses enclosed in brackets. */
+ if(host[0] == '[' && (bracket = strrchr(host, ']')) && bracket[1] == '\0')
+ {
+ *bracket = '\0';
+ ++host;
+ hints.ai_flags |= AI_NUMERICHOST;
+ hints.ai_family = AF_INET6;
+ }
- fd = socket(PF_INET, SOCK_STREAM, 0);
- if(fd == -1)
- return -1;
- if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ snprintf(service, sizeof(service), "%hu", port);
+ if(getaddrinfo(host, service, &hints, &results))
+ /* FIXME: use gai_strerror, and fill in error connection */
return -1;
+
+ for(addr = results; addr; addr = addr->ai_next)
+ {
+ fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if(fd >= 0 && connect(fd, addr->ai_addr, addr->ai_addrlen) >= 0)
+ break;
+ fd = -1;
+ }
+ freeaddrinfo(results);
return fd;
}