a3e8f4145eb0182058a22710a420fff9a8753d2c
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / caconnectivitymanager.c
1 /******************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <stdbool.h>
25
26 #include "octypes.h"
27 #include "ocrandom.h"
28 #include "cainterface.h"
29 #include "caremotehandler.h"
30 #include "camessagehandler.h"
31 #include "caprotocolmessage.h"
32 #include "canetworkconfigurator.h"
33 #include "cainterfacecontroller.h"
34 #include "logger.h"
35 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
36 #include "ca_adapter_net_ssl.h"
37 #endif // __WITH_DTLS__ or __WITH_TLS__
38
39 #ifdef TCP_ADAPTER
40 #include "catcpadapter.h"
41 #endif
42
43 CAGlobals_t caglobals = { .clientFlags = 0,
44                           .serverFlags = 0, };
45
46 #define TAG "OIC_CA_CONN_MGR"
47
48 static bool g_isInitialized = false;
49
50 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
51 // Taking callback all the way through adapters not the right approach, hence calling here.
52 extern void CAsetPkixInfoCallback(CAgetPkixInfoHandler infCallback);
53 extern void CAsetPskCredentialsCallback(CAgetPskCredentialsHandler credCallback);
54 extern void CAsetCredentialTypesCallback(CAgetCredentialTypesHandler credCallback);
55 extern void CAsetSetupPkContextCallback(CAsetupPkContextHandler setupPkCtxCallback);
56 #endif // __WITH_DTLS__ or __WITH_TLS__
57
58
59 CAResult_t CAInitialize(CATransportAdapter_t transportType)
60 {
61     OIC_LOG_V(DEBUG, TAG, "IoTivity version is v%s", IOTIVITY_VERSION);
62     OIC_LOG_V(DEBUG, TAG, "CAInitialize type : %d", transportType);
63
64     if (!g_isInitialized)
65     {
66         if (0 != OCSeedRandom())
67         {
68             OIC_LOG(ERROR, TAG, "Seed Random Failed");
69         }
70
71         CAResult_t res = CAInitializeMessageHandler(transportType);
72         if (res != CA_STATUS_OK)
73         {
74             OIC_LOG(ERROR, TAG, "CAInitialize has failed");
75             CATerminateMessageHandler();
76             return res;
77         }
78         g_isInitialized = true;
79     }
80
81     return CA_STATUS_OK;
82 }
83
84 void CATerminate()
85 {
86     OIC_LOG(DEBUG, TAG, "CATerminate");
87
88     if (g_isInitialized)
89     {
90         CATerminateMessageHandler();
91         CATerminateNetworkType();
92
93         g_isInitialized = false;
94     }
95 }
96
97 CAResult_t CAStartListeningServer()
98 {
99     OIC_LOG(DEBUG, TAG, "CAStartListeningServer");
100
101     if (!g_isInitialized)
102     {
103         return CA_STATUS_NOT_INITIALIZED;
104     }
105
106     return CAStartListeningServerAdapters();
107 }
108
109 CAResult_t CAStopListeningServer()
110 {
111     OIC_LOG(DEBUG, TAG, "CAStopListeningServer");
112
113     if (!g_isInitialized)
114     {
115         return CA_STATUS_NOT_INITIALIZED;
116     }
117
118     return CAStopListeningServerAdapters();
119 }
120
121 CAResult_t CAStartDiscoveryServer()
122 {
123     OIC_LOG(DEBUG, TAG, "CAStartDiscoveryServer");
124
125     if (!g_isInitialized)
126     {
127         return CA_STATUS_NOT_INITIALIZED;
128     }
129
130     return CAStartDiscoveryServerAdapters();
131 }
132
133 void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHandler,
134                        CAErrorCallback ErrorHandler)
135 {
136     OIC_LOG(DEBUG, TAG, "CARegisterHandler");
137
138     if (!g_isInitialized)
139     {
140         OIC_LOG(DEBUG, TAG, "CA is not initialized");
141         return;
142     }
143
144     CASetInterfaceCallbacks(ReqHandler, RespHandler, ErrorHandler);
145 }
146
147 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
148 #ifdef MULTIPLE_OWNER
149 const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer)
150 {
151     OIC_LOG(DEBUG, TAG, "IN CAGetSecurePeerInfo");
152
153     if (!g_isInitialized)
154     {
155         OIC_LOG(DEBUG, TAG, "CA is not initialized");
156         return NULL;
157     }
158
159     OIC_LOG(DEBUG, TAG, "OUT CAGetSecurePeerInfo");
160     return GetCASecureEndpointData(peer);
161 }
162 #endif //MULTIPLE_OWNER
163
164 CAResult_t CASetSecureEndpointUuid(const CAEndpoint_t *peer, const char *uuid)
165 {
166     OIC_LOG(DEBUG, TAG, "IN CASetSecureEndpointUuid");
167
168     if (!g_isInitialized)
169     {
170         OIC_LOG(DEBUG, TAG, "CA is not initialized");
171         return CA_STATUS_NOT_INITIALIZED;
172     }
173
174     OIC_LOG(DEBUG, TAG, "OUT CASetSecureEndpointUuid");
175     return SetCASecureEndpointUuid(peer, uuid);
176 }
177
178 CAResult_t CAregisterSslHandshakeCallback(CAErrorCallback tlsHandshakeCallback)
179 {
180     OIC_LOG(DEBUG, TAG, "CAregisterSslHandshakeCallback");
181     if(!g_isInitialized)
182     {
183         return CA_STATUS_NOT_INITIALIZED;
184     }
185
186     CAsetSslHandshakeCallback(tlsHandshakeCallback);
187     return CA_STATUS_OK;
188 }
189
190 CAResult_t CAregisterPskCredentialsHandler(CAgetPskCredentialsHandler getTlsCredentialsHandler)
191 {
192     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
193
194     if (!g_isInitialized)
195     {
196         return CA_STATUS_NOT_INITIALIZED;
197     }
198     CAsetPskCredentialsCallback(getTlsCredentialsHandler);
199     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
200     return CA_STATUS_OK;
201 }
202
203 CAResult_t CAregisterPkixInfoHandler(CAgetPkixInfoHandler getPkixInfoHandler)
204 {
205     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
206
207     if (!g_isInitialized)
208     {
209         return CA_STATUS_NOT_INITIALIZED;
210     }
211     CAsetPkixInfoCallback(getPkixInfoHandler);
212     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
213     return CA_STATUS_OK;
214 }
215
216 CAResult_t CAregisterGetCredentialTypesHandler(CAgetCredentialTypesHandler getCredTypesHandler)
217 {
218     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
219
220     if (!g_isInitialized)
221     {
222         return CA_STATUS_NOT_INITIALIZED;
223     }
224     CAsetCredentialTypesCallback(getCredTypesHandler);
225     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
226     return CA_STATUS_OK;
227 }
228
229 CAResult_t CAregisterSetupPkContextHandler(CAsetupPkContextHandler setupPkContextCallback)
230 {
231     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
232
233     if (!g_isInitialized)
234     {
235         return CA_STATUS_NOT_INITIALIZED;
236     }
237     CAsetSetupPkContextCallback(setupPkContextCallback);
238     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
239     return CA_STATUS_OK;
240 }
241 #endif // __WITH_DTLS__ or __WITH_TLS__
242
243 CAResult_t CACreateEndpoint(CATransportFlags_t flags,
244                             CATransportAdapter_t adapter,
245                             const char *addr,
246                             uint16_t port,
247                             CAEndpoint_t **object)
248 {
249     if (!object)
250     {
251         OIC_LOG(ERROR, TAG, "Invalid Parameter");
252         return CA_STATUS_INVALID_PARAM;
253     }
254
255     CAEndpoint_t *endpoint = CACreateEndpointObject(flags, adapter, addr, port);
256     if (!endpoint)
257     {
258         return CA_STATUS_FAILED;
259     }
260     *object = endpoint;
261     return CA_STATUS_OK;
262 }
263
264 void CADestroyEndpoint(CAEndpoint_t *rep)
265 {
266     OIC_LOG(DEBUG, TAG, "CADestroyEndpoint");
267
268     CAFreeEndpoint(rep);
269 }
270
271 CAResult_t CAGenerateToken(CAToken_t *token, uint8_t tokenLength)
272 {
273     OIC_LOG(DEBUG, TAG, "CAGenerateToken");
274
275     return CAGenerateTokenInternal(token, tokenLength);
276 }
277
278 void CADestroyToken(CAToken_t token)
279 {
280     OIC_LOG(DEBUG, TAG, "CADestroyToken");
281
282     CADestroyTokenInternal(token);
283
284     OIC_LOG(DEBUG, TAG, "OUT");
285 }
286
287 CAResult_t CAGetNetworkInformation(CAEndpoint_t **info, uint32_t *size)
288 {
289     OIC_LOG(DEBUG, TAG, "CAGetNetworkInformation");
290
291     if (!g_isInitialized)
292     {
293         return CA_STATUS_NOT_INITIALIZED;
294     }
295
296     return CAGetNetworkInformationInternal(info, size);
297 }
298
299 static CAResult_t CASendMessageMultiAdapter(const CAEndpoint_t *object, const void *sendMsg,
300                                             CADataType_t dataType)
301 {
302     OIC_LOG(DEBUG, TAG, "CASendMessageMultipleAdapter");
303
304     CATransportAdapter_t connTypes[] = {
305             CA_ADAPTER_IP
306 #ifdef LE_ADAPTER
307             ,CA_ADAPTER_GATT_BTLE
308 #endif
309 #ifdef EDR_ADAPTER
310             ,CA_ADAPTER_RFCOMM_BTEDR
311 #endif
312 #ifdef NFC_ADAPTER
313             ,CA_ADAPTER_NFC
314 #endif
315 #ifdef RA_ADAPTER
316             ,CA_ADAPTER_REMOTE_ACCESS
317 #endif
318 #ifdef TCP_ADAPTER
319             ,CA_ADAPTER_TCP
320 #endif
321         };
322
323     CAEndpoint_t *cloneEp = CACloneEndpoint(object);
324     if (!cloneEp)
325     {
326         OIC_LOG(ERROR, TAG, "Failed to clone CAEndpoint");
327         return CA_MEMORY_ALLOC_FAILED;
328     }
329
330     CAResult_t ret = CA_STATUS_OK;
331     size_t numConnTypes = sizeof(connTypes) / sizeof(connTypes[0]);
332
333     for (size_t i = 0; i < numConnTypes && ret == CA_STATUS_OK; i++)
334     {
335         cloneEp->adapter = connTypes[i];
336         ret = CADetachSendMessage(cloneEp, sendMsg, dataType);
337     }
338     CAFreeEndpoint(cloneEp);
339     return ret;
340 }
341
342 CAResult_t CASendRequest(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo)
343 {
344     OIC_LOG(DEBUG, TAG, "CASendRequest");
345
346     if (!g_isInitialized)
347     {
348         return CA_STATUS_NOT_INITIALIZED;
349     }
350
351     if (requestInfo && requestInfo->isMulticast &&
352             (object->adapter == CA_DEFAULT_ADAPTER || object->adapter == CA_ALL_ADAPTERS))
353     {
354         return CASendMessageMultiAdapter(object, requestInfo, CA_REQUEST_DATA);
355     }
356     else if (requestInfo && requestInfo->info.event == CA_REQ_DISCONNECT &&
357             (object->adapter == CA_ADAPTER_TCP || object->adapter == CA_ALL_ADAPTERS))
358     {
359         return CADetachSendNetworkReqMessage(object, requestInfo->info.event, CA_NETWORK_COMMAND);
360     }
361     else
362     {
363         return CADetachSendMessage(object, requestInfo, CA_REQUEST_DATA);
364     }
365 }
366
367 CAResult_t CASendResponse(const CAEndpoint_t *object, const CAResponseInfo_t *responseInfo)
368 {
369     OIC_LOG(DEBUG, TAG, "CASendResponse");
370
371     if (!g_isInitialized)
372     {
373         return CA_STATUS_NOT_INITIALIZED;
374     }
375
376     if (!responseInfo || !object)
377     {
378         return CA_STATUS_INVALID_PARAM;
379     }
380
381     if (responseInfo->isMulticast &&
382             (object->adapter == CA_DEFAULT_ADAPTER || object->adapter == CA_ALL_ADAPTERS))
383     {
384         return CASendMessageMultiAdapter(object, responseInfo, responseInfo->info.dataType);
385     }
386     else
387     {
388         return CADetachSendMessage(object, responseInfo, responseInfo->info.dataType);
389     }
390 }
391
392 CAResult_t CASelectNetwork(CATransportAdapter_t interestedNetwork)
393 {
394     if (!g_isInitialized)
395     {
396         return CA_STATUS_NOT_INITIALIZED;
397     }
398
399     CAResult_t res = CA_STATUS_OK;
400
401     if (interestedNetwork & CA_ADAPTER_IP)
402     {
403         res = CAAddNetworkType(CA_ADAPTER_IP);
404         OIC_LOG_V(DEBUG, TAG, "CAAddNetworkType(CA_IP_ADAPTER) function returns result: %d", res);
405     }
406     else if (interestedNetwork & CA_ADAPTER_RFCOMM_BTEDR)
407     {
408         res = CAAddNetworkType(CA_ADAPTER_RFCOMM_BTEDR);
409         OIC_LOG_V(DEBUG, TAG, "CAAddNetworkType(CA_RFCOMM_ADAPTER) function returns result : %d", res);
410     }
411     else if (interestedNetwork & CA_ADAPTER_GATT_BTLE)
412     {
413         res = CAAddNetworkType(CA_ADAPTER_GATT_BTLE);
414         OIC_LOG_V(DEBUG, TAG, "CAAddNetworkType(CA_GATT_ADAPTER) function returns result : %d", res);
415     }
416
417 #ifdef RA_ADAPTER
418     else if (interestedNetwork & CA_ADAPTER_REMOTE_ACCESS)
419     {
420         res = CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS);
421         OIC_LOG_V(DEBUG, TAG,
422                   "CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns result : %d", res);
423     }
424 #endif
425
426 #ifdef TCP_ADAPTER
427     else if (interestedNetwork & CA_ADAPTER_TCP)
428     {
429         res = CAAddNetworkType(CA_ADAPTER_TCP);
430         OIC_LOG_V(DEBUG, TAG,
431                   "CAAddNetworkType(CA_ADAPTER_TCP) function returns result : %d", res);
432     }
433 #endif
434     else if (interestedNetwork & CA_ADAPTER_NFC)
435     {
436         res = CAAddNetworkType(CA_ADAPTER_NFC);
437         OIC_LOG_V(DEBUG, TAG, "CAAddNetworkType(CA_ADAPTER_NFC) function returns result : %d", res);
438     }
439     else
440     {
441         res = CA_NOT_SUPPORTED;
442     }
443     return res;
444 }
445
446 CAResult_t CAUnSelectNetwork(CATransportAdapter_t nonInterestedNetwork)
447 {
448     OIC_LOG_V(DEBUG, TAG, "unselected network : %d", nonInterestedNetwork);
449
450     if (!g_isInitialized)
451     {
452         return CA_STATUS_NOT_INITIALIZED;
453     }
454
455     CAResult_t res = CA_STATUS_OK;
456
457     if (nonInterestedNetwork & CA_ADAPTER_IP)
458     {
459         res = CARemoveNetworkType(CA_ADAPTER_IP);
460         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_IP_ADAPTER) function returns result : %d", res);
461     }
462     else if (nonInterestedNetwork & CA_ADAPTER_RFCOMM_BTEDR)
463     {
464         res = CARemoveNetworkType(CA_ADAPTER_RFCOMM_BTEDR);
465         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_RFCOMM_ADAPTER) function returns result : %d", res);
466     }
467     else if (nonInterestedNetwork & CA_ADAPTER_GATT_BTLE)
468     {
469         res = CARemoveNetworkType(CA_ADAPTER_GATT_BTLE);
470         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_GATT_ADAPTER) function returns result : %d", res);
471     }
472 #ifdef RA_ADAPTER
473     else if (nonInterestedNetwork & CA_ADAPTER_REMOTE_ACCESS)
474     {
475         res = CARemoveNetworkType(CA_ADAPTER_REMOTE_ACCESS);
476         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns result : %d",
477                   res);
478     }
479 #endif
480
481
482 #ifdef TCP_ADAPTER
483     else if (nonInterestedNetwork & CA_ADAPTER_TCP)
484     {
485         res = CARemoveNetworkType(CA_ADAPTER_TCP);
486         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_ADAPTER_TCP) function returns result : %d",
487                   res);
488     }
489 #endif
490
491     else
492     {
493         res = CA_STATUS_FAILED;
494     }
495     return res;
496 }
497
498 CAResult_t CAHandleRequestResponse()
499 {
500     if (!g_isInitialized)
501     {
502         OIC_LOG(ERROR, TAG, "not initialized");
503         return CA_STATUS_NOT_INITIALIZED;
504     }
505
506     CAHandleRequestResponseCallbacks();
507
508     return CA_STATUS_OK;
509 }
510
511 CAResult_t CASelectCipherSuite(const uint16_t cipher, CATransportAdapter_t adapter)
512 {
513     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
514     OIC_LOG_V(DEBUG, TAG, "cipher : %d , CATransportAdapter : %d", cipher, adapter);
515     CAResult_t res = CA_STATUS_FAILED;
516 #if defined (__WITH_DTLS__) || defined(__WITH_TLS__)
517     res = CAsetTlsCipherSuite(cipher);
518     if (CA_STATUS_OK != res)
519     {
520         OIC_LOG_V(ERROR, TAG, "Failed to CAsetTlsCipherSuite : %d", res);
521     }
522 #else
523     OIC_LOG(ERROR, TAG, "Method not supported");
524 #endif
525     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
526     return res;
527 }
528
529 CAResult_t CAEnableAnonECDHCipherSuite(const bool enable)
530 {
531     OIC_LOG_V(DEBUG, TAG, "CAEnableAnonECDHCipherSuite");
532     CAResult_t res = CA_STATUS_FAILED;
533 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
534     // TLS_ECDH_ANON_WITH_AES_128_CBC_SHA256    0xFF00 replaces 0xC018
535     res = CAsetTlsCipherSuite(enable ? 0xFF00 : 0x00);
536     if (CA_STATUS_OK != res)
537     {
538         OIC_LOG_V(ERROR, TAG, "Failed to CAsetTlsCipherSuite : %d", res);
539     }
540 #else
541     OIC_LOG(ERROR, TAG, "Method not supported");
542 #endif
543     OIC_LOG_V(ERROR, TAG, "Out %s", __func__);
544     return res;
545 }
546
547 CAResult_t CAGenerateOwnerPSK(const CAEndpoint_t* endpoint,
548                     const uint8_t* label, const size_t labelLen,
549                     const uint8_t* rsrcServerDeviceID, const size_t rsrcServerDeviceIDLen,
550                     const uint8_t* provServerDeviceID, const size_t provServerDeviceIDLen,
551                     uint8_t* ownerPSK, const size_t ownerPskSize)
552 {
553     OIC_LOG_V(DEBUG, TAG, "IN : CAGenerateOwnerPSK");
554     CAResult_t res = CA_STATUS_FAILED;
555 #if defined (__WITH_DTLS__) || defined(__WITH_TLS__)
556     //newOwnerLabel and prevOwnerLabe can be NULL
557     if (!endpoint || !label || 0 == labelLen || !ownerPSK || 0 == ownerPskSize)
558     {
559         return CA_STATUS_INVALID_PARAM;
560     }
561
562     res = CAsslGenerateOwnerPsk(endpoint, label, labelLen,
563                                       rsrcServerDeviceID, rsrcServerDeviceIDLen,
564                                       provServerDeviceID, provServerDeviceIDLen,
565                                       ownerPSK, ownerPskSize);
566     if (CA_STATUS_OK != res)
567     {
568         OIC_LOG_V(ERROR, TAG, "Failed to CAGenerateOwnerPSK : %d", res);
569     }
570 #else
571     OIC_LOG(ERROR, TAG, "Method not supported");
572 #endif
573     OIC_LOG_V(DEBUG, TAG, "OUT : CAGenerateOwnerPSK");
574     return res;
575 }
576
577 CAResult_t CAInitiateHandshake(const CAEndpoint_t *endpoint)
578 {
579     OIC_LOG_V(DEBUG, TAG, "IN : CAInitiateHandshake");
580     CAResult_t res = CA_STATUS_FAILED;
581 #if defined (__WITH_DTLS__) || defined(__WITH_TLS__)
582     if (!endpoint)
583     {
584         return CA_STATUS_INVALID_PARAM;
585     }
586
587     res = CAinitiateSslHandshake(endpoint);
588     if (CA_STATUS_OK != res)
589     {
590         OIC_LOG_V(ERROR, TAG, "Failed to CAinitiateSslHandshake : %d", res);
591     }
592 #else
593         OIC_LOG(ERROR, TAG, "Method not supported");
594 #endif
595     OIC_LOG_V(DEBUG, TAG, "OUT : CAInitiateHandshake");
596     return res;
597 }
598
599 CAResult_t CAcloseSslSession(const CAEndpoint_t *endpoint)
600 {
601     OIC_LOG_V(DEBUG, TAG, "IN : CAcloseSslSession");
602     CAResult_t res = CA_STATUS_FAILED;
603 #if defined (__WITH_DTLS__) || defined(__WITH_TLS__)
604     if (!endpoint)
605     {
606         return CA_STATUS_INVALID_PARAM;
607     }
608
609     res = CAcloseSslConnection(endpoint);
610     if (CA_STATUS_OK != res)
611     {
612         OIC_LOG_V(ERROR, TAG, "Failed to CAsslClose : %d", res);
613     }
614 #else
615     OIC_LOG(ERROR, TAG, "Method not supported");
616 #endif
617     OIC_LOG_V(DEBUG, TAG, "OUT : CAcloseSslSession");
618     return res;
619 }
620
621 #ifdef TCP_ADAPTER
622 void CARegisterKeepAliveHandler(CAKeepAliveConnectionCallback ConnHandler)
623 {
624     CATCPSetKeepAliveCallbacks(ConnHandler);
625 }
626 #endif
627
628 #ifdef WITH_PROCESS_EVENT
629 void CARegisterProcessEvent(oc_event event)
630 {
631     CARegisterMessageProcessEvent(event);
632 }
633 #endif // WITH_PROCESS_EVENT