"curraddr", and turn "family" into a macro-derived property of the
other fields. The idea is that this renders SockAddrs immutable once
created, which should open up the possibility of duplicating and
reusing one without having to redo the actual DNS lookup.
I _hope_ I haven't broken anything. The new code architecture
contains several rather dubious-looking operations (namely the
arbitrary choice of the first returned address in functions like
sk_getaddr and sk_address_is_local - what if, for instance, a DNS
lookup returned a local and a non-local address?), but I think they
were functionally just as dubious beforehand and all this change has
done is to make them more obviously so to a reader.
git-svn-id: svn://svn.tartarus.org/sgt/putty@8293
cda61777-01e9-0310-a592-
d414129be87e
*/
typedef struct Socket_tag *Actual_Socket;
*/
typedef struct Socket_tag *Actual_Socket;
+/*
+ * Mutable state that goes with a SockAddr: stores information
+ * about where in the list of candidate IP(v*) addresses we've
+ * currently got to.
+ */
+typedef struct SockAddrStep_tag SockAddrStep;
+struct SockAddrStep_tag {
+#ifndef NO_IPV6
+ struct addrinfo *ai; /* steps along addr->ais */
+#endif
+ int curraddr;
+};
+
struct Socket_tag {
struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
struct Socket_tag {
struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
int nodelay, keepalive; /* for connect()-type sockets */
int privport, port; /* and again */
SockAddr addr;
int nodelay, keepalive; /* for connect()-type sockets */
int privport, port; /* and again */
SockAddr addr;
/*
* We sometimes need pairs of Socket structures to be linked:
* if we are listening on the same IPv6 and v4 port, for
/*
* We sometimes need pairs of Socket structures to be linked:
* if we are listening on the same IPv6 and v4 port, for
struct SockAddr_tag {
const char *error;
struct SockAddr_tag {
const char *error;
- /*
- * Which address family this address belongs to. AF_INET for
- * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
- * resolution has not been done and a simple host name is held
- * in this SockAddr structure.
- */
- int family;
+ enum { UNRESOLVED, UNIX, IP } superfamily;
#ifndef NO_IPV6
struct addrinfo *ais; /* Addresses IPv6 style. */
#ifndef NO_IPV6
struct addrinfo *ais; /* Addresses IPv6 style. */
- struct addrinfo *ai; /* steps along the linked list */
#else
unsigned long *addresses; /* Addresses IPv4 style. */
#else
unsigned long *addresses; /* Addresses IPv4 style. */
- int naddresses, curraddr;
#endif
char hostname[512]; /* Store an unresolved host name. */
};
#endif
char hostname[512]; /* Store an unresolved host name. */
};
+/*
+ * Which address family this address belongs to. AF_INET for IPv4;
+ * AF_INET6 for IPv6; AF_UNSPEC indicates that name resolution has
+ * not been done and a simple host name is held in this SockAddr
+ * structure.
+ */
+#ifndef NO_IPV6
+#define SOCKADDR_FAMILY(addr, step) \
+ ((addr)->superfamily == UNRESOLVED ? AF_UNSPEC : \
+ (addr)->superfamily == UNIX ? AF_UNIX : \
+ (step).ai ? (step).ai->ai_family : AF_INET)
+#else
+#define SOCKADDR_FAMILY(addr, step) \
+ ((addr)->superfamily == UNRESOLVED ? AF_UNSPEC : \
+ (addr)->superfamily == UNIX ? AF_UNIX : AF_INET)
+#endif
+
+/*
+ * Start a SockAddrStep structure to step through multiple
+ * addresses.
+ */
+#ifndef NO_IPV6
+#define START_STEP(addr, step) \
+ ((step).ai = (addr)->ais, (step).curraddr = 0)
+#else
+#define START_STEP(addr, step) \
+ ((step).curraddr = 0)
+#endif
+
static tree234 *sktree;
static void uxsel_tell(Actual_Socket s);
static tree234 *sktree;
static void uxsel_tell(Actual_Socket s);
/* Clear the structure and default to IPv4. */
memset(ret, 0, sizeof(struct SockAddr_tag));
/* Clear the structure and default to IPv4. */
memset(ret, 0, sizeof(struct SockAddr_tag));
- ret->family = 0; /* We set this one when we have resolved the host. */
+ ret->superfamily = UNRESOLVED;
*realhost = '\0';
ret->error = NULL;
*realhost = '\0';
ret->error = NULL;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
err = getaddrinfo(host, NULL, &hints, &ret->ais);
hints.ai_canonname = NULL;
hints.ai_next = NULL;
err = getaddrinfo(host, NULL, &hints, &ret->ais);
if (err != 0) {
ret->error = gai_strerror(err);
return ret;
}
if (err != 0) {
ret->error = gai_strerror(err);
return ret;
}
- ret->family = ret->ai->ai_family;
- if (ret->ai->ai_canonname != NULL)
- strncat(realhost, ret->ai->ai_canonname, sizeof(realhost) - 1);
+ if (ret->ais->ai_canonname != NULL)
+ strncat(realhost, ret->ais->ai_canonname, sizeof(realhost) - 1);
else
strncat(realhost, host, sizeof(realhost) - 1);
#else
else
strncat(realhost, host, sizeof(realhost) - 1);
#else
* Otherwise use the IPv4-only gethostbyname... (NOTE:
* we don't use gethostbyname as a fallback!)
*/
* Otherwise use the IPv4-only gethostbyname... (NOTE:
* we don't use gethostbyname as a fallback!)
*/
- if (ret->family == 0) {
+ if (ret->superfamily == UNRESOLVED) {
/*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
if ( (h = gethostbyname(host)) )
/*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
if ( (h = gethostbyname(host)) )
- if (ret->family == 0) {
+ if (ret->superfamily == UNRESOLVED) {
ret->error = (h_errno == HOST_NOT_FOUND ||
h_errno == NO_DATA ||
h_errno == NO_ADDRESS ? "Host does not exist" :
ret->error = (h_errno == HOST_NOT_FOUND ||
h_errno == NO_DATA ||
h_errno == NO_ADDRESS ? "Host does not exist" :
* This must be a numeric IPv4 address because it caused a
* success return from inet_addr.
*/
* This must be a numeric IPv4 address because it caused a
* success return from inet_addr.
*/
strncpy(realhost, host, sizeof(realhost));
ret->addresses = snew(unsigned long);
ret->naddresses = 1;
ret->addresses[0] = ntohl(a);
strncpy(realhost, host, sizeof(realhost));
ret->addresses = snew(unsigned long);
ret->naddresses = 1;
ret->addresses[0] = ntohl(a);
}
#endif
realhost[lenof(realhost)-1] = '\0';
}
#endif
realhost[lenof(realhost)-1] = '\0';
{
SockAddr ret = snew(struct SockAddr_tag);
ret->error = NULL;
{
SockAddr ret = snew(struct SockAddr_tag);
ret->error = NULL;
- ret->family = AF_UNSPEC;
+ ret->superfamily = UNRESOLVED;
strncpy(ret->hostname, host, lenof(ret->hostname));
ret->hostname[lenof(ret->hostname)-1] = '\0';
#ifndef NO_IPV6
strncpy(ret->hostname, host, lenof(ret->hostname));
ret->hostname[lenof(ret->hostname)-1] = '\0';
#ifndef NO_IPV6
-static int sk_nextaddr(SockAddr addr)
+static int sk_nextaddr(SockAddr addr, SockAddrStep *step)
- if (addr->ai && addr->ai->ai_next) {
- addr->ai = addr->ai->ai_next;
- addr->family = addr->ai->ai_family;
+ if (step->ai && step->ai->ai_next) {
+ step->ai = step->ai->ai_next;
return TRUE;
} else
return FALSE;
#else
return TRUE;
} else
return FALSE;
#else
- if (addr->curraddr+1 < addr->naddresses) {
- addr->curraddr++;
+ if (step->curraddr+1 < addr->naddresses) {
+ step->curraddr++;
return TRUE;
} else {
return FALSE;
return TRUE;
} else {
return FALSE;
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
- if (addr->family == AF_UNSPEC) {
+ if (addr->superfamily == UNRESOLVED) {
strncpy(buf, addr->hostname, buflen);
buf[buflen-1] = '\0';
} else {
#ifndef NO_IPV6
strncpy(buf, addr->hostname, buflen);
buf[buflen-1] = '\0';
} else {
#ifndef NO_IPV6
- if (getnameinfo(addr->ai->ai_addr, addr->ai->ai_addrlen, buf, buflen,
+ if (getnameinfo(addr->ais->ai_addr, addr->ais->ai_addrlen, buf, buflen,
NULL, 0, NI_NUMERICHOST) != 0) {
buf[0] = '\0';
strncat(buf, "<unknown>", buflen - 1);
}
#else
struct in_addr a;
NULL, 0, NI_NUMERICHOST) != 0) {
buf[0] = '\0';
strncat(buf, "<unknown>", buflen - 1);
}
#else
struct in_addr a;
- assert(addr->family == AF_INET);
- a.s_addr = htonl(addr->addresses[addr->curraddr]);
+ SockAddrStep step;
+ START_STEP(addr, step);
+ assert(SOCKADDR_FAMILY(addr, step) == AF_INET);
+ a.s_addr = htonl(addr->addresses[0]);
strncpy(buf, inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
#endif
strncpy(buf, inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
#endif
int sk_address_is_local(SockAddr addr)
{
int sk_address_is_local(SockAddr addr)
{
- if (addr->family == AF_UNSPEC)
+ if (addr->superfamily == UNRESOLVED)
return 0; /* we don't know; assume not */
else {
#ifndef NO_IPV6
return 0; /* we don't know; assume not */
else {
#ifndef NO_IPV6
- return sockaddr_is_loopback(addr->ai->ai_addr);
+ return sockaddr_is_loopback(addr->ais->ai_addr);
- assert(addr->family == AF_INET);
- a.s_addr = htonl(addr->addresses[addr->curraddr]);
+ SockAddrStep step;
+ START_STEP(addr, step);
+ assert(SOCKADDR_FAMILY(addr, step) == AF_INET);
+ a.s_addr = htonl(addr->addresses[0]);
return ipv4_is_loopback(a);
#endif
}
return ipv4_is_loopback(a);
#endif
}
int sk_addrtype(SockAddr addr)
{
int sk_addrtype(SockAddr addr)
{
- return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
+ SockAddrStep step;
+ int family;
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
+
+ return (family == AF_INET ? ADDRTYPE_IPV4 :
- addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
+ family == AF_INET6 ? ADDRTYPE_IPV6 :
#endif
ADDRTYPE_NAME);
}
void sk_addrcopy(SockAddr addr, char *buf)
{
#endif
ADDRTYPE_NAME);
}
void sk_addrcopy(SockAddr addr, char *buf)
{
+ SockAddrStep step;
+ int family;
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
- if (addr->family == AF_INET)
- memcpy(buf, &((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr,
+ if (family == AF_INET)
+ memcpy(buf, &((struct sockaddr_in *)step.ai->ai_addr)->sin_addr,
- else if (addr->family == AF_INET6)
- memcpy(buf, &((struct sockaddr_in6 *)addr->ai->ai_addr)->sin6_addr,
+ else if (family == AF_INET6)
+ memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
else
assert(FALSE);
#else
struct in_addr a;
sizeof(struct in6_addr));
else
assert(FALSE);
#else
struct in_addr a;
- assert(addr->family == AF_INET);
- a.s_addr = htonl(addr->addresses[addr->curraddr]);
+ assert(family == AF_INET);
+ a.s_addr = htonl(addr->addresses[step.curraddr]);
memcpy(buf, (char*) &a.s_addr, 4);
#endif
}
memcpy(buf, (char*) &a.s_addr, 4);
#endif
}
const struct sockaddr *sa;
int err = 0;
short localport;
const struct sockaddr *sa;
int err = 0;
short localport;
/*
* Remove the socket from the tree before we overwrite its
/*
* Remove the socket from the tree before we overwrite its
- assert(sock->addr->family != AF_UNSPEC);
- s = socket(sock->addr->family, SOCK_STREAM, 0);
+ family = SOCKADDR_FAMILY(sock->addr, sock->step);
+ assert(family != AF_UNSPEC);
+ s = socket(family, SOCK_STREAM, 0);
sock->s = s;
if (s < 0) {
sock->s = s;
if (s < 0) {
/* We don't try to bind to a local address for UNIX domain sockets. (Why
* do we bother doing the bind when localport == 0 anyway?) */
/* We don't try to bind to a local address for UNIX domain sockets. (Why
* do we bother doing the bind when localport == 0 anyway?) */
- if(sock->addr->family != AF_UNIX) {
+ if (family != AF_UNIX) {
/* Loop round trying to bind */
while (1) {
int retcode;
#ifndef NO_IPV6
/* Loop round trying to bind */
while (1) {
int retcode;
#ifndef NO_IPV6
- if (sock->addr->family == AF_INET6) {
+ if (family == AF_INET6) {
/* XXX use getaddrinfo to get a local address? */
a6.sin6_family = AF_INET6;
a6.sin6_addr = in6addr_any;
/* XXX use getaddrinfo to get a local address? */
a6.sin6_family = AF_INET6;
a6.sin6_addr = in6addr_any;
- assert(sock->addr->family == AF_INET);
+ assert(family == AF_INET);
a.sin_family = AF_INET;
a.sin_addr.s_addr = htonl(INADDR_ANY);
a.sin_port = htons(localport);
a.sin_family = AF_INET;
a.sin_addr.s_addr = htonl(INADDR_ANY);
a.sin_port = htons(localport);
/*
* Connect to remote address.
*/
/*
* Connect to remote address.
*/
- switch(sock->addr->family) {
#ifndef NO_IPV6
case AF_INET:
/* XXX would be better to have got getaddrinfo() to fill in the port. */
#ifndef NO_IPV6
case AF_INET:
/* XXX would be better to have got getaddrinfo() to fill in the port. */
- ((struct sockaddr_in *)sock->addr->ai->ai_addr)->sin_port =
+ ((struct sockaddr_in *)sock->step.ai->ai_addr)->sin_port =
- sa = (const struct sockaddr *)sock->addr->ai->ai_addr;
- salen = sock->addr->ai->ai_addrlen;
+ sa = (const struct sockaddr *)sock->step.ai->ai_addr;
+ salen = sock->step.ai->ai_addrlen;
- ((struct sockaddr_in *)sock->addr->ai->ai_addr)->sin_port =
+ ((struct sockaddr_in *)sock->step.ai->ai_addr)->sin_port =
- sa = (const struct sockaddr *)sock->addr->ai->ai_addr;
- salen = sock->addr->ai->ai_addrlen;
+ sa = (const struct sockaddr *)sock->step.ai->ai_addr;
+ salen = sock->step.ai->ai_addrlen;
break;
#else
case AF_INET:
a.sin_family = AF_INET;
break;
#else
case AF_INET:
a.sin_family = AF_INET;
- a.sin_addr.s_addr = htonl(sock->addr->addresses[sock->addr->curraddr]);
+ a.sin_addr.s_addr = htonl(sock->addr->addresses[sock->step.curraddr]);
a.sin_port = htons((short) sock->port);
sa = (const struct sockaddr *)&a;
salen = sizeof a;
a.sin_port = htons((short) sock->port);
sa = (const struct sockaddr *)&a;
salen = sizeof a;
ret->oobpending = FALSE;
ret->listener = 0;
ret->addr = addr;
ret->oobpending = FALSE;
ret->listener = 0;
ret->addr = addr;
+ START_STEP(ret->addr, ret->step);
ret->s = -1;
ret->oobinline = oobinline;
ret->nodelay = nodelay;
ret->s = -1;
ret->oobinline = oobinline;
ret->nodelay = nodelay;
err = 0;
do {
err = try_connect(ret);
err = 0;
do {
err = try_connect(ret);
- } while (err && sk_nextaddr(ret->addr));
+ } while (err && sk_nextaddr(ret->addr, &ret->step));
if (err)
ret->error = strerror(err);
if (err)
ret->error = strerror(err);
int err = errno;
if (s->addr) {
plug_log(s->plug, 1, s->addr, s->port, strerror(err), err);
int err = errno;
if (s->addr) {
plug_log(s->plug, 1, s->addr, s->port, strerror(err), err);
- while (s->addr && sk_nextaddr(s->addr)) {
+ while (s->addr && sk_nextaddr(s->addr, &s->step)) {
err = try_connect(s);
}
}
err = try_connect(s);
}
}
int n;
memset(ret, 0, sizeof *ret);
int n;
memset(ret, 0, sizeof *ret);
+ ret->superfamily = UNIX;
/*
* Mac OS X Leopard uses an innovative X display naming
* convention in which the entire display name is the path to
/*
* Mac OS X Leopard uses an innovative X display naming
* convention in which the entire display name is the path to
else
*canonicalname = dupstr(ret->hostname);
#ifndef NO_IPV6
else
*canonicalname = dupstr(ret->hostname);
#ifndef NO_IPV6
- ret->ai = ret->ais = NULL;
#else
ret->addresses = NULL;
#else
ret->addresses = NULL;
- ret->curraddr = ret->naddresses = 0;
*/
typedef struct Socket_tag *Actual_Socket;
*/
typedef struct Socket_tag *Actual_Socket;
+/*
+ * Mutable state that goes with a SockAddr: stores information
+ * about where in the list of candidate IP(v*) addresses we've
+ * currently got to.
+ */
+typedef struct SockAddrStep_tag SockAddrStep;
+struct SockAddrStep_tag {
+#ifndef NO_IPV6
+ struct addrinfo *ai; /* steps along addr->ais */
+#endif
+ int curraddr;
+};
+
struct Socket_tag {
const struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
struct Socket_tag {
const struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
int sending_oob;
int oobinline, nodelay, keepalive, privport;
SockAddr addr;
int sending_oob;
int oobinline, nodelay, keepalive, privport;
SockAddr addr;
int port;
int pending_error; /* in case send() returns error */
/*
int port;
int pending_error; /* in case send() returns error */
/*
struct SockAddr_tag {
char *error;
struct SockAddr_tag {
char *error;
- /*
- * Which address family this address belongs to. AF_INET for
- * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
- * resolution has not been done and a simple host name is held
- * in this SockAddr structure.
- * The hostname field is also used when the hostname has both
- * an IPv6 and IPv4 address and the IPv6 connection attempt
- * fails. We then try the IPv4 address.
- * This 'family' should become an option in the GUI and
- * on the commandline for selecting a default protocol.
- */
- int family;
#ifndef NO_IPV6
struct addrinfo *ais; /* Addresses IPv6 style. */
#ifndef NO_IPV6
struct addrinfo *ais; /* Addresses IPv6 style. */
- struct addrinfo *ai; /* steps along the linked list */
#endif
unsigned long *addresses; /* Addresses IPv4 style. */
#endif
unsigned long *addresses; /* Addresses IPv4 style. */
- int naddresses, curraddr;
char hostname[512]; /* Store an unresolved host name. */
};
char hostname[512]; /* Store an unresolved host name. */
};
+/*
+ * Which address family this address belongs to. AF_INET for IPv4;
+ * AF_INET6 for IPv6; AF_UNSPEC indicates that name resolution has
+ * not been done and a simple host name is held in this SockAddr
+ * structure.
+ */
+#ifndef NO_IPV6
+#define SOCKADDR_FAMILY(addr, step) \
+ (!(addr)->resolved ? AF_UNSPEC : \
+ (step).ai ? (step).ai->ai_family : AF_INET)
+#else
+#define SOCKADDR_FAMILY(addr, step) \
+ (!(addr)->resolved ? AF_UNSPEC : AF_INET)
+#endif
+
+/*
+ * Start a SockAddrStep structure to step through multiple
+ * addresses.
+ */
+#ifndef NO_IPV6
+#define START_STEP(addr, step) \
+ ((step).ai = (addr)->ais, (step).curraddr = 0)
+#else
+#define START_STEP(addr, step) \
+ ((step).curraddr = 0)
+#endif
+
static tree234 *sktree;
static int cmpfortree(void *av, void *bv)
static tree234 *sktree;
static int cmpfortree(void *av, void *bv)
unsigned long a;
struct hostent *h = NULL;
char realhost[8192];
unsigned long a;
struct hostent *h = NULL;
char realhost[8192];
- /* Clear the structure and default to IPv4. */
- memset(ret, 0, sizeof(struct SockAddr_tag));
- ret->family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
+ /* Default to IPv4. */
+ hint_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
#ifndef NO_IPV6
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
+
+ /* Clear the structure and default to IPv4. */
+ memset(ret, 0, sizeof(struct SockAddr_tag));
- ret->ai = ret->ais = NULL;
#endif
ret->addresses = NULL;
#endif
ret->addresses = NULL;
- ret_family = AF_UNSPEC;
*realhost = '\0';
if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
*realhost = '\0';
if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
logevent(NULL, "Using getaddrinfo() for resolving");
#endif
memset(&hints, 0, sizeof(hints));
logevent(NULL, "Using getaddrinfo() for resolving");
#endif
memset(&hints, 0, sizeof(hints));
- hints.ai_family = ret->family;
+ hints.ai_family = hint_family;
hints.ai_flags = AI_CANONNAME;
if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0)
hints.ai_flags = AI_CANONNAME;
if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0)
- ret_family = ret->ais->ai_family;
- ret->ai = ret->ais;
* (NOTE: we don't use gethostbyname as a fallback!)
*/
if ( (h = p_gethostbyname(host)) )
* (NOTE: we don't use gethostbyname as a fallback!)
*/
if ( (h = p_gethostbyname(host)) )
else
err = p_WSAGetLastError();
}
else
err = p_WSAGetLastError();
}
- if (ret_family == AF_UNSPEC) {
ret->error = (err == WSAENETDOWN ? "Network is down" :
err == WSAHOST_NOT_FOUND ? "Host does not exist" :
err == WSATRY_AGAIN ? "Host not found" :
ret->error = (err == WSAENETDOWN ? "Network is down" :
err == WSAHOST_NOT_FOUND ? "Host does not exist" :
err == WSATRY_AGAIN ? "Host not found" :
"gethostbyname: unknown error");
} else {
ret->error = NULL;
"gethostbyname: unknown error");
} else {
ret->error = NULL;
- ret->family = ret_family;
#ifndef NO_IPV6
/* If we got an address info use that... */
#ifndef NO_IPV6
/* If we got an address info use that... */
/* Are we in IPv4 fallback mode? */
/* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
/* Are we in IPv4 fallback mode? */
/* We put the IPv4 address into the a variable so we can further-on use the IPv4 code... */
- if (ret->family == AF_INET)
+ if (ret->ais->ai_family == AF_INET)
- (char *) &((SOCKADDR_IN *) ret->ai->
+ (char *) &((SOCKADDR_IN *) ret->ais->
ai_addr)->sin_addr, sizeof(a));
ai_addr)->sin_addr, sizeof(a));
- if (ret->ai->ai_canonname)
- strncpy(realhost, ret->ai->ai_canonname, lenof(realhost));
+ if (ret->ais->ai_canonname)
+ strncpy(realhost, ret->ais->ai_canonname, lenof(realhost));
else
strncpy(realhost, host, lenof(realhost));
}
else
strncpy(realhost, host, lenof(realhost));
}
memcpy(&a, h->h_addr_list[n], sizeof(a));
ret->addresses[n] = p_ntohl(a);
}
memcpy(&a, h->h_addr_list[n], sizeof(a));
ret->addresses[n] = p_ntohl(a);
}
memcpy(&a, h->h_addr, sizeof(a));
/* This way we are always sure the h->h_name is valid :) */
strncpy(realhost, h->h_name, sizeof(realhost));
memcpy(&a, h->h_addr, sizeof(a));
/* This way we are always sure the h->h_name is valid :) */
strncpy(realhost, h->h_name, sizeof(realhost));
*/
ret->addresses = snewn(1, unsigned long);
ret->naddresses = 1;
*/
ret->addresses = snewn(1, unsigned long);
ret->naddresses = 1;
ret->addresses[0] = p_ntohl(a);
ret->addresses[0] = p_ntohl(a);
strncpy(realhost, host, sizeof(realhost));
}
realhost[lenof(realhost)-1] = '\0';
strncpy(realhost, host, sizeof(realhost));
}
realhost[lenof(realhost)-1] = '\0';
{
SockAddr ret = snew(struct SockAddr_tag);
ret->error = NULL;
{
SockAddr ret = snew(struct SockAddr_tag);
ret->error = NULL;
- ret->family = AF_UNSPEC;
- ret->ai = ret->ais = NULL;
#endif
ret->addresses = NULL;
ret->naddresses = 0;
#endif
ret->addresses = NULL;
ret->naddresses = 0;
-int sk_nextaddr(SockAddr addr)
+int sk_nextaddr(SockAddr addr, SockAddrStep *step)
- if (addr->ai) {
- if (addr->ai->ai_next) {
- addr->ai = addr->ai->ai_next;
- addr->family = addr->ai->ai_family;
+ if (step->ai) {
+ if (step->ai->ai_next) {
+ step->ai = step->ai->ai_next;
return TRUE;
} else
return FALSE;
}
#endif
return TRUE;
} else
return FALSE;
}
#endif
- if (addr->curraddr+1 < addr->naddresses) {
- addr->curraddr++;
+ if (step->curraddr+1 < addr->naddresses) {
+ step->curraddr++;
return TRUE;
} else {
return FALSE;
return TRUE;
} else {
return FALSE;
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
+ SockAddrStep step;
+ START_STEP(addr, step);
+
if (p_WSAAddressToStringA) {
if (p_WSAAddressToStringA) {
- p_WSAAddressToStringA(addr->ai->ai_addr, addr->ai->ai_addrlen,
+ p_WSAAddressToStringA(step.ai->ai_addr, step.ai->ai_addrlen,
NULL, buf, &buflen);
} else
strncpy(buf, "IPv6", buflen);
} else
#endif
NULL, buf, &buflen);
} else
strncpy(buf, "IPv6", buflen);
} else
#endif
- if (addr->family == AF_INET) {
+ if (SOCKADDR_FAMILY(addr, step) == AF_INET) {
- assert(addr->addresses && addr->curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[addr->curraddr]);
+ assert(addr->addresses && step.curraddr < addr->naddresses);
+ a.s_addr = p_htonl(addr->addresses[step.curraddr]);
strncpy(buf, p_inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
} else {
strncpy(buf, p_inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
} else {
int sk_address_is_local(SockAddr addr)
{
int sk_address_is_local(SockAddr addr)
{
+ SockAddrStep step;
+ int family;
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
+
- if (addr->family == AF_INET6) {
- return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)addr->ai->ai_addr);
+ if (family == AF_INET6) {
+ return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)step.ai->ai_addr);
- if (addr->family == AF_INET) {
+ if (family == AF_INET) {
- if (addr->ai) {
- return ipv4_is_local_addr(((struct sockaddr_in *)addr->ai->ai_addr)
+ if (step.ai) {
+ return ipv4_is_local_addr(((struct sockaddr_in *)step.ai->ai_addr)
->sin_addr);
} else
#endif
{
struct in_addr a;
->sin_addr);
} else
#endif
{
struct in_addr a;
- assert(addr->addresses && addr->curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[addr->curraddr]);
+ assert(addr->addresses && step.curraddr < addr->naddresses);
+ a.s_addr = p_htonl(addr->addresses[step.curraddr]);
return ipv4_is_local_addr(a);
}
} else {
return ipv4_is_local_addr(a);
}
} else {
- assert(addr->family == AF_UNSPEC);
+ assert(family == AF_UNSPEC);
return 0; /* we don't know; assume not */
}
}
int sk_addrtype(SockAddr addr)
{
return 0; /* we don't know; assume not */
}
}
int sk_addrtype(SockAddr addr)
{
- return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
+ SockAddrStep step;
+ int family;
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
+
+ return (family == AF_INET ? ADDRTYPE_IPV4 :
- addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
+ family == AF_INET6 ? ADDRTYPE_IPV6 :
#endif
ADDRTYPE_NAME);
}
void sk_addrcopy(SockAddr addr, char *buf)
{
#endif
ADDRTYPE_NAME);
}
void sk_addrcopy(SockAddr addr, char *buf)
{
- assert(addr->family != AF_UNSPEC);
+ SockAddrStep step;
+ int family;
+ START_STEP(addr, step);
+ family = SOCKADDR_FAMILY(addr, step);
+
+ assert(family != AF_UNSPEC);
- if (addr->ai) {
- if (addr->family == AF_INET)
- memcpy(buf, &((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr,
+ if (step.ai) {
+ if (family == AF_INET)
+ memcpy(buf, &((struct sockaddr_in *)step.ai->ai_addr)->sin_addr,
- else if (addr->family == AF_INET6)
- memcpy(buf, &((struct sockaddr_in6 *)addr->ai->ai_addr)->sin6_addr,
+ else if (family == AF_INET6)
+ memcpy(buf, &((struct sockaddr_in6 *)step.ai->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
else
assert(FALSE);
} else
#endif
sizeof(struct in6_addr));
else
assert(FALSE);
} else
#endif
- if (addr->family == AF_INET) {
+ if (family == AF_INET) {
- assert(addr->addresses && addr->curraddr < addr->naddresses);
- a.s_addr = p_htonl(addr->addresses[addr->curraddr]);
+ assert(addr->addresses && step.curraddr < addr->naddresses);
+ a.s_addr = p_htonl(addr->addresses[step.curraddr]);
memcpy(buf, (char*) &a.s_addr, 4);
}
}
memcpy(buf, (char*) &a.s_addr, 4);
}
}
-#ifndef NO_IPV6
- /* Let's default to IPv6, this shouldn't hurt anybody
- * If the stack supports IPv6 it will also allow IPv4 connections. */
- if (sock->addr->ai) {
- family = sock->addr->ai->ai_family;
- } else
-#endif
- {
- /* Default to IPv4 */
- family = AF_INET;
- }
+ family = SOCKADDR_FAMILY(sock->addr, sock->step);
/*
* Remove the socket from the tree before we overwrite its
/*
* Remove the socket from the tree before we overwrite its
a.sin_port = p_htons(localport);
}
#ifndef NO_IPV6
a.sin_port = p_htons(localport);
}
#ifndef NO_IPV6
- sockcode = p_bind(s, (sock->addr->family == AF_INET6 ?
- (struct sockaddr *) &a6 :
- (struct sockaddr *) &a),
- (sock->addr->family ==
- AF_INET6 ? sizeof(a6) : sizeof(a)));
+ sockcode = p_bind(s, (family == AF_INET6 ?
+ (struct sockaddr *) &a6 :
+ (struct sockaddr *) &a),
+ (family == AF_INET6 ? sizeof(a6) : sizeof(a)));
#else
sockcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
#endif
#else
sockcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
#endif
* Connect to remote address.
*/
#ifndef NO_IPV6
* Connect to remote address.
*/
#ifndef NO_IPV6
if (family == AF_INET6) {
a6.sin6_family = AF_INET6;
a6.sin6_port = p_htons((short) sock->port);
a6.sin6_addr =
if (family == AF_INET6) {
a6.sin6_family = AF_INET6;
a6.sin6_port = p_htons((short) sock->port);
a6.sin6_addr =
- ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_addr;
- a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_flowinfo;
- a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_scope_id;
+ ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_addr;
+ a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_flowinfo;
+ a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->step.ai->ai_addr)->sin6_scope_id;
} else {
a.sin_family = AF_INET;
a.sin_addr =
} else {
a.sin_family = AF_INET;
a.sin_addr =
- ((struct sockaddr_in *) sock->addr->ai->ai_addr)->sin_addr;
+ ((struct sockaddr_in *) sock->step.ai->ai_addr)->sin_addr;
a.sin_port = p_htons((short) sock->port);
}
} else
#endif
{
a.sin_port = p_htons((short) sock->port);
}
} else
#endif
{
- assert(sock->addr->addresses && sock->addr->curraddr < sock->addr->naddresses);
+ assert(sock->addr->addresses && sock->step.curraddr < sock->addr->naddresses);
- a.sin_addr.s_addr = p_htonl(sock->addr->addresses[sock->addr->curraddr]);
+ a.sin_addr.s_addr = p_htonl(sock->addr->addresses[sock->step.curraddr]);
a.sin_port = p_htons((short) sock->port);
}
a.sin_port = p_htons((short) sock->port);
}
ret->privport = privport;
ret->port = port;
ret->addr = addr;
ret->privport = privport;
ret->port = port;
ret->addr = addr;
+ START_STEP(ret->addr, ret->step);
ret->s = INVALID_SOCKET;
err = 0;
do {
err = try_connect(ret);
ret->s = INVALID_SOCKET;
err = 0;
do {
err = try_connect(ret);
- } while (err && sk_nextaddr(ret->addr));
+ } while (err && sk_nextaddr(ret->addr, &ret->step));
if (s->addr) {
plug_log(s->plug, 1, s->addr, s->port,
winsock_error_string(err), err);
if (s->addr) {
plug_log(s->plug, 1, s->addr, s->port,
winsock_error_string(err), err);
- while (s->addr && sk_nextaddr(s->addr)) {
+ while (s->addr && sk_nextaddr(s->addr, &s->step)) {
err = try_connect(s);
}
}
err = try_connect(s);
}
}