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