}
}
-/*! @internal Create a UDP/TCP handle */
-static uv_handle_t *ioreq_spawn(struct qr_task *task, int socktype)
+/*! @internal Create a UDP/TCP handle for an outgoing AF_INET* connection.
+ * socktype is SOCK_* */
+static uv_handle_t *ioreq_spawn(struct qr_task *task, int socktype, sa_family_t family)
{
+ bool precond = (socktype == SOCK_DGRAM || socktype == SOCK_STREAM)
+ && (family == AF_INET || family == AF_INET6);
+ if (!precond) {
+ assert(false);
+ return NULL;
+ }
+
if (task->pending_count >= MAX_PENDING) {
return NULL;
}
return NULL;
}
io_create(task->worker->loop, handle, socktype);
+
+ /* Bind to outgoing address, according to IP v4/v6. */
+ union inaddr *addr;
+ if (family == AF_INET) {
+ addr = (union inaddr *)&task->worker->out_addr4;
+ } else {
+ addr = (union inaddr *)&task->worker->out_addr6;
+ }
+ int ret = 0;
+ if (addr->ip.sa_family != AF_UNSPEC) {
+ assert(addr->ip.sa_family == family);
+ if (socktype == SOCK_DGRAM) {
+ ret = uv_udp_bind((uv_udp_t *)handle, &addr->ip, 0);
+ } else {
+ ret = uv_tcp_bind((uv_tcp_t *)handle, &addr->ip, 0);
+ }
+ }
+
/* Set current handle as a subrequest type. */
struct session *session = handle->data;
- session->outgoing = true;
- int ret = array_push(session->tasks, task);
+ if (ret == 0) {
+ session->outgoing = true;
+ ret = array_push(session->tasks, task);
+ }
if (ret < 0) {
io_deinit(handle);
req_release(task->worker, (struct req *)handle);
static bool retransmit(struct qr_task *task)
{
if (task && task->addrlist && task->addrlist_count > 0) {
- uv_handle_t *subreq = ioreq_spawn(task, SOCK_DGRAM);
+ struct sockaddr_in6 *choice = &((struct sockaddr_in6 *)task->addrlist)[task->addrlist_turn];
+ uv_handle_t *subreq = ioreq_spawn(task, SOCK_DGRAM, choice->sin6_family);
if (subreq) { /* Create connection for iterative query */
- struct sockaddr_in6 *choice = &((struct sockaddr_in6 *)task->addrlist)[task->addrlist_turn];
if (qr_task_send(task, subreq, (struct sockaddr *)choice, task->pktbuf) == 0) {
task->addrlist_turn = (task->addrlist_turn + 1) % task->addrlist_count; /* Round robin */
return true;
if (!conn) {
return qr_task_step(task, NULL, NULL);
}
- uv_handle_t *client = ioreq_spawn(task, sock_type);
+ const struct sockaddr *addr =
+ packet_source ? packet_source : task->addrlist;
+ uv_handle_t *client = ioreq_spawn(task, sock_type, addr->sa_family);
if (!client) {
req_release(task->worker, (struct req *)conn);
return qr_task_step(task, NULL, NULL);
}
conn->data = task;
- if (uv_tcp_connect(conn, (uv_tcp_t *)client, packet_source?packet_source:task->addrlist, on_connect) != 0) {
+ if (uv_tcp_connect(conn, (uv_tcp_t *)client, addr , on_connect) != 0) {
req_release(task->worker, (struct req *)conn);
return qr_task_step(task, NULL, NULL);
}
worker->count = worker_count;
worker->engine = engine;
worker_reserve(worker, MP_FREELIST_SIZE);
+ worker->out_addr4.sin_family = AF_UNSPEC;
+ worker->out_addr6.sin6_family = AF_UNSPEC;
/* Register worker in Lua thread */
lua_pushlightuserdata(engine->L, worker);
lua_setglobal(engine->L, "__worker");