ASYNC_WAIT_CTX_NEW(3SSL)
β¨ NAME β¨
okay so this is the ASYNC_WAIT_CTX_new(3SSL) page from the OpenSSL manual (section 3SSL, the library-functions shelf π
) and it's lowkey a whole friend group of functions that manage waiting for asynchronous jobs to complete. Like, "bestie the job isn't done yet, hold my hand while we wait" energy.
The full squad assembled:
ASYNC_WAIT_CTX_newASYNC_WAIT_CTX_freeASYNC_WAIT_CTX_set_wait_fdASYNC_WAIT_CTX_get_fdASYNC_WAIT_CTX_get_all_fdsASYNC_WAIT_CTX_get_changed_fdsASYNC_WAIT_CTX_clear_fdASYNC_WAIT_CTX_set_callbackASYNC_WAIT_CTX_get_callbackASYNC_WAIT_CTX_set_statusASYNC_WAIT_CTX_get_statusASYNC_callback_fnASYNC_STATUS_UNSUPPORTEDASYNC_STATUS_ERRASYNC_STATUS_OKASYNC_STATUS_EAGAIN
πΈ SYNOPSIS πΈ
#include <openssl/async.h>
#define ASYNC_STATUS_UNSUPPORTED 0
#define ASYNC_STATUS_ERR 1
#define ASYNC_STATUS_OK 2
#define ASYNC_STATUS_EAGAIN 3
typedef int (*ASYNC_callback_fn)(void *arg);
ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
OSSL_ASYNC_FD fd,
void *custom_data,
void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
OSSL_ASYNC_FD, void *));
int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
OSSL_ASYNC_FD *fd, void **custom_data);
int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
size_t *numfds);
int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
size_t *numaddfds, OSSL_ASYNC_FD *delfd,
size_t *numdelfds);
int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
ASYNC_callback_fn callback,
void *callback_arg);
int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
ASYNC_callback_fn *callback,
void **callback_arg);
int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
π¦ DESCRIPTION π¦
So if you want the big-picture lore on how async operations are even implemented in OpenSSL, go read ASYNC_start_job(3). An ASYNC_WAIT_CTX object represents an asynchronous "session", i.e. a related set of crypto operations. In SSL terms? It's a strict one-to-one correspondence with an SSL connection. Periodt. π
Application code must create an ASYNC_WAIT_CTX with ASYNC_WAIT_CTX_new() before it calls ASYNC_start_job() (again, see ASYNC_start_job(3)). When the job is started it gets associated with that ASYNC_WAIT_CTX for the duration of the job. One ASYNC_WAIT_CTX should only ever be used for one ASYNC_JOB at any one time β no sharing, bestie, it's giving monogamy β but it can be reused for a subsequent ASYNC_JOB once the previous one has finished. When the session is complete (like, the SSL connection is closed), application code cleans up with ASYNC_WAIT_CTX_free().
the fd situation π
ASYNC_WAIT_CTXs can have "wait" file descriptors associated with them. Call ASYNC_WAIT_CTX_get_all_fds() and hand it a pointer to an ASYNC_WAIT_CTX in the ctx parameter, and it'll return the wait file descriptors associated with that job in fd. How many came back? That number lands in numfds. And heads up: it is the caller's responsibility to make sure enough memory has been allocated in fd to receive all the file descriptors. If you call ASYNC_WAIT_CTX_get_all_fds() with a NULL fd value, you get no file descriptors but numfds still gets populated. So the typical move is calling this function twice: once to learn how many fds, then again once you've allocated enough memory. If only one asynchronous provider is in play, normally this call only ever returns one fd. Multiple async providers? Then you might get more back. icons only.
And ASYNC_WAIT_CTX_get_changed_fds() is your detective function β it detects whether any fds have changed since the last time ASYNC_start_job() returned ASYNC_PAUSE (or since the ASYNC_WAIT_CTX was created, if no ASYNC_PAUSE result has been received yet). The numaddfds and numdelfds parameters get populated with the number of fds added or deleted respectively, and *addfd and *delfd get populated with the list of added and deleted fds respectively. Same energy as ASYNC_WAIT_CTX_get_all_fds(): either of these can be NULL, but if they're not NULL then the caller is responsible for ensuring sufficient memory is allocated.
Implementers of async aware code (hi, providers π) are encouraged to return a stable fd for the lifetime of the ASYNC_WAIT_CTX, to reduce the "churn" of regularly changing fds β though ngl, no guarantees of this are provided to applications. So don't build your whole personality on it.
Applications can wait for the file descriptor to be ready for "read" using a system function call such as select or poll β being ready for "read" indicates the job should be resumed, iykyk. And if no file descriptor is made available? Then an application has to periodically "poll" the job by attempting to restart it, just checking if it's ready to continue. Not me refreshing the job like a group chat π.
talking to the job π«Ά
Async aware code (providers, again) can grab the current ASYNC_WAIT_CTX from the job via ASYNC_get_wait_ctx(3), and hand over a file descriptor to wait on by calling ASYNC_WAIT_CTX_set_wait_fd(). Typically a provider does this right before calling ASYNC_pause_job() β this is not end user code behaviour, bestie, stay in your lane. An existing association with a file descriptor can be fetched with ASYNC_WAIT_CTX_get_fd() and cleared with ASYNC_WAIT_CTX_clear_fd(). Both of these need a key value that's unique to the async aware code β could be literally any unique value. The custom_data parameter can be any value too, and it'll come back to you in a subsequent call to ASYNC_WAIT_CTX_get_fd().
ASYNC_WAIT_CTX_set_wait_fd() also expects a pointer to a "cleanup" routine. It can be NULL, but if provided it automatically gets called when the ASYNC_WAIT_CTX is freed β giving the provider the chance to close the fd or tidy up other resources.
β οΈ Note: the "cleanup" routine does not get called if the fd is cleared directly via a call to ASYNC_WAIT_CTX_clear_fd(). So don't expect it and then act brand new when it doesn't show up. π
the typical usage pipeline β¨
An example of typical usage might be an async capable provider. User code initiates cryptographic operations. The provider initiates those operations asynchronously, then calls ASYNC_WAIT_CTX_set_wait_fd() followed by ASYNC_pause_job() to hand control back to the user code. The user code can then do other tasks, or wait for the job to be ready by calling select or another similar function on the wait file descriptor. The provider signals that the job should be resumed by making the wait file descriptor "readable". Once resumed, the provider should clear the wake signal on the wait file descriptor. Clean, coordinated, ate. π
callback era β
As well as a file descriptor, user code may also be notified via a callback. The callback and data pointers are stored within the ASYNC_WAIT_CTX along with an additional status field, which can be used for the notification of retries from a provider. This extra method is your bestie when the user thinks a file descriptor is too costly in terms of CPU cycles, or in some context where a file descriptor just isn't appropriate.
ASYNC_WAIT_CTX_set_callback()sets the callback and the callback argument. The callback gets called to notify user code when a provider completes a cryptography operation.
π¨ Big requirement: the callback function must be small and nonblocking, because it will be run in the context of a polling mechanism or an interrupt. No long monologues in there, queen.
ASYNC_WAIT_CTX_get_callback()returns the callback set in theASYNC_WAIT_CTXstructure.ASYNC_WAIT_CTX_set_status()lets a provider set the current provider status. The possible status values are:ASYNC_STATUS_UNSUPPORTEDβ the provider does not support the callback mechanism. This is the default value. The provider must callASYNC_WAIT_CTX_set_status()to set the status to some value other thanASYNC_STATUS_UNSUPPORTEDif it intends to enable the callback mechanism.ASYNC_STATUS_ERRβ the provider has a fatal problem with this request. The user code should clean up this session. π«ASYNC_STATUS_OKβ the request has been successfully submitted. slay.ASYNC_STATUS_EAGAINβ the provider has some problem which will be recovered soon, such as a buffer is full, so user code should resume the job.
ASYNC_WAIT_CTX_get_status() lets user code obtain the current status value. And listen: if the status is any value other than ASYNC_STATUS_OK, then the user code should not expect to receive a callback from the provider β even if one has been set. Don't wait up for a text that isn't coming. π
An example of the usage of the callback method might be the following. User code would initiate cryptographic operations, and the provider code would dispatch this operation to hardware, and if the dispatch is successful, then the provider code would call ASYNC_pause_job() to return control to the user code. After that, user code can perform other tasks. When the hardware completes the operation β normally detected by a polling function or an interrupt β since the user code set a callback by calling ASYNC_WAIT_CTX_set_callback() previously, the registered callback will be called. Main character hardware energy, fr fr. π₯
ASYNC_WAIT_CTX_free() frees up a single ASYNC_WAIT_CTX object. If the argument is NULL, nothing is done. No drama, no crash. π
π RETURN VALUES π
ASYNC_WAIT_CTX_new()returns a pointer to the newly allocatedASYNC_WAIT_CTX, orNULLon error.ASYNC_WAIT_CTX_set_wait_fd,ASYNC_WAIT_CTX_get_fd,ASYNC_WAIT_CTX_get_all_fds,ASYNC_WAIT_CTX_get_changed_fds,ASYNC_WAIT_CTX_clear_fd,ASYNC_WAIT_CTX_set_callback,ASYNC_WAIT_CTX_get_callbackandASYNC_WAIT_CTX_set_statusall return1on success or0on error.ASYNC_WAIT_CTX_get_status()returns the provider status.
π§ NOTES π§
On Windows platforms, the <openssl/async.h> header is dependent on some of the types customarily made available by including <windows.h>. The application developer is likely to require control over when the latter is included β commonly as one of the first included headers. Therefore, it is defined as an application developer's responsibility to include <windows.h> prior to <openssl/async.h>. Yes bestie, that's on you. πͺ
π SEE ALSO π
π HISTORY π
ASYNC_WAIT_CTX_new(),ASYNC_WAIT_CTX_free(),ASYNC_WAIT_CTX_set_wait_fd(),ASYNC_WAIT_CTX_get_fd(),ASYNC_WAIT_CTX_get_all_fds(),ASYNC_WAIT_CTX_get_changed_fds()andASYNC_WAIT_CTX_clear_fd()were added in OpenSSL 1.1.0. πΌASYNC_WAIT_CTX_set_callback(),ASYNC_WAIT_CTX_get_callback(),ASYNC_WAIT_CTX_set_status(), andASYNC_WAIT_CTX_get_status()were added in OpenSSL 3.0. β¨
...and there's more where that came from, bestie β pt. 2 loading π¦
π COPYRIGHT π
okay bestie, legal bit, but make it cute π
Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. π«Ά
Licensed under the Apache License 2.0 (the "License"). β¨
real talk: you may not use this file except in compliance with the License. like, that's the whole vibe check and you gotta pass it. π«
You can obtain a copy of the License in the file LICENSE in the source distribution, or at https://www.openssl.org/source/license.html π¦
and that's a wrap on the whole page, no cap π this one shipped as version 4.0.3, dated 2026-09-29, and it lives in the manual as ASYNC_WAIT_CTX_NEW(3SSL) β go forth and async responsibly, mwah πβ¨π
π¦ where this page comes from
- ubuntu stonking: libssl-doc 4.0.3-1ubuntu1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms