Do better with unbound transport mapping and fix problems with sync fallback

This commit is contained in:
Sara Dickinson 2015-06-25 20:21:00 +01:00
parent 8819d29535
commit cb5bbac26d
3 changed files with 123 additions and 105 deletions

View File

@ -1217,7 +1217,7 @@ getdns_set_base_dns_transports(struct getdns_context *context,
static getdns_return_t static getdns_return_t
set_ub_dns_transport(struct getdns_context* context) { set_ub_dns_transport(struct getdns_context* context) {
/* These mappings are not exact because Unbound is configured differently, /* These mappings are not exact because Unbound is configured differently,
so just map as close as possible from the first 1 or 2 transports. */ so just map as close as possible. Not all options can be supported.*/
switch (context->dns_transports[0]) { switch (context->dns_transports[0]) {
case GETDNS_TRANSPORT_UDP: case GETDNS_TRANSPORT_UDP:
set_ub_string_opt(context, "do-udp:", "yes"); set_ub_string_opt(context, "do-udp:", "yes");
@ -1226,24 +1226,37 @@ set_ub_dns_transport(struct getdns_context* context) {
else else
set_ub_string_opt(context, "do-tcp:", "no"); set_ub_string_opt(context, "do-tcp:", "no");
break; break;
case GETDNS_TRANSPORT_TLS: case GETDNS_TRANSPORT_TCP:
/* Note: If TLS is used in recursive mode this will try TLS on port
* 53... So this is prohibited when preparing for resolution.*/
if (context->dns_transport_count == 0) {
set_ub_string_opt(context, "ssl-upstream:", "yes");
set_ub_string_opt(context, "do-udp:", "no"); set_ub_string_opt(context, "do-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes"); set_ub_string_opt(context, "do-tcp:", "yes");
break; break;
case GETDNS_TRANSPORT_TLS:
case GETDNS_TRANSPORT_STARTTLS:
set_ub_string_opt(context, "do-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes");
/* Find out if there is a fallback available. */
int fallback = 0;
for (size_t i = 1; i < context->dns_transport_count; i++) {
if (context->dns_transports[i] == GETDNS_TRANSPORT_TCP) {
fallback = 1;
break;
} }
if (context->dns_transports[1] != GETDNS_TRANSPORT_TCP) else if (context->dns_transports[i] == GETDNS_TRANSPORT_UDP) {
set_ub_string_opt(context, "do-udp:", "yes");
set_ub_string_opt(context, "do-tcp:", "no");
fallback = 1;
break; break;
/* Fallthrough */ }
case GETDNS_TRANSPORT_STARTTLS: }
case GETDNS_TRANSPORT_TCP: if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS) {
/* Note: no STARTTLS or fallback to TCP available directly in unbound, so we just if (fallback == 0)
* use TCP for now to make sure the messages are sent. */ /* Use TLS if it is the only thing.*/
set_ub_string_opt(context, "do-udp:", "no"); set_ub_string_opt(context, "ssl-upstream:", "yes");
set_ub_string_opt(context, "do-tcp:", "yes"); break;
} else if (fallback == 0)
/* Can't support STARTTLS with no fallback. This leads to
* timeouts with un stub validation.... */
set_ub_string_opt(context, "do-tcp:", "no");
break; break;
default: default:
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
@ -2011,10 +2024,13 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
return GETDNS_RETURN_BAD_CONTEXT; return GETDNS_RETURN_BAD_CONTEXT;
} }
} }
/* Block use of TLS ONLY in recursive mode as it won't work */ /* Block use of STARTTLS/TLS ONLY in recursive mode as it won't work */
/* Note: If TLS is used in recursive mode this will try TLS on port
* 53 so it is blocked here. So is STARTTLS only at the moment. */
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING && if (context->resolution_type == GETDNS_RESOLUTION_RECURSING &&
context->dns_transports[0] == GETDNS_TRANSPORT_TLS && context->dns_transport_count == 1 &&
context->dns_transport_count == 1) (context->dns_transports[0] == GETDNS_TRANSPORT_TLS ||
context->dns_transports[0] == GETDNS_TRANSPORT_STARTTLS))
return GETDNS_RETURN_BAD_CONTEXT; return GETDNS_RETURN_BAD_CONTEXT;
if (context->resolution_type_set == context->resolution_type) if (context->resolution_type_set == context->resolution_type)

