mirror of
https://github.com/openssl/openssl.git
synced 2024-12-21 06:09:35 +08:00
e6be47e427
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18345)
195 lines
5.5 KiB
C
195 lines
5.5 KiB
C
/*
|
|
* 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;
|
|
}
|