racket/udp: fixed for udp-bind!' and udp-connect!'

Fix ephemeral-port support in `udp-bind!', and
change `udp-bind!' and `udp-connect!' to try address
resolutions in order to find one that works (which is
typically needed to auto-select an IPv4 or IPv6 variant
of an address).
This commit is contained in:
Matthew Flatt 2013-04-10 08:56:12 -06:00
parent 7c0f35e138
commit 842da32e48

View File

@ -3175,7 +3175,7 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
Scheme_UDP *udp;
char *address = NULL;
unsigned short port = 0;
GC_CAN_IGNORE struct mz_addrinfo *udp_bind_addr = NULL;
GC_CAN_IGNORE struct mz_addrinfo *udp_bind_addr = NULL, *addr;
udp = (Scheme_UDP *)argv[0];
@ -3219,8 +3219,8 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
return NULL;
}
/* DISCONNECT */
if (SCHEME_FALSEP(argv[1]) && SCHEME_FALSEP(argv[2])) {
/* DISCONNECT */
int errid = 0;
if (udp->connected) {
int ok;
@ -3253,8 +3253,8 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
return scheme_void;
}
{
/* RESOLVE ADDRESS */
if (address || port) {
int err;
udp_bind_addr = scheme_get_host_address(address, port, &err, -1, do_bind, 0);
if (!udp_bind_addr) {
@ -3269,15 +3269,23 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
}
}
/* CONNECT CASE */
if (!do_bind) {
int ok = !connect(udp->s, udp_bind_addr->ai_addr, udp_bind_addr->ai_addrlen);
mz_freeaddrinfo(udp_bind_addr);
/* CONNECT CASE */
int ok, errid = -1;
/* connect using first address that works: */
for (addr = udp_bind_addr; addr; addr = addr->ai_next) {
ok = !connect(udp->s, addr->ai_addr, addr->ai_addrlen);
if (ok) {
udp->connected = 1;
mz_freeaddrinfo(udp_bind_addr);
return scheme_void;
} else
errid = SOCK_ERRNO();
}
else {
mz_freeaddrinfo(udp_bind_addr);
scheme_raise_exn(MZEXN_FAIL_NETWORK,
"%s: can't connect\n"
" address: %s\n"
@ -3286,13 +3294,12 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
name,
address ? address : "#f",
port,
SOCK_ERRNO());
errid);
return NULL;
}
}
} else {
/* BIND CASE */
else {
int ok;
int ok, errid = -1;
if ((argc > 3) && SCHEME_TRUEP(argv[3])) {
int one = 1;
@ -3306,24 +3313,19 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
}
}
if (udp_bind_addr == NULL ) {
GC_CAN_IGNORE mz_unspec_address ua;
memset(&ua, 0, sizeof(mz_unspec_address));
ua.sin_family = AF_UNSPEC;
ua.sin_port = 0;
memset(&(ua.sin_addr), 0, sizeof(ua.sin_addr));
memset(&(ua.sin_zero), 0, sizeof(ua.sin_zero));
ok = !bind(udp->s, (struct sockaddr *)&ua, sizeof(ua));
}
else {
ok = !bind(udp->s, udp_bind_addr->ai_addr, udp_bind_addr->ai_addrlen);
mz_freeaddrinfo(udp_bind_addr);
}
/* bind using first address that works: */
for (addr = udp_bind_addr; addr; addr = addr->ai_next) {
ok = !bind(udp->s, addr->ai_addr, addr->ai_addrlen);
if (ok) {
udp->bound = 1;
mz_freeaddrinfo(udp_bind_addr);
return scheme_void;
} else
errid = SOCK_ERRNO();
}
else {
mz_freeaddrinfo(udp_bind_addr);
scheme_raise_exn(MZEXN_FAIL_NETWORK,
"%s: can't bind\n"
" address: %s\n"
@ -3332,11 +3334,10 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj
name,
address ? address : "#f",
port,
SOCK_ERRNO());
errid);
return NULL;
}
}
}
#else
return scheme_void;
#endif