request.c revision 74717eef53ba5d6aefc80eb262bbb090ff4bb3b5
/*
* Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000-2002 Internet Software Consortium.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
#include <config.h>
#include <dns/compress.h>
#include <dns/dispatch.h>
#include <dns/rdatastruct.h>
#define DNS_REQUEST_NLOCKS 7
struct dns_requestmgr {
unsigned int magic;
/* locked */
unsigned int hash;
};
struct dns_request {
unsigned int magic;
unsigned int hash;
unsigned int udpcount;
};
#define DNS_REQUEST_F_CONNECTING 0x0001
#define DNS_REQUEST_F_SENDING 0x0002
synchronously canceled */
#define DNS_REQUEST_CANCELED(r) \
(((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
#define DNS_REQUEST_CONNECTING(r) \
(((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
#define DNS_REQUEST_SENDING(r) \
(((r)->flags & DNS_REQUEST_F_SENDING) != 0)
#define DNS_REQUEST_TIMEDOUT(r) \
(((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
/***
*** Forward
***/
/***
*** Public
***/
{
int i;
unsigned int dispattr;
if (dispatchv4 != NULL) {
}
if (dispatchv6 != NULL) {
}
if (requestmgr == NULL)
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS) {
return (result);
}
for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
if (result != ISC_R_SUCCESS) {
while (--i >= 0)
return (result);
}
}
if (dispatchv4 != NULL)
if (dispatchv6 != NULL)
requestmgr->iref = 0;
requestmgr->hash = 0;
return (ISC_R_SUCCESS);
}
void
{
if (requestmgr->exiting) {
/*
* We're already shutdown. Send the event.
*/
} else {
}
}
void
}
static void
/*
* Caller holds lock.
*/
if (!requestmgr->exiting) {
}
if (requestmgr->iref == 0) {
}
}
}
static void
/*
* Locked by caller.
*/
}
static void
*requestmgrp = NULL;
requestmgr->iref--;
if (requestmgr->eref == 0)
}
if (need_destroy)
}
void
}
void
requestmgr->eref--;
}
if (need_destroy)
*requestmgrp = NULL;
}
static void
/*
* Caller must be holding the manager lock.
*/
event = next_event) {
}
}
static void
int i;
for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
requestmgr->magic = 0;
}
static unsigned int
/*
* Locked by caller.
*/
requestmgr->hash++;
}
static inline isc_result_t
isc_region_t r;
/*
* We could connect the socket when we are using an exclusive dispatch
* as we do in resolver.c, but we prefer implementation simplicity
* at this moment.
*/
} else {
}
sendevent, 0);
if (result == ISC_R_SUCCESS)
return (result);
}
static isc_result_t
{
return (ISC_R_NOMEMORY);
/*
* Zero structure.
*/
return (ISC_R_SUCCESS);
}
static isc_boolean_t
int match;
char netaddrstr[ISC_NETADDR_FORMATSIZE];
match > 0)
}
if (drop) {
}
return (drop);
}
static isc_result_t
{
unsigned int attrs;
if (result == ISC_R_SUCCESS) {
char peer[ISC_SOCKADDR_FORMATSIZE];
"connection to %s", peer);
return (result);
}
if (result != ISC_R_SUCCESS)
return (result);
#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
} else {
isc_sockaddr_setport(&src, 0);
}
if (result != ISC_R_SUCCESS)
goto cleanup;
#endif
attrs = 0;
else
4096, 32768, 32768, 16411, 16433,
return (result);
}
static isc_result_t
{
switch (isc_sockaddr_pf(destaddr)) {
case PF_INET:
break;
case PF_INET6:
break;
default:
return (ISC_R_NOTIMPLEMENTED);
}
return (ISC_R_FAMILYNOSUPPORT);
return (ISC_R_SUCCESS);
}
attrs = 0;
switch (isc_sockaddr_pf(srcaddr)) {
case PF_INET:
break;
case PF_INET6:
break;
default:
return (ISC_R_NOTIMPLEMENTED);
}
attrmask = 0;
srcaddr, 4096,
32768, 32768, 16411, 16433,
dispatchp));
}
static isc_result_t
{
if (tcp)
else
return (result);
}
static isc_result_t
if (result == ISC_R_SUCCESS)
return (result);
}
{
}
{
unsigned int udpretries = 0;
if (udptimeout != 0)
requestp));
}
unsigned int udptimeout, unsigned int udpretries,
{
requestp));
}
unsigned int timeout, unsigned int udptimeout,
{
isc_region_t r;
return (DNS_R_BLACKHOLED);
if (result != ISC_R_SUCCESS)
return (result);
if (udptimeout == 0 && udpretries != 0) {
if (udptimeout == 0)
udptimeout = 1;
}
/*
* Create timer now. We will set it below once.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
goto cleanup;
}
isc_buffer_usedregion(msgbuf, &r);
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (tcp)
if (result != ISC_R_SUCCESS)
goto cleanup;
/* Add message ID. */
if (tcp)
isc_region_consume(&r, 2);
if (requestmgr->exiting) {
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto unlink;
if (result != ISC_R_SUCCESS)
goto unlink;
} else {
if (result != ISC_R_SUCCESS)
goto unlink;
}
request);
return (ISC_R_SUCCESS);
return (result);
}
{
}
{
}
unsigned int timeout, unsigned int udptimeout,
{
unsigned int udpretries = 0;
if (udptimeout != 0)
requestp));
}
unsigned int timeout, unsigned int udptimeout,
{
requestp));
}
unsigned int udptimeout, unsigned int udpretries,
{
return (ISC_R_FAMILYMISMATCH);
return (DNS_R_BLACKHOLED);
if (result != ISC_R_SUCCESS)
return (result);
if (udptimeout == 0 && udpretries != 0) {
if (udptimeout == 0)
udptimeout = 1;
}
/*
* Create timer now. We will set it below once.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (setkey) {
if (result != ISC_R_SUCCESS)
goto cleanup;
}
if (result == DNS_R_USETCP &&
(options & DNS_REQUESTOPT_TCP) == 0) {
/*
* Try again using TCP.
*/
goto use_tcp;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (requestmgr->exiting) {
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto unlink;
if (result != ISC_R_SUCCESS)
goto unlink;
} else {
if (result != ISC_R_SUCCESS)
goto unlink;
}
request);
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
{
isc_region_t r;
/*
* Create buffer able to hold largest possible message.
*/
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if ((options & DNS_REQUESTOPT_CASE) != 0)
/*
* Render message.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Copy rendered message to exact sized buffer.
*/
isc_buffer_usedregion(buf1, &r);
if ((options & DNS_REQUESTOPT_TCP) != 0) {
} else if (r.length > 512) {
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
if (tcp)
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* Cleanup and return.
*/
return (ISC_R_SUCCESS);
if (cleanup_cctx)
return (result);
}
/*
* If this request is no longer waiting for events,
* send the completion event. This will ultimately
* cause the request to be destroyed.
*
* Requires:
* 'request' is locked by the caller.
*/
static void
}
/*
* Handle the control event.
*/
static void
if (!DNS_REQUEST_CANCELED(request))
}
void
}
}
unsigned int options)
{
request);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
return (result);
return (result);
}
}
void
/*
* These should have been cleaned up by req_cancel() before
* the completion event was sent.
*/
}
/***
*** Private: request.
***/
static isc_socket_t *
unsigned int dispattr;
if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
} else
return (socket);
}
static void
if (DNS_REQUEST_CANCELED(request)) {
/*
* Send delayed event.
*/
if (DNS_REQUEST_TIMEDOUT(request))
else
} else {
if (result == ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
}
}
}
static void
if (DNS_REQUEST_CANCELED(request)) {
/*
* Send delayed event.
*/
if (DNS_REQUEST_TIMEDOUT(request))
else
}
}
static void
isc_region_t r;
if (result != ISC_R_SUCCESS)
goto done;
/*
* Copy buffer to request.
*/
r.length);
if (result != ISC_R_SUCCESS)
goto done;
if (result != ISC_R_SUCCESS)
done:
/*
* Cleanup.
*/
/*
* Send completion event.
*/
}
static void
if (! DNS_REQUEST_SENDING(request)) {
if (result != ISC_R_SUCCESS) {
}
}
} else {
}
}
static void
/*
* Lock held by caller.
*/
}
static void
}
/*
* Stop the current request. Must be called from the request's task.
*/
static void
unsigned int dispattr;
/*
* Lock held by caller.
*/
if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
}
} else
}
}
static void
}