mirror of
https://github.com/openssl/openssl.git
synced 2025-02-17 14:32:04 +08:00
ssl: implement an event queue
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18345)
This commit is contained in:
parent
16612c1929
commit
e6be47e427
163
include/internal/event_queue.h
Normal file
163
include/internal/event_queue.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_INTERNAL_EVENT_QUEUE_H
|
||||
# define OSSL_INTERNAL_EVENT_QUEUE_H
|
||||
# pragma once
|
||||
|
||||
# include "internal/priority_queue.h"
|
||||
# include "internal/time.h"
|
||||
|
||||
/*
|
||||
* Opaque type holding an event.
|
||||
*/
|
||||
typedef struct ossl_event_st OSSL_EVENT;
|
||||
|
||||
DEFINE_PRIORITY_QUEUE_OF(OSSL_EVENT);
|
||||
|
||||
/*
|
||||
* Public type representing an event queue, the underlying structure being
|
||||
* opaque.
|
||||
*/
|
||||
typedef struct ossl_event_queue_st OSSL_EVENT_QUEUE;
|
||||
|
||||
/*
|
||||
* Public type representing a event queue entry.
|
||||
* It is (internally) public so that it can be embedded into other structures,
|
||||
* it should otherwise be treated as opaque.
|
||||
*/
|
||||
struct ossl_event_st {
|
||||
uint32_t type; /* What type of event this is */
|
||||
uint32_t priority; /* What priority this event has */
|
||||
OSSL_TIME when; /* When the event is scheduled to happen */
|
||||
void *ctx; /* User argument passed to call backs */
|
||||
void *payload; /* Event specific data of unknown kind */
|
||||
size_t payload_size; /* Length (in bytes) of event specific data */
|
||||
|
||||
/* These fields are for internal use only */
|
||||
PRIORITY_QUEUE_OF(OSSL_EVENT) *queue; /* Queue containing this event */
|
||||
size_t ref; /* ID for this event */
|
||||
unsigned int flag_dynamic : 1; /* Malloced or not? */
|
||||
};
|
||||
|
||||
/*
|
||||
* Utility function to populate an event structure and add it to the queue
|
||||
*/
|
||||
int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
|
||||
uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size);
|
||||
|
||||
/*
|
||||
* Utility functions to extract event fields
|
||||
*/
|
||||
static ossl_unused ossl_inline
|
||||
uint32_t ossl_event_get_type(const OSSL_EVENT *event)
|
||||
{
|
||||
return event->type;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
uint32_t ossl_event_get_priority(const OSSL_EVENT *event)
|
||||
{
|
||||
return event->priority;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_event_get_when(const OSSL_EVENT *event)
|
||||
{
|
||||
return event->when;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
void *ossl_event_get0_ctx(const OSSL_EVENT *event)
|
||||
{
|
||||
return event->ctx;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
void *ossl_event_get0_payload(const OSSL_EVENT *event, size_t *length)
|
||||
{
|
||||
if (length != NULL)
|
||||
*length = event->payload_size;
|
||||
return event->payload;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and free a queue.
|
||||
*/
|
||||
OSSL_EVENT_QUEUE *ossl_event_queue_new(void);
|
||||
void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue);
|
||||
|
||||
/*
|
||||
* Schedule a new event into an event queue.
|
||||
*
|
||||
* The event parameters are taken from the function arguments.
|
||||
*
|
||||
* The function reutrns NULL on failure and the added event on success.
|
||||
*/
|
||||
OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
|
||||
uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size)
|
||||
;
|
||||
|
||||
/*
|
||||
* Schedule an event into an event queue.
|
||||
*
|
||||
* The event parameters are taken from the function arguments.
|
||||
*
|
||||
* The function reutrns 0 on failure and 1 on success.
|
||||
*/
|
||||
int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
|
||||
uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size);
|
||||
|
||||
/*
|
||||
* Delete an event from the queue.
|
||||
* This will cause the early deletion function to be called if it is non-NULL.
|
||||
* A pointer to the event structure is returned.
|
||||
*/
|
||||
int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event);
|
||||
|
||||
/*
|
||||
* Free a dynamic event.
|
||||
* Is a NOP for a static event.
|
||||
*/
|
||||
void ossl_event_free(OSSL_EVENT *event);
|
||||
|
||||
/*
|
||||
* Return the time until the next event for the specified event, if the event's
|
||||
* time is past, zero is returned. Once activated, the event reference becomes
|
||||
* invalid and this function becomes undefined.
|
||||
*/
|
||||
OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event);
|
||||
|
||||
/*
|
||||
* Return the time until the next event in the queue.
|
||||
* If the next event is in the past, zero is returned.
|
||||
*/
|
||||
OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue);
|
||||
|
||||
/*
|
||||
* Postpone an event to trigger at the specified time.
|
||||
* If the event has triggered, this function's behaviour is undefined.
|
||||
*/
|
||||
int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
|
||||
OSSL_EVENT *event,
|
||||
OSSL_TIME when);
|
||||
|
||||
/*
|
||||
* Return the next event to process.
|
||||
*/
|
||||
int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
|
||||
OSSL_EVENT **event);
|
||||
|
||||
#endif
|
@ -43,7 +43,7 @@ IF[{- !$disabled{'deprecated-3.0'} -}]
|
||||
ENDIF
|
||||
|
||||
IF[{- !$disabled{quic} -}]
|
||||
SOURCE[../libssl]=priority_queue.c
|
||||
SOURCE[../libssl]=priority_queue.c event_queue.c
|
||||
ENDIF
|
||||
|
||||
DEFINE[../libssl]=$AESDEF
|
||||
|
194
ssl/event_queue.c
Normal file
194
ssl/event_queue.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "internal/event_queue.h"
|
||||
#include "crypto/sparse_array.h"
|
||||
#include "ssl_local.h"
|
||||
|
||||
struct ossl_event_queue_st {
|
||||
PRIORITY_QUEUE_OF(OSSL_EVENT) *timed_events;
|
||||
PRIORITY_QUEUE_OF(OSSL_EVENT) *now_events;
|
||||
};
|
||||
|
||||
static int event_compare_times(const OSSL_EVENT *a, const OSSL_EVENT *b)
|
||||
{
|
||||
return ossl_time_compare(a->when, b->when);
|
||||
}
|
||||
|
||||
static int event_compare_priority(const OSSL_EVENT *a, const OSSL_EVENT *b)
|
||||
{
|
||||
if (a->priority > b->priority)
|
||||
return -1;
|
||||
if (a->priority < b->priority)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSSL_EVENT_QUEUE *ossl_event_queue_new(void)
|
||||
{
|
||||
OSSL_EVENT_QUEUE *r = OPENSSL_malloc(sizeof(*r));
|
||||
|
||||
if (r != NULL) {
|
||||
r->timed_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_times);
|
||||
r->now_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_priority);
|
||||
if (r->timed_events == NULL || r->now_events == NULL) {
|
||||
ossl_event_queue_free(r);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void ossl_event_free(OSSL_EVENT *event)
|
||||
{
|
||||
if (event != NULL) {
|
||||
if (event->flag_dynamic)
|
||||
OPENSSL_free(event);
|
||||
else
|
||||
event->queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void event_queue_free(PRIORITY_QUEUE_OF(OSSL_EVENT) *queue)
|
||||
{
|
||||
OSSL_EVENT *e;
|
||||
|
||||
if (queue != NULL) {
|
||||
while ((e = ossl_pqueue_OSSL_EVENT_pop(queue)) != NULL)
|
||||
ossl_event_free(e);
|
||||
ossl_pqueue_OSSL_EVENT_free(queue);
|
||||
}
|
||||
}
|
||||
|
||||
void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue)
|
||||
{
|
||||
if (queue != NULL) {
|
||||
event_queue_free(queue->now_events);
|
||||
event_queue_free(queue->timed_events);
|
||||
OPENSSL_free(queue);
|
||||
}
|
||||
}
|
||||
|
||||
static ossl_inline
|
||||
int event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
|
||||
{
|
||||
PRIORITY_QUEUE_OF(OSSL_EVENT) *pq =
|
||||
ossl_time_compare(event->when, ossl_time_now()) <= 0
|
||||
? queue->now_events
|
||||
: queue->timed_events;
|
||||
|
||||
if (ossl_pqueue_OSSL_EVENT_push(pq, event, &event->ref)) {
|
||||
event->queue = pq;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ossl_inline
|
||||
void ossl_event_set(OSSL_EVENT *event, uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size)
|
||||
{
|
||||
event->type = type;
|
||||
event->priority = priority;
|
||||
event->when = when;
|
||||
event->ctx = ctx;
|
||||
event->payload = payload;
|
||||
event->payload_size = payload_size;
|
||||
}
|
||||
|
||||
OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
|
||||
uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size)
|
||||
{
|
||||
OSSL_EVENT *e = OPENSSL_malloc(sizeof(*e));
|
||||
|
||||
if (e == NULL || queue == NULL)
|
||||
return NULL;
|
||||
ossl_event_set(e, type, priority, when, ctx, payload, payload_size);
|
||||
e->flag_dynamic = 1;
|
||||
if (event_queue_add(queue, e))
|
||||
return e;
|
||||
OPENSSL_free(e);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
|
||||
uint32_t type, uint32_t priority,
|
||||
OSSL_TIME when, void *ctx,
|
||||
void *payload, size_t payload_size)
|
||||
{
|
||||
if (event == NULL || queue == NULL)
|
||||
return 0;
|
||||
ossl_event_set(event, type, priority, when, ctx, payload, payload_size);
|
||||
event->flag_dynamic = 0;
|
||||
return event_queue_add(queue, event);
|
||||
}
|
||||
|
||||
int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
|
||||
{
|
||||
if (event != NULL && event->queue != NULL) {
|
||||
ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref);
|
||||
event->queue = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event)
|
||||
{
|
||||
if (event == NULL)
|
||||
return OSSL_TIME_INFINITY;
|
||||
return ossl_time_subtract(event->when, ossl_time_now());
|
||||
}
|
||||
|
||||
OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue)
|
||||
{
|
||||
if (queue == NULL)
|
||||
return OSSL_TIME_INFINITY;
|
||||
if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0)
|
||||
return OSSL_TIME_IMMEDIATE;
|
||||
return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events));
|
||||
}
|
||||
|
||||
int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
|
||||
OSSL_EVENT *event,
|
||||
OSSL_TIME when)
|
||||
{
|
||||
if (ossl_event_queue_remove(queue, event)) {
|
||||
event->when = when;
|
||||
return event_queue_add(queue, event);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
|
||||
OSSL_EVENT **event)
|
||||
{
|
||||
OSSL_TIME now = ossl_time_now();
|
||||
OSSL_EVENT *e;
|
||||
|
||||
/* Check for expired timer based events and convert them to now events */
|
||||
while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL
|
||||
&& ossl_time_compare(e->when, now) <= 0) {
|
||||
e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events);
|
||||
if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) {
|
||||
e->queue = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get next event from the now queue.
|
||||
* The pop returns NULL when there is none.
|
||||
*/
|
||||
*event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events);
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user