RDNS_RC_NETERR = 12,
RDNS_RC_NOREC = 13
};
-
+
struct rdns_reply {
struct rdns_request *request;
struct rdns_resolver *resolver;
void (*cleanup)(void *priv_data);
};
+struct rdns_upstream_elt {
+ void *server;
+ void *lib_data;
+};
+
+struct rdns_upstream_context {
+ void *data;
+ struct rdns_upstream_elt* (*select)(const char *name,
+ size_t len, void *ups_data);
+ struct rdns_upstream_elt* (*select_retransmit)(const char *name,
+ size_t len, void *ups_data);
+ void (*ok)(struct rdns_upstream_elt *elt, void *ups_data);
+ void (*fail)(struct rdns_upstream_elt *elt, void *ups_data);
+};
+
/**
* Type of rdns plugin
*/
enum rdns_plugin_type {
- RDNS_PLUGIN_CURVE = 0//!< use the specified plugin instead of send/recv functions
+ RDNS_PLUGIN_CURVE = 0
};
typedef ssize_t (*rdns_network_send_callback) (struct rdns_request *req, void *plugin_data);
* @param name name of DNS server (should be ipv4 or ipv6 address)
* @param priority priority (can be 0 for fair round-robin)
* @param io_cnt a number of sockets that are simultaneously opened to this server
- * @return true if a server has been added to resolver
+ * @return opaque pointer that could be used to select upstream
*/
-bool rdns_resolver_add_server (struct rdns_resolver *resolver,
+void* rdns_resolver_add_server (struct rdns_resolver *resolver,
const char *name, unsigned int port,
int priority, unsigned int io_cnt);
void rdns_resolver_set_log_level (struct rdns_resolver *resolver,
enum rdns_log_level level);
+/**
+ * Set upstream library for selecting DNS upstreams
+ * @param resolver resolver object
+ * @param ups_ctx upstream functions
+ * @param ups_data opaque data
+ */
+void rdns_resolver_set_upstream_lib (struct rdns_resolver *resolver,
+ struct rdns_upstream_context *ups_ctx,
+ void *ups_data);
/**
* Set maximum number of dns requests to be sent to a socket to be refreshed
* should take care about events processing
*/
return 0;
- }
+ }
else {
rdns_debug ("send failed: %s for server %s", strerror (errno), serv->name);
return -1;
}
}
-
+
if (new_req) {
/* Add request to hash table */
HASH_ADD_INT (req->io->requests, id, req);
struct rdns_request *req;
int id;
struct rdns_resolver *resolver = ioc->resolver;
-
+
id = header->qid;
HASH_FIND_INT (ioc->requests, &id, req);
if (req == NULL) {
return false;
}
- /*
+ /*
* Now we have request and query data is now at the end of header, so compare
* request QR section and reply QR section
*/
}
}
}
-
+
if (!found && type != RDNS_REQUEST_ANY) {
/* We have not found the requested RR type */
rep->code = RDNS_RC_NOREC;
uint8_t in[UDP_PACKET_SIZE];
resolver = ioc->resolver;
-
+
/* First read packet from socket */
if (resolver->curve_plugin == NULL) {
r = read (fd, in, sizeof (in));
if (req != NULL) {
if (rdns_parse_reply (in, r, req, &rep)) {
UPSTREAM_OK (req->io->srv);
+
+ if (req->resolver->ups && req->io->srv->ups_elt) {
+ req->resolver->ups->ok (req->io->srv->ups_elt,
+ req->resolver->ups->data);
+ }
+
req->state = RDNS_REQUEST_REPLIED;
rdns_request_unschedule (req);
req->func (rep, req->arg);
resolver = req->resolver;
if (req->retransmits == 0) {
- UPSTREAM_FAIL (req->io->srv, time (NULL));
+ if (req->resolver->ups && req->io->srv->ups_elt) {
+ req->resolver->ups->fail (req->io->srv->ups_elt,
+ req->resolver->ups->data);
+ }
+ else {
+ UPSTREAM_FAIL (req->io->srv, time (NULL));
+ }
+
rep = rdns_make_reply (req, RDNS_RC_TIMEOUT);
req->state = RDNS_REQUEST_REPLIED;
rdns_request_unschedule (req);
return;
}
- if (!req->io->active) {
+ if (!req->io->active || req->retransmits == 1) {
/* Do not reschedule IO requests on inactive sockets */
rdns_debug ("reschedule request with id: %d", (int)req->id);
rdns_request_unschedule (req);
REF_RELEASE (req->io);
- UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ if (resolver->ups) {
+ struct rdns_upstream_elt *elt;
+
+ elt = resolver->ups->select_retransmit (req->requested_names[0].name,
+ req->requested_names[0].len, resolver->ups->data);
+
+ if (elt) {
+ serv = elt->server;
+ serv->ups_elt = elt;
+ }
+ else {
+ UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ }
+ }
+ else {
+ UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ }
if (serv == NULL) {
rdns_warn ("cannot find suitable server for request");
req->state = RDNS_REQUEST_REGISTERED;
}
else if (r == -1) {
- UPSTREAM_FAIL (req->io->srv, time (NULL));
+ if (req->resolver->ups && req->io->srv->ups_elt) {
+ req->resolver->ups->fail (req->io->srv->ups_elt,
+ req->resolver->ups->data);
+ }
+ else {
+ UPSTREAM_FAIL (req->io->srv, time (NULL));
+ }
+
rep = rdns_make_reply (req, RDNS_RC_NETERR);
req->state = RDNS_REQUEST_REPLIED;
rdns_request_unschedule (req);
req->state = RDNS_REQUEST_REGISTERED;
}
else if (r == -1) {
- UPSTREAM_FAIL (req->io->srv, time (NULL));
+ if (req->resolver->ups && req->io->srv->ups_elt) {
+ req->resolver->ups->fail (req->io->srv->ups_elt,
+ req->resolver->ups->data);
+ }
+ else {
+ UPSTREAM_FAIL (req->io->srv, time (NULL));
+ }
+
rep = rdns_make_reply (req, RDNS_RC_NETERR);
req->state = RDNS_REQUEST_REPLIED;
req->func (rep, req->arg);
req->curve_plugin_data = NULL;
#endif
REF_INIT_RETAIN (req, rdns_request_free);
-
+
/* Calculate packet's total length based on records count */
va_start (args, queries);
for (i = 0; i < queries * 2; i += 2) {
req->state = RDNS_REQUEST_NEW;
req->async = resolver->async;
- UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ if (resolver->ups) {
+ struct rdns_upstream_elt *elt;
+
+ elt = resolver->ups->select (req->requested_names[0].name,
+ req->requested_names[0].len, resolver->ups->data);
+
+ if (elt) {
+ serv = elt->server;
+ serv->ups_elt = elt;
+ }
+ else {
+ UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ }
+ }
+ else {
+ UPSTREAM_SELECT_ROUND_ROBIN (resolver->servers, serv);
+ }
if (serv == NULL) {
rdns_warn ("cannot find suitable server for request");
REF_RELEASE (req);
return NULL;
}
-
+
/* Select random IO channel */
req->io = serv->io_channels[ottery_rand_uint32 () % serv->io_cnt];
req->io->uses ++;
-
+
/* Now send request to server */
r = rdns_send_request (req, req->io->sock, true);
if (!resolver->async_binded) {
return false;
}
-
+
if (resolver->servers == NULL) {
return false;
}
}
}
-bool
+void *
rdns_resolver_add_server (struct rdns_resolver *resolver,
const char *name, unsigned int port,
int priority, unsigned int io_cnt)
if (inet_pton (AF_INET, name, &addr) == 0 &&
inet_pton (AF_INET6, name, &addr) == 0) {
/* Invalid IP */
- return false;
+ return NULL;
}
if (io_cnt == 0) {
- return false;
+ return NULL;
}
if (port == 0 || port > UINT16_MAX) {
- return false;
+ return NULL;
}
serv = calloc (1, sizeof (struct rdns_server));
if (serv == NULL) {
- return false;
+ return NULL;
}
serv->name = strdup (name);
if (serv->name == NULL) {
free (serv);
- return false;
+ return NULL;
}
serv->io_cnt = io_cnt;
UPSTREAM_ADD (resolver->servers, serv, priority);
- return true;
+ return serv;
}
void
resolver->log_level = level;
}
+void
+rdns_resolver_set_upstream_lib (struct rdns_resolver *resolver,
+ struct rdns_upstream_context *ups_ctx,
+ void *ups_data)
+{
+ resolver->ups = ups_ctx;
+ resolver->ups->data = ups_data;
+}
+
void
rdns_resolver_set_max_io_uses (struct rdns_resolver *resolver,