FreeRDP
Loading...
Searching...
No Matches
PubSub.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23
24#include <winpr/collections.h>
25
26#include "../log.h"
27#define TAG WINPR_TAG("pubsub")
28
34struct s_wPubSub
35{
37 BOOL synchronized;
38
39 size_t size;
40 size_t count;
41 wEventType* events;
42};
43
48wEventType* PubSub_GetEventTypes(wPubSub* pubSub, size_t* count)
49{
50 WINPR_ASSERT(pubSub);
51 if (count)
52 *count = pubSub->count;
53
54 return pubSub->events;
55}
56
61void PubSub_Lock(wPubSub* pubSub)
62{
63 WINPR_ASSERT(pubSub);
64 if (pubSub->synchronized)
65 EnterCriticalSection(&pubSub->lock);
66}
67
68void PubSub_Unlock(wPubSub* pubSub)
69{
70 WINPR_ASSERT(pubSub);
71 if (pubSub->synchronized)
72 LeaveCriticalSection(&pubSub->lock);
73}
74
75wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
76{
77 wEventType* event = nullptr;
78
79 WINPR_ASSERT(pubSub);
80 WINPR_ASSERT(EventName);
81 for (size_t index = 0; index < pubSub->count; index++)
82 {
83 if (strcmp(pubSub->events[index].EventName, EventName) == 0)
84 {
85 event = &(pubSub->events[index]);
86 break;
87 }
88 }
89
90 return event;
91}
92
93void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
94{
95 WINPR_ASSERT(pubSub);
96 WINPR_ASSERT(events || (count == 0));
97 if (pubSub->synchronized)
98 PubSub_Lock(pubSub);
99
100 const size_t required = pubSub->count + count;
101 WINPR_ASSERT((required >= pubSub->count) && (required >= count));
102
103 if (required >= pubSub->size)
104 {
105 size_t new_size = pubSub->size;
106 do
107 {
108 WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
109 new_size += 128ull;
110 } while (new_size <= required);
111
112 wEventType* new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
113 if (!new_event)
114 goto fail;
115 pubSub->size = new_size;
116 pubSub->events = new_event;
117 }
118
119 CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
120 pubSub->count += count;
121
122fail:
123 if (pubSub->synchronized)
124 PubSub_Unlock(pubSub);
125}
126
127int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, ...)
128{
129 wEventType* event = nullptr;
130 int status = -1;
131 WINPR_ASSERT(pubSub);
132
133 va_list ap = WINPR_C_ARRAY_INIT;
134 va_start(ap, EventName);
135 pEventHandler EventHandler = va_arg(ap, pEventHandler);
136
137 if (pubSub->synchronized)
138 PubSub_Lock(pubSub);
139
140 event = PubSub_FindEventType(pubSub, EventName);
141
142 if (event)
143 {
144 status = 0;
145
146 if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
147 event->EventHandlers[event->EventHandlerCount++] = EventHandler;
148 else
149 status = -1;
150 }
151
152 if (pubSub->synchronized)
153 PubSub_Unlock(pubSub);
154
155 va_end(ap);
156 return status;
157}
158
159int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, ...)
160{
161 wEventType* event = nullptr;
162 int status = -1;
163 WINPR_ASSERT(pubSub);
164 WINPR_ASSERT(EventName);
165
166 va_list ap = WINPR_C_ARRAY_INIT;
167 va_start(ap, EventName);
168 pEventHandler EventHandler = va_arg(ap, pEventHandler);
169
170 if (pubSub->synchronized)
171 PubSub_Lock(pubSub);
172
173 event = PubSub_FindEventType(pubSub, EventName);
174
175 if (event)
176 {
177 status = 0;
178
179 for (size_t index = 0; index < event->EventHandlerCount; index++)
180 {
181 if (event->EventHandlers[index] == EventHandler)
182 {
183 event->EventHandlers[index] = nullptr;
184 event->EventHandlerCount--;
185 MoveMemory((void*)&event->EventHandlers[index],
186 (void*)&event->EventHandlers[index + 1],
187 (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
188 status = 1;
189 }
190 }
191 }
192
193 if (pubSub->synchronized)
194 PubSub_Unlock(pubSub);
195
196 va_end(ap);
197 return status;
198}
199
200int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
201{
202 WINPR_ASSERT(pubSub);
203 WINPR_ASSERT(EventName);
204 WINPR_ASSERT(e);
205
206 if (!pubSub)
207 {
208 WLog_ERR(TAG, "pubSub(%s)=nullptr!", EventName);
209 return -1;
210 }
211
212 if (pubSub->synchronized)
213 PubSub_Lock(pubSub);
214
215 int status = 0;
216 wEventType* event = PubSub_FindEventType(pubSub, EventName);
217 if (event)
218 {
219 for (size_t index = 0; index < event->EventHandlerCount; index++)
220 {
221 if (event->EventHandlers[index])
222 {
223 event->EventHandlers[index](context, e);
224 status++;
225 }
226 }
227 }
228 if (pubSub->synchronized)
229 PubSub_Unlock(pubSub);
230
231 return status;
232}
233
238wPubSub* PubSub_New(BOOL synchronized)
239{
240 wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
241
242 if (!pubSub)
243 return nullptr;
244
245 pubSub->synchronized = synchronized;
246
247 if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
248 goto fail;
249
250 pubSub->count = 0;
251 pubSub->size = 64;
252
253 pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
254 if (!pubSub->events)
255 goto fail;
256
257 return pubSub;
258fail:
259 WINPR_PRAGMA_DIAG_PUSH
260 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
261 PubSub_Free(pubSub);
262 WINPR_PRAGMA_DIAG_POP
263 return nullptr;
264}
265
266void PubSub_Free(wPubSub* pubSub)
267{
268 if (pubSub)
269 {
270 if (pubSub->synchronized)
271 DeleteCriticalSection(&pubSub->lock);
272
273 free(pubSub->events);
274 free(pubSub);
275 }
276}