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.
This commit is contained in:
Josh Triplett 2006-11-20 17:53:30 -08:00
parent 6c3a8db3f6
commit 48776ce233

View File

@ -96,28 +96,28 @@ int xcb_parse_display(const char *name, char **host, int *displayp, int *screenp
return 1; 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); static int _xcb_open_unix(const char *file);
#ifdef DNETCONN #ifdef DNETCONN
static int _xcb_open_decnet(const char *host, const unsigned short port); static int _xcb_open_decnet(const char *host, const unsigned short port);
#endif #endif
static int _xcb_open(const char *host, const int display) static int _xcb_open(char *host, const int display)
{ {
int fd; int fd;
if(*host) if(*host)
{ {
#ifdef DNETCONN #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 *colon = '\0';
one at the end */ fd = _xcb_open_decnet(host, display);
char *dnethost = strdup(host);
dnethost[strlen(dnethost)-1] = '\0';
fd = _xcb_open_decnet(dnethost, display);
free(dnethost);
} }
else else
#endif #endif
@ -173,22 +173,37 @@ static int _xcb_open_decnet(const char *host, const unsigned short port)
} }
#endif #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; int fd = -1;
struct sockaddr_in addr; struct addrinfo hints = { AI_ADDRCONFIG | AI_NUMERICSERV, AF_UNSPEC,
struct hostent *hostaddr = gethostbyname(host); SOCK_STREAM };
if(!hostaddr) char service[6]; /* "65535" with the trailing '\0' */
return -1; struct addrinfo *results, *addr;
addr.sin_family = AF_INET; char *bracket;
addr.sin_port = htons(port);
memcpy(&addr.sin_addr, hostaddr->h_addr_list[0], sizeof(addr.sin_addr)); /* 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); snprintf(service, sizeof(service), "%hu", port);
if(fd == -1) if(getaddrinfo(host, service, &hints, &results))
return -1; /* FIXME: use gai_strerror, and fill in error connection */
if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
return -1; 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; return fd;
} }