Improve TCP close handling and sync connection closing

This commit is contained in:
Sara Dickinson 2015-06-29 09:09:13 +01:00
parent 8c61ecd024
commit e20d679bc8
3 changed files with 36 additions and 31 deletions

View File

@ -537,6 +537,31 @@ priv_getdns_upstreams_dereference(getdns_upstreams *upstreams)
}
}
void
priv_getdns_upstream_shutdown(getdns_upstream *upstream) {
/*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;
/* If the connection had a problem, but had worked this time,
* then allow re-use in the future*/
if (upstream->tcp.write_error == 1 &&
upstream->responses_received > 0)
upstream->tcp.write_error = 0;
upstream->writes_done = 0;
upstream->responses_received = 0;
if (upstream->tls_hs_state != GETDNS_HS_FAILED)
upstream->tls_hs_state = GETDNS_HS_NONE;
/* Now TLS stuff*/
if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
if (fd != -1)
close(fd);
}
static uint8_t*
upstream_addr(getdns_upstream *upstream)
{
@ -597,7 +622,7 @@ upstream_init(getdns_upstream *upstream,
/* How is this upstream doing? */
upstream->writes_done = 0;
upstream->responses_recieved = 0;
upstream->responses_received = 0;
upstream->to_retry = 2;
upstream->back_off = 1;

View File

@ -87,7 +87,7 @@ typedef struct getdns_upstream {
/* How is this upstream doing? */
size_t writes_done;
size_t responses_recieved;
size_t responses_received;
int to_retry;
int back_off;
@ -241,4 +241,6 @@ void priv_getdns_context_ub_read_cb(void *userarg);
void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams);
void priv_getdns_upstream_shutdown(getdns_upstream *upstreams);
#endif /* _GETDNS_CONTEXT_H_ */

View File

@ -505,13 +505,7 @@ upstream_erred(getdns_upstream *upstream)
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
if (upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
close(upstream->fd);
upstream->fd = -1;
priv_getdns_upstream_shutdown(upstream);
}
void
@ -555,30 +549,20 @@ stub_timeout_cb(void *userarg)
(void) getdns_context_request_timed_out(netreq->owner);
}
static void
upstream_idle_timeout_cb(void *userarg)
{
getdns_upstream *upstream = (getdns_upstream *)userarg;
DEBUG_STUB("*** %s: **Closing connection %d**\n",
__FUNCTION__, upstream->fd);
/*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;
upstream->event.read_cb = NULL;
upstream->event.write_cb = NULL;
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->tls_hs_state != GETDNS_HS_FAILED)
upstream->tls_hs_state = GETDNS_HS_NONE;
if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
priv_getdns_upstream_shutdown(upstream);
}
close(fd);
}
static void
upstream_tls_timeout_cb(void *userarg)
@ -1329,7 +1313,7 @@ upstream_read_cb(void *userarg)
netreq->response_len =
upstream->tcp.read_pos - upstream->tcp.read_buf;
upstream->tcp.read_buf = NULL;
upstream->responses_recieved++;
upstream->responses_received++;
/* TODO[TLS]: I don't think we should do this for TCP. We should stay
* on a working connection until we hit a problem.*/
upstream->upstreams->current = 0;
@ -1674,7 +1658,7 @@ fallback_on_write(getdns_network_req *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)
if (netreq->owner->loop != upstream->loop)
upstream_reschedule_netreq_events(upstream, upstream->write_queue);
if (result != GETDNS_RETURN_GOOD)
@ -1751,13 +1735,7 @@ upstream_reschedule_netreq_events(getdns_upstream *upstream,
* So we will have to be aggressive and shut the connection....*/
DEBUG_STUB("# %s: **Closing connection %d**\n",
__FUNCTION__, upstream->fd);
if (upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
close(upstream->fd);
upstream->fd = -1;
priv_getdns_upstream_shutdown(upstream);
}
}