File: host_resolver.h

package info (click to toggle)
aws-crt-python 0.16.8%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,328 kB
  • sloc: ansic: 330,743; python: 18,949; makefile: 6,271; sh: 3,712; asm: 754; cpp: 699; ruby: 208; java: 77; perl: 73; javascript: 46; xml: 11
file content (299 lines) | stat: -rw-r--r-- 11,993 bytes parent folder | download
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#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>

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;
};

struct aws_host_listener;

struct aws_host_listener_options;

/** 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, struct aws_host_address *address);
    /** wipe out anything you have cached. */
    int (*purge_cache)(struct aws_host_resolver *resolver);
    /** 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);

    /** creates and adds a listener to the host resolver. */
    struct aws_host_listener *(
        *add_host_listener)(struct aws_host_resolver *resolver, const struct aws_host_listener_options *options);

    /** removes a host listener from the host resolver and frees it. */
    int (*remove_host_listener)(struct aws_host_resolver *resolver, struct aws_host_listener *listener);
};

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,
    struct aws_host_address *address);

/**
 * calls purge_cache on the vtable.
 */
AWS_IO_API int aws_host_resolver_purge_cache(struct aws_host_resolver *resolver);

/**
 * 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);

/* Callback for receiving new host addresses from a listener. Memory for the new address list is only guaranteed to
 * exist during the callback, and must be copied if the caller needs it to persist after. */
typedef void(aws_host_listener_resolved_address_fn)(
    /* Listener that owns this callback. */
    struct aws_host_listener *listener,

    /* Array list of aws_host_address structures.  To get an item:
     *
     * struct aws_host_address *host_address = NULL;
     * aws_array_list_get_at_ptr(new_address_list, (void **)&host_address, address_index);
     * */
    const struct aws_array_list *new_address_list,

    /* User data that was specified when adding the listener. */
    void *user_data);

/* Callback for learning of an expired address from a listener. Memory for the expired address list is only guaranteed
 * to exist during the callback, and must be copied if the caller needs it to persist after. */
typedef void(aws_host_listener_expired_address_fn)(
    /* Listener that owns this callback. */
    struct aws_host_listener *listener,

    /* Array list of aws_host_address structures.  To get an item:
     *
     * struct aws_host_address *host_address = NULL;
     * aws_array_list_get_at_ptr(new_address_list, (void **)&host_address, address_index);
     * */
    const struct aws_array_list *expired_address_list,

    /* User data that was specified when adding the listener. */
    void *user_data);

/* Callback for when the listener has completed its clean up. */
typedef void(aws_host_listener_shutdown_fn)(void *user_data);

struct aws_host_listener_options {

    /* Name of the host to listen for notifications from. */
    struct aws_byte_cursor host_name;

    /* Callback for when an address is resolved for the specified host. */
    aws_host_listener_resolved_address_fn *resolved_address_callback;

    /* Callback for when a resolved address expires for the specified host. */
    aws_host_listener_expired_address_fn *expired_address_callback;

    /* Callback for when a listener has completely shutdown. */
    aws_host_listener_shutdown_fn *shutdown_callback;

    /* User data to be passed into each callback. */
    void *user_data;

    /* Lets the resolver know to keep the resolution thread alive for as long as this listener is attached */
    bool pin_host_entry;
};

/* Create and add a listener to the host resolver using the specified options. */
AWS_IO_API struct aws_host_listener *aws_host_resolver_add_host_listener(
    struct aws_host_resolver *resolver,
    const struct aws_host_listener_options *options);

/* Remove the specified listener from the host resolver, triggering clean up of the listener. Note: this may not happen
 * synchronously, and it is necessary to wait for the listener's shutdown callback to trigger. */
AWS_IO_API int aws_host_resolver_remove_host_listener(
    struct aws_host_resolver *resolver,
    struct aws_host_listener *listener);

AWS_EXTERN_C_END

#endif /* AWS_IO_HOST_RESOLVER_H */