Change internal transport handling to use a list, not a fixed type

This commit is contained in:
Sara Dickinson 2015-04-24 16:29:08 +01:00
parent f2ae55858f
commit 3de15ad782
5 changed files with 190 additions and 183 deletions

View File

@ -526,8 +526,7 @@ upstream_scope_id(getdns_upstream *upstream)
}
static void
upstream_ntop_buf(getdns_upstream *upstream, getdns_transport_t transport,
char *buf, size_t len)
upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
{
/* Also possible but prints scope_id by name (nor parsed by unbound)
*
@ -566,9 +565,8 @@ upstream_init(getdns_upstream *upstream,
/* For sharing a socket to this upstream with TCP */
upstream->fd = -1;
upstream->tls_obj = NULL;
upstream->base_transport = (upstream_port(upstream) == GETDNS_PORT_NUM_TLS ?
GETDNS_TRANSPORT_TLS :
GETDNS_TRANSPORT_TCP);
upstream->dns_base_transport = (upstream_port(upstream) == GETDNS_PORT_NUM_TLS ?
GETDNS_BASE_TRANSPORT_TLS : GETDNS_BASE_TRANSPORT_TCP);
upstream->tls_hs_state = GETDNS_HS_NONE;
upstream->loop = NULL;
(void) getdns_eventloop_event_init(
@ -672,10 +670,10 @@ set_os_defaults(struct getdns_context *context)
token = parse + strcspn(parse, " \t\r\n");
*token = 0;
//getdns_port_type_t port_type = GETDNS_PORT_FIRST;
//for (; port_type < GETDNS_PORT_LAST; port_type++) {
// TODO[TLS]: Seeing strange crash in ub_create_ctx when using the loop here....
//fprintf(stderr,"creating upstream %s\n", parse);
getdns_port_type_t port_type = GETDNS_PORT_FIRST;
for (; port_type < GETDNS_PORT_LAST; port_type++) {
// TODO[TLS]: Seeing strange crash in ub_create_ctx when using the loop here....
fprintf(stderr,"creating upstream %s\n", parse);
if ((s = getaddrinfo(parse, "53", /*getdns_port_str_array[port_type],*/ &hints, &result)))
continue;
@ -690,7 +688,7 @@ set_os_defaults(struct getdns_context *context)
upstream = &context->upstreams->
upstreams[context->upstreams->count++];
upstream_init(upstream, context->upstreams, result);
//}
}
freeaddrinfo(result);
}
fclose(in);
@ -819,6 +817,7 @@ getdns_context_create_with_extended_memory_functions(
result->dnssec_allowed_skew = 0;
result->edns_maximum_udp_payload_size = -1;
result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP;
priv_set_base_dns_transports(result->dns_base_transports, result->dns_transport);
result->limit_outstanding_queries = 0;
result->has_ta = priv_getdns_parse_ta_file(NULL, NULL);
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
@ -1142,31 +1141,38 @@ getdns_context_set_namespaces(struct getdns_context *context,
return GETDNS_RETURN_GOOD;
} /* getdns_context_set_namespaces */
getdns_base_transport_t
priv_get_base_transport(getdns_transport_t transport, int level) {
if (!(level == 0 || level == 1)) return GETDNS_TRANSPORT_NONE;
switch (transport) {
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
if (level == 0) return GETDNS_TRANSPORT_UDP;
if (level == 1) return GETDNS_TRANSPORT_TCP;
case GETDNS_TRANSPORT_UDP_ONLY:
if (level == 0) return GETDNS_TRANSPORT_UDP;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TCP_ONLY:
if (level == 0) return GETDNS_TRANSPORT_TCP_SINGLE;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TCP;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TLS;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TLS;
if (level == 1) return GETDNS_TRANSPORT_TCP;
default:
return GETDNS_TRANSPORT_NONE;
}
/* TODO[TLS]: Modify further when API changed.*/
getdns_return_t
priv_set_base_dns_transports(getdns_base_transport_t *dns_base_transports,
getdns_transport_t value)
{
for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
dns_base_transports[i] = GETDNS_BASE_TRANSPORT_NONE;
switch (value) {
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP;
dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP_SINGLE;
break;
case GETDNS_TRANSPORT_UDP_ONLY:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP;
break;
case GETDNS_TRANSPORT_TCP_ONLY:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TCP_SINGLE;
break;
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TCP;
break;
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS;
break;
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS;
dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP;
break;
default:
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
@ -1188,9 +1194,8 @@ set_ub_dns_transport(struct getdns_context* context,
set_ub_string_opt(context, "do-tcp:", "yes");
break;
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
/* Hum. If used in recursive mode this will try TLS on port 53...
* So we need to fix or document that or delay setting it until
* resolution.*/
/* Note: If TLS is used in recursive mode this will try TLS on port
* 53... So this is prohibited when preparing for resolution.*/
set_ub_string_opt(context, "ssl-upstream:", "yes");
/* Fall through*/
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
@ -1213,17 +1218,22 @@ getdns_return_t
getdns_context_set_dns_transport(struct getdns_context *context,
getdns_transport_t value)
{
/* TODO[TLS]: Modify further when API changed.*/
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
/* Note that the call below does not have any effect in unbound after the
* ctx is finalised. So will not apply for recursive mode or stub + dnssec.
* ctx is finalised so for recursive mode or stub + dnssec only the first
* transport specified on the first query is used.
* However the method returns success as otherwise the transport could not
* be reset for stub mode.....
* be reset for stub mode.
* Also, not all transport options supported in libunbound yet */
if (set_ub_dns_transport(context, value) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
if (value != context->dns_transport) {
/*TODO[TLS]: remove this line*/
context->dns_transport = value;
if (priv_set_base_dns_transports(context->dns_base_transports, value) != GETDNS_RETURN_GOOD)
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT);
}
@ -1752,10 +1762,10 @@ ub_setup_stub(struct ub_ctx *ctx, getdns_context *context)
getdns_upstreams *upstreams = context->upstreams;
(void) ub_ctx_set_fwd(ctx, NULL);
/*TODO[TLS]: Order the upstreams so the TLS ones are first if doing TLS*/
/*TODO[TLS]: Use only the subset of upstreams that match the first transport */
for (i = 0; i < upstreams->count; i++) {
upstream = &upstreams->upstreams[i];
upstream_ntop_buf(upstream, context->dns_transport, addr, 1024);
upstream_ntop_buf(upstream, addr, 1024);
ub_ctx_set_fwd(ctx, addr);
}
@ -1850,27 +1860,22 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
}
/* Transport can in theory be set per query in stub mode */
/* TODO: move this transport logic to a separate functions*/
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
switch (context->dns_transport) {
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
if (context->tls_ctx == NULL) {
/*TODO[TLS]: Check if TLS is in the list of transports.*/
if (context->tls_ctx == NULL) {
#ifdef HAVE_LIBTLS1_2
/* Create client context, use TLS v1.2 only for now */
context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
/* Create client context, use TLS v1.2 only for now */
context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
#endif
if(!context->tls_ctx && context->dns_transport ==
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
return GETDNS_RETURN_BAD_CONTEXT;
}
}
break;
default:
break;
/* TODO[TLS]: Check if TLS is the only option in the list*/
// if(!context->tls_ctx && context->dns_transport ==
// GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
// return GETDNS_RETURN_BAD_CONTEXT;
// }
}
}
/* Block use of TLS ONLY in recursive mode as it won't work */
/* TODO[TLS]: Check if TLS is the only option in the list*/
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING
&& context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
return GETDNS_RETURN_BAD_CONTEXT;

View File

@ -75,14 +75,6 @@ struct filechg {
struct stat *prevstat;
};
typedef enum getdns_base_transport {
GETDNS_TRANSPORT_NONE,
GETDNS_TRANSPORT_UDP,
GETDNS_TRANSPORT_TCP_SINGLE,
GETDNS_TRANSPORT_TCP,
GETDNS_TRANSPORT_TLS
} getdns_base_transport_t;
typedef enum getdns_port_type {
GETDNS_PORT_FIRST = 0,
GETDNS_PORT_TCP = 0,
@ -111,7 +103,7 @@ typedef struct getdns_upstream {
/* For sharing a TCP socket to this upstream */
int fd;
SSL* tls_obj;
getdns_base_transport_t base_transport;
getdns_base_transport_t dns_base_transport;
getdns_tls_hs_state_t tls_hs_state;
getdns_eventloop_event event;
getdns_eventloop *loop;
@ -156,6 +148,7 @@ struct getdns_context {
struct getdns_list *dnssec_trust_anchors;
getdns_upstreams *upstreams;
getdns_transport_t dns_transport;
getdns_base_transport_t dns_base_transports[GETDNS_BASE_TRANSPORT_MAX];
uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew;
@ -251,6 +244,9 @@ int filechg_check(struct getdns_context *context, struct filechg *fchg);
void priv_getdns_context_ub_read_cb(void *userarg);
getdns_return_t priv_set_base_dns_transports(getdns_base_transport_t *,
getdns_transport_t);
getdns_base_transport_t priv_get_base_transport(getdns_transport_t transport, int level);
void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams);

View File

@ -89,7 +89,9 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
net_req->upstream = NULL;
net_req->fd = -1;
net_req->transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP;
priv_set_base_dns_transports(net_req->dns_base_transports,
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
net_req->dns_base_transport = net_req->dns_base_transports;
memset(&net_req->event, 0, sizeof(net_req->event));
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
net_req->query_id = 0;

View File

@ -407,6 +407,7 @@ stub_udp_read_cb(void *userarg)
return; /* Client cookie didn't match? */
close(netreq->fd);
/*TODO[TLS]: Switch this to use the transport fallback list*/
if (GLDNS_TC_WIRE(netreq->response) &&
dnsreq->context->dns_transport ==
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP) {
@ -478,51 +479,49 @@ stub_udp_write_cb(void *userarg)
static int
transport_matches(struct getdns_upstream *upstream, getdns_base_transport_t transport) {
if (upstream->base_transport != transport)
transport_valid(struct getdns_upstream *upstream, getdns_base_transport_t transport) {
if (upstream->dns_base_transport != transport)
return 0;
if (transport == GETDNS_TRANSPORT_TLS &&
if (transport == GETDNS_BASE_TRANSPORT_TLS &&
upstream->tls_hs_state == GETDNS_HS_FAILED)
return 0;
return 1;
}
static getdns_upstream *
pick_upstream(getdns_dns_req *dnsreq, int level)
pick_upstream(getdns_network_req *netreq, getdns_base_transport_t transport)
{
getdns_upstream *upstream;
getdns_upstreams *upstreams = netreq->owner->context->upstreams;
size_t i;
if (!dnsreq->upstreams->count)
if (!upstreams->count)
return NULL;
getdns_base_transport_t transport = priv_get_base_transport(
dnsreq->context->dns_transport, level);
for (i = 0; i < upstreams->count; i++)
if (upstreams->upstreams[i].to_retry <= 0)
upstreams->upstreams[i].to_retry++;
for (i = 0; i < dnsreq->upstreams->count; i++)
if (dnsreq->upstreams->upstreams[i].to_retry <= 0)
dnsreq->upstreams->upstreams[i].to_retry++;
i = dnsreq->upstreams->current;
i = upstreams->current;
do {
if (dnsreq->upstreams->upstreams[i].to_retry > 0 &&
transport_matches(&dnsreq->upstreams->upstreams[i], transport)) {
dnsreq->upstreams->current = i;
return &dnsreq->upstreams->upstreams[i];
if (upstreams->upstreams[i].to_retry > 0 &&
transport_valid(&upstreams->upstreams[i], transport)) {
upstreams->current = i;
return &upstreams->upstreams[i];
}
if (++i > dnsreq->upstreams->count)
if (++i > upstreams->count)
i = 0;
} while (i != dnsreq->upstreams->current);
} while (i != upstreams->current);
upstream = dnsreq->upstreams->upstreams;
for (i = 1; i < dnsreq->upstreams->count; i++)
if (dnsreq->upstreams->upstreams[i].back_off < upstream->back_off &&
transport_matches(&dnsreq->upstreams->upstreams[i], transport))
upstream = &dnsreq->upstreams->upstreams[i];
upstream = upstreams->upstreams;
for (i = 1; i < upstreams->count; i++)
if (upstreams->upstreams[i].back_off < upstream->back_off &&
transport_valid(&upstreams->upstreams[i], transport))
upstream = &upstreams->upstreams[i];
upstream->back_off++;
upstream->to_retry = 1;
dnsreq->upstreams->current = upstream - dnsreq->upstreams->upstreams;
upstreams->current = upstream - upstreams->upstreams;
return upstream;
}
@ -698,58 +697,61 @@ do_tls_handshake(getdns_upstream *upstream)
return 0;
}
/* TODO[TLS]: Could think about fallback on read error aswell.*/
/* TODO[TLS]: Make generic function for switching transport */
/* TODO[TLS]: Should think about fallback on read error aswell.*/
static int
fallback_on_write(getdns_network_req *netreq) {
fallback_on_tls_write_error(getdns_network_req *netreq) {
/* This should really check if any request in the queue can fallback...*/
if (netreq->transport != GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN)
return STUB_TCP_ERROR;
fprintf(stderr,"[TLS]: method: fallback_on_tls_write_error\n");
getdns_base_transport_t *next_transport = netreq->dns_base_transport;
if (*(++next_transport) != GETDNS_BASE_TRANSPORT_TCP)
/* TODO[TLS]: Fallback through upstreams....?*/
return STUB_TCP_ERROR;
/* Deal with old upstream */
getdns_upstream *upstream = netreq->upstream;
upstream->write_queue = NULL;
upstream->write_queue_last = NULL;
upstream->event.write_cb = NULL;
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
/* Remove from queue, clearing event if we are the last*/
if (!(upstream->write_queue = netreq->write_queue_tail)) {
upstream->write_queue_last = NULL;
upstream->event.write_cb = NULL;
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
}
/* Now set up new upstream */
getdns_upstream *new_upstream = pick_upstream(netreq->owner, 1);
getdns_upstream *new_upstream = pick_upstream(netreq, *next_transport);
/* TODO[TLS]: Fallback through upstreams....?*/
if (!new_upstream)
return STUB_TCP_ERROR;
/* get transport generically*/
int fd = connect_to_upstream(new_upstream, GETDNS_TRANSPORT_TCP, netreq->owner->context);
return STUB_TCP_ERROR;
int fd = connect_to_upstream(new_upstream, *next_transport, netreq->owner->context);
if (fd == -1)
return STUB_TCP_ERROR;
fprintf(stderr,"[TLS]: tcp_fallback to %d \n", new_upstream->fd);
getdns_network_req *next_req;
while (netreq != NULL) {
next_req = netreq->write_queue_tail;
if (netreq->transport == GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN) {
netreq->upstream = new_upstream;
upstream_schedule_netreq(new_upstream, netreq);
/* TODO: Timout need to be adjusted and rescheduled on the new fd ....*/
/* Note, setup timeout should be shorter than message timeout for
* messages with fallback or don't have time to re-try. */
}
/*else.... leave request to timeout?*/
netreq = next_req;
}
netreq->upstream = new_upstream;
upstream_schedule_netreq(new_upstream, netreq);
/* TODO[TLS]: Timout need to be adjusted and rescheduled on the new fd ....*/
/* Note, setup timeout should be shorter than message timeout for
* messages with fallback or don't have time to re-try. */
// GETDNS_SCHEDULE_EVENT(
// dnsreq->loop, upstream->fd, dnsreq->context->timeout,
// getdns_eventloop_event_init(&netreq->event, netreq, NULL,
// ( dnsreq->loop != upstream->loop /* Synchronous lookup? */
// ? netreq_upstream_write_cb : NULL), stub_timeout_cb));
return STUB_TCP_AGAIN;
}
static int
setup_tls(getdns_upstream* upstream)
check_tls(getdns_upstream* upstream)
{
int ret;
/* Already have a connection*/
if (upstream->tls_hs_state == GETDNS_HS_DONE &&
(upstream->tls_obj != NULL) && (upstream->fd != -1))
return 0;
/* This upstream can't be used, so let the fallback code take care of things */
if (upstream->tls_hs_state == GETDNS_HS_FAILED)
return STUB_TLS_SETUP_ERROR;
/* Lets make sure the connection is up before we try a handshake*/
int error = 0;
socklen_t len = (socklen_t)sizeof(error);
@ -774,17 +776,7 @@ setup_tls(getdns_upstream* upstream)
return STUB_TLS_SETUP_ERROR;
}
ret = do_tls_handshake(upstream);
switch (ret) {
case STUB_TCP_AGAIN:
return ret;
case STUB_TCP_ERROR:
fprintf(stderr,"[TLS]: W: Handshake has failed %d\n", upstream->tls_hs_state);
return STUB_TLS_SETUP_ERROR;
default:
fprintf(stderr,"[TLS]: W:after handshake %d, %s\n", upstream->tls_hs_state, upstream->tls_obj== NULL? "NULL":"Not NULL" );
return 0;
}
return do_tls_handshake(upstream);
}
static int
@ -795,7 +787,7 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, struct mem_funcs
size_t buf_size;
SSL* tls_obj = upstream->tls_obj;
int q = setup_tls(upstream);
int q = check_tls(upstream);
if (q != 0)
return q;
@ -883,7 +875,7 @@ upstream_read_cb(void *userarg)
fprintf(stderr,"[TLS]: upstream_read_cb on %d\n", upstream->fd);
if (upstream->tls_obj)
if (upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS)
q = stub_tls_read(upstream, &upstream->tcp,
&upstream->upstreams->mf);
else
@ -1114,7 +1106,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, getdns_network_
intptr_t query_id_intptr;
SSL* tls_obj = upstream->tls_obj;
int q = setup_tls(upstream);
int q = check_tls(upstream);
if (q != 0)
return q;
@ -1169,7 +1161,7 @@ upstream_write_cb(void *userarg)
fprintf(stderr,"[TLS]: method: upstream_write_cb %d\n", upstream->fd);
if (upstream->tls_obj)
if (upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS)
q = stub_tls_write(upstream, &upstream->tcp, netreq);
else
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
@ -1185,13 +1177,14 @@ upstream_write_cb(void *userarg)
case STUB_TLS_SETUP_ERROR:
/* Could not complete the TLS set up. Need to fallback on this upstream
* if possible.*/
if (fallback_on_write(netreq) == STUB_TCP_ERROR)
if (fallback_on_tls_write_error(netreq) == STUB_TCP_ERROR)
//TODO[TLS]: Need a different error case here for msg_erred?
stub_erred(netreq);
return;
default:
netreq->query_id = (uint16_t) q;
fprintf(stderr,"[TLS]: method: upstream_write_cb, successfull write %d\n", upstream->fd);
fprintf(stderr,"[TLS]: method: upstream_write_cb, successfull write %d\n", upstream->fd);
/* Unqueue the netreq from the write_queue */
if (!(upstream->write_queue = netreq->write_queue_tail)) {
@ -1231,6 +1224,7 @@ upstream_write_cb(void *userarg)
static void
netreq_upstream_write_cb(void *userarg)
{
fprintf(stderr,"[TLS]: method: SYNC netreq_upstream_write_cb \n");
upstream_write_cb(((getdns_network_req *)userarg)->upstream);
}
@ -1267,8 +1261,8 @@ tcp_connect(getdns_upstream *upstream, getdns_base_transport_t transport)
getdns_sock_nonblock(fd);
#ifdef USE_TCP_FASTOPEN
/* Leave the connect to the later call to sendto() if using TCP*/
if (transport == GETDNS_TRANSPORT_TCP ||
transport == GETDNS_TRANSPORT_TCP_SINGLE)
if (transport == GETDNS_BASE_TRANSPORT_TCP ||
transport == GETDNS_BASE_TRANSPORT_TCP_SINGLE)
return fd;
#endif
if (connect(fd, (struct sockaddr *)&upstream->addr,
@ -1286,31 +1280,33 @@ connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport
getdns_context *context)
{
if ((transport == GETDNS_TRANSPORT_TCP ||
transport == GETDNS_TRANSPORT_TLS)
if ((transport == GETDNS_BASE_TRANSPORT_TCP ||
transport == GETDNS_BASE_TRANSPORT_TLS)
&& upstream->fd != -1) {
fprintf(stderr,"[TLS]: method: tcp_connect using existing fd %d\n", upstream->fd);
return upstream->fd;
}
int fd;
int fd = -1;
switch(transport) {
case GETDNS_TRANSPORT_UDP:
case GETDNS_BASE_TRANSPORT_UDP:
if ((fd = socket(
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
return -1;
getdns_sock_nonblock(fd);
return fd;
case GETDNS_TRANSPORT_TCP_SINGLE:
case GETDNS_TRANSPORT_TCP:
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
case GETDNS_BASE_TRANSPORT_TCP:
fd = tcp_connect(upstream, transport);
break;
case GETDNS_TRANSPORT_TLS:
case GETDNS_BASE_TRANSPORT_TLS:
fd = tcp_connect(upstream, transport);
if (fd == -1 ||
(upstream->tls_obj = create_tls_object(context, fd)) == NULL ) {
if (fd == -1) return -1;
upstream->tls_obj = create_tls_object(context, fd);
if (upstream->tls_obj == NULL) {
fprintf(stderr,"[TLS]: could not create tls object\n");
close(fd);
return -1;
}
@ -1331,50 +1327,47 @@ connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport
getdns_return_t
priv_getdns_submit_stub_request(getdns_network_req *netreq)
{
getdns_dns_req *dnsreq = netreq->owner;
int fd = -1;
int i;
getdns_dns_req *dnsreq = netreq->owner;
getdns_upstream *upstream = NULL;
/* TODO[TLS - 1]: This will become a double while loop trying all the upstreams on all the
* transports for a connection since we need a fd to schedule on, using previous known capabilities
* All other set up is done async*/
/* Work out the primary and fallback transport options */
getdns_base_transport_t transport = priv_get_base_transport(
dnsreq->context->dns_transport,0);
getdns_base_transport_t fb_transport = priv_get_base_transport(
dnsreq->context->dns_transport,1);
getdns_upstream *upstream = pick_upstream(dnsreq, 0);
if (!upstream)
return GETDNS_RETURN_GENERIC_ERROR;
int fd = connect_to_upstream(upstream, transport, dnsreq->context);
if (fd == -1) {
if (fb_transport == GETDNS_TRANSPORT_NONE)
return GETDNS_RETURN_GENERIC_ERROR;
upstream = pick_upstream(dnsreq, 1);
if ((fd = connect_to_upstream(upstream, fb_transport, dnsreq->context)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
/* This loop does a best effort to get a initial fd falling back through
* transport (then upstream?). All other set up is done async*/
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
netreq->dns_base_transports[i] = dnsreq->context->dns_base_transports[i];
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX &&
netreq->dns_base_transports[i] != GETDNS_BASE_TRANSPORT_NONE; i++) {
/*TODO[TLS]: Loop over upstreams, but don't loop more than once*/
upstream = pick_upstream(netreq, netreq->dns_base_transports[i]);
if (!upstream) {
continue;
}
fd = connect_to_upstream(upstream, netreq->dns_base_transports[i],
dnsreq->context);
if (fd != -1)
break;
}
if (fd == -1)
return GETDNS_RETURN_GENERIC_ERROR;
netreq->upstream = upstream;
netreq->transport = dnsreq->context->dns_transport;
netreq->dns_base_transport = &(netreq->dns_base_transports[i]);
switch(transport) {
case GETDNS_TRANSPORT_UDP:
case GETDNS_TRANSPORT_TCP_SINGLE:
switch(*netreq->dns_base_transport) {
case GETDNS_BASE_TRANSPORT_UDP:
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
netreq->fd = fd;
GETDNS_SCHEDULE_EVENT(
dnsreq->loop, netreq->fd, dnsreq->context->timeout,
getdns_eventloop_event_init(&netreq->event, netreq,
NULL, (transport == GETDNS_TRANSPORT_UDP ? stub_udp_write_cb:
stub_tcp_write_cb), stub_timeout_cb));
NULL, (*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_UDP ?
stub_udp_write_cb: stub_tcp_write_cb), stub_timeout_cb));
return GETDNS_RETURN_GOOD;
case GETDNS_TRANSPORT_TCP:
case GETDNS_TRANSPORT_TLS:
case GETDNS_BASE_TRANSPORT_TCP:
case GETDNS_BASE_TRANSPORT_TLS:
/* In coming comments, "global" means "context wide" */
if (upstream->fd == -1) {
upstream->loop = dnsreq->context->extension;
upstream->fd = fd;
}
upstream_schedule_netreq(upstream, netreq);
/* TODO[TLS]: Timeout handling for async calls must change....
* Maybe even change scheduling for sync calls here too*/

View File

@ -164,6 +164,16 @@ typedef struct getdns_tcp_state {
} getdns_tcp_state;
typedef enum getdns_base_transport {
GETDNS_BASE_TRANSPORT_NONE,
GETDNS_BASE_TRANSPORT_UDP,
GETDNS_BASE_TRANSPORT_TCP_SINGLE, /* To be removed? */
GETDNS_BASE_TRANSPORT_TCP,
GETDNS_BASE_TRANSPORT_TLS,
GETDNS_BASE_TRANSPORT_STARTTLS, /* Not yet implemented*/
GETDNS_BASE_TRANSPORT_MAX
} getdns_base_transport_t;
/**
* Request data
**/
@ -191,7 +201,8 @@ typedef struct getdns_network_req
/* For stub resolving */
struct getdns_upstream *upstream;
int fd;
getdns_transport_t transport;
getdns_base_transport_t dns_base_transports[GETDNS_BASE_TRANSPORT_MAX];
getdns_base_transport_t *dns_base_transport;
getdns_eventloop_event event;
getdns_tcp_state tcp;
uint16_t query_id;