host_resolver.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/io/event_loop.h>
  6. #include <aws/io/host_resolver.h>
  7. #include <aws/common/atomics.h>
  8. #include <aws/common/clock.h>
  9. #include <aws/common/condition_variable.h>
  10. #include <aws/common/hash_table.h>
  11. #include <aws/common/lru_cache.h>
  12. #include <aws/common/mutex.h>
  13. #include <aws/common/string.h>
  14. #include <aws/common/task_scheduler.h>
  15. #include <aws/common/thread.h>
  16. #include <aws/io/logging.h>
  17. #include <inttypes.h>
  18. const uint64_t NS_PER_SEC = 1000000000;
  19. const size_t AWS_DEFAULT_DNS_TTL = 30;
  20. int aws_host_address_copy(const struct aws_host_address *from, struct aws_host_address *to) {
  21. to->allocator = from->allocator;
  22. to->address = aws_string_new_from_string(to->allocator, from->address);
  23. to->host = aws_string_new_from_string(to->allocator, from->host);
  24. to->record_type = from->record_type;
  25. to->use_count = from->use_count;
  26. to->connection_failure_count = from->connection_failure_count;
  27. to->expiry = from->expiry;
  28. to->weight = from->weight;
  29. return AWS_OP_SUCCESS;
  30. }
  31. void aws_host_address_move(struct aws_host_address *from, struct aws_host_address *to) {
  32. to->allocator = from->allocator;
  33. to->address = from->address;
  34. to->host = from->host;
  35. to->record_type = from->record_type;
  36. to->use_count = from->use_count;
  37. to->connection_failure_count = from->connection_failure_count;
  38. to->expiry = from->expiry;
  39. to->weight = from->weight;
  40. AWS_ZERO_STRUCT(*from);
  41. }
  42. void aws_host_address_clean_up(struct aws_host_address *address) {
  43. if (address->address) {
  44. aws_string_destroy((void *)address->address);
  45. }
  46. if (address->host) {
  47. aws_string_destroy((void *)address->host);
  48. }
  49. AWS_ZERO_STRUCT(*address);
  50. }
  51. int aws_host_resolver_resolve_host(
  52. struct aws_host_resolver *resolver,
  53. const struct aws_string *host_name,
  54. aws_on_host_resolved_result_fn *res,
  55. const struct aws_host_resolution_config *config,
  56. void *user_data) {
  57. AWS_ASSERT(resolver->vtable && resolver->vtable->resolve_host);
  58. return resolver->vtable->resolve_host(resolver, host_name, res, config, user_data);
  59. }
  60. int aws_host_resolver_purge_cache(struct aws_host_resolver *resolver) {
  61. AWS_ASSERT(resolver->vtable && resolver->vtable->purge_cache);
  62. return resolver->vtable->purge_cache(resolver);
  63. }
  64. int aws_host_resolver_purge_cache_with_callback(
  65. struct aws_host_resolver *resolver,
  66. aws_simple_completion_callback *on_purge_cache_complete_callback,
  67. void *user_data) {
  68. AWS_PRECONDITION(resolver);
  69. AWS_PRECONDITION(resolver->vtable);
  70. if (!resolver->vtable->purge_cache_with_callback) {
  71. AWS_LOGF_ERROR(AWS_LS_IO_DNS, "purge_cache_with_callback function is not supported");
  72. return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
  73. }
  74. return resolver->vtable->purge_cache_with_callback(resolver, on_purge_cache_complete_callback, user_data);
  75. }
  76. int aws_host_resolver_purge_host_cache(
  77. struct aws_host_resolver *resolver,
  78. const struct aws_host_resolver_purge_host_options *options) {
  79. AWS_PRECONDITION(resolver);
  80. AWS_PRECONDITION(resolver->vtable);
  81. if (!resolver->vtable->purge_host_cache) {
  82. AWS_LOGF_ERROR(AWS_LS_IO_DNS, "purge_host_cache function is not supported");
  83. return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
  84. }
  85. return resolver->vtable->purge_host_cache(resolver, options);
  86. }
  87. int aws_host_resolver_record_connection_failure(
  88. struct aws_host_resolver *resolver,
  89. const struct aws_host_address *address) {
  90. AWS_ASSERT(resolver->vtable && resolver->vtable->record_connection_failure);
  91. return resolver->vtable->record_connection_failure(resolver, address);
  92. }
  93. /*
  94. * Used by both the resolver for its lifetime state as well as individual host entries for theirs.
  95. */
  96. enum default_resolver_state {
  97. DRS_ACTIVE,
  98. DRS_SHUTTING_DOWN,
  99. };
  100. struct default_host_resolver {
  101. struct aws_allocator *allocator;
  102. /*
  103. * Mutually exclusion for the whole resolver, includes all member data and all host_entry_table operations. Once
  104. * an entry is retrieved, this lock MAY be dropped but certain logic may hold both the resolver and the entry lock.
  105. * The two locks must be taken in that order.
  106. */
  107. struct aws_mutex resolver_lock;
  108. /* host_name (aws_string*) -> host_entry* */
  109. struct aws_hash_table host_entry_table;
  110. /* Hash table of listener entries per host name. We keep this decoupled from the host entry table to allow for
  111. * listeners to be added/removed regardless of whether or not a corresponding host entry exists.
  112. *
  113. * Any time the listener list in the listener entry becomes empty, we remove the entry from the table. This
  114. * includes when a resolver thread moves all of the available listeners to its local list.
  115. */
  116. /* host_name (aws_string*) -> host_listener_entry* */
  117. struct aws_hash_table listener_entry_table;
  118. enum default_resolver_state state;
  119. /*
  120. * Tracks the number of launched resolution threads that have not yet invoked their shutdown completion
  121. * callback.
  122. */
  123. uint32_t pending_host_entry_shutdown_completion_callbacks;
  124. /*
  125. * Function to use to query current time. Overridable in construction options.
  126. */
  127. aws_io_clock_fn *system_clock_fn;
  128. struct aws_event_loop_group *event_loop_group;
  129. };
  130. struct host_entry {
  131. /* immutable post-creation */
  132. struct aws_allocator *allocator;
  133. struct aws_host_resolver *resolver;
  134. struct aws_thread resolver_thread;
  135. const struct aws_string *host_name;
  136. int64_t resolve_frequency_ns;
  137. struct aws_host_resolution_config resolution_config;
  138. /* synchronized data and its lock */
  139. struct aws_mutex entry_lock;
  140. struct aws_condition_variable entry_signal;
  141. struct aws_cache *aaaa_records;
  142. struct aws_cache *a_records;
  143. struct aws_cache *failed_connection_aaaa_records;
  144. struct aws_cache *failed_connection_a_records;
  145. struct aws_linked_list pending_resolution_callbacks;
  146. uint32_t resolves_since_last_request;
  147. uint64_t last_resolve_request_timestamp_ns;
  148. enum default_resolver_state state;
  149. struct aws_array_list new_addresses;
  150. struct aws_array_list expired_addresses;
  151. aws_simple_completion_callback *on_host_purge_complete;
  152. void *on_host_purge_complete_user_data;
  153. };
  154. /*
  155. * A host entry's caches hold things of this type. By using this and not the host_address directly, our
  156. * on_remove callbacks for the cache have access to the host_entry. We wouldn't need to do this if those
  157. * callbacks supported user data injection, but they don't and too many internal code bases already depend
  158. * on the public API.
  159. */
  160. struct aws_host_address_cache_entry {
  161. struct aws_host_address address;
  162. struct host_entry *entry;
  163. };
  164. int aws_host_address_cache_entry_copy(
  165. const struct aws_host_address_cache_entry *from,
  166. struct aws_host_address_cache_entry *to) {
  167. if (aws_host_address_copy(&from->address, &to->address)) {
  168. return AWS_OP_ERR;
  169. }
  170. to->entry = from->entry;
  171. return AWS_OP_SUCCESS;
  172. }
  173. static void s_shutdown_host_entry(struct host_entry *entry) {
  174. aws_mutex_lock(&entry->entry_lock);
  175. entry->state = DRS_SHUTTING_DOWN;
  176. /*
  177. * intentionally signal under the lock; we can't guarantee the resolver
  178. * is still around once the lock is released.
  179. */
  180. aws_condition_variable_notify_all(&entry->entry_signal);
  181. aws_mutex_unlock(&entry->entry_lock);
  182. }
  183. struct host_purge_callback_options {
  184. struct aws_allocator *allocator;
  185. struct aws_ref_count ref_count;
  186. aws_simple_completion_callback *on_purge_cache_complete_callback;
  187. void *user_data;
  188. };
  189. static void s_host_purge_callback_options_destroy(void *user_data) {
  190. struct host_purge_callback_options *options = user_data;
  191. options->on_purge_cache_complete_callback(options->user_data);
  192. aws_mem_release(options->allocator, options);
  193. }
  194. static struct host_purge_callback_options *s_host_purge_callback_options_new(
  195. struct aws_allocator *allocator,
  196. aws_simple_completion_callback *on_purge_cache_complete_callback,
  197. void *user_data) {
  198. struct host_purge_callback_options *purge_callback_options =
  199. aws_mem_calloc(allocator, 1, sizeof(struct host_purge_callback_options));
  200. purge_callback_options->allocator = allocator;
  201. aws_ref_count_init(
  202. &purge_callback_options->ref_count, purge_callback_options, s_host_purge_callback_options_destroy);
  203. purge_callback_options->on_purge_cache_complete_callback = on_purge_cache_complete_callback;
  204. purge_callback_options->user_data = user_data;
  205. return purge_callback_options;
  206. }
  207. static void s_purge_cache_callback(void *user_data) {
  208. struct host_purge_callback_options *purge_callback_options = user_data;
  209. aws_ref_count_release(&purge_callback_options->ref_count);
  210. }
  211. /*
  212. * resolver lock must be held before calling this function
  213. */
  214. static void s_clear_default_resolver_entry_table_synced(struct default_host_resolver *resolver) {
  215. struct aws_hash_table *table = &resolver->host_entry_table;
  216. for (struct aws_hash_iter iter = aws_hash_iter_begin(table); !aws_hash_iter_done(&iter);
  217. aws_hash_iter_next(&iter)) {
  218. struct host_entry *entry = iter.element.value;
  219. s_shutdown_host_entry(entry);
  220. }
  221. aws_hash_table_clear(table);
  222. }
  223. static int s_resolver_purge_cache(struct aws_host_resolver *resolver) {
  224. struct default_host_resolver *default_host_resolver = resolver->impl;
  225. aws_mutex_lock(&default_host_resolver->resolver_lock);
  226. s_clear_default_resolver_entry_table_synced(default_host_resolver);
  227. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  228. return AWS_OP_SUCCESS;
  229. }
  230. static void s_purge_host_cache_callback_task(struct aws_task *task, void *arg, enum aws_task_status status) {
  231. (void)status;
  232. struct host_purge_callback_options *options = arg;
  233. aws_mem_release(options->allocator, task);
  234. aws_ref_count_release(&options->ref_count);
  235. }
  236. static void s_sechdule_purge_cache_callback_async(
  237. struct default_host_resolver *default_host_resolver,
  238. struct host_purge_callback_options *purge_callback_options) {
  239. struct aws_task *task = aws_mem_calloc(default_host_resolver->allocator, 1, sizeof(struct aws_task));
  240. aws_task_init(task, s_purge_host_cache_callback_task, purge_callback_options, "async_purge_host_callback_task");
  241. struct aws_event_loop *loop = aws_event_loop_group_get_next_loop(default_host_resolver->event_loop_group);
  242. AWS_FATAL_ASSERT(loop != NULL);
  243. aws_event_loop_schedule_task_now(loop, task);
  244. }
  245. static int s_resolver_purge_cache_with_callback(
  246. struct aws_host_resolver *resolver,
  247. aws_simple_completion_callback *on_purge_cache_complete_callback,
  248. void *user_data) {
  249. if (!on_purge_cache_complete_callback) {
  250. return s_resolver_purge_cache(resolver);
  251. }
  252. struct default_host_resolver *default_host_resolver = resolver->impl;
  253. aws_mutex_lock(&default_host_resolver->resolver_lock);
  254. struct aws_hash_table *table = &default_host_resolver->host_entry_table;
  255. struct host_purge_callback_options *purge_callback_options = s_host_purge_callback_options_new(
  256. default_host_resolver->allocator, on_purge_cache_complete_callback, user_data);
  257. /* purge all cache */
  258. for (struct aws_hash_iter iter = aws_hash_iter_begin(table); !aws_hash_iter_done(&iter);
  259. aws_hash_iter_next(&iter)) {
  260. struct host_entry *entry = iter.element.value;
  261. /* acquire a refernce to wait for the callback to trigger */
  262. aws_ref_count_acquire(&purge_callback_options->ref_count);
  263. aws_mutex_lock(&entry->entry_lock);
  264. entry->on_host_purge_complete = s_purge_cache_callback;
  265. entry->on_host_purge_complete_user_data = purge_callback_options;
  266. entry->state = DRS_SHUTTING_DOWN;
  267. aws_mutex_unlock(&entry->entry_lock);
  268. }
  269. aws_hash_table_clear(table);
  270. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  271. /* release the original reference async */
  272. s_sechdule_purge_cache_callback_async(default_host_resolver, purge_callback_options);
  273. return AWS_OP_SUCCESS;
  274. }
  275. static void s_cleanup_default_resolver(struct aws_host_resolver *resolver) {
  276. struct default_host_resolver *default_host_resolver = resolver->impl;
  277. aws_event_loop_group_release(default_host_resolver->event_loop_group);
  278. aws_hash_table_clean_up(&default_host_resolver->host_entry_table);
  279. aws_hash_table_clean_up(&default_host_resolver->listener_entry_table);
  280. aws_mutex_clean_up(&default_host_resolver->resolver_lock);
  281. aws_simple_completion_callback *shutdown_callback = resolver->shutdown_options.shutdown_callback_fn;
  282. void *shutdown_completion_user_data = resolver->shutdown_options.shutdown_callback_user_data;
  283. aws_mem_release(resolver->allocator, resolver);
  284. /* invoke shutdown completion finally */
  285. if (shutdown_callback != NULL) {
  286. shutdown_callback(shutdown_completion_user_data);
  287. }
  288. }
  289. static void resolver_destroy(struct aws_host_resolver *resolver) {
  290. struct default_host_resolver *default_host_resolver = resolver->impl;
  291. bool cleanup_resolver = false;
  292. aws_mutex_lock(&default_host_resolver->resolver_lock);
  293. AWS_FATAL_ASSERT(default_host_resolver->state == DRS_ACTIVE);
  294. s_clear_default_resolver_entry_table_synced(default_host_resolver);
  295. default_host_resolver->state = DRS_SHUTTING_DOWN;
  296. if (default_host_resolver->pending_host_entry_shutdown_completion_callbacks == 0) {
  297. cleanup_resolver = true;
  298. }
  299. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  300. if (cleanup_resolver) {
  301. s_cleanup_default_resolver(resolver);
  302. }
  303. }
  304. struct pending_callback {
  305. aws_on_host_resolved_result_fn *callback;
  306. void *user_data;
  307. struct aws_linked_list_node node;
  308. };
  309. static void s_clear_address_list(struct aws_array_list *address_list) {
  310. for (size_t i = 0; i < aws_array_list_length(address_list); ++i) {
  311. struct aws_host_address *address = NULL;
  312. aws_array_list_get_at_ptr(address_list, (void **)&address, i);
  313. aws_host_address_clean_up(address);
  314. }
  315. aws_array_list_clear(address_list);
  316. }
  317. static void s_clean_up_host_entry(struct host_entry *entry) {
  318. if (entry == NULL) {
  319. return;
  320. }
  321. /*
  322. * This can happen if the resolver's final reference drops while an unanswered query is pending on an entry.
  323. *
  324. * You could add an assertion that the resolver is in the shut down state if this condition hits but that
  325. * requires additional locking just to make the assert.
  326. */
  327. if (!aws_linked_list_empty(&entry->pending_resolution_callbacks)) {
  328. aws_raise_error(AWS_IO_DNS_HOST_REMOVED_FROM_CACHE);
  329. }
  330. while (!aws_linked_list_empty(&entry->pending_resolution_callbacks)) {
  331. struct aws_linked_list_node *resolution_callback_node =
  332. aws_linked_list_pop_front(&entry->pending_resolution_callbacks);
  333. struct pending_callback *pending_callback =
  334. AWS_CONTAINER_OF(resolution_callback_node, struct pending_callback, node);
  335. pending_callback->callback(
  336. entry->resolver, entry->host_name, AWS_IO_DNS_HOST_REMOVED_FROM_CACHE, NULL, pending_callback->user_data);
  337. aws_mem_release(entry->allocator, pending_callback);
  338. }
  339. aws_cache_destroy(entry->aaaa_records);
  340. aws_cache_destroy(entry->a_records);
  341. aws_cache_destroy(entry->failed_connection_a_records);
  342. aws_cache_destroy(entry->failed_connection_aaaa_records);
  343. aws_string_destroy((void *)entry->host_name);
  344. s_clear_address_list(&entry->new_addresses);
  345. aws_array_list_clean_up(&entry->new_addresses);
  346. s_clear_address_list(&entry->expired_addresses);
  347. aws_array_list_clean_up(&entry->expired_addresses);
  348. aws_mem_release(entry->allocator, entry);
  349. }
  350. static void s_on_host_entry_shutdown_completion(void *user_data) {
  351. struct host_entry *entry = user_data;
  352. struct aws_host_resolver *resolver = entry->resolver;
  353. struct default_host_resolver *default_host_resolver = resolver->impl;
  354. s_clean_up_host_entry(entry);
  355. bool cleanup_resolver = false;
  356. aws_mutex_lock(&default_host_resolver->resolver_lock);
  357. --default_host_resolver->pending_host_entry_shutdown_completion_callbacks;
  358. if (default_host_resolver->state == DRS_SHUTTING_DOWN &&
  359. default_host_resolver->pending_host_entry_shutdown_completion_callbacks == 0) {
  360. cleanup_resolver = true;
  361. }
  362. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  363. if (cleanup_resolver) {
  364. s_cleanup_default_resolver(resolver);
  365. }
  366. }
  367. static int s_copy_address_into_array_list(struct aws_host_address *address, struct aws_array_list *address_list) {
  368. /*
  369. * This is the worst.
  370. *
  371. * We have to copy the cache address while we still have a write lock. Otherwise, connection failures
  372. * can sneak in and destroy our address by moving the address to/from the various lru caches.
  373. *
  374. * But there's no nice copy construction into an array list, so we get to
  375. * (1) Push a zeroed dummy element onto the array list
  376. * (2) Get its pointer
  377. * (3) Call aws_host_address_copy onto it. If that fails, pop the dummy element.
  378. */
  379. struct aws_host_address dummy;
  380. AWS_ZERO_STRUCT(dummy);
  381. if (aws_array_list_push_back(address_list, &dummy)) {
  382. return AWS_OP_ERR;
  383. }
  384. struct aws_host_address *dest_copy = NULL;
  385. aws_array_list_get_at_ptr(address_list, (void **)&dest_copy, aws_array_list_length(address_list) - 1);
  386. AWS_FATAL_ASSERT(dest_copy != NULL);
  387. if (aws_host_address_copy(address, dest_copy)) {
  388. aws_array_list_pop_back(address_list);
  389. return AWS_OP_ERR;
  390. }
  391. return AWS_OP_SUCCESS;
  392. }
  393. static uint64_t s_get_system_time_for_default_resolver(struct aws_host_resolver *resolver) {
  394. struct default_host_resolver *default_resolver = resolver->impl;
  395. uint64_t timestamp = 0;
  396. (*default_resolver->system_clock_fn)(&timestamp);
  397. return timestamp;
  398. }
  399. /* this only ever gets called after resolution has already run. We expect that the entry's lock
  400. has been acquired for writing before this function is called and released afterwards. */
  401. static inline void process_records(
  402. struct host_entry *host_entry,
  403. struct aws_cache *records,
  404. struct aws_cache *failed_records) {
  405. struct aws_host_resolver *resolver = host_entry->resolver;
  406. uint64_t timestamp = s_get_system_time_for_default_resolver(resolver);
  407. size_t record_count = aws_cache_get_element_count(records);
  408. size_t expired_records = 0;
  409. /* since this only ever gets called after resolution has already run, we're in a dns outage
  410. * if everything is expired. Leave an element so we can keep trying. */
  411. for (size_t index = 0; index < record_count && expired_records < record_count - 1; ++index) {
  412. struct aws_host_address_cache_entry *lru_element_entry = aws_lru_cache_use_lru_element(records);
  413. if (lru_element_entry->address.expiry < timestamp) {
  414. AWS_LOGF_DEBUG(
  415. AWS_LS_IO_DNS,
  416. "static: purging expired record %s for %s",
  417. lru_element_entry->address.address->bytes,
  418. lru_element_entry->address.host->bytes);
  419. expired_records++;
  420. aws_cache_remove(records, lru_element_entry->address.address);
  421. }
  422. }
  423. record_count = aws_cache_get_element_count(records);
  424. AWS_LOGF_TRACE(AWS_LS_IO_DNS, "static: remaining record count for host %d", (int)record_count);
  425. /* if we don't have any known good addresses, take the least recently used, but not expired address with a history
  426. * of spotty behavior and upgrade it for reuse. If it's expired, leave it and let the resolve fail. Better to fail
  427. * than accidentally give a kids' app an IP address to somebody's adult website when the IP address gets rebound to
  428. * a different endpoint. The moral of the story here is to not disable SSL verification! */
  429. if (!record_count) {
  430. size_t failed_count = aws_cache_get_element_count(failed_records);
  431. for (size_t index = 0; index < failed_count; ++index) {
  432. struct aws_host_address_cache_entry *lru_element_entry = aws_lru_cache_use_lru_element(failed_records);
  433. if (timestamp >= lru_element_entry->address.expiry) {
  434. continue;
  435. }
  436. struct aws_host_address_cache_entry *to_add =
  437. aws_mem_calloc(host_entry->allocator, 1, sizeof(struct aws_host_address_cache_entry));
  438. if (to_add == NULL) {
  439. continue;
  440. }
  441. if (aws_host_address_cache_entry_copy(lru_element_entry, to_add) ||
  442. aws_cache_put(records, to_add->address.address, to_add)) {
  443. aws_host_address_clean_up(&to_add->address);
  444. aws_mem_release(host_entry->allocator, to_add);
  445. continue;
  446. }
  447. /*
  448. * Promoting an address from failed to good should trigger the new address callback
  449. */
  450. s_copy_address_into_array_list(&lru_element_entry->address, &host_entry->new_addresses);
  451. AWS_LOGF_INFO(
  452. AWS_LS_IO_DNS,
  453. "static: promoting spotty record %s for %s back to good list",
  454. lru_element_entry->address.address->bytes,
  455. lru_element_entry->address.host->bytes);
  456. aws_cache_remove(failed_records, lru_element_entry->address.address);
  457. /* we only want to promote one per process run.*/
  458. break;
  459. }
  460. }
  461. }
  462. static int s_resolver_purge_host_cache(
  463. struct aws_host_resolver *resolver,
  464. const struct aws_host_resolver_purge_host_options *options) {
  465. AWS_PRECONDITION(resolver);
  466. if (options == NULL) {
  467. AWS_LOGF_ERROR(AWS_LS_IO_DNS, "Cannot purge host cache; options structure is NULL.");
  468. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  469. }
  470. struct default_host_resolver *default_host_resolver = resolver->impl;
  471. AWS_LOGF_INFO(AWS_LS_IO_DNS, "id=%p: purging record for %s", (void *)resolver, options->host->bytes);
  472. aws_mutex_lock(&default_host_resolver->resolver_lock);
  473. struct aws_hash_element *element = NULL;
  474. aws_hash_table_find(&default_host_resolver->host_entry_table, options->host, &element);
  475. /* Success if entry doesn't exist in cache. */
  476. if (element == NULL) {
  477. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  478. if (options->on_host_purge_complete_callback != NULL) {
  479. /* Schedule completion callback asynchronouly */
  480. struct host_purge_callback_options *purge_callback_options = s_host_purge_callback_options_new(
  481. default_host_resolver->allocator, options->on_host_purge_complete_callback, options->user_data);
  482. s_sechdule_purge_cache_callback_async(default_host_resolver, purge_callback_options);
  483. }
  484. return AWS_OP_SUCCESS;
  485. }
  486. struct host_entry *host_entry = element->value;
  487. AWS_FATAL_ASSERT(host_entry);
  488. /* Setup the on_host_purge_complete callback. */
  489. aws_mutex_lock(&host_entry->entry_lock);
  490. AWS_FATAL_ASSERT(!host_entry->on_host_purge_complete);
  491. AWS_FATAL_ASSERT(!host_entry->on_host_purge_complete_user_data);
  492. host_entry->on_host_purge_complete = options->on_host_purge_complete_callback;
  493. host_entry->on_host_purge_complete_user_data = options->user_data;
  494. aws_mutex_unlock(&host_entry->entry_lock);
  495. s_shutdown_host_entry(host_entry);
  496. aws_hash_table_remove_element(&default_host_resolver->host_entry_table, element);
  497. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  498. return AWS_OP_SUCCESS;
  499. }
  500. static int resolver_record_connection_failure(
  501. struct aws_host_resolver *resolver,
  502. const struct aws_host_address *address) {
  503. struct default_host_resolver *default_host_resolver = resolver->impl;
  504. AWS_LOGF_INFO(
  505. AWS_LS_IO_DNS,
  506. "id=%p: recording failure for record %s for %s, moving to bad list",
  507. (void *)resolver,
  508. address->address->bytes,
  509. address->host->bytes);
  510. aws_mutex_lock(&default_host_resolver->resolver_lock);
  511. struct aws_hash_element *element = NULL;
  512. if (aws_hash_table_find(&default_host_resolver->host_entry_table, address->host, &element)) {
  513. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  514. return AWS_OP_ERR;
  515. }
  516. struct host_entry *host_entry = NULL;
  517. if (element != NULL) {
  518. host_entry = element->value;
  519. AWS_FATAL_ASSERT(host_entry);
  520. }
  521. if (host_entry) {
  522. struct aws_host_address_cache_entry *cached_address_entry = NULL;
  523. aws_mutex_lock(&host_entry->entry_lock);
  524. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  525. struct aws_cache *address_table =
  526. address->record_type == AWS_ADDRESS_RECORD_TYPE_AAAA ? host_entry->aaaa_records : host_entry->a_records;
  527. struct aws_cache *failed_table = address->record_type == AWS_ADDRESS_RECORD_TYPE_AAAA
  528. ? host_entry->failed_connection_aaaa_records
  529. : host_entry->failed_connection_a_records;
  530. aws_cache_find(address_table, address->address, (void **)&cached_address_entry);
  531. struct aws_host_address_cache_entry *address_entry_copy = NULL;
  532. if (cached_address_entry) {
  533. address_entry_copy = aws_mem_calloc(resolver->allocator, 1, sizeof(struct aws_host_address_cache_entry));
  534. if (!address_entry_copy || aws_host_address_cache_entry_copy(cached_address_entry, address_entry_copy)) {
  535. goto error_host_entry_cleanup;
  536. }
  537. /*
  538. * This will trigger an expiration callback since the good caches add the removed address to the
  539. * host_entry's expired list, via the cache's on_delete callback
  540. */
  541. if (aws_cache_remove(address_table, cached_address_entry->address.address)) {
  542. goto error_host_entry_cleanup;
  543. }
  544. address_entry_copy->address.connection_failure_count += 1;
  545. if (aws_cache_put(failed_table, address_entry_copy->address.address, address_entry_copy)) {
  546. goto error_host_entry_cleanup;
  547. }
  548. } else {
  549. if (aws_cache_find(failed_table, address->address, (void **)&cached_address_entry)) {
  550. goto error_host_entry_cleanup;
  551. }
  552. if (cached_address_entry) {
  553. cached_address_entry->address.connection_failure_count += 1;
  554. }
  555. }
  556. aws_mutex_unlock(&host_entry->entry_lock);
  557. return AWS_OP_SUCCESS;
  558. error_host_entry_cleanup:
  559. if (address_entry_copy) {
  560. aws_host_address_clean_up(&address_entry_copy->address);
  561. aws_mem_release(resolver->allocator, address_entry_copy);
  562. }
  563. aws_mutex_unlock(&host_entry->entry_lock);
  564. return AWS_OP_ERR;
  565. }
  566. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  567. return AWS_OP_SUCCESS;
  568. }
  569. /*
  570. * A bunch of convenience functions for the host resolver background thread function
  571. */
  572. static struct aws_host_address_cache_entry *s_find_cached_address_entry_aux(
  573. struct aws_cache *primary_records,
  574. struct aws_cache *fallback_records,
  575. const struct aws_string *address) {
  576. struct aws_host_address_cache_entry *found = NULL;
  577. aws_cache_find(primary_records, address, (void **)&found);
  578. if (found == NULL) {
  579. aws_cache_find(fallback_records, address, (void **)&found);
  580. }
  581. return found;
  582. }
  583. /*
  584. * Looks in both the good and failed connection record sets for a given host record
  585. */
  586. static struct aws_host_address_cache_entry *s_find_cached_address_entry(
  587. struct host_entry *entry,
  588. const struct aws_string *address,
  589. enum aws_address_record_type record_type) {
  590. switch (record_type) {
  591. case AWS_ADDRESS_RECORD_TYPE_AAAA:
  592. return s_find_cached_address_entry_aux(entry->aaaa_records, entry->failed_connection_aaaa_records, address);
  593. case AWS_ADDRESS_RECORD_TYPE_A:
  594. return s_find_cached_address_entry_aux(entry->a_records, entry->failed_connection_a_records, address);
  595. default:
  596. return NULL;
  597. }
  598. }
  599. static struct aws_host_address_cache_entry *s_get_lru_address_entry_aux(
  600. struct aws_cache *primary_records,
  601. struct aws_cache *fallback_records) {
  602. struct aws_host_address_cache_entry *address_entry = aws_lru_cache_use_lru_element(primary_records);
  603. if (address_entry == NULL) {
  604. aws_lru_cache_use_lru_element(fallback_records);
  605. }
  606. return address_entry;
  607. }
  608. /*
  609. * Looks in both the good and failed connection record sets for the LRU host record
  610. */
  611. static struct aws_host_address_cache_entry *s_get_lru_address(
  612. struct host_entry *entry,
  613. enum aws_address_record_type record_type) {
  614. switch (record_type) {
  615. case AWS_ADDRESS_RECORD_TYPE_AAAA:
  616. return s_get_lru_address_entry_aux(entry->aaaa_records, entry->failed_connection_aaaa_records);
  617. case AWS_ADDRESS_RECORD_TYPE_A:
  618. return s_get_lru_address_entry_aux(entry->a_records, entry->failed_connection_a_records);
  619. default:
  620. return NULL;
  621. }
  622. }
  623. static void s_update_address_cache(
  624. struct host_entry *host_entry,
  625. struct aws_array_list *address_list,
  626. uint64_t new_expiration) {
  627. AWS_PRECONDITION(host_entry);
  628. AWS_PRECONDITION(address_list);
  629. for (size_t i = 0; i < aws_array_list_length(address_list); ++i) {
  630. struct aws_host_address *fresh_resolved_address = NULL;
  631. aws_array_list_get_at_ptr(address_list, (void **)&fresh_resolved_address, i);
  632. struct aws_host_address_cache_entry *address_to_cache_entry = s_find_cached_address_entry(
  633. host_entry, fresh_resolved_address->address, fresh_resolved_address->record_type);
  634. if (address_to_cache_entry) {
  635. address_to_cache_entry->address.expiry = new_expiration;
  636. AWS_LOGF_TRACE(
  637. AWS_LS_IO_DNS,
  638. "static: updating expiry for %s for host %s to %llu",
  639. address_to_cache_entry->address.address->bytes,
  640. host_entry->host_name->bytes,
  641. (unsigned long long)new_expiration);
  642. } else {
  643. address_to_cache_entry =
  644. aws_mem_calloc(host_entry->allocator, 1, sizeof(struct aws_host_address_cache_entry));
  645. aws_host_address_move(fresh_resolved_address, &address_to_cache_entry->address);
  646. address_to_cache_entry->address.expiry = new_expiration;
  647. address_to_cache_entry->entry = host_entry;
  648. struct aws_cache *address_table =
  649. address_to_cache_entry->address.record_type == AWS_ADDRESS_RECORD_TYPE_AAAA ? host_entry->aaaa_records
  650. : host_entry->a_records;
  651. if (aws_cache_put(address_table, address_to_cache_entry->address.address, address_to_cache_entry)) {
  652. AWS_LOGF_ERROR(
  653. AWS_LS_IO_DNS,
  654. "static: could not add new address to host entry cache for host '%s' in "
  655. "s_update_address_cache.",
  656. host_entry->host_name->bytes);
  657. continue;
  658. }
  659. AWS_LOGF_DEBUG(
  660. AWS_LS_IO_DNS,
  661. "static: new address resolved %s for host %s caching",
  662. address_to_cache_entry->address.address->bytes,
  663. host_entry->host_name->bytes);
  664. struct aws_host_address new_address_copy;
  665. if (aws_host_address_copy(&address_to_cache_entry->address, &new_address_copy)) {
  666. AWS_LOGF_ERROR(
  667. AWS_LS_IO_DNS,
  668. "static: could not copy address for new-address list for host '%s' in s_update_address_cache.",
  669. host_entry->host_name->bytes);
  670. continue;
  671. }
  672. if (aws_array_list_push_back(&host_entry->new_addresses, &new_address_copy)) {
  673. aws_host_address_clean_up(&new_address_copy);
  674. AWS_LOGF_ERROR(
  675. AWS_LS_IO_DNS,
  676. "static: could not push address to new-address list for host '%s' in s_update_address_cache.",
  677. host_entry->host_name->bytes);
  678. continue;
  679. }
  680. }
  681. }
  682. }
  683. static void s_copy_address_into_callback_set(
  684. struct aws_host_address_cache_entry *entry,
  685. struct aws_array_list *callback_addresses,
  686. const struct aws_string *host_name) {
  687. if (entry != NULL) {
  688. if (s_copy_address_into_array_list(&entry->address, callback_addresses)) {
  689. AWS_LOGF_ERROR(
  690. AWS_LS_IO_DNS,
  691. "static: failed to vend address %s for host %s to caller",
  692. entry->address.address->bytes,
  693. host_name->bytes);
  694. return;
  695. }
  696. entry->address.use_count += 1;
  697. AWS_LOGF_TRACE(
  698. AWS_LS_IO_DNS,
  699. "static: vending address %s for host %s to caller",
  700. entry->address.address->bytes,
  701. host_name->bytes);
  702. }
  703. }
  704. static bool s_host_entry_finished_pred(void *user_data) {
  705. struct host_entry *entry = user_data;
  706. return entry->state == DRS_SHUTTING_DOWN;
  707. }
  708. static bool s_host_entry_finished_or_pending_request_pred(void *user_data) {
  709. struct host_entry *entry = user_data;
  710. return entry->state == DRS_SHUTTING_DOWN || !aws_linked_list_empty(&entry->pending_resolution_callbacks);
  711. }
  712. static const uint64_t AWS_MINIMUM_WAIT_BETWEEN_DNS_QUERIES_NS = 100000000; /* 100 ms */
  713. static void aws_host_resolver_thread(void *arg) {
  714. struct host_entry *host_entry = arg;
  715. uint64_t max_no_solicitation_interval = aws_timestamp_convert(
  716. aws_max_u64(1, host_entry->resolution_config.max_ttl), AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_NANOS, NULL);
  717. uint64_t wait_between_resolves_interval =
  718. aws_min_u64(max_no_solicitation_interval, host_entry->resolve_frequency_ns);
  719. uint64_t shutdown_only_wait_time = AWS_MINIMUM_WAIT_BETWEEN_DNS_QUERIES_NS;
  720. uint64_t request_interruptible_wait_time = 0;
  721. if (wait_between_resolves_interval > shutdown_only_wait_time) {
  722. request_interruptible_wait_time = wait_between_resolves_interval - shutdown_only_wait_time;
  723. }
  724. struct aws_linked_list listener_list;
  725. aws_linked_list_init(&listener_list);
  726. struct aws_linked_list listener_destroy_list;
  727. aws_linked_list_init(&listener_destroy_list);
  728. bool keep_going = true;
  729. struct aws_array_list address_list;
  730. AWS_ZERO_STRUCT(address_list);
  731. struct aws_array_list new_address_list;
  732. AWS_ZERO_STRUCT(new_address_list);
  733. struct aws_array_list expired_address_list;
  734. AWS_ZERO_STRUCT(expired_address_list);
  735. if (aws_array_list_init_dynamic(&address_list, host_entry->allocator, 4, sizeof(struct aws_host_address))) {
  736. goto done;
  737. }
  738. if (aws_array_list_init_dynamic(&new_address_list, host_entry->allocator, 4, sizeof(struct aws_host_address))) {
  739. goto done;
  740. }
  741. if (aws_array_list_init_dynamic(&expired_address_list, host_entry->allocator, 4, sizeof(struct aws_host_address))) {
  742. goto done;
  743. }
  744. while (keep_going) {
  745. /* resolve and then process each record */
  746. int err_code = AWS_ERROR_SUCCESS;
  747. if (host_entry->resolution_config.impl(
  748. host_entry->allocator, host_entry->host_name, &address_list, host_entry->resolution_config.impl_data)) {
  749. err_code = aws_last_error();
  750. }
  751. if (err_code == AWS_ERROR_SUCCESS) {
  752. AWS_LOGF_DEBUG(
  753. AWS_LS_IO_DNS,
  754. "static, resolving host %s successful, returned %d addresses",
  755. aws_string_c_str(host_entry->host_name),
  756. (int)aws_array_list_length(&address_list));
  757. } else {
  758. AWS_LOGF_WARN(
  759. AWS_LS_IO_DNS,
  760. "static, resolving host %s failed, ec %d (%s)",
  761. aws_string_c_str(host_entry->host_name),
  762. err_code,
  763. aws_error_debug_str(err_code));
  764. }
  765. uint64_t timestamp = s_get_system_time_for_default_resolver(host_entry->resolver);
  766. uint64_t new_expiry = timestamp + (host_entry->resolution_config.max_ttl * NS_PER_SEC);
  767. struct aws_linked_list pending_resolve_copy;
  768. aws_linked_list_init(&pending_resolve_copy);
  769. /*
  770. * Within the lock we
  771. * (1) Update the cache with the newly resolved addresses
  772. * (2) Process all held addresses looking for expired or promotable ones
  773. * (3) Prep for callback invocations
  774. */
  775. aws_mutex_lock(&host_entry->entry_lock);
  776. if (!err_code) {
  777. s_update_address_cache(host_entry, &address_list, new_expiry);
  778. }
  779. /*
  780. * process and clean_up records in the entry. occasionally, failed connect records will be upgraded
  781. * for retry.
  782. */
  783. process_records(host_entry, host_entry->aaaa_records, host_entry->failed_connection_aaaa_records);
  784. process_records(host_entry, host_entry->a_records, host_entry->failed_connection_a_records);
  785. aws_linked_list_swap_contents(&pending_resolve_copy, &host_entry->pending_resolution_callbacks);
  786. aws_mutex_unlock(&host_entry->entry_lock);
  787. /*
  788. * Clean up resolved addressed outside of the lock
  789. */
  790. s_clear_address_list(&address_list);
  791. struct aws_host_address address_array[2];
  792. AWS_ZERO_ARRAY(address_array);
  793. /*
  794. * Perform the actual subscriber notifications
  795. */
  796. while (!aws_linked_list_empty(&pending_resolve_copy)) {
  797. struct aws_linked_list_node *resolution_callback_node = aws_linked_list_pop_front(&pending_resolve_copy);
  798. struct pending_callback *pending_callback =
  799. AWS_CONTAINER_OF(resolution_callback_node, struct pending_callback, node);
  800. struct aws_array_list callback_address_list;
  801. aws_array_list_init_static(&callback_address_list, address_array, 2, sizeof(struct aws_host_address));
  802. aws_mutex_lock(&host_entry->entry_lock);
  803. s_copy_address_into_callback_set(
  804. s_get_lru_address(host_entry, AWS_ADDRESS_RECORD_TYPE_AAAA),
  805. &callback_address_list,
  806. host_entry->host_name);
  807. s_copy_address_into_callback_set(
  808. s_get_lru_address(host_entry, AWS_ADDRESS_RECORD_TYPE_A),
  809. &callback_address_list,
  810. host_entry->host_name);
  811. aws_mutex_unlock(&host_entry->entry_lock);
  812. size_t callback_address_list_size = aws_array_list_length(&callback_address_list);
  813. if (callback_address_list_size > 0) {
  814. AWS_LOGF_DEBUG(
  815. AWS_LS_IO_DNS,
  816. "static, invoking resolution callback for host %s with %d addresses",
  817. aws_string_c_str(host_entry->host_name),
  818. (int)callback_address_list_size);
  819. } else {
  820. AWS_LOGF_DEBUG(
  821. AWS_LS_IO_DNS,
  822. "static, invoking resolution callback for host %s with failure",
  823. aws_string_c_str(host_entry->host_name));
  824. }
  825. if (callback_address_list_size > 0) {
  826. pending_callback->callback(
  827. host_entry->resolver,
  828. host_entry->host_name,
  829. AWS_OP_SUCCESS,
  830. &callback_address_list,
  831. pending_callback->user_data);
  832. } else {
  833. int error_code = (err_code != AWS_ERROR_SUCCESS) ? err_code : AWS_IO_DNS_QUERY_FAILED;
  834. pending_callback->callback(
  835. host_entry->resolver, host_entry->host_name, error_code, NULL, pending_callback->user_data);
  836. }
  837. s_clear_address_list(&callback_address_list);
  838. aws_mem_release(host_entry->allocator, pending_callback);
  839. }
  840. aws_mutex_lock(&host_entry->entry_lock);
  841. ++host_entry->resolves_since_last_request;
  842. /*
  843. * A long resolve frequency matched with a connection failure can induce a state of DNS starvation, where
  844. * additional resolution requests go into the queue but since there's no good records and the thread is sleeping
  845. * for a long time, nothing happens.
  846. *
  847. * While we could make the wait predicate also check the queue of requests, there is a worry that a
  848. * host that can't be resolved (user error, dns record removal, etc...) could lead to a "spammy" scenario
  849. * where the thread generates DNS requests extremely quickly, ie, the sleep becomes almost instant.
  850. *
  851. * We'd like to be able to express the wait here as something a bit more complex:
  852. *
  853. * "Wait until either (1) shutdown notice, or (2) a small amount of time has passed and there are pending
  854. * requests, or (3) the resolution interval has passed"
  855. *
  856. * While seemingly complicated, we can do this actually just by chaining two waits:
  857. *
  858. * (1) The first wait is for a short amount of time and only predicates on the shutdown notice
  859. * (2) The second wait is for the remaining frequency interval and predicates on either the shutdown notice
  860. * or a pending resolve request
  861. *
  862. * This leaves us with wait behavior where:
  863. * (1) Shutdown always fully interrupts and immediately causes the thread function to complete
  864. * (2) Absent shutdown, there is always a controllable, non-trivial sleep between resolves
  865. * (3) Starvation is avoided as pending requests can wake the resolver thread independent of resolution
  866. * frequency
  867. */
  868. aws_condition_variable_wait_for_pred(
  869. &host_entry->entry_signal,
  870. &host_entry->entry_lock,
  871. shutdown_only_wait_time,
  872. s_host_entry_finished_pred,
  873. host_entry);
  874. if (request_interruptible_wait_time > 0) {
  875. aws_condition_variable_wait_for_pred(
  876. &host_entry->entry_signal,
  877. &host_entry->entry_lock,
  878. request_interruptible_wait_time,
  879. s_host_entry_finished_or_pending_request_pred,
  880. host_entry);
  881. }
  882. aws_mutex_unlock(&host_entry->entry_lock);
  883. /*
  884. * This is a bit awkward that we unlock the entry and then relock both the resolver and the entry, but it
  885. * is mandatory that -- in order to maintain the consistent view of the resolver table (entry exist => entry
  886. * is alive and can be queried) -- we have the resolver lock as well before making the decision to remove
  887. * the entry from the table and terminate the thread.
  888. */
  889. struct default_host_resolver *resolver = host_entry->resolver->impl;
  890. aws_mutex_lock(&resolver->resolver_lock);
  891. aws_mutex_lock(&host_entry->entry_lock);
  892. uint64_t now = s_get_system_time_for_default_resolver(host_entry->resolver);
  893. /*
  894. * The only way we terminate the loop with pending queries is if the resolver itself has no more references
  895. * to it and is going away. In that case, the pending queries will be completed (with failure) by the
  896. * final clean up of this entry.
  897. */
  898. if (aws_linked_list_empty(&host_entry->pending_resolution_callbacks) &&
  899. host_entry->last_resolve_request_timestamp_ns + max_no_solicitation_interval < now) {
  900. host_entry->state = DRS_SHUTTING_DOWN;
  901. }
  902. keep_going = host_entry->state == DRS_ACTIVE;
  903. if (!keep_going) {
  904. aws_hash_table_remove(&resolver->host_entry_table, host_entry->host_name, NULL, NULL);
  905. }
  906. aws_array_list_swap_contents(&host_entry->new_addresses, &new_address_list);
  907. aws_array_list_swap_contents(&host_entry->expired_addresses, &expired_address_list);
  908. aws_mutex_unlock(&host_entry->entry_lock);
  909. aws_mutex_unlock(&resolver->resolver_lock);
  910. s_clear_address_list(&new_address_list);
  911. s_clear_address_list(&expired_address_list);
  912. }
  913. AWS_LOGF_DEBUG(
  914. AWS_LS_IO_DNS,
  915. "static: Either no requests have been made for an address for %s for the duration "
  916. "of the ttl, or this thread is being forcibly shutdown. Killing thread.",
  917. host_entry->host_name->bytes);
  918. done:
  919. AWS_FATAL_ASSERT(aws_array_list_length(&address_list) == 0);
  920. AWS_FATAL_ASSERT(aws_array_list_length(&new_address_list) == 0);
  921. AWS_FATAL_ASSERT(aws_array_list_length(&expired_address_list) == 0);
  922. aws_array_list_clean_up(&address_list);
  923. aws_array_list_clean_up(&new_address_list);
  924. aws_array_list_clean_up(&expired_address_list);
  925. /* trigger the purge complete callback */
  926. if (host_entry->on_host_purge_complete != NULL) {
  927. host_entry->on_host_purge_complete(host_entry->on_host_purge_complete_user_data);
  928. }
  929. /* please don't fail */
  930. aws_thread_current_at_exit(s_on_host_entry_shutdown_completion, host_entry);
  931. }
  932. static void on_cache_entry_removed_helper(struct aws_host_address_cache_entry *entry) {
  933. AWS_LOGF_DEBUG(
  934. AWS_LS_IO_DNS,
  935. "static: purging address %s for host %s from "
  936. "the cache due to cache eviction or shutdown",
  937. entry->address.address->bytes,
  938. entry->address.host->bytes);
  939. struct aws_allocator *allocator = entry->address.allocator;
  940. aws_host_address_clean_up(&entry->address);
  941. aws_mem_release(allocator, entry);
  942. }
  943. static void on_good_address_entry_removed(void *value) {
  944. struct aws_host_address_cache_entry *entry = value;
  945. if (entry == NULL) {
  946. return;
  947. }
  948. s_copy_address_into_array_list(&entry->address, &entry->entry->expired_addresses);
  949. on_cache_entry_removed_helper(entry);
  950. }
  951. static void on_failed_address_entry_removed(void *value) {
  952. struct aws_host_address_cache_entry *entry = value;
  953. on_cache_entry_removed_helper(entry);
  954. }
  955. /*
  956. * The resolver lock must be held before calling this function
  957. */
  958. static inline int create_and_init_host_entry(
  959. struct aws_host_resolver *resolver,
  960. const struct aws_string *host_name,
  961. aws_on_host_resolved_result_fn *res,
  962. const struct aws_host_resolution_config *config,
  963. uint64_t timestamp,
  964. void *user_data) {
  965. struct host_entry *new_host_entry = aws_mem_calloc(resolver->allocator, 1, sizeof(struct host_entry));
  966. if (!new_host_entry) {
  967. return AWS_OP_ERR;
  968. }
  969. new_host_entry->resolver = resolver;
  970. new_host_entry->allocator = resolver->allocator;
  971. new_host_entry->last_resolve_request_timestamp_ns = timestamp;
  972. new_host_entry->resolves_since_last_request = 0;
  973. new_host_entry->resolve_frequency_ns =
  974. (config->resolve_frequency_ns != 0) ? config->resolve_frequency_ns : NS_PER_SEC;
  975. new_host_entry->state = DRS_ACTIVE;
  976. bool thread_init = false;
  977. struct pending_callback *pending_callback = NULL;
  978. const struct aws_string *host_string_copy = aws_string_new_from_string(resolver->allocator, host_name);
  979. if (AWS_UNLIKELY(!host_string_copy)) {
  980. goto setup_host_entry_error;
  981. }
  982. new_host_entry->host_name = host_string_copy;
  983. new_host_entry->a_records = aws_cache_new_lru(
  984. new_host_entry->allocator,
  985. aws_hash_string,
  986. aws_hash_callback_string_eq,
  987. NULL,
  988. on_good_address_entry_removed,
  989. config->max_ttl);
  990. if (AWS_UNLIKELY(!new_host_entry->a_records)) {
  991. goto setup_host_entry_error;
  992. }
  993. new_host_entry->aaaa_records = aws_cache_new_lru(
  994. new_host_entry->allocator,
  995. aws_hash_string,
  996. aws_hash_callback_string_eq,
  997. NULL,
  998. on_good_address_entry_removed,
  999. config->max_ttl);
  1000. if (AWS_UNLIKELY(!new_host_entry->aaaa_records)) {
  1001. goto setup_host_entry_error;
  1002. }
  1003. new_host_entry->failed_connection_a_records = aws_cache_new_lru(
  1004. new_host_entry->allocator,
  1005. aws_hash_string,
  1006. aws_hash_callback_string_eq,
  1007. NULL,
  1008. on_failed_address_entry_removed,
  1009. config->max_ttl);
  1010. if (AWS_UNLIKELY(!new_host_entry->failed_connection_a_records)) {
  1011. goto setup_host_entry_error;
  1012. }
  1013. new_host_entry->failed_connection_aaaa_records = aws_cache_new_lru(
  1014. new_host_entry->allocator,
  1015. aws_hash_string,
  1016. aws_hash_callback_string_eq,
  1017. NULL,
  1018. on_failed_address_entry_removed,
  1019. config->max_ttl);
  1020. if (AWS_UNLIKELY(!new_host_entry->failed_connection_aaaa_records)) {
  1021. goto setup_host_entry_error;
  1022. }
  1023. if (aws_array_list_init_dynamic(
  1024. &new_host_entry->new_addresses, new_host_entry->allocator, 4, sizeof(struct aws_host_address))) {
  1025. goto setup_host_entry_error;
  1026. }
  1027. if (aws_array_list_init_dynamic(
  1028. &new_host_entry->expired_addresses, new_host_entry->allocator, 4, sizeof(struct aws_host_address))) {
  1029. goto setup_host_entry_error;
  1030. }
  1031. aws_linked_list_init(&new_host_entry->pending_resolution_callbacks);
  1032. pending_callback = aws_mem_acquire(resolver->allocator, sizeof(struct pending_callback));
  1033. if (AWS_UNLIKELY(!pending_callback)) {
  1034. goto setup_host_entry_error;
  1035. }
  1036. /*add the current callback here */
  1037. pending_callback->user_data = user_data;
  1038. pending_callback->callback = res;
  1039. aws_linked_list_push_back(&new_host_entry->pending_resolution_callbacks, &pending_callback->node);
  1040. aws_mutex_init(&new_host_entry->entry_lock);
  1041. new_host_entry->resolution_config = *config;
  1042. aws_condition_variable_init(&new_host_entry->entry_signal);
  1043. aws_thread_init(&new_host_entry->resolver_thread, resolver->allocator);
  1044. thread_init = true;
  1045. struct default_host_resolver *default_host_resolver = resolver->impl;
  1046. if (AWS_UNLIKELY(
  1047. aws_hash_table_put(&default_host_resolver->host_entry_table, host_string_copy, new_host_entry, NULL))) {
  1048. goto setup_host_entry_error;
  1049. }
  1050. struct aws_thread_options thread_options = *aws_default_thread_options();
  1051. thread_options.join_strategy = AWS_TJS_MANAGED;
  1052. thread_options.name = aws_byte_cursor_from_c_str("AwsHostResolver"); /* 15 characters is max for Linux */
  1053. if (aws_thread_launch(
  1054. &new_host_entry->resolver_thread, aws_host_resolver_thread, new_host_entry, &thread_options)) {
  1055. goto setup_host_entry_error;
  1056. }
  1057. ++default_host_resolver->pending_host_entry_shutdown_completion_callbacks;
  1058. return AWS_OP_SUCCESS;
  1059. setup_host_entry_error:
  1060. if (thread_init) {
  1061. aws_thread_clean_up(&new_host_entry->resolver_thread);
  1062. }
  1063. // If we registered a callback, clear it. So that we don’t trigger callback and return an error.
  1064. if (!aws_linked_list_empty(&new_host_entry->pending_resolution_callbacks)) {
  1065. aws_linked_list_remove(&pending_callback->node);
  1066. }
  1067. s_clean_up_host_entry(new_host_entry);
  1068. return AWS_OP_ERR;
  1069. }
  1070. static int default_resolve_host(
  1071. struct aws_host_resolver *resolver,
  1072. const struct aws_string *host_name,
  1073. aws_on_host_resolved_result_fn *res,
  1074. const struct aws_host_resolution_config *config,
  1075. void *user_data) {
  1076. int result = AWS_OP_SUCCESS;
  1077. AWS_LOGF_DEBUG(AWS_LS_IO_DNS, "id=%p: Host resolution requested for %s", (void *)resolver, host_name->bytes);
  1078. uint64_t timestamp = s_get_system_time_for_default_resolver(resolver);
  1079. struct default_host_resolver *default_host_resolver = resolver->impl;
  1080. aws_mutex_lock(&default_host_resolver->resolver_lock);
  1081. struct aws_hash_element *element = NULL;
  1082. /* we don't care about the error code here, only that the host_entry was found or not. */
  1083. aws_hash_table_find(&default_host_resolver->host_entry_table, host_name, &element);
  1084. struct host_entry *host_entry = NULL;
  1085. if (element != NULL) {
  1086. host_entry = element->value;
  1087. AWS_FATAL_ASSERT(host_entry != NULL);
  1088. }
  1089. if (!host_entry) {
  1090. AWS_LOGF_DEBUG(
  1091. AWS_LS_IO_DNS,
  1092. "id=%p: No cached entries found for %s starting new resolver thread.",
  1093. (void *)resolver,
  1094. host_name->bytes);
  1095. result = create_and_init_host_entry(resolver, host_name, res, config, timestamp, user_data);
  1096. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  1097. return result;
  1098. }
  1099. aws_mutex_lock(&host_entry->entry_lock);
  1100. /*
  1101. * We don't need to make any resolver side-affects in the remaining logic and it's impossible for the entry
  1102. * to disappear underneath us while holding its lock, so its safe to release the resolver lock and let other
  1103. * things query other entries.
  1104. */
  1105. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  1106. host_entry->last_resolve_request_timestamp_ns = timestamp;
  1107. host_entry->resolves_since_last_request = 0;
  1108. struct aws_host_address_cache_entry *aaaa_entry = aws_lru_cache_use_lru_element(host_entry->aaaa_records);
  1109. struct aws_host_address *aaaa_record = (aaaa_entry != NULL) ? &aaaa_entry->address : NULL;
  1110. struct aws_host_address_cache_entry *a_entry = aws_lru_cache_use_lru_element(host_entry->a_records);
  1111. struct aws_host_address *a_record = (a_entry != NULL) ? &a_entry->address : NULL;
  1112. struct aws_host_address address_array[2];
  1113. AWS_ZERO_ARRAY(address_array);
  1114. struct aws_array_list callback_address_list;
  1115. aws_array_list_init_static(&callback_address_list, address_array, 2, sizeof(struct aws_host_address));
  1116. if ((aaaa_record || a_record)) {
  1117. AWS_LOGF_DEBUG(
  1118. AWS_LS_IO_DNS,
  1119. "id=%p: cached entries found for %s returning to caller.",
  1120. (void *)resolver,
  1121. host_name->bytes);
  1122. /* these will all need to be copied so that we don't hold the lock during the callback. */
  1123. if (aaaa_record) {
  1124. struct aws_host_address aaaa_record_cpy;
  1125. aws_host_address_copy(aaaa_record, &aaaa_record_cpy);
  1126. aws_array_list_push_back(&callback_address_list, &aaaa_record_cpy);
  1127. AWS_LOGF_TRACE(
  1128. AWS_LS_IO_DNS,
  1129. "id=%p: vending address %s for host %s to caller",
  1130. (void *)resolver,
  1131. aaaa_record->address->bytes,
  1132. host_entry->host_name->bytes);
  1133. }
  1134. if (a_record) {
  1135. struct aws_host_address a_record_cpy;
  1136. aws_host_address_copy(a_record, &a_record_cpy);
  1137. aws_array_list_push_back(&callback_address_list, &a_record_cpy);
  1138. AWS_LOGF_TRACE(
  1139. AWS_LS_IO_DNS,
  1140. "id=%p: vending address %s for host %s to caller",
  1141. (void *)resolver,
  1142. a_record->address->bytes,
  1143. host_entry->host_name->bytes);
  1144. }
  1145. aws_mutex_unlock(&host_entry->entry_lock);
  1146. /* we don't want to do the callback WHILE we hold the lock someone may reentrantly call us. */
  1147. // TODO: Fire the callback asynchronously
  1148. res(resolver, host_name, AWS_OP_SUCCESS, &callback_address_list, user_data);
  1149. for (size_t i = 0; i < aws_array_list_length(&callback_address_list); ++i) {
  1150. struct aws_host_address *address_ptr = NULL;
  1151. aws_array_list_get_at_ptr(&callback_address_list, (void **)&address_ptr, i);
  1152. aws_host_address_clean_up(address_ptr);
  1153. }
  1154. aws_array_list_clean_up(&callback_address_list);
  1155. return result;
  1156. }
  1157. struct pending_callback *pending_callback =
  1158. aws_mem_acquire(default_host_resolver->allocator, sizeof(struct pending_callback));
  1159. if (pending_callback != NULL) {
  1160. pending_callback->user_data = user_data;
  1161. pending_callback->callback = res;
  1162. aws_linked_list_push_back(&host_entry->pending_resolution_callbacks, &pending_callback->node);
  1163. /*
  1164. * intentionally signal under the lock; similar to the shutdown case, we can't guarantee the resolver
  1165. * is still around once the lock is released.
  1166. */
  1167. aws_condition_variable_notify_all(&host_entry->entry_signal);
  1168. } else {
  1169. result = AWS_OP_ERR;
  1170. }
  1171. aws_mutex_unlock(&host_entry->entry_lock);
  1172. return result;
  1173. }
  1174. static size_t default_get_host_address_count(
  1175. struct aws_host_resolver *host_resolver,
  1176. const struct aws_string *host_name,
  1177. uint32_t flags) {
  1178. struct default_host_resolver *default_host_resolver = host_resolver->impl;
  1179. size_t address_count = 0;
  1180. aws_mutex_lock(&default_host_resolver->resolver_lock);
  1181. struct aws_hash_element *element = NULL;
  1182. aws_hash_table_find(&default_host_resolver->host_entry_table, host_name, &element);
  1183. if (element != NULL) {
  1184. struct host_entry *host_entry = element->value;
  1185. if (host_entry != NULL) {
  1186. aws_mutex_lock(&host_entry->entry_lock);
  1187. if ((flags & AWS_GET_HOST_ADDRESS_COUNT_RECORD_TYPE_A) != 0) {
  1188. address_count += aws_cache_get_element_count(host_entry->a_records);
  1189. }
  1190. if ((flags & AWS_GET_HOST_ADDRESS_COUNT_RECORD_TYPE_AAAA) != 0) {
  1191. address_count += aws_cache_get_element_count(host_entry->aaaa_records);
  1192. }
  1193. aws_mutex_unlock(&host_entry->entry_lock);
  1194. }
  1195. }
  1196. aws_mutex_unlock(&default_host_resolver->resolver_lock);
  1197. return address_count;
  1198. }
  1199. static struct aws_host_resolver_vtable s_vtable = {
  1200. .purge_cache = s_resolver_purge_cache,
  1201. .purge_cache_with_callback = s_resolver_purge_cache_with_callback,
  1202. .resolve_host = default_resolve_host,
  1203. .record_connection_failure = resolver_record_connection_failure,
  1204. .get_host_address_count = default_get_host_address_count,
  1205. .destroy = resolver_destroy,
  1206. .purge_host_cache = s_resolver_purge_host_cache,
  1207. };
  1208. static void s_aws_host_resolver_destroy(struct aws_host_resolver *resolver) {
  1209. AWS_ASSERT(resolver->vtable && resolver->vtable->destroy);
  1210. resolver->vtable->destroy(resolver);
  1211. }
  1212. struct aws_host_resolver *aws_host_resolver_new_default(
  1213. struct aws_allocator *allocator,
  1214. const struct aws_host_resolver_default_options *options) {
  1215. AWS_FATAL_ASSERT(options != NULL);
  1216. AWS_ASSERT(options->el_group);
  1217. struct aws_host_resolver *resolver = NULL;
  1218. struct default_host_resolver *default_host_resolver = NULL;
  1219. if (!aws_mem_acquire_many(
  1220. allocator,
  1221. 2,
  1222. &resolver,
  1223. sizeof(struct aws_host_resolver),
  1224. &default_host_resolver,
  1225. sizeof(struct default_host_resolver))) {
  1226. return NULL;
  1227. }
  1228. AWS_ZERO_STRUCT(*resolver);
  1229. AWS_ZERO_STRUCT(*default_host_resolver);
  1230. AWS_LOGF_INFO(
  1231. AWS_LS_IO_DNS,
  1232. "id=%p: Initializing default host resolver with %llu max host entries.",
  1233. (void *)resolver,
  1234. (unsigned long long)options->max_entries);
  1235. resolver->vtable = &s_vtable;
  1236. resolver->allocator = allocator;
  1237. resolver->impl = default_host_resolver;
  1238. default_host_resolver->event_loop_group = aws_event_loop_group_acquire(options->el_group);
  1239. default_host_resolver->allocator = allocator;
  1240. default_host_resolver->pending_host_entry_shutdown_completion_callbacks = 0;
  1241. default_host_resolver->state = DRS_ACTIVE;
  1242. aws_mutex_init(&default_host_resolver->resolver_lock);
  1243. if (aws_hash_table_init(
  1244. &default_host_resolver->host_entry_table,
  1245. allocator,
  1246. options->max_entries,
  1247. aws_hash_string,
  1248. aws_hash_callback_string_eq,
  1249. NULL,
  1250. NULL)) {
  1251. goto on_error;
  1252. }
  1253. aws_ref_count_init(&resolver->ref_count, resolver, (aws_simple_completion_callback *)s_aws_host_resolver_destroy);
  1254. if (options->shutdown_options != NULL) {
  1255. resolver->shutdown_options = *options->shutdown_options;
  1256. }
  1257. if (options->system_clock_override_fn != NULL) {
  1258. default_host_resolver->system_clock_fn = options->system_clock_override_fn;
  1259. } else {
  1260. default_host_resolver->system_clock_fn = aws_high_res_clock_get_ticks;
  1261. }
  1262. return resolver;
  1263. on_error:
  1264. s_cleanup_default_resolver(resolver);
  1265. return NULL;
  1266. }
  1267. struct aws_host_resolver *aws_host_resolver_acquire(struct aws_host_resolver *resolver) {
  1268. if (resolver != NULL) {
  1269. aws_ref_count_acquire(&resolver->ref_count);
  1270. }
  1271. return resolver;
  1272. }
  1273. void aws_host_resolver_release(struct aws_host_resolver *resolver) {
  1274. if (resolver != NULL) {
  1275. aws_ref_count_release(&resolver->ref_count);
  1276. }
  1277. }
  1278. size_t aws_host_resolver_get_host_address_count(
  1279. struct aws_host_resolver *resolver,
  1280. const struct aws_string *host_name,
  1281. uint32_t flags) {
  1282. return resolver->vtable->get_host_address_count(resolver, host_name, flags);
  1283. }
  1284. struct aws_host_resolution_config aws_host_resolver_init_default_resolution_config(void) {
  1285. struct aws_host_resolution_config config = {
  1286. .impl = aws_default_dns_resolve,
  1287. .max_ttl = AWS_DEFAULT_DNS_TTL,
  1288. .impl_data = NULL,
  1289. .resolve_frequency_ns = NS_PER_SEC,
  1290. };
  1291. return config;
  1292. }