View File

@ -48,6 +48,7 @@
#define STUB_TCP_AGAIN -3 #define STUB_TCP_AGAIN -3
#define STUB_TCP_ERROR -2 #define STUB_TCP_ERROR -2
/* Don't currently have access to the context whilst doing handshake */
#define TIMEOUT_TLS 2500 #define TIMEOUT_TLS 2500
static time_t secret_rollover_time = 0; static time_t secret_rollover_time = 0;
@ -59,9 +60,9 @@ static void upstream_write_cb(void *userarg);
static void upstream_idle_timeout_cb(void *userarg); static void upstream_idle_timeout_cb(void *userarg);
static void upstream_schedule_netreq(getdns_upstream *upstream, static void upstream_schedule_netreq(getdns_upstream *upstream,
getdns_network_req *netreq); getdns_network_req *netreq);
static void upstream_schedule_events(getdns_upstream *upstream, static void upstream_reschedule_events(getdns_upstream *upstream,
size_t idle_timeout); size_t idle_timeout);
static void upstream_schedule_netreq_events(getdns_upstream *upstream, static void upstream_reschedule_netreq_events(getdns_upstream *upstream,
getdns_network_req *netreq); getdns_network_req *netreq);
static int upstream_connect(getdns_upstream *upstream, static int upstream_connect(getdns_upstream *upstream,
getdns_transport_list_t transport, getdns_transport_list_t transport,
@ -340,14 +341,6 @@ is_starttls_response(getdns_network_req *netreq)
return 0; return 0;
} }
static int
is_starttls_request(getdns_network_req *netreq)
{
return ((strcmp(netreq->owner->name, "STARTTLS") == 0) &&
netreq->request_type == GETDNS_RRTYPE_TXT &&
netreq->request_class == GLDNS_RR_CLASS_CH);
}
/** best effort to set nonblocking */ /** best effort to set nonblocking */
static void static void
getdns_sock_nonblock(int sockfd) getdns_sock_nonblock(int sockfd)
@ -415,7 +408,7 @@ stub_next_upstream(getdns_network_req *netreq)
static void static void
stub_cleanup(getdns_network_req *netreq) stub_cleanup(getdns_network_req *netreq)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
getdns_dns_req *dnsreq = netreq->owner; getdns_dns_req *dnsreq = netreq->owner;
getdns_network_req *r, *prev_r; getdns_network_req *r, *prev_r;
getdns_upstream *upstream; getdns_upstream *upstream;
@ -449,13 +442,13 @@ stub_cleanup(getdns_network_req *netreq)
prev_r ? prev_r : NULL; prev_r ? prev_r : NULL;
break; break;
} }
upstream_schedule_events(upstream, netreq->owner->context->idle_timeout); upstream_reschedule_events(upstream, netreq->owner->context->idle_timeout);
} }
static int static int
tls_cleanup(getdns_upstream *upstream) tls_cleanup(getdns_upstream *upstream)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
SSL_free(upstream->tls_obj); SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL; upstream->tls_obj = NULL;
upstream->tls_hs_state = GETDNS_HS_FAILED; upstream->tls_hs_state = GETDNS_HS_FAILED;
@ -464,7 +457,7 @@ tls_cleanup(getdns_upstream *upstream)
GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER,
getdns_eventloop_event_init(&upstream->event, upstream, getdns_eventloop_event_init(&upstream->event, upstream,
NULL, upstream_write_cb, NULL)); NULL, upstream_write_cb, NULL));
/* Reset sync event, with wrong timeout*/ /* Reset sync event, with full timeout (which isn't correct)*/
getdns_network_req *netreq = upstream->write_queue; getdns_network_req *netreq = upstream->write_queue;
if (netreq && (netreq->event.write_cb || netreq->event.read_cb)) { if (netreq && (netreq->event.write_cb || netreq->event.read_cb)) {
GETDNS_CLEAR_EVENT(netreq->owner->loop, &netreq->event); GETDNS_CLEAR_EVENT(netreq->owner->loop, &netreq->event);
@ -504,14 +497,6 @@ upstream_erred(getdns_upstream *upstream)
upstream->fd = -1; upstream->fd = -1;
} }
static void
message_erred(getdns_network_req *netreq)
{
stub_cleanup(netreq);
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
void void
priv_getdns_cancel_stub_request(getdns_network_req *netreq) priv_getdns_cancel_stub_request(getdns_network_req *netreq)
{ {
@ -522,7 +507,7 @@ priv_getdns_cancel_stub_request(getdns_network_req *netreq)
static void static void
stub_erred(getdns_network_req *netreq) stub_erred(getdns_network_req *netreq)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
stub_next_upstream(netreq); stub_next_upstream(netreq);
stub_cleanup(netreq); stub_cleanup(netreq);
/* TODO[TLS]: When we get an error (which is probably a timeout) and are /* TODO[TLS]: When we get an error (which is probably a timeout) and are
@ -535,12 +520,12 @@ stub_erred(getdns_network_req *netreq)
static void static void
stub_timeout_cb(void *userarg) stub_timeout_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
getdns_network_req *netreq = (getdns_network_req *)userarg; getdns_network_req *netreq = (getdns_network_req *)userarg;
/* For now, mark a STARTTLS timeout as a failured negotiation and allow /* For now, mark a STARTTLS timeout as a failured negotiation and allow
* fallback but don't close the connection. */ * fallback but don't close the connection. */
if (is_starttls_request(netreq)) { if (netreq->owner == netreq->upstream->starttls_req) {
netreq->upstream->tls_hs_state = GETDNS_HS_FAILED; netreq->upstream->tls_hs_state = GETDNS_HS_FAILED;
stub_next_upstream(netreq); stub_next_upstream(netreq);
stub_cleanup(netreq); stub_cleanup(netreq);
@ -549,7 +534,6 @@ stub_timeout_cb(void *userarg)
stub_next_upstream(netreq); stub_next_upstream(netreq);
stub_cleanup(netreq); stub_cleanup(netreq);
DEBUG_STUB("%d\n", netreq->upstream->transport);
if (netreq->fd >= 0) close(netreq->fd); if (netreq->fd >= 0) close(netreq->fd);
(void) getdns_context_request_timed_out(netreq->owner); (void) getdns_context_request_timed_out(netreq->owner);
} }
@ -557,12 +541,11 @@ stub_timeout_cb(void *userarg)
static void static void
upstream_idle_timeout_cb(void *userarg) upstream_idle_timeout_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_upstream *upstream = (getdns_upstream *)userarg;
/*There is a race condition with a new request being scheduled while this happens /*There is a race condition with a new request being scheduled while this happens
so take ownership of the fd asap*/ so take ownership of the fd asap*/
int fd = upstream->fd; int fd = upstream->fd;
DEBUG_STUB("%d\n", upstream->transport);
upstream->fd = -1; upstream->fd = -1;
upstream->event.timeout_cb = NULL; upstream->event.timeout_cb = NULL;
upstream->event.read_cb = NULL; upstream->event.read_cb = NULL;
@ -582,7 +565,7 @@ upstream_idle_timeout_cb(void *userarg)
static void static void
upstream_tls_timeout_cb(void *userarg) upstream_tls_timeout_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_upstream *upstream = (getdns_upstream *)userarg;
/* Clean up and trigger a write to let the fallback code to its job */ /* Clean up and trigger a write to let the fallback code to its job */
tls_cleanup(upstream); tls_cleanup(upstream);
@ -608,7 +591,7 @@ upstream_tls_timeout_cb(void *userarg)
static void static void
stub_tls_timeout_cb(void *userarg) stub_tls_timeout_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("*** %s\n", __FUNCTION__);
getdns_network_req *netreq = (getdns_network_req *)userarg; getdns_network_req *netreq = (getdns_network_req *)userarg;
getdns_upstream *upstream = netreq->upstream; getdns_upstream *upstream = netreq->upstream;
/* Clean up and trigger a write to let the fallback code to its job */ /* Clean up and trigger a write to let the fallback code to its job */
@ -879,7 +862,7 @@ tls_create_object(getdns_context *context, int fd)
static int static int
tls_do_handshake(getdns_upstream *upstream) tls_do_handshake(getdns_upstream *upstream)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("--- %s\n", __FUNCTION__);
int r; int r;
int want; int want;
ERR_clear_error(); ERR_clear_error();
@ -1303,7 +1286,7 @@ stub_tcp_write_cb(void *userarg)
static void static void
upstream_read_cb(void *userarg) upstream_read_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("--- READ: %s\n", __FUNCTION__);
getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_upstream *upstream = (getdns_upstream *)userarg;
getdns_network_req *netreq; getdns_network_req *netreq;
getdns_dns_req *dnsreq; getdns_dns_req *dnsreq;
@ -1355,14 +1338,6 @@ upstream_read_cb(void *userarg)
netreq->secure = 0; netreq->secure = 0;
netreq->bogus = 0; netreq->bogus = 0;
/* This also reschedules events for the upstream*/
stub_cleanup(netreq);
/* More to read/write for syncronous lookups? */
if (netreq->event.read_cb) {
upstream_schedule_netreq_events(upstream, netreq);
}
if (netreq->owner == upstream->starttls_req) { if (netreq->owner == upstream->starttls_req) {
dnsreq = netreq->owner; dnsreq = netreq->owner;
if (is_starttls_response(netreq)) { if (is_starttls_response(netreq)) {
@ -1380,7 +1355,16 @@ upstream_read_cb(void *userarg)
netreq->owner->context->timeout, netreq->owner->context->timeout,
getdns_eventloop_event_init(&upstream->event, upstream, getdns_eventloop_event_init(&upstream->event, upstream,
NULL, upstream_write_cb, NULL)); NULL, upstream_write_cb, NULL));
} else }
/* This also reschedules events for the upstream*/
stub_cleanup(netreq);
/* More to read/write for syncronous lookups? */
if (netreq->event.read_cb)
upstream_reschedule_netreq_events(upstream, netreq);
if (netreq->owner != upstream->starttls_req)
priv_getdns_check_dns_req_complete(netreq->owner); priv_getdns_check_dns_req_complete(netreq->owner);
} }
} }
@ -1388,19 +1372,20 @@ upstream_read_cb(void *userarg)
static void static void
netreq_upstream_read_cb(void *userarg) netreq_upstream_read_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("--- READ: %s\n", __FUNCTION__);
upstream_read_cb(((getdns_network_req *)userarg)->upstream); upstream_read_cb(((getdns_network_req *)userarg)->upstream);
} }
static void static void
upstream_write_cb(void *userarg) upstream_write_cb(void *userarg)
{ {
DEBUG_STUB("%s\n", __FUNCTION__);
getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_upstream *upstream = (getdns_upstream *)userarg;
getdns_network_req *netreq = upstream->write_queue; getdns_network_req *netreq = upstream->write_queue;
getdns_dns_req *dnsreq = netreq->owner; getdns_dns_req *dnsreq = netreq->owner;
int q; int q;
DEBUG_STUB("--- WRITE: %s: %p TYPE: %d\n", __FUNCTION__, netreq,
netreq->request_type);
if (tls_requested(netreq) && tls_should_write(upstream)) if (tls_requested(netreq) && tls_should_write(upstream))
q = stub_tls_write(upstream, &upstream->tcp, netreq); q = stub_tls_write(upstream, &upstream->tcp, netreq);
else else
@ -1411,18 +1396,18 @@ upstream_write_cb(void *userarg)
return; return;
case STUB_TCP_ERROR: case STUB_TCP_ERROR:
/* Could not complete the TLS set up. Need to fallback.*/ /* Problem with the TCP connection itself. Need to fallback.*/
DEBUG_STUB("Setting write error\n"); DEBUG_STUB("--- WRITE: Setting write error\n");
upstream->tcp.write_error = 1; upstream->tcp.write_error = 1;
stub_next_upstream(netreq); stub_next_upstream(netreq);
if (fallback_on_write(netreq) == STUB_TCP_ERROR) /* Fall through */
message_erred(netreq);
return;
case STUB_TLS_SETUP_ERROR: case STUB_TLS_SETUP_ERROR:
/* Could not complete the TLS set up. Need to fallback.*/ /* Could not complete the TLS set up. Need to fallback.*/
if (fallback_on_write(netreq) == STUB_TCP_ERROR) stub_cleanup(netreq);
message_erred(netreq); if (fallback_on_write(netreq) == STUB_TCP_ERROR) {
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
return; return;
default: default:
@ -1480,6 +1465,9 @@ upstream_write_cb(void *userarg)
static void static void
netreq_upstream_write_cb(void *userarg) netreq_upstream_write_cb(void *userarg)
{ {
DEBUG_STUB("--- WRITE: %s: %p TYPE: %d\n", __FUNCTION__,
((getdns_network_req *)userarg),
((getdns_network_req *)userarg)->request_type);
upstream_write_cb(((getdns_network_req *)userarg)->upstream); upstream_write_cb(((getdns_network_req *)userarg)->upstream);
} }
@ -1518,7 +1506,7 @@ upstream_transport_valid(getdns_upstream *upstream,
static getdns_upstream * static getdns_upstream *
upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport) upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB(" %s\n", __FUNCTION__);
getdns_upstream *upstream; getdns_upstream *upstream;
getdns_upstreams *upstreams = netreq->owner->upstreams; getdns_upstreams *upstreams = netreq->owner->upstreams;
size_t i; size_t i;
@ -1535,12 +1523,12 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
/* TODO[TLS]: Should we create a tmp array of upstreams with correct*/ /* TODO[TLS]: Should we create a tmp array of upstreams with correct*/
/* transport type and/or maintain separate current for transports?*/ /* transport type and/or maintain separate current for transports?*/
i = upstreams->current; i = upstreams->current;
DEBUG_STUB("Current upstream %d\n",(int)i); DEBUG_STUB(" current upstream: %d\n",(int)i);
do { do {
if (upstreams->upstreams[i].to_retry > 0 && if (upstreams->upstreams[i].to_retry > 0 &&
upstream_transport_valid(&upstreams->upstreams[i], transport)) { upstream_transport_valid(&upstreams->upstreams[i], transport)) {
upstreams->current = i; upstreams->current = i;
DEBUG_STUB("Selected upstream %d\n",(int)i); DEBUG_STUB(" selected upstream: %d\n",(int)i);
return &upstreams->upstreams[i]; return &upstreams->upstreams[i];
} }
if (++i > upstreams->count) if (++i > upstreams->count)
@ -1554,8 +1542,10 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
upstream = &upstreams->upstreams[i]; upstream = &upstreams->upstreams[i];
/* Need to check again that the transport is valid */ /* Need to check again that the transport is valid */
if (!upstream_transport_valid(upstream, transport)) if (!upstream_transport_valid(upstream, transport)) {
DEBUG_STUB(" ! No valid upstream available\n");
return NULL; return NULL;
}
upstream->back_off++; upstream->back_off++;
upstream->to_retry = 1; upstream->to_retry = 1;
upstreams->current = upstream - upstreams->upstreams; upstreams->current = upstream - upstreams->upstreams;
@ -1567,7 +1557,7 @@ int
upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport,
getdns_dns_req *dnsreq) getdns_dns_req *dnsreq)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB(" %s\n", __FUNCTION__);
int fd = -1; int fd = -1;
switch(transport) { switch(transport) {
case GETDNS_TRANSPORT_UDP: case GETDNS_TRANSPORT_UDP:
@ -1635,7 +1625,7 @@ find_upstream_for_specific_transport(getdns_network_req *netreq,
getdns_transport_list_t transport, getdns_transport_list_t transport,
int *fd) int *fd)
{ {
DEBUG_STUB("%s %d \n", __FUNCTION__, transport); DEBUG_STUB(" %s: %d \n", __FUNCTION__, transport);
getdns_upstream *upstream = upstream_select(netreq, transport); getdns_upstream *upstream = upstream_select(netreq, transport);
if (!upstream) if (!upstream)
return NULL; return NULL;
@ -1672,52 +1662,62 @@ fallback_on_write(getdns_network_req *netreq)
/* Deal with UDP and change error code*/ /* Deal with UDP and change error code*/
DEBUG_STUB("%s ***\n", __FUNCTION__); DEBUG_STUB("#-> %s: %p TYPE: %d\n", __FUNCTION__, netreq, netreq->request_type);
getdns_upstream *upstream = netreq->upstream; getdns_upstream *upstream = netreq->upstream;
/* Remove from queue*/ /* Remove from queue and deal with the old upstream events*/
if (!(upstream->write_queue = netreq->write_queue_tail)) { if (!(upstream->write_queue = netreq->write_queue_tail)) {
upstream->write_queue_last = NULL; upstream->write_queue_last = NULL;
upstream->event.write_cb = NULL; upstream->event.write_cb = NULL;
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
} }
netreq->write_queue_tail = NULL; netreq->write_queue_tail = NULL;
upstream_schedule_events(upstream, netreq->owner->context->idle_timeout); upstream_reschedule_events(upstream, netreq->owner->context->idle_timeout);
if (priv_getdns_submit_stub_request(netreq) != GETDNS_RETURN_GOOD) /* Try to find a fallback transport*/
getdns_return_t result = priv_getdns_submit_stub_request(netreq);
/* For sync messages we must re-schedule the events on the old upstream
* here too. Must schedule this last to make sure it is called back first! */
if (netreq->owner->loop != upstream->loop && upstream->write_queue)
upstream_reschedule_netreq_events(upstream, upstream->write_queue);
if (result != GETDNS_RETURN_GOOD)
return STUB_TCP_ERROR; return STUB_TCP_ERROR;
/* For sync messages we must re-schedule the events on the original upstream
* here.*/
if (netreq->owner->loop != upstream->loop && upstream->write_queue) {
/* Must schedule this last to make sure it is called back first....?*/
upstream_schedule_netreq_events(upstream, upstream->write_queue);
}
return (netreq->transports[netreq->transport_current] return (netreq->transports[netreq->transport_current]
== GETDNS_TRANSPORT_UDP) ? == GETDNS_TRANSPORT_UDP) ?
netreq->fd : netreq->upstream->fd; netreq->fd : netreq->upstream->fd;
} }
static void static void
upstream_schedule_events(getdns_upstream *upstream, size_t idle_timeout) { upstream_reschedule_events(getdns_upstream *upstream, size_t idle_timeout) {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("# %s\n", __FUNCTION__);
int reschedule = 0; int reschedule = 0;
if (!upstream->write_queue && upstream->event.write_cb) { if (!upstream->write_queue && upstream->event.write_cb) {
upstream->event.write_cb = NULL; upstream->event.write_cb = NULL;
reschedule = 1; reschedule = 1;
} }
if (upstream->write_queue && !upstream->event.write_cb) {
upstream->event.write_cb = upstream_write_cb;
reschedule = 1;
}
if (!upstream->netreq_by_query_id.count && upstream->event.read_cb) { if (!upstream->netreq_by_query_id.count && upstream->event.read_cb) {
upstream->event.read_cb = NULL; upstream->event.read_cb = NULL;
reschedule = 1; reschedule = 1;
} }
if (upstream->netreq_by_query_id.count && !upstream->event.read_cb) {
upstream->event.read_cb = upstream_read_cb;
reschedule = 1;
}
if (reschedule) { if (reschedule) {
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->event.read_cb || upstream->event.write_cb) if (upstream->event.read_cb || upstream->event.write_cb)
GETDNS_SCHEDULE_EVENT(upstream->loop, GETDNS_SCHEDULE_EVENT(upstream->loop,
upstream->fd, TIMEOUT_FOREVER, &upstream->event); upstream->fd, TIMEOUT_FOREVER, &upstream->event);
else { else {
DEBUG_STUB("# %s: *Idle connection* \n", __FUNCTION__);
upstream->event.timeout_cb = upstream_idle_timeout_cb; upstream->event.timeout_cb = upstream_idle_timeout_cb;
if (upstream->tcp.write_error != 0) if (upstream->tcp.write_error != 0)
idle_timeout = 0; idle_timeout = 0;
@ -1728,9 +1728,9 @@ upstream_schedule_events(getdns_upstream *upstream, size_t idle_timeout) {
} }
static void static void
upstream_schedule_netreq_events(getdns_upstream *upstream, upstream_reschedule_netreq_events(getdns_upstream *upstream,
getdns_network_req *netreq) { getdns_network_req *netreq) {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("# %s: %p: TYPE: %d\n", __FUNCTION__, netreq, netreq->request_type);
getdns_dns_req *dnsreq = netreq->owner; getdns_dns_req *dnsreq = netreq->owner;
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
if (upstream->netreq_by_query_id.count || upstream->write_queue) if (upstream->netreq_by_query_id.count || upstream->write_queue)
@ -1746,7 +1746,7 @@ upstream_schedule_netreq_events(getdns_upstream *upstream,
/* This is a sync call, and the connection is idle. But we can't set a /* This is a sync call, and the connection is idle. But we can't set a
* timeout since we won't have an event loop if there are no netreqs * timeout since we won't have an event loop if there are no netreqs
* So we will have to be aggressive and shut the connection....*/ * So we will have to be aggressive and shut the connection....*/
DEBUG_STUB("%s -> closing connection\n", __FUNCTION__); DEBUG_STUB("# %s: **Closing connection**\n", __FUNCTION__);
if (upstream->tls_obj) { if (upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj); SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj); SSL_free(upstream->tls_obj);
@ -1760,7 +1760,7 @@ upstream_schedule_netreq_events(getdns_upstream *upstream,
static void static void
upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("# %s: %p TYPE: %d\n", __FUNCTION__, netreq, netreq->request_type);
/* We have a connected socket and a global event loop */ /* We have a connected socket and a global event loop */
assert(upstream->fd >= 0); assert(upstream->fd >= 0);
assert(upstream->loop); assert(upstream->loop);
@ -1794,7 +1794,7 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
getdns_return_t getdns_return_t
priv_getdns_submit_stub_request(getdns_network_req *netreq) priv_getdns_submit_stub_request(getdns_network_req *netreq)
{ {
DEBUG_STUB("%s\n", __FUNCTION__); DEBUG_STUB("--> %s\n", __FUNCTION__);
int fd = -1; int fd = -1;
getdns_dns_req *dnsreq = netreq->owner; getdns_dns_req *dnsreq = netreq->owner;

View File

@ -277,6 +277,11 @@ getdns_return_t parse_args(int argc, char **argv)
" %d", r); " %d", r);
break; break;
} }
} else if (arg[1] == '0') {
/* Unset all existing extensions*/
getdns_dict_destroy(extensions);
extensions = getdns_dict_create();
break;
} else if ((r = getdns_dict_set_int(extensions, arg+1, } else if ((r = getdns_dict_set_int(extensions, arg+1,
GETDNS_EXTENSION_TRUE))) { GETDNS_EXTENSION_TRUE))) {
fprintf(stderr, "Could not set extension " fprintf(stderr, "Could not set extension "
@ -605,9 +610,7 @@ main(int argc, char **argv)
r = GETDNS_RETURN_GENERIC_ERROR; r = GETDNS_RETURN_GENERIC_ERROR;
break; break;
} }
if (r) if (response && !quiet) {
goto done_destroy_extensions;
if (!quiet) {
if ((response_str = json ? if ((response_str = json ?
getdns_print_json_dict(response, json == 1) getdns_print_json_dict(response, json == 1)
: getdns_pretty_print_dict(response))) { : getdns_pretty_print_dict(response))) {
@ -620,14 +623,15 @@ main(int argc, char **argv)
fprintf( stderr fprintf( stderr
, "Could not print response\n"); , "Could not print response\n");
} }
} else if (r == GETDNS_RETURN_GOOD) { }
if (r == GETDNS_RETURN_GOOD) {
uint32_t status; uint32_t status;
getdns_dict_get_int(response, "status", &status); getdns_dict_get_int(response, "status", &status);
fprintf(stdout, "Response code was: GOOD. Status was: %s\n", fprintf(stdout, "Response code was: GOOD. Status was: %s\n",
getdns_get_errorstr_by_id(status)); getdns_get_errorstr_by_id(status));
} } else
else if (interactive) fprintf(stderr, "An error occurred: %d '%s'\n", r,
fprintf(stderr, "An error occurred: %d\n", r); getdns_get_errorstr_by_id(r));
} }
} while (interactive); } while (interactive);
@ -646,8 +650,6 @@ done_destroy_context:
if (r == CONTINUE) if (r == CONTINUE)
return 0; return 0;
if (r)
fprintf(stderr, "An error occurred: %d\n", r);
fprintf(stdout, "\nAll done.\n"); fprintf(stdout, "\nAll done.\n");
return r; return r;
} }