diff --git a/spec/index.html b/spec/index.html index 7c9d1a45..b6ead3e1 100644 --- a/spec/index.html +++ b/spec/index.html @@ -2233,6 +2233,16 @@ getdns_context_set_timeout(

Specifies number of milliseconds the API will wait for request to return. The default is not specified.

+
+getdns_return_t +getdns_context_set_idle_timeout( + getdns_context *context, + uint64_t timeout +);
+

Specifies number of milliseconds the API will leave an idle TCP, TLS or STARTTLS +connection open for (idle means no outstanding responses and no pending queries). +The default is 0.

+

8.4 Context for Recursive Resolvers

@@ -2444,7 +2454,8 @@ The response dicts inherit the custom memory management functions and the value

Change related to getdns_context_set_memory_functions

GETDNS_CONTEXT_CODE_TIMEOUT

Change related to getdns_context_set_timeout

- +

GETDNS_CONTEXT_CODE_IDLE_TIMEOUT

+

Change related to getdns_context_set_idle_timeout

8.11 Getting API information and current Contexts

An application might want to see information about the API itself and inspect the current context. diff --git a/src/const-info.c b/src/const-info.c index 8ed8b1fe..ecad9e5b 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -63,6 +63,7 @@ static struct const_info consts_info[] = { { 614, "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT }, { 615, "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT }, { 616, "GETDNS_CONTEXT_CODE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_TEXT }, + { 617, "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_IDLE_TEXT }, { 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT }, { 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT }, { 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT }, diff --git a/src/context.c b/src/context.c index 873a7a7a..ec92e852 100644 --- a/src/context.c +++ b/src/context.c @@ -847,6 +847,7 @@ getdns_context_create_with_extended_memory_functions( goto error; result->timeout = 5000; + result->idle_timeout = 0; result->follow_redirects = GETDNS_REDIRECTS_FOLLOW; result->dns_root_servers = create_default_root_servers(); result->append_name = GETDNS_APPEND_NAME_ALWAYS; @@ -1387,6 +1388,27 @@ getdns_context_set_timeout(struct getdns_context *context, uint64_t timeout) return GETDNS_RETURN_GOOD; } /* getdns_context_set_timeout */ +/* + * getdns_context_set_idle_timeout + * + */ +getdns_return_t +getdns_context_set_idle_timeout(struct getdns_context *context, uint64_t timeout) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + + if (timeout == 0) { + return GETDNS_RETURN_INVALID_PARAMETER; + } + + context->idle_timeout = timeout; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_IDLE_TIMEOUT); + + return GETDNS_RETURN_GOOD; +} /* getdns_context_set_timeout */ + + /* * getdns_context_set_follow_redirects * @@ -2575,6 +2597,14 @@ getdns_context_get_timeout(getdns_context *context, uint64_t* value) { return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_idle_timeout(getdns_context *context, uint64_t* value) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); + *value = context->idle_timeout; + return GETDNS_RETURN_GOOD; +} + getdns_return_t getdns_context_get_follow_redirects(getdns_context *context, getdns_redirects_t* value) { diff --git a/src/context.h b/src/context.h index 75ba33da..040f18d3 100644 --- a/src/context.h +++ b/src/context.h @@ -131,6 +131,7 @@ struct getdns_context { getdns_namespace_t *namespaces; int namespace_count; uint64_t timeout; + uint64_t idle_timeout; getdns_redirects_t follow_redirects; struct getdns_list *dns_root_servers; getdns_append_name_t append_name; diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index fcd0d7f1..3f133a4f 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -242,7 +242,8 @@ typedef enum getdns_context_code_t { GETDNS_CONTEXT_CODE_EDNS_DO_BIT = 613, GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW = 614, GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS = 615, - GETDNS_CONTEXT_CODE_TIMEOUT = 616 + GETDNS_CONTEXT_CODE_TIMEOUT = 616, + GETDNS_CONTEXT_CODE_IDLE_TIMEOUT = 617 } getdns_context_code_t; /** @@ -266,6 +267,7 @@ typedef enum getdns_context_code_t { #define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT "Change related to getdns_context_set_dnssec_allowed_skew" #define GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT "Change related to getdns_context_set_memory_functions" #define GETDNS_CONTEXT_CODE_TIMEOUT_TEXT "Change related to getdns_context_set_timeout" +#define GETDNS_CONTEXT_CODE_TIMEOUT_IDLE_TEXT "Change related to getdns_context_set_idle_timeout" /** @} */ @@ -973,6 +975,9 @@ getdns_context_set_limit_outstanding_queries(getdns_context *context, getdns_return_t getdns_context_set_timeout(getdns_context *context, uint64_t timeout); +getdns_return_t +getdns_context_set_idle_timeout(getdns_context *context, uint64_t timeout); + getdns_return_t getdns_context_set_follow_redirects(getdns_context *context, getdns_redirects_t value); diff --git a/src/getdns/getdns_extra.h b/src/getdns/getdns_extra.h index 66fbb942..36e0497d 100644 --- a/src/getdns/getdns_extra.h +++ b/src/getdns/getdns_extra.h @@ -150,6 +150,9 @@ getdns_context_get_limit_outstanding_queries(getdns_context *context, getdns_return_t getdns_context_get_timeout(getdns_context *context, uint64_t* timeout); +getdns_return_t +getdns_context_get_idle_timeout(getdns_context *context, uint64_t* timeout); + getdns_return_t getdns_context_get_follow_redirects(getdns_context *context, getdns_redirects_t* value); diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index f42334c1..656c29be 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -24,6 +24,7 @@ getdns_context_get_num_pending_requests getdns_context_get_resolution_type getdns_context_get_suffix getdns_context_get_timeout +getdns_context_get_idle_timeout getdns_context_get_update_callback getdns_context_get_upstream_recursive_servers getdns_context_process_async @@ -49,6 +50,7 @@ getdns_context_set_resolution_type getdns_context_set_return_dnssec_status getdns_context_set_suffix getdns_context_set_timeout +getdns_context_set_idle_timeout getdns_context_set_update_callback getdns_context_set_upstream_recursive_servers getdns_context_set_use_threads diff --git a/src/stub.c b/src/stub.c index d9097f85..df06c9c4 100644 --- a/src/stub.c +++ b/src/stub.c @@ -539,6 +539,26 @@ stub_timeout_cb(void *userarg) (void) getdns_context_request_timed_out(netreq->owner); } +static void +upstream_idle_timeout_cb(void *userarg) +{ + DEBUG_STUB("%s\n", __FUNCTION__); + getdns_upstream *upstream = (getdns_upstream *)userarg; + /*There is a race condition with a new request being scheduled while this happens + so take ownership of the fd asap*/ + int fd = upstream->fd; + upstream->fd = -1; + upstream->event.timeout_cb = NULL; + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); + upstream->tls_hs_state = GETDNS_HS_NONE; + if (upstream->tls_obj != NULL) { + SSL_shutdown(upstream->tls_obj); + SSL_free(upstream->tls_obj); + } + close(fd); +} + + static void upstream_tls_timeout_cb(void *userarg) { @@ -1205,6 +1225,7 @@ upstream_read_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq; getdns_dns_req *dnsreq; + uint64_t idle_timeout; int q; uint16_t query_id; intptr_t query_id_intptr; @@ -1244,6 +1265,8 @@ upstream_read_cb(void *userarg) upstream->tcp.read_pos - upstream->tcp.read_buf; upstream->tcp.read_buf = NULL; upstream->upstreams->current = 0; + /* netreq may die before setting timeout*/ + idle_timeout = netreq->owner->context->idle_timeout; /* TODO: DNSSEC */ netreq->secure = 0; @@ -1297,6 +1320,12 @@ upstream_read_cb(void *userarg) GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, &upstream->event); + else { + upstream->event.timeout_cb = upstream_idle_timeout_cb; + GETDNS_SCHEDULE_EVENT(upstream->loop, + upstream->fd, idle_timeout, + &upstream->event); + } } } } @@ -1657,6 +1686,7 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) /* Append netreq to write_queue */ if (!upstream->write_queue) { upstream->write_queue = upstream->write_queue_last = netreq; + upstream->event.timeout_cb = NULL; GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); if (upstream->tls_hs_state == GETDNS_HS_WRITE || (upstream->starttls_req && diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 0ae3216a..83064557 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -152,6 +152,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); fprintf(out, "\t-S\tservice lookup ( is ignored)\n"); fprintf(out, "\t-t \tSet timeout in miliseconds\n"); + fprintf(out, "\t-e \tSet idle timeout in miliseconds\n"); fprintf(out, "\t-T\tSet transport to TCP only\n"); fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n"); fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n"); @@ -377,20 +378,36 @@ getdns_return_t parse_args(int argc, char **argv) break; case 't': if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "ttl expected " + fprintf(stderr, "timeout expected " "after -t\n"); return GETDNS_RETURN_GENERIC_ERROR; } timeout = strtol(argv[i], &endptr, 10); if (*endptr || timeout < 0) { fprintf(stderr, "positive " - "numeric ttl expected " + "numeric timeout expected " "after -t\n"); return GETDNS_RETURN_GENERIC_ERROR; } getdns_context_set_timeout( context, timeout); goto next; + case 'e': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + timeout = strtol(argv[i], &endptr, 10); + if (*endptr || timeout < 0) { + fprintf(stderr, "positive " + "numeric idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_context_set_idle_timeout( + context, timeout); + goto next; case 'T': getdns_context_set_dns_transport(context, GETDNS_TRANSPORT_TCP_ONLY); diff --git a/src/test/tests_stub_async.c b/src/test/tests_stub_async.c index 14f6f642..ceaa54d6 100644 --- a/src/test/tests_stub_async.c +++ b/src/test/tests_stub_async.c @@ -139,7 +139,7 @@ main(int argc, char** argv) getdns_context_run(this_context); } - getdns_transport_t get_transport = GETDNS_TRANSPORT_UDP_ONLY; + getdns_transport_t get_transport; return_value = getdns_context_get_dns_transport(this_context, &get_transport); if (return_value != GETDNS_RETURN_GOOD) { fprintf(stderr, "Trying to get transport type failed: %d\n", @@ -150,8 +150,6 @@ main(int argc, char** argv) size_t transport_count = 0; getdns_transport_list_t *get_transport_list; - getdns_transport_list_t tmp[1] = {GETDNS_TRANSPORT_UDP}; - get_transport_list = tmp; return_value = getdns_context_get_dns_transport_list(this_context, &transport_count, &get_transport_list); if (return_value != GETDNS_RETURN_GOOD) { fprintf(stderr, "Trying to get transport type failed: %d\n", @@ -161,6 +159,7 @@ main(int argc, char** argv) for (size_t i = 0; i < transport_count; i++) { fprintf(stderr, "Transport %d is %d\n", (int)i, get_transport_list[i]); } + free(get_transport_list); /* Clean up */ getdns_context_destroy(this_context);