diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 4b6590e70b..0cdbc96d45 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsupdate.c,v 1.120 2002/08/06 03:21:59 marka Exp $ */ +/* $Id: nsupdate.c,v 1.121 2002/11/12 23:58:13 explorer Exp $ */ #include @@ -135,6 +135,9 @@ static isc_boolean_t interactive = ISC_TRUE; static isc_boolean_t seenerror = ISC_FALSE; static const dns_master_style_t *style; static int requests = 0; +static unsigned int timeout = 300; +static unsigned int udp_timeout = 3; +static unsigned int udp_retries = 3; typedef struct nsu_requestinfo { dns_message_t *msg; @@ -594,7 +597,8 @@ parse_args(int argc, char **argv) { isc_result_t result; debug("parse_args"); - while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:")) != -1) { + while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1) + { switch (ch) { case 'd': debugging = ISC_TRUE; @@ -619,6 +623,34 @@ parse_args(int argc, char **argv) { case 'k': keyfile = isc_commandline_argument; break; + case 't': + result = isc_parse_uint32(&timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); + exit(1); + } + if (timeout == 0) + timeout = ULONG_MAX; + break; + case 'u': + result = isc_parse_uint32(&udp_timeout, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); + exit(1); + } + if (udp_timeout == 0) + udp_timeout = ULONG_MAX; + break; + case 'r': + result = isc_parse_uint32(&udp_retries, + isc_commandline_argument, 10); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); + exit(1); + } + break; default: fprintf(stderr, "%s: invalid argument -%c\n", argv[0], ch); @@ -1022,8 +1054,8 @@ evaluate_key(char *cmdline) { if (tsigkey != NULL) dns_tsigkey_detach(&tsigkey); result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, - secret, secretlen, ISC_TRUE, NULL, 0, 0, - mctx, NULL, &tsigkey); + secret, secretlen, ISC_TRUE, NULL, 0, 0, + mctx, NULL, &tsigkey); isc_mem_free(mctx, secret); if (result != ISC_R_SUCCESS) { fprintf(stderr, "could not create key from %s %s: %s\n", @@ -1468,11 +1500,11 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master, isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); fprintf(stderr, "Sending update to %s\n", addrbuf); } - result = dns_request_createvia(requestmgr, updatemsg, srcaddr, - master, options, tsigkey, - FIND_TIMEOUT, global_task, - update_completed, NULL, &request); - check_result(result, "dns_request_createvia"); + result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, + master, options, tsigkey, timeout, + udp_timeout, udp_retries, global_task, + update_completed, NULL, &request); + check_result(result, "dns_request_createvia3"); if (debugging) show_message(updatemsg); @@ -1713,9 +1745,10 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, fatal("out of memory"); reqinfo->msg = msg; reqinfo->addr = destaddr; - result = dns_request_createvia(requestmgr, msg, srcaddr, destaddr, - 0, NULL, FIND_TIMEOUT, global_task, - recvsoa, reqinfo, request); + result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, + 0, NULL, FIND_TIMEOUT * 20, + FIND_TIMEOUT, 3, global_task, recvsoa, + reqinfo, request); check_result(result, "dns_request_createvia"); requests++; } diff --git a/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook index 680db2d144..7154400786 100644 --- a/bin/nsupdate/nsupdate.docbook +++ b/bin/nsupdate/nsupdate.docbook @@ -16,7 +16,7 @@ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --> - + @@ -39,6 +39,9 @@ + + + filename @@ -153,7 +156,8 @@ specified is not an HMAC-MD5 key. By default nsupdate -uses UDP to send update requests to the name server. +uses UDP to send update requests to the name server unless they are too +large to fit in a UDP request in which case TCP will be used. The option makes @@ -161,6 +165,17 @@ option makes use a TCP connection. This may be preferable when a batch of update requests is made. +The option sets the maximum time a update request can +take before it is aborted. The default is 300 seconds. Zero can be used +to disable the timeout. + +The option sets the UDP retry interval. The default is +3 seconds. If zero the interval will be computed from the timeout interval +and number of UDP retries. + +The option sets the number of UDP retries. The default is +3. If zero only one update request will be made. + diff --git a/doc/private/branches b/doc/private/branches index d9ff560ed8..fc66a25262 100644 --- a/doc/private/branches +++ b/doc/private/branches @@ -11,7 +11,7 @@ rt3892 closed explorer rt4090 closed explorer rt4112 closed explorer adb_race review explorer -rt4319 review explorer +rt4319 closed explorer rt3907 closed explorer rt3507 closed ogud (pull down by explorer) v6source diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index ebd491f68d..97ca238392 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.h,v 1.19 2001/11/30 01:59:27 gson Exp $ */ +/* $Id: request.h,v 1.20 2002/11/12 23:58:14 explorer Exp $ */ #ifndef DNS_REQUEST_H #define DNS_REQUEST_H 1 @@ -204,9 +204,18 @@ isc_result_t dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, unsigned int options, dns_tsigkey_t *key, - unsigned int timeout, unsigned int udpretry, + unsigned int timeout, unsigned int udptimeout, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); + +isc_result_t +dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + unsigned int options, dns_tsigkey_t *key, + unsigned int timeout, unsigned int udptimeout, + unsigned int udpretries, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp); /* * Create and send a request. * @@ -215,7 +224,7 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, * 'message' will be rendered and sent to 'address'. If the * DNS_REQUESTOPT_TCP option is set, TCP will be used. The request * will timeout after 'timeout' seconds. UDP requests will be resent - * at 'udpretry' intervals if non-zero. + * at 'udptimeout' intervals if non-zero or 'udpretries' is non-zero. * * When the request completes, successfully, due to a timeout, or * because it was canceled, a completion event will be sent to 'task'. @@ -248,9 +257,17 @@ isc_result_t dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, unsigned int options, unsigned int timeout, - unsigned int udpretry, isc_task_t *task, + unsigned int udptimeout, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); + +isc_result_t +dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + unsigned int options, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_request_t **requestp); /* * Create and send a request. * @@ -259,8 +276,8 @@ dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, * 'msgbuf' will be sent to 'destaddr' after setting the id. If the * DNS_REQUESTOPT_TCP option is set, TCP will be used. The request * will timeout after 'timeout' seconds. UDP requests will be resent - * at 'udpretry' intervals if non-zero. - * + * at 'udptimeout' intervals if non-zero or if 'udpretries' is not zero. + * * When the request completes, successfully, due to a timeout, or * because it was canceled, a completion event will be sent to 'task'. * diff --git a/lib/dns/request.c b/lib/dns/request.c index 4cf4b43442..fe9031562a 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.c,v 1.70 2001/11/30 01:59:16 gson Exp $ */ +/* $Id: request.c,v 1.71 2002/11/12 23:58:14 explorer Exp $ */ #include @@ -86,6 +86,7 @@ struct dns_request { isc_event_t ctlevent; isc_boolean_t canceling; /* ctlevent outstanding */ isc_sockaddr_t destaddr; + unsigned int udpcount; }; #define DNS_REQUEST_F_CONNECTING 0x0001 @@ -463,6 +464,7 @@ new_request(isc_mem_t *mctx, dns_request_t **requestp) { DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, NULL); request->canceling = ISC_FALSE; + request->udpcount = 0; isc_mem_attach(mctx, &request->mctx); @@ -631,17 +633,37 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return(dns_request_createraw2(requestmgr, msgbuf, srcaddr, destaddr, - options, timeout, 0, task, action, arg, - requestp)); + return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr, + options, timeout, 0, 0, task, action, + arg, requestp)); } isc_result_t dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, - unsigned int options, unsigned int timeout, unsigned int udpretry, isc_task_t *task, + unsigned int options, unsigned int timeout, + unsigned int udptimeout, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) +{ + unsigned int udpretries = 0; + + if (udptimeout != 0) + udpretries = timeout / udptimeout; + + return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr, + options, timeout, udptimeout, + udpretries, task, action, arg, + requestp)); +} + +isc_result_t +dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + unsigned int options, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; @@ -674,6 +696,12 @@ dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if (result != ISC_R_SUCCESS) return (result); + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + if (udptimeout == 0) + udptimeout = 1; + } + /* * Create timer now. We will set it below once. */ @@ -745,7 +773,7 @@ dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udpretry); + result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); if (result != ISC_R_SUCCESS) goto unlink; @@ -789,9 +817,9 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return (dns_request_createvia2(requestmgr, message, NULL, address, - options, key, timeout, 0, task, action, - arg, requestp)); + return (dns_request_createvia3(requestmgr, message, NULL, address, + options, key, timeout, 0, 0, task, + action, arg, requestp)); } isc_result_t @@ -802,18 +830,37 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return(dns_request_createvia2(requestmgr, message, srcaddr, destaddr, - options, key, timeout, 0, task, action, - arg, requestp)); + return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr, + options, key, timeout, 0, 0, task, + action, arg, requestp)); } isc_result_t dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, unsigned int options, dns_tsigkey_t *key, - unsigned int timeout, unsigned int udpretry, + unsigned int timeout, unsigned int udptimeout, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) +{ + unsigned int udpretries = 0; + + if (udptimeout != 0) + udpretries = timeout / udptimeout; + return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr, + options, key, timeout, udptimeout, + udpretries, task, action, arg, + requestp)); +} + +isc_result_t +dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + unsigned int options, dns_tsigkey_t *key, + unsigned int timeout, unsigned int udptimeout, + unsigned int udpretries, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; @@ -846,6 +893,12 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, if (result != ISC_R_SUCCESS) return (result); + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + if (udptimeout == 0) + udptimeout = 1; + } + /* * Create timer now. We will set it below once. */ @@ -922,7 +975,7 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udpretry); + result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); if (result != ISC_R_SUCCESS) goto unlink; @@ -1293,7 +1346,8 @@ req_timeout(isc_task_t *task, isc_event_t *event) { UNUSED(task); LOCK(&request->requestmgr->locks[request->hash]); - if (event->ev_type == ISC_TIMEREVENT_TICK) { + if (event->ev_type == ISC_TIMEREVENT_TICK && + request->udpcount-- != 0) { if (! DNS_REQUEST_SENDING(request)) { result = req_send(request, task, &request->destaddr); if (result != ISC_R_SUCCESS) {