xref: /openssl/ssl/event_queue.c (revision d13c8b77)
1 /*
2  * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdlib.h>
11 #include "internal/event_queue.h"
12 #include "crypto/sparse_array.h"
13 #include "ssl_local.h"
14 
15 struct ossl_event_queue_st {
16     PRIORITY_QUEUE_OF(OSSL_EVENT) *timed_events;
17     PRIORITY_QUEUE_OF(OSSL_EVENT) *now_events;
18 };
19 
event_compare_times(const OSSL_EVENT * a,const OSSL_EVENT * b)20 static int event_compare_times(const OSSL_EVENT *a, const OSSL_EVENT *b)
21 {
22     return ossl_time_compare(a->when, b->when);
23 }
24 
event_compare_priority(const OSSL_EVENT * a,const OSSL_EVENT * b)25 static int event_compare_priority(const OSSL_EVENT *a, const OSSL_EVENT *b)
26 {
27     if (a->priority > b->priority)
28         return -1;
29     if (a->priority < b->priority)
30         return 1;
31     return 0;
32 }
33 
ossl_event_queue_new(void)34 OSSL_EVENT_QUEUE *ossl_event_queue_new(void)
35 {
36     OSSL_EVENT_QUEUE *r = OPENSSL_malloc(sizeof(*r));
37 
38     if (r != NULL) {
39         r->timed_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_times);
40         r->now_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_priority);
41         if (r->timed_events == NULL || r->now_events == NULL) {
42             ossl_event_queue_free(r);
43             return NULL;
44         }
45     }
46     return r;
47 }
48 
ossl_event_free(OSSL_EVENT * event)49 void ossl_event_free(OSSL_EVENT *event)
50 {
51     if (event != NULL) {
52         if (event->flag_dynamic)
53             OPENSSL_free(event);
54         else
55             event->queue = NULL;
56     }
57 }
58 
event_queue_free(PRIORITY_QUEUE_OF (OSSL_EVENT)* queue)59 static void event_queue_free(PRIORITY_QUEUE_OF(OSSL_EVENT) *queue)
60 {
61     OSSL_EVENT *e;
62 
63     if (queue != NULL) {
64         while ((e = ossl_pqueue_OSSL_EVENT_pop(queue)) != NULL)
65             ossl_event_free(e);
66         ossl_pqueue_OSSL_EVENT_free(queue);
67     }
68 }
69 
ossl_event_queue_free(OSSL_EVENT_QUEUE * queue)70 void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue)
71 {
72     if (queue != NULL) {
73         event_queue_free(queue->now_events);
74         event_queue_free(queue->timed_events);
75         OPENSSL_free(queue);
76     }
77 }
78 
79 static ossl_inline
event_queue_add(OSSL_EVENT_QUEUE * queue,OSSL_EVENT * event)80 int event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
81 {
82     PRIORITY_QUEUE_OF(OSSL_EVENT) *pq =
83             ossl_time_compare(event->when, ossl_time_now()) <= 0
84             ? queue->now_events
85             : queue->timed_events;
86 
87     if (ossl_pqueue_OSSL_EVENT_push(pq, event, &event->ref)) {
88         event->queue = pq;
89         return 1;
90     }
91     return 0;
92 }
93 
94 static ossl_inline
ossl_event_set(OSSL_EVENT * event,uint32_t type,uint32_t priority,OSSL_TIME when,void * ctx,void * payload,size_t payload_size)95 void ossl_event_set(OSSL_EVENT *event, uint32_t type, uint32_t priority,
96                     OSSL_TIME when, void *ctx,
97                     void *payload, size_t payload_size)
98 {
99     event->type = type;
100     event->priority = priority;
101     event->when = when;
102     event->ctx = ctx;
103     event->payload = payload;
104     event->payload_size = payload_size;
105 }
106 
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)107 OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
108                                      uint32_t type, uint32_t priority,
109                                      OSSL_TIME when, void *ctx,
110                                      void *payload, size_t payload_size)
111 {
112     OSSL_EVENT *e = OPENSSL_malloc(sizeof(*e));
113 
114     if (e == NULL || queue == NULL)
115         return NULL;
116     ossl_event_set(e, type, priority, when, ctx, payload, payload_size);
117     e->flag_dynamic = 1;
118     if (event_queue_add(queue, e))
119         return e;
120     OPENSSL_free(e);
121     return NULL;
122 }
123 
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)124 int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
125                          uint32_t type, uint32_t priority,
126                          OSSL_TIME when, void *ctx,
127                          void *payload, size_t payload_size)
128 {
129     if (event == NULL || queue == NULL)
130         return 0;
131     ossl_event_set(event, type, priority, when, ctx, payload, payload_size);
132     event->flag_dynamic = 0;
133     return event_queue_add(queue, event);
134 }
135 
ossl_event_queue_remove(OSSL_EVENT_QUEUE * queue,OSSL_EVENT * event)136 int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
137 {
138     if (event != NULL && event->queue != NULL) {
139         ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref);
140         event->queue = NULL;
141     }
142     return 1;
143 }
144 
ossl_event_time_until(const OSSL_EVENT * event)145 OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event)
146 {
147     if (event == NULL)
148         return ossl_time_infinite();
149     return ossl_time_subtract(event->when, ossl_time_now());
150 }
151 
ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE * queue)152 OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue)
153 {
154     if (queue == NULL)
155         return ossl_time_infinite();
156     if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0)
157         return ossl_time_zero();
158     return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events));
159 }
160 
ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE * queue,OSSL_EVENT * event,OSSL_TIME when)161 int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
162                                     OSSL_EVENT *event,
163                                     OSSL_TIME when)
164 {
165     if (ossl_event_queue_remove(queue, event)) {
166         event->when = when;
167         return event_queue_add(queue, event);
168     }
169     return 0;
170 }
171 
ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE * queue,OSSL_EVENT ** event)172 int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
173                                      OSSL_EVENT **event)
174 {
175     OSSL_TIME now = ossl_time_now();
176     OSSL_EVENT *e;
177 
178     /* Check for expired timer based events and convert them to now events */
179     while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL
180            && ossl_time_compare(e->when, now) <= 0) {
181         e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events);
182         if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) {
183             e->queue = NULL;
184             return 0;
185         }
186     }
187 
188     /*
189      * Get next event from the now queue.
190      * The pop returns NULL when there is none.
191      */
192     *event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events);
193     return 1;
194 }
195