ntp_intres.c (302408) | ntp_intres.c (309007) |
---|---|
1/* 2 * ntp_intres.c - Implements a generic blocking worker child or thread, 3 * initially to provide a nonblocking solution for DNS 4 * name to address lookups available with getaddrinfo(). 5 * 6 * This is a new implementation as of 2009 sharing the filename and 7 * very little else with the prior implementation, which used a 8 * temporary file to receive a single set of requests from the parent, --- 104 unchanged lines hidden (view full) --- 113 * parameters into a request blob which is processed in the child by 114 * the second routine, blocking_*(), which serializes the results into 115 * a response blob unpacked by the third routine, *_complete(), which 116 * calls the callback routine provided with the request and frees 117 * _request_ memory allocated by the first routine. Response memory 118 * is managed by the code which calls the *_complete routines. 119 */ 120 | 1/* 2 * ntp_intres.c - Implements a generic blocking worker child or thread, 3 * initially to provide a nonblocking solution for DNS 4 * name to address lookups available with getaddrinfo(). 5 * 6 * This is a new implementation as of 2009 sharing the filename and 7 * very little else with the prior implementation, which used a 8 * temporary file to receive a single set of requests from the parent, --- 104 unchanged lines hidden (view full) --- 113 * parameters into a request blob which is processed in the child by 114 * the second routine, blocking_*(), which serializes the results into 115 * a response blob unpacked by the third routine, *_complete(), which 116 * calls the callback routine provided with the request and frees 117 * _request_ memory allocated by the first routine. Response memory 118 * is managed by the code which calls the *_complete routines. 119 */ 120 |
121 |
|
121/* === typedefs === */ 122typedef struct blocking_gai_req_tag { /* marshalled args */ 123 size_t octets; 124 u_int dns_idx; 125 time_t scheduled; 126 time_t earliest; | 122/* === typedefs === */ 123typedef struct blocking_gai_req_tag { /* marshalled args */ 124 size_t octets; 125 u_int dns_idx; 126 time_t scheduled; 127 time_t earliest; |
127 struct addrinfo hints; | |
128 int retry; | 128 int retry; |
129 struct addrinfo hints; 130 u_int qflags; |
|
129 gai_sometime_callback callback; 130 void * context; 131 size_t nodesize; 132 size_t servsize; 133} blocking_gai_req; 134 135typedef struct blocking_gai_resp_tag { 136 size_t octets; --- 63 unchanged lines hidden (view full) --- 200 201/* === forward declarations === */ 202static u_int reserve_dnschild_ctx(void); 203static u_int get_dnschild_ctx(void); 204static dnsworker_ctx * get_worker_context(blocking_child *, u_int); 205static void scheduled_sleep(time_t, time_t, 206 dnsworker_ctx *); 207static void manage_dns_retry_interval(time_t *, time_t *, | 131 gai_sometime_callback callback; 132 void * context; 133 size_t nodesize; 134 size_t servsize; 135} blocking_gai_req; 136 137typedef struct blocking_gai_resp_tag { 138 size_t octets; --- 63 unchanged lines hidden (view full) --- 202 203/* === forward declarations === */ 204static u_int reserve_dnschild_ctx(void); 205static u_int get_dnschild_ctx(void); 206static dnsworker_ctx * get_worker_context(blocking_child *, u_int); 207static void scheduled_sleep(time_t, time_t, 208 dnsworker_ctx *); 209static void manage_dns_retry_interval(time_t *, time_t *, |
208 int *, 209 time_t *); | 210 int *, time_t *, 211 int/*BOOL*/); |
210static int should_retry_dns(int, int); 211#ifdef HAVE_RES_INIT 212static void reload_resolv_conf(dnsworker_ctx *); 213#else 214# define reload_resolv_conf(wc) \ 215 do { \ 216 (void)(wc); \ 217 } while (FALSE) --- 7 unchanged lines hidden (view full) --- 225 226 227/* === functions === */ 228/* 229 * getaddrinfo_sometime - uses blocking child to call getaddrinfo then 230 * invokes provided callback completion function. 231 */ 232int | 212static int should_retry_dns(int, int); 213#ifdef HAVE_RES_INIT 214static void reload_resolv_conf(dnsworker_ctx *); 215#else 216# define reload_resolv_conf(wc) \ 217 do { \ 218 (void)(wc); \ 219 } while (FALSE) --- 7 unchanged lines hidden (view full) --- 227 228 229/* === functions === */ 230/* 231 * getaddrinfo_sometime - uses blocking child to call getaddrinfo then 232 * invokes provided callback completion function. 233 */ 234int |
233getaddrinfo_sometime( | 235getaddrinfo_sometime_ex( |
234 const char * node, 235 const char * service, 236 const struct addrinfo * hints, 237 int retry, 238 gai_sometime_callback callback, | 236 const char * node, 237 const char * service, 238 const struct addrinfo * hints, 239 int retry, 240 gai_sometime_callback callback, |
239 void * context | 241 void * context, 242 u_int qflags |
240 ) 241{ 242 blocking_gai_req * gai_req; 243 u_int idx; 244 dnschild_ctx * child_ctx; 245 size_t req_size; 246 size_t nodesize; 247 size_t servsize; --- 24 unchanged lines hidden (view full) --- 272 child_ctx->next_dns_timeslot = gai_req->earliest; 273 if (hints != NULL) 274 gai_req->hints = *hints; 275 gai_req->retry = retry; 276 gai_req->callback = callback; 277 gai_req->context = context; 278 gai_req->nodesize = nodesize; 279 gai_req->servsize = servsize; | 243 ) 244{ 245 blocking_gai_req * gai_req; 246 u_int idx; 247 dnschild_ctx * child_ctx; 248 size_t req_size; 249 size_t nodesize; 250 size_t servsize; --- 24 unchanged lines hidden (view full) --- 275 child_ctx->next_dns_timeslot = gai_req->earliest; 276 if (hints != NULL) 277 gai_req->hints = *hints; 278 gai_req->retry = retry; 279 gai_req->callback = callback; 280 gai_req->context = context; 281 gai_req->nodesize = nodesize; 282 gai_req->servsize = servsize; |
283 gai_req->qflags = qflags; |
|
280 281 memcpy((char *)gai_req + sizeof(*gai_req), node, nodesize); 282 memcpy((char *)gai_req + sizeof(*gai_req) + nodesize, service, 283 servsize); 284 285 if (queue_blocking_request( 286 BLOCKING_GETADDRINFO, 287 gai_req, --- 158 unchanged lines hidden (view full) --- 446 if (queue_blocking_response(c, resp, resp_octets, req)) { 447 msyslog(LOG_ERR, "blocking_getaddrinfo can not queue response"); 448 return -1; 449 } 450 451 return 0; 452} 453 | 284 285 memcpy((char *)gai_req + sizeof(*gai_req), node, nodesize); 286 memcpy((char *)gai_req + sizeof(*gai_req) + nodesize, service, 287 servsize); 288 289 if (queue_blocking_request( 290 BLOCKING_GETADDRINFO, 291 gai_req, --- 158 unchanged lines hidden (view full) --- 450 if (queue_blocking_response(c, resp, resp_octets, req)) { 451 msyslog(LOG_ERR, "blocking_getaddrinfo can not queue response"); 452 return -1; 453 } 454 455 return 0; 456} 457 |
458int 459getaddrinfo_sometime( 460 const char * node, 461 const char * service, 462 const struct addrinfo * hints, 463 int retry, 464 gai_sometime_callback callback, 465 void * context 466 ) 467{ 468 return getaddrinfo_sometime_ex(node, service, hints, retry, 469 callback, context, 0); 470} |
|
454 | 471 |
472 |
|
455static void 456getaddrinfo_sometime_complete( 457 blocking_work_req rtype, 458 void * context, 459 size_t respsize, 460 void * resp 461 ) 462{ 463 blocking_gai_req * gai_req; 464 blocking_gai_resp * gai_resp; 465 dnschild_ctx * child_ctx; 466 struct addrinfo * ai; 467 struct addrinfo * next_ai; 468 sockaddr_u * psau; 469 char * node; 470 char * service; 471 char * canon_start; 472 time_t time_now; | 473static void 474getaddrinfo_sometime_complete( 475 blocking_work_req rtype, 476 void * context, 477 size_t respsize, 478 void * resp 479 ) 480{ 481 blocking_gai_req * gai_req; 482 blocking_gai_resp * gai_resp; 483 dnschild_ctx * child_ctx; 484 struct addrinfo * ai; 485 struct addrinfo * next_ai; 486 sockaddr_u * psau; 487 char * node; 488 char * service; 489 char * canon_start; 490 time_t time_now; |
473 int again; | 491 int again, noerr; |
474 int af; 475 const char * fam_spec; 476 int i; 477 478 gai_req = context; 479 gai_resp = resp; 480 481 DEBUG_REQUIRE(BLOCKING_GETADDRINFO == rtype); --- 11 unchanged lines hidden (view full) --- 493 */ 494 if (gai_resp->retry > INITIAL_DNS_RETRY) { 495 time_now = time(NULL); 496 child_ctx->next_dns_timeslot = time_now; 497 TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n", 498 gai_req->dns_idx, humantime(time_now))); 499 } 500 } else { | 492 int af; 493 const char * fam_spec; 494 int i; 495 496 gai_req = context; 497 gai_resp = resp; 498 499 DEBUG_REQUIRE(BLOCKING_GETADDRINFO == rtype); --- 11 unchanged lines hidden (view full) --- 511 */ 512 if (gai_resp->retry > INITIAL_DNS_RETRY) { 513 time_now = time(NULL); 514 child_ctx->next_dns_timeslot = time_now; 515 TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n", 516 gai_req->dns_idx, humantime(time_now))); 517 } 518 } else { |
501 again = should_retry_dns(gai_resp->retcode, 502 gai_resp->gai_errno); | 519 noerr = !!(gai_req->qflags & GAIR_F_IGNDNSERR); 520 again = noerr || should_retry_dns( 521 gai_resp->retcode, gai_resp->gai_errno); |
503 /* 504 * exponential backoff of DNS retries to 64s 505 */ 506 if (gai_req->retry > 0 && again) { 507 /* log the first retry only */ 508 if (INITIAL_DNS_RETRY == gai_req->retry) 509 NLOG(NLOG_SYSINFO) { 510 af = gai_req->hints.ai_family; --- 12 unchanged lines hidden (view full) --- 523 } else 524#endif 525 msyslog(LOG_INFO, 526 "retrying DNS %s%s: %s (%d)", 527 node, fam_spec, 528 gai_strerror(gai_resp->retcode), 529 gai_resp->retcode); 530 } | 522 /* 523 * exponential backoff of DNS retries to 64s 524 */ 525 if (gai_req->retry > 0 && again) { 526 /* log the first retry only */ 527 if (INITIAL_DNS_RETRY == gai_req->retry) 528 NLOG(NLOG_SYSINFO) { 529 af = gai_req->hints.ai_family; --- 12 unchanged lines hidden (view full) --- 542 } else 543#endif 544 msyslog(LOG_INFO, 545 "retrying DNS %s%s: %s (%d)", 546 node, fam_spec, 547 gai_strerror(gai_resp->retcode), 548 gai_resp->retcode); 549 } |
531 manage_dns_retry_interval(&gai_req->scheduled, 532 &gai_req->earliest, &gai_req->retry, 533 &child_ctx->next_dns_timeslot); | 550 manage_dns_retry_interval( 551 &gai_req->scheduled, &gai_req->earliest, 552 &gai_req->retry, &child_ctx->next_dns_timeslot, 553 noerr); |
534 if (!queue_blocking_request( 535 BLOCKING_GETADDRINFO, 536 gai_req, 537 gai_req->octets, 538 &getaddrinfo_sometime_complete, 539 gai_req)) 540 return; 541 else --- 279 unchanged lines hidden (view full) --- 821 } else { 822 again = should_retry_dns(gni_resp->retcode, gni_resp->gni_errno); 823 /* 824 * exponential backoff of DNS retries to 64s 825 */ 826 if (gni_req->retry > 0) 827 manage_dns_retry_interval(&gni_req->scheduled, 828 &gni_req->earliest, &gni_req->retry, | 554 if (!queue_blocking_request( 555 BLOCKING_GETADDRINFO, 556 gai_req, 557 gai_req->octets, 558 &getaddrinfo_sometime_complete, 559 gai_req)) 560 return; 561 else --- 279 unchanged lines hidden (view full) --- 841 } else { 842 again = should_retry_dns(gni_resp->retcode, gni_resp->gni_errno); 843 /* 844 * exponential backoff of DNS retries to 64s 845 */ 846 if (gni_req->retry > 0) 847 manage_dns_retry_interval(&gni_req->scheduled, 848 &gni_req->earliest, &gni_req->retry, |
829 &child_ctx->next_dns_timeslot); | 849 &child_ctx->next_dns_timeslot, FALSE); |
830 831 if (gni_req->retry > 0 && again) { 832 if (!queue_blocking_request( 833 BLOCKING_GETNAMEINFO, 834 gni_req, 835 gni_req->octets, 836 &getnameinfo_sometime_complete, 837 gni_req)) --- 190 unchanged lines hidden (view full) --- 1028 * getaddrinfo_sometime_complete and getnameinfo_sometime_complete 1029 * to calculate the new retry interval and schedule the next query. 1030 */ 1031static void 1032manage_dns_retry_interval( 1033 time_t * pscheduled, 1034 time_t * pwhen, 1035 int * pretry, | 850 851 if (gni_req->retry > 0 && again) { 852 if (!queue_blocking_request( 853 BLOCKING_GETNAMEINFO, 854 gni_req, 855 gni_req->octets, 856 &getnameinfo_sometime_complete, 857 gni_req)) --- 190 unchanged lines hidden (view full) --- 1048 * getaddrinfo_sometime_complete and getnameinfo_sometime_complete 1049 * to calculate the new retry interval and schedule the next query. 1050 */ 1051static void 1052manage_dns_retry_interval( 1053 time_t * pscheduled, 1054 time_t * pwhen, 1055 int * pretry, |
1036 time_t * pnext_timeslot | 1056 time_t * pnext_timeslot, 1057 int forever |
1037 ) 1038{ 1039 time_t now; 1040 time_t when; 1041 int retry; | 1058 ) 1059{ 1060 time_t now; 1061 time_t when; 1062 int retry; |
1063 int retmax; |
|
1042 1043 now = time(NULL); 1044 retry = *pretry; 1045 when = max(now + retry, *pnext_timeslot); 1046 *pnext_timeslot = when; | 1064 1065 now = time(NULL); 1066 retry = *pretry; 1067 when = max(now + retry, *pnext_timeslot); 1068 *pnext_timeslot = when; |
1047 retry = min(64, retry << 1); | |
1048 | 1069 |
1070 /* this exponential backoff is slower than doubling up: The 1071 * sequence goes 2-3-4-6-8-12-16-24-32... and the upper limit is 1072 * 64 seconds for things that should not repeat forever, and 1073 * 1024 when repeated forever. 1074 */ 1075 retmax = forever ? 1024 : 64; 1076 retry <<= 1; 1077 if (retry & (retry - 1)) 1078 retry &= (retry - 1); 1079 else 1080 retry -= (retry >> 2); 1081 retry = min(retmax, retry); 1082 |
|
1049 *pscheduled = now; 1050 *pwhen = when; 1051 *pretry = retry; 1052} 1053 1054/* 1055 * should_retry_dns is a helper used by getaddrinfo_sometime_complete 1056 * and getnameinfo_sometime_complete which implements ntpd's DNS retry --- 64 unchanged lines hidden --- | 1083 *pscheduled = now; 1084 *pwhen = when; 1085 *pretry = retry; 1086} 1087 1088/* 1089 * should_retry_dns is a helper used by getaddrinfo_sometime_complete 1090 * and getnameinfo_sometime_complete which implements ntpd's DNS retry --- 64 unchanged lines hidden --- |