1 /* wolfevent.c
2 *
3 * Copyright (C) 2006-2021 wolfSSL Inc.
4 *
5 * This file is part of wolfSSL.
6 *
7 * wolfSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * wolfSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <wolfssl/wolfcrypt/settings.h>
27
28
29 #ifdef HAVE_WOLF_EVENT
30
31 #include <wolfssl/internal.h>
32 #include <wolfssl/error-ssl.h>
33 #include <wolfssl/wolfcrypt/error-crypt.h>
34
35 #include <wolfssl/wolfcrypt/wolfevent.h>
36
37
wolfEvent_Init(WOLF_EVENT * event,WOLF_EVENT_TYPE type,void * context)38 int wolfEvent_Init(WOLF_EVENT* event, WOLF_EVENT_TYPE type, void* context)
39 {
40 if (event == NULL) {
41 return BAD_FUNC_ARG;
42 }
43
44 if (event->state == WOLF_EVENT_STATE_PENDING) {
45 WOLFSSL_MSG("Event already pending!");
46 return BAD_COND_E;
47 }
48
49 XMEMSET(event, 0, sizeof(WOLF_EVENT));
50 event->type = type;
51 event->context = context;
52
53 return 0;
54 }
55
wolfEvent_Poll(WOLF_EVENT * event,WOLF_EVENT_FLAG flags)56 int wolfEvent_Poll(WOLF_EVENT* event, WOLF_EVENT_FLAG flags)
57 {
58 int ret = BAD_COND_E;
59
60 /* Check hardware */
61 #ifdef WOLFSSL_ASYNC_CRYPT
62 if (event->type >= WOLF_EVENT_TYPE_ASYNC_FIRST &&
63 event->type <= WOLF_EVENT_TYPE_ASYNC_LAST)
64 {
65 ret = wolfAsync_EventPoll(event, flags);
66 }
67 #endif /* WOLFSSL_ASYNC_CRYPT */
68
69 return ret;
70 }
71
wolfEventQueue_Init(WOLF_EVENT_QUEUE * queue)72 int wolfEventQueue_Init(WOLF_EVENT_QUEUE* queue)
73 {
74 int ret = 0;
75
76 if (queue == NULL) {
77 return BAD_FUNC_ARG;
78 }
79
80 XMEMSET(queue, 0, sizeof(WOLF_EVENT_QUEUE));
81 #ifndef SINGLE_THREADED
82 ret = wc_InitMutex(&queue->lock);
83 #endif
84 return ret;
85 }
86
87
wolfEventQueue_Push(WOLF_EVENT_QUEUE * queue,WOLF_EVENT * event)88 int wolfEventQueue_Push(WOLF_EVENT_QUEUE* queue, WOLF_EVENT* event)
89 {
90 int ret;
91
92 if (queue == NULL || event == NULL) {
93 return BAD_FUNC_ARG;
94 }
95
96 #ifndef SINGLE_THREADED
97 if ((ret = wc_LockMutex(&queue->lock)) != 0) {
98 return ret;
99 }
100 #endif
101
102 ret = wolfEventQueue_Add(queue, event);
103
104 #ifndef SINGLE_THREADED
105 wc_UnLockMutex(&queue->lock);
106 #endif
107
108 return ret;
109 }
110
wolfEventQueue_Pop(WOLF_EVENT_QUEUE * queue,WOLF_EVENT ** event)111 int wolfEventQueue_Pop(WOLF_EVENT_QUEUE* queue, WOLF_EVENT** event)
112 {
113 int ret = 0;
114
115 if (queue == NULL || event == NULL) {
116 return BAD_FUNC_ARG;
117 }
118
119 #ifndef SINGLE_THREADED
120 /* In single threaded mode "event_queue.lock" doesn't exist */
121 if ((ret = wc_LockMutex(&queue->lock)) != 0) {
122 return ret;
123 }
124 #endif
125
126 /* Pop first item off queue */
127 *event = queue->head;
128 ret = wolfEventQueue_Remove(queue, *event);
129
130 #ifndef SINGLE_THREADED
131 wc_UnLockMutex(&queue->lock);
132 #endif
133
134 return ret;
135 }
136
137 /* assumes queue is locked by caller */
wolfEventQueue_Add(WOLF_EVENT_QUEUE * queue,WOLF_EVENT * event)138 int wolfEventQueue_Add(WOLF_EVENT_QUEUE* queue, WOLF_EVENT* event)
139 {
140 if (queue == NULL || event == NULL) {
141 return BAD_FUNC_ARG;
142 }
143
144 event->next = NULL; /* added to end */
145 event->prev = NULL;
146 if (queue->tail == NULL) {
147 queue->head = event;
148 }
149 else {
150 queue->tail->next = event;
151 event->prev = queue->tail;
152 }
153 queue->tail = event; /* add to the end either way */
154 queue->count++;
155
156 return 0;
157 }
158
159 /* assumes queue is locked by caller */
wolfEventQueue_Remove(WOLF_EVENT_QUEUE * queue,WOLF_EVENT * event)160 int wolfEventQueue_Remove(WOLF_EVENT_QUEUE* queue, WOLF_EVENT* event)
161 {
162 int ret = 0;
163
164 if (queue == NULL || event == NULL) {
165 return BAD_FUNC_ARG;
166 }
167
168 if (event == queue->head && event == queue->tail) {
169 queue->head = NULL;
170 queue->tail = NULL;
171 }
172 else if (event == queue->head) {
173 queue->head = event->next;
174 queue->head->prev = NULL;
175 }
176 else if (event == queue->tail) {
177 queue->tail = event->prev;
178 queue->tail->next = NULL;
179 }
180 else {
181 WOLF_EVENT* next = event->next;
182 WOLF_EVENT* prev = event->prev;
183 next->prev = prev;
184 prev->next = next;
185 }
186 queue->count--;
187
188 return ret;
189 }
190
wolfEventQueue_Poll(WOLF_EVENT_QUEUE * queue,void * context_filter,WOLF_EVENT ** events,int maxEvents,WOLF_EVENT_FLAG flags,int * eventCount)191 int wolfEventQueue_Poll(WOLF_EVENT_QUEUE* queue, void* context_filter,
192 WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags, int* eventCount)
193 {
194 WOLF_EVENT* event;
195 int ret = 0, count = 0;
196
197 if (queue == NULL) {
198 return BAD_FUNC_ARG;
199 }
200
201 #ifndef SINGLE_THREADED
202 /* In single threaded mode "event_queue.lock" doesn't exist */
203 if ((ret = wc_LockMutex(&queue->lock)) != 0) {
204 return ret;
205 }
206 #endif
207
208 /* itterate event queue */
209 for (event = queue->head; event != NULL; event = event->next)
210 {
211 /* optional filter based on context */
212 if (context_filter == NULL || event->context == context_filter) {
213
214 /* poll event */
215 ret = wolfEvent_Poll(event, flags);
216 if (ret < 0) break; /* exit for */
217
218 /* If event is done then process */
219 if (event->state == WOLF_EVENT_STATE_DONE) {
220 /* remove from queue */
221 ret = wolfEventQueue_Remove(queue, event);
222 if (ret < 0) break; /* exit for */
223
224 /* return pointer in 'events' arg */
225 if (events) {
226 events[count] = event; /* return pointer */
227 }
228 count++;
229
230 /* check to make sure our event list isn't full */
231 if (events && count >= maxEvents) {
232 break; /* exit for */
233 }
234 }
235 }
236 }
237
238 #ifndef SINGLE_THREADED
239 wc_UnLockMutex(&queue->lock);
240 #endif
241
242 /* return number of properly populated events */
243 if (eventCount) {
244 *eventCount = count;
245 }
246
247 return ret;
248 }
249
wolfEventQueue_Count(WOLF_EVENT_QUEUE * queue)250 int wolfEventQueue_Count(WOLF_EVENT_QUEUE* queue)
251 {
252 int ret;
253
254 if (queue == NULL) {
255 return BAD_FUNC_ARG;
256 }
257
258 #ifndef SINGLE_THREADED
259 /* In single threaded mode "event_queue.lock" doesn't exist */
260 if ((ret = wc_LockMutex(&queue->lock)) != 0) {
261 return ret;
262 }
263 #endif
264
265 ret = queue->count;
266
267 #ifndef SINGLE_THREADED
268 wc_UnLockMutex(&queue->lock);
269 #endif
270
271 return ret;
272 }
273
wolfEventQueue_Free(WOLF_EVENT_QUEUE * queue)274 void wolfEventQueue_Free(WOLF_EVENT_QUEUE* queue)
275 {
276 if (queue) {
277 #ifndef SINGLE_THREADED
278 wc_FreeMutex(&queue->lock);
279 #endif
280 }
281 }
282
283 #endif /* HAVE_WOLF_EVENT */
284