1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
|
#ifndef AWS_IO_HOST_RESOLVER_H
#define AWS_IO_HOST_RESOLVER_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/ref_count.h>
#include <aws/io/io.h>
AWS_PUSH_SANE_WARNING_LEVEL
struct aws_event_loop_group;
enum aws_address_record_type {
/* ipv4 address. */
AWS_ADDRESS_RECORD_TYPE_A,
/* ipv6 address. */
AWS_ADDRESS_RECORD_TYPE_AAAA
};
enum aws_get_host_address_flags {
/* get number of ipv4 addresses. */
AWS_GET_HOST_ADDRESS_COUNT_RECORD_TYPE_A = 0x00000001,
/* get number of ipv6 addresses. */
AWS_GET_HOST_ADDRESS_COUNT_RECORD_TYPE_AAAA = 0x00000002
};
struct aws_string;
struct aws_host_address {
struct aws_allocator *allocator;
const struct aws_string *host;
const struct aws_string *address;
enum aws_address_record_type record_type;
uint64_t expiry;
/* This next section is strictly for mitigating the impact of sticky hosts that aren't performing well. */
/*for use in DNS-based load balancing.*/
size_t use_count;
/* give a hint on when to remove a bad host from service. */
size_t connection_failure_count;
/* we don't implement this yet, but we will asap. */
uint8_t weight;
};
struct aws_host_resolver;
/**
* Invoked once an address has been resolved for host. The type in host_addresses is struct aws_host_address (by-value).
* The caller does not own this memory and you must copy the host address before returning from this function if you
* plan to use it later. For convenience, we've provided the aws_host_address_copy() and aws_host_address_clean_up()
* functions.
*/
typedef void(aws_on_host_resolved_result_fn)(
struct aws_host_resolver *resolver,
const struct aws_string *host_name,
int err_code,
const struct aws_array_list *host_addresses,
void *user_data);
/**
* Function signature for configuring your own resolver (the default just uses getaddrinfo()). The type in
* output_addresses is struct aws_host_address (by-value). We assume this function blocks, hence this absurdly
* complicated design.
*/
typedef int(aws_resolve_host_implementation_fn)(
struct aws_allocator *allocator,
const struct aws_string *host_name,
struct aws_array_list *output_addresses,
void *user_data);
struct aws_host_resolution_config {
aws_resolve_host_implementation_fn *impl;
size_t max_ttl;
void *impl_data;
uint64_t resolve_frequency_ns; /* 0 defaults to 1 second interval */
};
struct aws_host_listener;
struct aws_host_listener_options;
struct aws_host_resolver_purge_host_options {
/* the host to purge the cache for */
const struct aws_string *host;
/* Callback to invoke when the purge is complete */
aws_simple_completion_callback *on_host_purge_complete_callback;
/* user_data will be passed as it is in the callback. */
void *user_data;
};
/** should you absolutely disdain the default implementation, feel free to implement your own. */
struct aws_host_resolver_vtable {
/** clean up everything you allocated, but not resolver itself. */
void (*destroy)(struct aws_host_resolver *resolver);
/** resolve the host by host_name, the user owns host_name, so it needs to be copied if you persist it,
* invoke res with the result. This function should never block. */
int (*resolve_host)(
struct aws_host_resolver *resolver,
const struct aws_string *host_name,
aws_on_host_resolved_result_fn *res,
const struct aws_host_resolution_config *config,
void *user_data);
/** gives your implementation a hint that an address has some failed connections occuring. Do whatever you want (or
* nothing) about it.
*/
int (*record_connection_failure)(struct aws_host_resolver *resolver, const struct aws_host_address *address);
/**
* @Deprecated Use purge_cache_with_callback instead
* wipe out anything you have cached. */
int (*purge_cache)(struct aws_host_resolver *resolver);
/** wipe out anything you have cached. */
int (*purge_cache_with_callback)(
struct aws_host_resolver *resolver,
aws_simple_completion_callback *on_purge_cache_complete_callback,
void *user_data);
/** wipe out anything cached for a specific host */
int (*purge_host_cache)(
struct aws_host_resolver *resolver,
const struct aws_host_resolver_purge_host_options *options);
/** get number of addresses for a given host. */
size_t (*get_host_address_count)(
struct aws_host_resolver *resolver,
const struct aws_string *host_name,
uint32_t flags);
};
struct aws_host_resolver {
struct aws_allocator *allocator;
void *impl;
struct aws_host_resolver_vtable *vtable;
struct aws_ref_count ref_count;
struct aws_shutdown_callback_options shutdown_options;
};
struct aws_host_resolver_default_options {
size_t max_entries;
struct aws_event_loop_group *el_group;
const struct aws_shutdown_callback_options *shutdown_options;
aws_io_clock_fn *system_clock_override_fn;
};
AWS_EXTERN_C_BEGIN
/**
* Copies `from` to `to`.
*/
AWS_IO_API int aws_host_address_copy(const struct aws_host_address *from, struct aws_host_address *to);
/**
* Moves `from` to `to`. After this call, from is no longer usable. Though, it could be resused for another
* move or copy operation.
*/
AWS_IO_API void aws_host_address_move(struct aws_host_address *from, struct aws_host_address *to);
/**
* Cleans up the memory for `address`
*/
AWS_IO_API void aws_host_address_clean_up(struct aws_host_address *address);
/** WARNING! do not call this function directly (getaddrinfo()): it blocks. Provide a pointer to this function for other
* resolution functions. */
AWS_IO_API int aws_default_dns_resolve(
struct aws_allocator *allocator,
const struct aws_string *host_name,
struct aws_array_list *output_addresses,
void *user_data);
/**
* Creates a host resolver with the default behavior. Here's the behavior:
*
* Since there's not a reliable way to do non-blocking DNS without a ton of risky work that would need years of testing
* on every Unix system in existence, we work around it by doing a threaded implementation.
*
* When you request an address, it checks the cache. If the entry isn't in the cache it creates a new one.
* Each entry has a potentially short lived back-ground thread based on ttl for the records. Once we've populated the
* cache and you keep the resolver active, the resolution callback will be invoked immediately. When it's idle, it will
* take a little while in the background thread to fetch more, evaluate TTLs etc... In that case your callback will be
* invoked from the background thread.
*
* --------------------------------------------------------------------------------------------------------------------
*
* A few things to note about TTLs and connection failures.
*
* We attempt to honor your max ttl but will not honor it if dns queries are failing or all of your connections are
* marked as failed. Once we are able to query dns again, we will re-evaluate the TTLs.
*
* Upon notification connection failures, we move them to a separate list. Eventually we retry them when it's likely
* that the endpoint is healthy again or we don't really have another choice, but we try to keep them out of your
* hot path.
*
* ---------------------------------------------------------------------------------------------------------------------
*
* Finally, this entire design attempts to prevent problems where developers have to choose between large TTLs and thus
* sticky hosts or short TTLs and good fleet utilization but now higher latencies. In this design, we resolve every
* second in the background (only while you're actually using the record), but we do not expire the earlier resolved
* addresses until max ttl has passed.
*
* This for example, should enable you to hit thousands of hosts in the Amazon S3 fleet instead of just one or two.
*/
AWS_IO_API struct aws_host_resolver *aws_host_resolver_new_default(
struct aws_allocator *allocator,
const struct aws_host_resolver_default_options *options);
/**
* Increments the reference count on the host resolver, allowing the caller to take a reference to it.
*
* Returns the same host resolver passed in.
*/
AWS_IO_API struct aws_host_resolver *aws_host_resolver_acquire(struct aws_host_resolver *resolver);
/**
* Decrements a host resolver's ref count. When the ref count drops to zero, the resolver will be destroyed.
*/
AWS_IO_API void aws_host_resolver_release(struct aws_host_resolver *resolver);
/**
* calls resolve_host on the vtable. config will be copied.
*/
AWS_IO_API int aws_host_resolver_resolve_host(
struct aws_host_resolver *resolver,
const struct aws_string *host_name,
aws_on_host_resolved_result_fn *res,
const struct aws_host_resolution_config *config,
void *user_data);
/**
* calls record_connection_failure on the vtable.
*/
AWS_IO_API int aws_host_resolver_record_connection_failure(
struct aws_host_resolver *resolver,
const struct aws_host_address *address);
/**
* @Deprecated Use purge_cache_with_callback instead
* calls purge_cache on the vtable.
*/
AWS_IO_API int aws_host_resolver_purge_cache(struct aws_host_resolver *resolver);
/**
* Calls aws_host_resolver_purge_cache_with_callback on the vtable which will wipe out everything host resolver has
* cached.
*/
AWS_IO_API int aws_host_resolver_purge_cache_with_callback(
struct aws_host_resolver *resolver,
aws_simple_completion_callback *on_purge_cache_complete_callback,
void *user_data);
/**
* Removes the cache for a host asynchronously.
*/
AWS_IO_API int aws_host_resolver_purge_host_cache(
struct aws_host_resolver *resolver,
const struct aws_host_resolver_purge_host_options *options);
/**
* get number of addresses for a given host.
*/
AWS_IO_API size_t aws_host_resolver_get_host_address_count(
struct aws_host_resolver *resolver,
const struct aws_string *host_name,
uint32_t flags);
/**
* Returns the default host resolution config used internally if none specified.
*
* @return default host resolution config
*/
AWS_IO_API struct aws_host_resolution_config aws_host_resolver_init_default_resolution_config(void);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_IO_HOST_RESOLVER_H */
|