]>
Commit | Line | Data |
---|---|---|
e6be47e4 | 1 | /* |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
e6be47e4 P |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | |
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 | |
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 | ||
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 | ||
77a66117 HL |
114 | if (e == NULL || queue == NULL) { |
115 | OPENSSL_free(e); | |
e6be47e4 | 116 | return NULL; |
77a66117 HL |
117 | } |
118 | ||
e6be47e4 P |
119 | ossl_event_set(e, type, priority, when, ctx, payload, payload_size); |
120 | e->flag_dynamic = 1; | |
121 | if (event_queue_add(queue, e)) | |
122 | return e; | |
123 | OPENSSL_free(e); | |
124 | return NULL; | |
125 | } | |
126 | ||
127 | int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event, | |
128 | uint32_t type, uint32_t priority, | |
129 | OSSL_TIME when, void *ctx, | |
130 | void *payload, size_t payload_size) | |
131 | { | |
132 | if (event == NULL || queue == NULL) | |
133 | return 0; | |
134 | ossl_event_set(event, type, priority, when, ctx, payload, payload_size); | |
135 | event->flag_dynamic = 0; | |
136 | return event_queue_add(queue, event); | |
137 | } | |
138 | ||
139 | int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event) | |
140 | { | |
141 | if (event != NULL && event->queue != NULL) { | |
142 | ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref); | |
143 | event->queue = NULL; | |
144 | } | |
145 | return 1; | |
146 | } | |
147 | ||
148 | OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event) | |
149 | { | |
150 | if (event == NULL) | |
d13c8b77 | 151 | return ossl_time_infinite(); |
e6be47e4 P |
152 | return ossl_time_subtract(event->when, ossl_time_now()); |
153 | } | |
154 | ||
155 | OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue) | |
156 | { | |
157 | if (queue == NULL) | |
d13c8b77 | 158 | return ossl_time_infinite(); |
e6be47e4 | 159 | if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0) |
d13c8b77 | 160 | return ossl_time_zero(); |
e6be47e4 P |
161 | return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)); |
162 | } | |
163 | ||
164 | int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue, | |
165 | OSSL_EVENT *event, | |
166 | OSSL_TIME when) | |
167 | { | |
168 | if (ossl_event_queue_remove(queue, event)) { | |
169 | event->when = when; | |
170 | return event_queue_add(queue, event); | |
171 | } | |
172 | return 0; | |
173 | } | |
174 | ||
175 | int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue, | |
176 | OSSL_EVENT **event) | |
177 | { | |
178 | OSSL_TIME now = ossl_time_now(); | |
179 | OSSL_EVENT *e; | |
180 | ||
181 | /* Check for expired timer based events and convert them to now events */ | |
182 | while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL | |
183 | && ossl_time_compare(e->when, now) <= 0) { | |
184 | e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events); | |
185 | if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) { | |
186 | e->queue = NULL; | |
187 | return 0; | |
188 | } | |
189 | } | |
190 | ||
191 | /* | |
192 | * Get next event from the now queue. | |
193 | * The pop returns NULL when there is none. | |
194 | */ | |
195 | *event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events); | |
196 | return 1; | |
197 | } |