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