C library update for VES5.4.1
[demo.git] / vnfs / VES5.0 / evel / evel-library / code / evel_library / evel_event_mgr.c
1 /*************************************************************************//**
2  *
3  * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
4  *
5  * Unless otherwise specified, all software contained herein is
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and 
15  * limitations under the License.
16  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17  ****************************************************************************/
18
19 /**************************************************************************//**
20  * @file
21  * Event Manager
22  *
23  * Simple event manager that is responsible for taking events (Heartbeats,
24  * Faults and Measurements) from the ring-buffer and posting them to the API.
25  *
26  ****************************************************************************/
27
28 #include <string.h>
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <pthread.h>
32
33 #include <curl/curl.h>
34
35 #include "evel.h"
36 #include "evel_internal.h"
37 #include "ring_buffer.h"
38 #include "evel_throttle.h"
39
40 /**************************************************************************//**
41  * How long we're prepared to wait for the API service to respond in
42  * seconds.
43  *****************************************************************************/
44 static const int EVEL_API_TIMEOUT = 10;
45
46 /*****************************************************************************/
47 /* Prototypes of locally scoped functions.                                   */
48 /*****************************************************************************/
49 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp);
50 static void * event_handler(void *arg);
51 static bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
52                                         const jsmntok_t * const json_tokens,
53                                         const int num_tokens,
54                                         MEMORY_CHUNK * const post);
55 static bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
56                                            const jsmntok_t * const json_token,
57                                            const int num_tokens);
58 static bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
59                                      const jsmntok_t * const json_token,
60                                      const char * check_string);
61 static void * event_multi_handler(void * arg __attribute__ ((unused)));
62
63 /**************************************************************************//**
64  * Buffers for error strings from libcurl.
65  *****************************************************************************/
66 static char curl_err_string[CURL_ERROR_SIZE] = "<NULL>";
67 static char curl_err_string2[CURL_ERROR_SIZE] = "<NULL>";
68
69 /**************************************************************************//**
70  * Handle for the API into libcurl.
71  *****************************************************************************/
72 static CURL * curl_handle = NULL;
73 static CURL * curl_handle2 = NULL;
74 static CURLM * multi_handle = NULL;
75 int curr_global_handles = 0;
76 int activmode = -1;
77
78 /**************************************************************************//**
79  * Special headers that we send.
80  *****************************************************************************/
81 static struct curl_slist * hdr_chunk = NULL;
82 static struct curl_slist * hdr_chunk2 = NULL;
83
84 /**************************************************************************//**
85  * Message queue for sending events to the API.
86  *****************************************************************************/
87 static ring_buffer event_buffer;
88
89 /**************************************************************************//**
90  * Single pending priority post, which can be generated as a result of a
91  * response to an event.  Currently only used to respond to a commandList.
92  *****************************************************************************/
93 static MEMORY_CHUNK priority_post;
94
95 /**************************************************************************//**
96  * The thread which is responsible for handling events off of the ring-buffer
97  * and posting them to the Event Handler API.
98  *****************************************************************************/
99 static pthread_t evt_handler_thread;
100
101 /**************************************************************************//**
102  * Variable to convey to the event handler thread what the foreground wants it
103  * to do.
104  *****************************************************************************/
105 static EVT_HANDLER_STATE evt_handler_state = EVT_HANDLER_UNINITIALIZED;
106
107 /**************************************************************************//**
108  * The configured API URL for event and throttling.
109  *****************************************************************************/
110 static char * evel_event_api_url;
111 static char * evel_throt_api_url;
112 static char * evel_batch_api_url;
113
114 static char * evel_bevent_api_url;
115 static char * evel_bthrot_api_url;
116 static char * evel_bbatch_api_url;
117
118
119 /**************************************************************************//**
120  * Initialize the event handler.
121  *
122  * Primarily responsible for getting CURL ready for use.
123  *
124  * @param[in] event_api_url
125  *                      The URL where the Vendor Event Listener API is expected
126  *                      to be.
127  * @param[in] throt_api_url
128  *                      The URL where the Throttling API is expected to be.
129  * @param[in] source_ip  Source IP of VES Agent
130  * @param[in] ring_buf_size     Initial size of ring buffer
131  * @param[in] secure     Whether Using http or https
132  * @param[in] cert_file_path  Path to Client Certificate file
133  * @param[in] key_file_path   Path to Client key file
134  * @param[in] ca_info         Path to CA info file
135  * @param[in] ca_file_path    Path to CA file 
136  * @param[in] verify_peer     Using peer verification or not 0 or 1
137  * @param[in] verify_host     Using host verification or not 0 or 1
138  * @param[in] username  The username for the Basic Authentication of requests.
139  * @param[in] password  The password for the Basic Authentication of requests.
140  * @param     verbosity 0 for normal operation, positive values for chattier
141  *                        logs.
142  *****************************************************************************/
143 EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
144                                         const char * const bakup_api_url,
145                                         const char * const throt_api_url,
146                                         const char * const source_ip,
147                                         const char * const source_ip_bakup,
148                                         int ring_buf_size,
149                                         int secure,
150                                         int activitymode,
151                                         const char * const cert_file_path,
152                                         const char * const key_file_path,
153                                         const char * const ca_info,
154                                         const char * const ca_file_path,
155                                         long verify_peer,
156                                         long verify_host,
157                                         const char * const username,
158                                         const char * const password,
159                                         const char * const username2,
160                                         const char * const password2,
161                                         int verbosity)
162 {
163   int rc = EVEL_SUCCESS;
164   CURLcode curl_rc = CURLE_OK;
165   char batch_api_url[EVEL_MAX_URL_LEN + 1] = {0};
166   char local_address[64];
167
168   EVEL_ENTER();
169
170   /***************************************************************************/
171   /* Check assumptions.                                                      */
172   /***************************************************************************/
173   assert(event_api_url != NULL);
174   assert(throt_api_url != NULL);
175   assert(username != NULL);
176   assert(password != NULL);
177   if( bakup_api_url != NULL )
178   {
179     assert(username2 != NULL);
180     assert(password2 != NULL);
181   }
182
183
184   /***************************************************************************/
185   /* Store the API URLs.                                                     */
186   /***************************************************************************/
187   evel_event_api_url = strdup(event_api_url);
188   assert(evel_event_api_url != NULL);
189   sprintf(batch_api_url,"%s/eventBatch",event_api_url);
190   evel_batch_api_url = strdup(batch_api_url);
191   assert(evel_batch_api_url != NULL);
192   evel_throt_api_url = strdup(throt_api_url);
193   assert(evel_throt_api_url != NULL);
194   curr_global_handles = 1;
195
196   if( bakup_api_url != NULL )
197   {
198     evel_bevent_api_url = strdup(bakup_api_url);
199     assert(evel_bevent_api_url != NULL);
200     sprintf(batch_api_url,"%s/eventBatch",event_api_url);
201     evel_bbatch_api_url = strdup(batch_api_url);
202     assert(evel_bbatch_api_url != NULL);
203     evel_bthrot_api_url = strdup(throt_api_url);
204     assert(evel_bthrot_api_url != NULL);
205     curr_global_handles = 2;
206   }
207
208
209   curl_version_info_data *d = curl_version_info(CURLVERSION_NOW);
210   /* compare with the 24 bit hex number in 8 bit fields */
211   if(d->version_num >= 0x072100) {
212      /* this is libcurl 7.33.0 or later */
213      EVEL_INFO("7.33 or later Curl version %x.",d->version_num);
214   }
215   else {
216      EVEL_INFO("Old Curl version.");
217   }
218   /***************************************************************************/
219   /* Start the CURL library. Note that this initialization is not threadsafe */
220   /* which imposes a constraint that the EVEL library is initialized before  */
221   /* any threads are started.                                                */
222   /***************************************************************************/
223   curl_rc = curl_global_init(CURL_GLOBAL_SSL);
224   if (curl_rc != CURLE_OK)
225   {
226     rc = EVEL_CURL_LIBRARY_FAIL;
227     log_error_state("Failed to initialize libCURL. Error code=%d", curl_rc);
228     goto exit_label;
229   }
230
231   /***************************************************************************/
232   /* Get a curl handle which we'll use for all of our output.                */
233   /***************************************************************************/
234   curl_handle = curl_easy_init();
235   if (curl_handle == NULL)
236   {
237     rc = EVEL_CURL_LIBRARY_FAIL;
238     log_error_state("Failed to get libCURL handle");
239     goto exit_label;
240   }
241
242   if( bakup_api_url != NULL )
243   {
244      curl_handle2 = curl_easy_init();
245      if (curl_handle2 == NULL)
246      {
247        rc = EVEL_CURL_LIBRARY_FAIL;
248        log_error_state("Failed to get backup libCURL handle");
249        goto exit_label;
250      }
251   }
252   /***************************************************************************/
253   /* Prime the library to give friendly error codes.                         */
254   /***************************************************************************/
255   curl_rc = curl_easy_setopt(curl_handle,
256                              CURLOPT_ERRORBUFFER,
257                              curl_err_string);
258   if (curl_rc != CURLE_OK)
259   {
260     rc = EVEL_CURL_LIBRARY_FAIL;
261     log_error_state("Failed to initialize libCURL to provide friendly errors. "
262                     "Error code=%d", curl_rc);
263     goto exit_label;
264   }
265
266   if( bakup_api_url != NULL )
267   {
268     curl_rc = curl_easy_setopt(curl_handle2,
269                              CURLOPT_ERRORBUFFER,
270                              curl_err_string2);
271     if (curl_rc != CURLE_OK)
272     {
273       rc = EVEL_CURL_LIBRARY_FAIL;
274       log_error_state("Failed to initialize libCURL2 to provide friendly errors. "
275                     "Error code=%d", curl_rc);
276       goto exit_label;
277     }
278   }
279
280
281   /***************************************************************************/
282   /* If running in verbose mode generate more output.                        */
283   /***************************************************************************/
284   if (verbosity > 0)
285   {
286     curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
287     if (curl_rc != CURLE_OK)
288     {
289       rc = EVEL_CURL_LIBRARY_FAIL;
290       log_error_state("Failed to initialize libCURL to be verbose. "
291                       "Error code=%d", curl_rc);
292       goto exit_label;
293     }
294   if( bakup_api_url != NULL )
295   {
296     curl_rc = curl_easy_setopt(curl_handle2, CURLOPT_VERBOSE, 1L);
297     if (curl_rc != CURLE_OK)
298     {
299       rc = EVEL_CURL_LIBRARY_FAIL;
300       log_error_state("Failed to initialize libCURL to be verbose. "
301                       "Error code=%d", curl_rc);
302       goto exit_label;
303     }
304    }
305
306   }
307
308
309
310   /***************************************************************************/
311   /* Set the URL for the API.                                                */
312   /***************************************************************************/
313   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, event_api_url);
314   if (curl_rc != CURLE_OK)
315   {
316     rc = EVEL_CURL_LIBRARY_FAIL;
317     log_error_state("Failed to initialize libCURL with the API URL. "
318                     "Error code=%d (%s)", curl_rc, curl_err_string);
319     goto exit_label;
320   }
321   EVEL_INFO("Initializing CURL to send events to: %s", event_api_url);
322
323   if( bakup_api_url != NULL )
324   {
325     curl_rc = curl_easy_setopt(curl_handle2,
326                              CURLOPT_URL,
327                              bakup_api_url);
328     if (curl_rc != CURLE_OK)
329     {
330       rc = EVEL_CURL_LIBRARY_FAIL;
331       log_error_state("Failed to initialize libCURL with the API URL. "
332                     "Error code=%d (%s)", curl_rc, curl_err_string2);
333       goto exit_label;
334     }
335   }
336
337
338   /***************************************************************************/
339   /* send all data to this function.                                         */
340   /***************************************************************************/
341   curl_rc = curl_easy_setopt(curl_handle,
342                              CURLOPT_WRITEFUNCTION,
343                              evel_write_callback);
344   if (curl_rc != CURLE_OK)
345   {
346     rc = EVEL_CURL_LIBRARY_FAIL;
347     log_error_state("Failed to initialize libCURL with the write callback. "
348                     "Error code=%d (%s)", curl_rc, curl_err_string);
349     goto exit_label;
350   }
351   if( bakup_api_url != NULL )
352   {
353     curl_rc = curl_easy_setopt(curl_handle2,
354                              CURLOPT_WRITEFUNCTION,
355                              evel_write_callback);
356     if (curl_rc != CURLE_OK)
357     {
358       rc = EVEL_CURL_LIBRARY_FAIL;
359       log_error_state("Failed to initialize libCURL with the API URL. "
360                     "Error code=%d (%s)", curl_rc, curl_err_string2);
361       goto exit_label;
362     }
363   }
364
365
366
367   /***************************************************************************/
368   /* configure local ip address if provided */
369   /* Default ip if NULL */
370   /***************************************************************************/
371   if( source_ip != NULL )
372   {
373     snprintf(local_address,sizeof(local_address),source_ip);
374     if( local_address[0] != '\0' )
375     {
376       curl_rc = curl_easy_setopt(curl_handle,
377                              CURLOPT_INTERFACE,
378                              local_address);
379       if (curl_rc != CURLE_OK)
380       {
381         rc = EVEL_CURL_LIBRARY_FAIL;
382         log_error_state("Failed to initialize libCURL with the local address. "
383                     "Error code=%d (%s)", curl_rc, curl_err_string);
384         goto exit_label;
385       }
386     }
387   }
388   if( source_ip_bakup != NULL )
389   {
390     snprintf(local_address,sizeof(local_address),source_ip_bakup);
391     if( local_address[0] != '\0' )
392     {
393       curl_rc = curl_easy_setopt(curl_handle2,
394                              CURLOPT_INTERFACE,
395                              local_address);
396       if (curl_rc != CURLE_OK)
397       {
398         rc = EVEL_CURL_LIBRARY_FAIL;
399         log_error_state("Failed to initialize bakup libCURL with the local address. "
400                     "Error code=%d (%s)", curl_rc, curl_err_string2);
401         goto exit_label;
402       }
403     }
404   }
405
406   /***************************************************************************/
407   /* configure SSL options for HTTPS transfers */
408   /***************************************************************************/
409   if( secure )
410   {
411     if( cert_file_path != NULL )
412     {
413       curl_rc = curl_easy_setopt(curl_handle,
414                              CURLOPT_SSLCERT,
415                              cert_file_path);
416       if (curl_rc != CURLE_OK)
417       {
418         rc = EVEL_CURL_LIBRARY_FAIL;
419         log_error_state("Failed to initialize libCURL with the client cert. "
420                     "Error code=%d (%s)", curl_rc, curl_err_string);
421         goto exit_label;
422       }
423   if( bakup_api_url != NULL )
424   {
425       curl_rc = curl_easy_setopt(curl_handle2,
426                              CURLOPT_SSLCERT,
427                              cert_file_path);
428       if (curl_rc != CURLE_OK)
429       {
430         rc = EVEL_CURL_LIBRARY_FAIL;
431         log_error_state("Failed to initialize libCURL with the client cert. "
432                     "Error code=%d (%s)", curl_rc, curl_err_string);
433         goto exit_label;
434       }
435   }
436     }
437
438     if( key_file_path != NULL )
439     {
440       curl_rc = curl_easy_setopt(curl_handle,
441                              CURLOPT_SSLKEY,
442                              key_file_path);
443       if (curl_rc != CURLE_OK)
444       {
445         rc = EVEL_CURL_LIBRARY_FAIL;
446         log_error_state("Failed to initialize libCURL with the client key. "
447                     "Error code=%d (%s)", curl_rc, curl_err_string);
448         goto exit_label;
449       }
450   if( bakup_api_url != NULL )
451   {
452       curl_rc = curl_easy_setopt(curl_handle2,
453                              CURLOPT_SSLKEY,
454                              key_file_path);
455       if (curl_rc != CURLE_OK)
456       {
457         rc = EVEL_CURL_LIBRARY_FAIL;
458         log_error_state("Failed to initialize libCURL with the client key. "
459                     "Error code=%d (%s)", curl_rc, curl_err_string);
460         goto exit_label;
461       }
462   }
463     }
464
465     if( ca_info != NULL )
466     {
467       curl_rc = curl_easy_setopt(curl_handle,
468                              CURLOPT_CAINFO,
469                              ca_info);
470       if (curl_rc != CURLE_OK)
471       {
472         rc = EVEL_CURL_LIBRARY_FAIL;
473         log_error_state("Failed to initialize libCURL with the CA cert file. "
474                     "Error code=%d (%s)", curl_rc, curl_err_string);
475         goto exit_label;
476       }
477   if( bakup_api_url != NULL )
478   {
479       curl_rc = curl_easy_setopt(curl_handle2,
480                              CURLOPT_CAINFO,
481                              ca_info);
482       if (curl_rc != CURLE_OK)
483       {
484         rc = EVEL_CURL_LIBRARY_FAIL;
485         log_error_state("Failed to initialize libCURL with the CA cert file. "
486                     "Error code=%d (%s)", curl_rc, curl_err_string);
487         goto exit_label;
488       }
489   }
490     }
491
492     if( ca_file_path != NULL )
493     {
494       curl_rc = curl_easy_setopt(curl_handle,
495                              CURLOPT_CAPATH,
496                              ca_file_path);
497       if (curl_rc != CURLE_OK)
498       {
499         rc = EVEL_CURL_LIBRARY_FAIL;
500         log_error_state("Failed to initialize libCURL with the CA cert path. "
501                     "Error code=%d (%s)", curl_rc, curl_err_string);
502         goto exit_label;
503       }
504   if( bakup_api_url != NULL )
505   {
506       curl_rc = curl_easy_setopt(curl_handle2,
507                              CURLOPT_CAPATH,
508                              ca_file_path);
509       if (curl_rc != CURLE_OK)
510       {
511         rc = EVEL_CURL_LIBRARY_FAIL;
512         log_error_state("Failed to initialize libCURL with the CA cert path. "
513                     "Error code=%d (%s)", curl_rc, curl_err_string);
514         goto exit_label;
515       }
516   }
517     }
518
519       curl_rc = curl_easy_setopt(curl_handle,
520                              CURLOPT_SSL_VERIFYPEER,
521                              verify_peer);
522       if (curl_rc != CURLE_OK)
523       {
524         rc = EVEL_CURL_LIBRARY_FAIL;
525         log_error_state("Failed to initialize libCURL with SSL Server verification. "
526                     "Error code=%d (%s)", curl_rc, curl_err_string);
527         goto exit_label;
528       }
529       curl_rc = curl_easy_setopt(curl_handle,
530                              CURLOPT_SSL_VERIFYHOST,
531                              verify_host);
532       if (curl_rc != CURLE_OK)
533       {
534         rc = EVEL_CURL_LIBRARY_FAIL;
535         log_error_state("Failed to initialize libCURL with Client host verification. "
536                     "Error code=%d (%s)", curl_rc, curl_err_string);
537         goto exit_label;
538       }
539
540      if( bakup_api_url != NULL )
541      {
542       curl_rc = curl_easy_setopt(curl_handle2,
543                              CURLOPT_SSL_VERIFYPEER,
544                              verify_peer);
545       if (curl_rc != CURLE_OK)
546       {
547         rc = EVEL_CURL_LIBRARY_FAIL;
548         log_error_state("Failed to initialize libCURL with SSL Server verification. "
549                     "Error code=%d (%s)", curl_rc, curl_err_string);
550         goto exit_label;
551       }
552       curl_rc = curl_easy_setopt(curl_handle2,
553                              CURLOPT_SSL_VERIFYHOST,
554                              verify_host);
555       if (curl_rc != CURLE_OK)
556       {
557         rc = EVEL_CURL_LIBRARY_FAIL;
558         log_error_state("Failed to initialize libCURL with Client host verification. "
559                     "Error code=%d (%s)", curl_rc, curl_err_string);
560         goto exit_label;
561       }
562      }
563   }
564
565
566
567   /***************************************************************************/
568   /* some servers don't like requests that are made without a user-agent     */
569   /* field, so we provide one.                                               */
570   /***************************************************************************/
571   curl_rc = curl_easy_setopt(curl_handle,
572                              CURLOPT_USERAGENT,
573                              "libcurl-agent/1.0");
574   if (curl_rc != CURLE_OK)
575   {
576     rc = EVEL_CURL_LIBRARY_FAIL;
577     log_error_state("Failed to initialize libCURL to upload. "
578                     "Error code=%d (%s)", curl_rc, curl_err_string);
579     goto exit_label;
580   }
581   if( bakup_api_url != NULL )
582   {
583     curl_rc = curl_easy_setopt(curl_handle2,
584                              CURLOPT_USERAGENT,
585                              "libcurl-agent/1.0");
586     if (curl_rc != CURLE_OK)
587     {
588       rc = EVEL_CURL_LIBRARY_FAIL;
589       log_error_state("Failed to initialize libCURL with the API URL. "
590                     "Error code=%d (%s)", curl_rc, curl_err_string2);
591       goto exit_label;
592     }
593   }
594
595
596   /***************************************************************************/
597   /* Specify that we are going to POST data.                                 */
598   /***************************************************************************/
599   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
600   if (curl_rc != CURLE_OK)
601   {
602     rc = EVEL_CURL_LIBRARY_FAIL;
603     log_error_state("Failed to initialize libCURL to upload. "
604                     "Error code=%d (%s)", curl_rc, curl_err_string);
605     goto exit_label;
606   }
607   if( bakup_api_url != NULL )
608   {
609     curl_rc = curl_easy_setopt(curl_handle2,CURLOPT_POST, 1L);
610     if (curl_rc != CURLE_OK)
611     {
612       rc = EVEL_CURL_LIBRARY_FAIL;
613       log_error_state("Failed to initialize libCURL with the API URL. "
614                     "Error code=%d (%s)", curl_rc, curl_err_string2);
615       goto exit_label;
616     }
617   }
618
619
620   /***************************************************************************/
621   /* we want to use our own read function.                                   */
622   /***************************************************************************/
623   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback);
624   if (curl_rc != CURLE_OK)
625   {
626     rc = EVEL_CURL_LIBRARY_FAIL;
627     log_error_state("Failed to initialize libCURL to upload using read "
628                     "function. Error code=%d (%s)", curl_rc, curl_err_string);
629     goto exit_label;
630   }
631   if( bakup_api_url != NULL )
632   {
633     curl_rc = curl_easy_setopt(curl_handle2,CURLOPT_READFUNCTION, read_callback);
634     if (curl_rc != CURLE_OK)
635     {
636       rc = EVEL_CURL_LIBRARY_FAIL;
637       log_error_state("Failed to initialize libCURL with the API URL. "
638                     "Error code=%d (%s)", curl_rc, curl_err_string2);
639       goto exit_label;
640     }
641   }
642
643
644   /***************************************************************************/
645   /* All of our events are JSON encoded.  We also suppress the               */
646   /* Expect: 100-continue   header that we would otherwise get since it      */
647   /* confuses some servers.                                                  */
648   /*                                                                         */
649   /* @TODO: do AT&T want this behavior?                                      */
650   /***************************************************************************/
651   hdr_chunk = curl_slist_append(hdr_chunk, "Content-type: application/json");
652   hdr_chunk = curl_slist_append(hdr_chunk, "Expect:");
653
654   /***************************************************************************/
655   /* set our custom set of headers.                                         */
656   /***************************************************************************/
657   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hdr_chunk);
658   if (curl_rc != CURLE_OK)
659   {
660     rc = EVEL_CURL_LIBRARY_FAIL;
661     log_error_state("Failed to initialize libCURL to use custom headers. "
662                     "Error code=%d (%s)", curl_rc, curl_err_string);
663     goto exit_label;
664   }
665   if( bakup_api_url != NULL )
666   {
667     hdr_chunk2 = curl_slist_append(hdr_chunk2, "Content-type: application/json");
668     hdr_chunk2 = curl_slist_append(hdr_chunk2, "Expect:");
669     curl_rc = curl_easy_setopt(curl_handle2,CURLOPT_HTTPHEADER, hdr_chunk2);
670     if (curl_rc != CURLE_OK)
671     {
672       rc = EVEL_CURL_LIBRARY_FAIL;
673       log_error_state("Failed to initialize libCURL with the API URL. "
674                     "Error code=%d (%s)", curl_rc, curl_err_string2);
675       goto exit_label;
676     }
677   }
678
679
680
681   /***************************************************************************/
682   /* Set the timeout for the operation.                                      */
683   /***************************************************************************/
684   curl_rc = curl_easy_setopt(curl_handle,
685                              CURLOPT_TIMEOUT,
686                              EVEL_API_TIMEOUT);
687   if (curl_rc != CURLE_OK)
688   {
689     rc = EVEL_CURL_LIBRARY_FAIL;
690     log_error_state("Failed to initialize libCURL for API timeout. "
691                     "Error code=%d (%s)", curl_rc, curl_err_string);
692     goto exit_label;
693   }
694   if( bakup_api_url != NULL )
695   {
696     curl_rc = curl_easy_setopt(curl_handle2,CURLOPT_TIMEOUT, EVEL_API_TIMEOUT);
697     if (curl_rc != CURLE_OK)
698     {
699       rc = EVEL_CURL_LIBRARY_FAIL;
700       log_error_state("Failed to initialize libCURL with the API URL. "
701                     "Error code=%d (%s)", curl_rc, curl_err_string2);
702       goto exit_label;
703     }
704   }
705
706
707   /***************************************************************************/
708   /* Set that we want Basic authentication with username:password Base-64    */
709   /* encoded for the operation.                                              */
710   /***************************************************************************/
711   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
712   if (curl_rc != CURLE_OK)
713   {
714     rc = EVEL_CURL_LIBRARY_FAIL;
715     log_error_state("Failed to initialize libCURL for Basic Authentication. "
716                     "Error code=%d (%s)", curl_rc, curl_err_string);
717     goto exit_label;
718   }
719   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_USERNAME, username);
720   if (curl_rc != CURLE_OK)
721   {
722     rc = EVEL_CURL_LIBRARY_FAIL;
723     log_error_state("Failed to initialize libCURL with username. "
724                     "Error code=%d (%s)", curl_rc, curl_err_string);
725     goto exit_label;
726   }
727   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password);
728   if (curl_rc != CURLE_OK)
729   {
730     rc = EVEL_CURL_LIBRARY_FAIL;
731     log_error_state("Failed to initialize libCURL with password. "
732                     "Error code=%d (%s)", curl_rc, curl_err_string);
733     goto exit_label;
734   }
735
736   if( bakup_api_url != NULL )
737   {
738   curl_rc = curl_easy_setopt(curl_handle2, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
739   if (curl_rc != CURLE_OK)
740   {
741     rc = EVEL_CURL_LIBRARY_FAIL;
742     log_error_state("Failed to initialize libCURL for Basic Authentication. "
743                     "Error code=%d (%s)", curl_rc, curl_err_string2);
744     goto exit_label;
745   }
746   curl_rc = curl_easy_setopt(curl_handle2, CURLOPT_USERNAME, username2);
747   if (curl_rc != CURLE_OK)
748   {
749     rc = EVEL_CURL_LIBRARY_FAIL;
750     log_error_state("Failed to initialize libCURL with username. "
751                     "Error code=%d (%s)", curl_rc, curl_err_string2);
752     goto exit_label;
753   }
754   curl_rc = curl_easy_setopt(curl_handle2, CURLOPT_PASSWORD, password2);
755   if (curl_rc != CURLE_OK)
756   {
757     rc = EVEL_CURL_LIBRARY_FAIL;
758     log_error_state("Failed to initialize libCURL with password. "
759                     "Error code=%d (%s)", curl_rc, curl_err_string2);
760     goto exit_label;
761   }
762
763      multi_handle = curl_multi_init();;
764      if (multi_handle == NULL)
765      {
766        rc = EVEL_CURL_LIBRARY_FAIL;
767        log_error_state("Failed to get libCURL Multi handle");
768        goto exit_label;
769      }
770      activmode = activitymode;
771
772   }
773
774
775   /***************************************************************************/
776   /* Initialize a message ring-buffer to be used between the foreground and  */
777   /* the thread which sends the messages.  This can't fail.                  */
778   /***************************************************************************/
779   if( ring_buf_size < EVEL_EVENT_BUFFER_DEPTH )
780   {
781     log_error_state("Warning: Failed to initialize Ring buffer size to %d. ",
782                     ring_buf_size);
783     goto exit_label;
784   }
785   ring_buffer_initialize(&event_buffer, EVEL_EVENT_BUFFER_DEPTH);
786
787   /***************************************************************************/
788   /* Initialize the priority post buffer to empty.                           */
789   /***************************************************************************/
790   priority_post.memory = NULL;
791
792 exit_label:
793   EVEL_EXIT();
794
795   return(rc);
796 }
797
798 /**************************************************************************//**
799  * Run the event handler.
800  *
801  * Spawns the thread responsible for handling events and sending them to the
802  * API.
803  *
804  *  @return Status code.
805  *  @retval ::EVEL_SUCCESS if everything OK.
806  *  @retval One of ::EVEL_ERR_CODES if there was a problem.
807  *****************************************************************************/
808 EVEL_ERR_CODES event_handler_run()
809 {
810   EVEL_ERR_CODES rc = EVEL_SUCCESS;
811   int pthread_rc = 0;
812
813   EVEL_ENTER();
814
815   /***************************************************************************/
816   /* Start the event handler thread.                                         */
817   /***************************************************************************/
818   evt_handler_state = EVT_HANDLER_INACTIVE;
819   if( curr_global_handles <= 1 )
820       pthread_rc = pthread_create(&evt_handler_thread, NULL, event_handler, NULL);
821   else
822       pthread_rc = pthread_create(&evt_handler_thread, NULL, event_multi_handler, NULL);
823
824   if (pthread_rc != 0)
825   {
826     rc = EVEL_PTHREAD_LIBRARY_FAIL;
827     log_error_state("Failed to start event handler thread. "
828                     "Error code=%d", pthread_rc);
829   }
830
831   EVEL_EXIT()
832   return rc;
833 }
834
835 /**************************************************************************//**
836  * Terminate the event handler.
837  *
838  * Shuts down the event handler thread in as clean a way as possible. Sets the
839  * global exit flag and then signals the thread to interrupt it since it's
840  * most likely waiting on the ring-buffer.
841  *
842  * Having achieved an orderly shutdown of the event handler thread, clean up
843  * the cURL library's resources cleanly.
844  *
845  *  @return Status code.
846  *  @retval ::EVEL_SUCCESS if everything OK.
847  *  @retval One of ::EVEL_ERR_CODES if there was a problem.
848  *****************************************************************************/
849 EVEL_ERR_CODES event_handler_terminate()
850 {
851   EVEL_ERR_CODES rc = EVEL_SUCCESS;
852
853   EVEL_ENTER();
854   EVENT_INTERNAL *event = NULL;
855
856   /***************************************************************************/
857   /* Make sure that we were initialized before trying to terminate the       */
858   /* event handler thread.                                                   */
859   /***************************************************************************/
860   if (evt_handler_state != EVT_HANDLER_UNINITIALIZED)
861   {
862     /*************************************************************************/
863     /* Make sure that the event handler knows it's time to die.              */
864     /*************************************************************************/
865     event = evel_new_internal_event(EVT_CMD_TERMINATE,"EVELinternal","EVELid");
866     if (event == NULL)
867     {
868       /***********************************************************************/
869       /* We failed to get an event, but we don't bail out - we will just     */
870       /* clean up what we can and continue on our way, since we're exiting   */
871       /* anyway.                                                             */
872       /***********************************************************************/
873       EVEL_ERROR("Failed to get internal event - perform dirty exit instead!");
874     }
875     else
876     {
877       /***********************************************************************/
878       /* Post the event then wait for the Event Handler to exit.  Set the    */
879       /* global command, too, in case the ring-buffer is full.               */
880       /***********************************************************************/
881       EVEL_DEBUG("Sending event to Event Hander to request it to exit.");
882       evt_handler_state = EVT_HANDLER_REQUEST_TERMINATE;
883       evel_post_event((EVENT_HEADER *) event);
884       pthread_join(evt_handler_thread, NULL);
885       EVEL_DEBUG("Event Handler thread has exited.");
886     }
887   }
888   else
889   {
890     EVEL_DEBUG("Event handler was not initialized, so no need to kill it");
891   }
892
893   /***************************************************************************/
894   /* Clean-up the cURL library.                                              */
895   /***************************************************************************/
896   if (multi_handle != NULL)
897   {
898      curl_multi_cleanup(multi_handle);
899   }
900   if (curl_handle != NULL)
901   {
902     curl_easy_cleanup(curl_handle);
903     curl_handle = NULL;
904   }
905   if (curl_handle2 != NULL)
906   {
907     curl_easy_cleanup(curl_handle2);
908     curl_handle2 = NULL;
909   }
910   if (hdr_chunk != NULL)
911   {
912     curl_slist_free_all(hdr_chunk);
913     hdr_chunk = NULL;
914   }
915   if (hdr_chunk2 != NULL)
916   {
917     curl_slist_free_all(hdr_chunk2);
918     hdr_chunk2 = NULL;
919   }
920
921
922   /***************************************************************************/
923   /* Free off the stored API URL strings.                                    */
924   /***************************************************************************/
925   if (evel_event_api_url != NULL)
926   {
927     free(evel_event_api_url);
928     evel_event_api_url = NULL;
929   }
930   if (evel_batch_api_url != NULL)
931   {
932     free(evel_batch_api_url);
933     evel_batch_api_url = NULL;
934   }
935   if (evel_throt_api_url != NULL)
936   {
937     free(evel_throt_api_url);
938     evel_throt_api_url = NULL;
939   }
940
941   EVEL_EXIT();
942   return rc;
943 }
944
945 /**************************************************************************//**
946  * Post an event.
947  *
948  * @note  So far as the caller is concerned, successfully posting the event
949  * relinquishes all responsibility for the event - the library will take care
950  * of freeing the event in due course.
951
952  * @param event   The event to be posted.
953  *
954  * @returns Status code
955  * @retval  EVEL_SUCCESS On success
956  * @retval  "One of ::EVEL_ERR_CODES" On failure.
957  *****************************************************************************/
958 EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event)
959 {
960   int rc = EVEL_SUCCESS;
961
962   EVEL_ENTER();
963
964   /***************************************************************************/
965   /* Check preconditions.                                                    */
966   /***************************************************************************/
967   assert(event != NULL);
968
969   /***************************************************************************/
970   /* We need to make sure that we are either initializing or running         */
971   /* normally before writing the event into the buffer so that we can        */
972   /* guarantee that the ring-buffer empties  properly on exit.               */
973   /***************************************************************************/
974   if ((evt_handler_state == EVT_HANDLER_ACTIVE) ||
975       (evt_handler_state == EVT_HANDLER_INACTIVE) ||
976       (evt_handler_state == EVT_HANDLER_REQUEST_TERMINATE))
977   {
978     if (ring_buffer_write(&event_buffer, event) == 0)
979     {
980       log_error_state("Failed to write event to buffer - event dropped!");
981       rc = EVEL_EVENT_BUFFER_FULL;
982       evel_free_event(event);
983     }
984   }
985   else
986   {
987     /*************************************************************************/
988     /* System is not in active operation, so reject the event.               */
989     /*************************************************************************/
990     log_error_state("Event Handler system not active - event dropped!");
991     rc = EVEL_EVENT_HANDLER_INACTIVE;
992     evel_free_event(event);
993   }
994
995   EVEL_EXIT();
996   return (rc);
997 }
998
999 /**************************************************************************//**
1000  * Post an event to the Vendor Event Listener API.
1001  *
1002  * @returns Status code
1003  * @retval  EVEL_SUCCESS On success
1004  * @retval  "One of ::EVEL_ERR_CODES" On failure.
1005  *****************************************************************************/
1006 static EVEL_ERR_CODES evel_post_api(char * msg, size_t size)
1007 {
1008   int rc = EVEL_SUCCESS;
1009   CURLcode curl_rc = CURLE_OK;
1010   MEMORY_CHUNK rx_chunk;
1011   MEMORY_CHUNK tx_chunk;
1012   int http_response_code = 0;
1013
1014   EVEL_ENTER();
1015
1016   /***************************************************************************/
1017   /* Create the memory chunk to be used for the response to the post.  The   */
1018   /* will be realloced.                                                      */
1019   /***************************************************************************/
1020   rx_chunk.memory = malloc(1);
1021   assert(rx_chunk.memory != NULL);
1022   rx_chunk.size = 0;
1023
1024   /***************************************************************************/
1025   /* Create the memory chunk to be sent as the body of the post.             */
1026   /***************************************************************************/
1027   tx_chunk.memory = msg;
1028   tx_chunk.size = size;
1029   EVEL_DEBUG("Sending chunk of size %d", tx_chunk.size);
1030
1031   /***************************************************************************/
1032   /* Point to the data to be received.                                       */
1033   /***************************************************************************/
1034   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &rx_chunk);
1035   if (curl_rc != CURLE_OK)
1036   {
1037     rc = EVEL_CURL_LIBRARY_FAIL;
1038     log_error_state("Failed to initialize libCURL to upload. "
1039                     "Error code=%d (%s)", curl_rc, curl_err_string);
1040     goto exit_label;
1041   }
1042   EVEL_DEBUG("Initialized data to receive");
1043
1044   /***************************************************************************/
1045   /* Pointer to pass to our read function                                    */
1046   /***************************************************************************/
1047   curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READDATA, &tx_chunk);
1048   if (curl_rc != CURLE_OK)
1049   {
1050     rc = EVEL_CURL_LIBRARY_FAIL;
1051     log_error_state("Failed to set upload data for libCURL to upload. "
1052                     "Error code=%d (%s)", curl_rc, curl_err_string);
1053     goto exit_label;
1054   }
1055   EVEL_DEBUG("Initialized data to send");
1056
1057   /***************************************************************************/
1058   /* Size of the data to transmit.                                           */
1059   /***************************************************************************/
1060   curl_rc = curl_easy_setopt(curl_handle,
1061                              CURLOPT_POSTFIELDSIZE,
1062                              tx_chunk.size);
1063   if (curl_rc != CURLE_OK)
1064   {
1065     rc = EVEL_CURL_LIBRARY_FAIL;
1066     log_error_state("Failed to set length of upload data for libCURL to "
1067                     "upload.  Error code=%d (%s)", curl_rc, curl_err_string);
1068     goto exit_label;
1069   }
1070   EVEL_DEBUG("Initialized length of data to send");
1071
1072   /***************************************************************************/
1073   /* Now run off and do what you've been told!                               */
1074   /***************************************************************************/
1075   curl_rc = curl_easy_perform(curl_handle);
1076   if (curl_rc != CURLE_OK)
1077   {
1078     rc = EVEL_CURL_LIBRARY_FAIL;
1079     log_error_state("Failed to transfer an event to Vendor Event Listener! "
1080                     "Error code=%d (%s)", curl_rc, curl_err_string);
1081     EVEL_ERROR("Dropped event: %s", msg);
1082     goto exit_label;
1083   }
1084
1085   /***************************************************************************/
1086   /* See what response we got - any 2XX response is good.                    */
1087   /***************************************************************************/
1088   curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
1089   EVEL_DEBUG("HTTP response code: %d", http_response_code);
1090   if ((http_response_code / 100) == 2)
1091   {
1092     /*************************************************************************/
1093     /* If the server responded with data it may be interesting but not a     */
1094     /* problem.                                                              */
1095     /*************************************************************************/
1096     if ((rx_chunk.size > 0) && (rx_chunk.memory != NULL))
1097     {
1098       EVEL_DEBUG("Server returned data = %d (%s)",
1099                  rx_chunk.size,
1100                  rx_chunk.memory);
1101
1102       /***********************************************************************/
1103       /* If this is a response to priority post, then we're not interested.  */
1104       /***********************************************************************/
1105       if (priority_post.memory != NULL)
1106       {
1107         EVEL_ERROR("Ignoring priority post response");
1108       }
1109       else
1110       {
1111         evel_handle_event_response(&rx_chunk, &priority_post);
1112       }
1113     }
1114   }
1115   else
1116   {
1117     EVEL_ERROR("Unexpected HTTP response code: %d with data size %d (%s)",
1118                 http_response_code,
1119                 rx_chunk.size,
1120                 rx_chunk.size > 0 ? rx_chunk.memory : "NONE");
1121     EVEL_ERROR("Potentially dropped event: %s", msg);
1122   }
1123
1124 exit_label:
1125   free(rx_chunk.memory);
1126   EVEL_EXIT();
1127   return(rc);
1128 }
1129
1130 /**************************************************************************//**
1131  * Callback function to provide data to send.
1132  *
1133  * Copy data into the supplied buffer, read_callback::ptr, checking size
1134  * limits.
1135  *
1136  * @returns   Number of bytes placed into read_callback::ptr. 0 for EOF.
1137  *****************************************************************************/
1138 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
1139 {
1140   size_t rtn = 0;
1141   size_t bytes_to_write = 0;
1142   MEMORY_CHUNK *tx_chunk = (MEMORY_CHUNK *)userp;
1143
1144   EVEL_ENTER();
1145
1146   bytes_to_write = min(size*nmemb, tx_chunk->size);
1147
1148   if (bytes_to_write > 0)
1149   {
1150     EVEL_DEBUG("Going to try to write %d bytes", bytes_to_write);
1151     strncpy((char *)ptr, tx_chunk->memory, bytes_to_write);
1152     tx_chunk->memory += bytes_to_write;
1153     tx_chunk->size -= bytes_to_write;
1154     rtn = bytes_to_write;
1155   }
1156   else
1157   {
1158     EVEL_DEBUG("Reached EOF");
1159   }
1160
1161   EVEL_EXIT();
1162   return rtn;
1163 }
1164
1165 /**************************************************************************//**
1166  * Callback function to provide returned data.
1167  *
1168  * Copy data into the supplied buffer, write_callback::ptr, checking size
1169  * limits.
1170  *
1171  * @returns   Number of bytes placed into write_callback::ptr. 0 for EOF.
1172  *****************************************************************************/
1173 size_t evel_write_callback(void *contents,
1174                              size_t size,
1175                              size_t nmemb,
1176                              void *userp)
1177 {
1178   size_t realsize = size * nmemb;
1179   MEMORY_CHUNK * rx_chunk = (MEMORY_CHUNK *)userp;
1180
1181   EVEL_ENTER();
1182
1183   EVEL_DEBUG("Called with %d chunks of %d size = %d", nmemb, size, realsize);
1184   EVEL_DEBUG("rx chunk size is %d", rx_chunk->size);
1185
1186   rx_chunk->memory = realloc(rx_chunk->memory, rx_chunk->size + realsize + 1);
1187   if(rx_chunk->memory == NULL) {
1188     /* out of memory! */
1189     printf("not enough memory (realloc returned NULL)\n");
1190     return 0;
1191   }
1192
1193   memcpy(&(rx_chunk->memory[rx_chunk->size]), contents, realsize);
1194   rx_chunk->size += realsize;
1195   rx_chunk->memory[rx_chunk->size] = 0;
1196
1197   EVEL_DEBUG("Rx data: %s", rx_chunk->memory);
1198   EVEL_DEBUG("Returning: %d", realsize);
1199
1200   EVEL_EXIT();
1201   return realsize;
1202 }
1203
1204
1205 /**************************************************************************//**
1206  * Post an event to the Vendor Event Listener API.
1207  *
1208  * @returns Status code
1209  * @retval  EVEL_SUCCESS On success
1210  * @retval  "One of ::EVEL_ERR_CODES" On failure.
1211  *****************************************************************************/
1212 static EVEL_ERR_CODES evel_postmulti_message(char *msg, size_t size, int *still,
1213                 CURL *handle, CURL *bhandle, int numhandles )
1214 {
1215   int rc = EVEL_SUCCESS;
1216   CURLcode curl_rc = CURLE_OK;
1217   MEMORY_CHUNK rx_chunk[2];
1218   MEMORY_CHUNK tx_chunk[2];
1219   int http_response_code = 0, i;
1220
1221   EVEL_ENTER();
1222
1223   EVEL_INFO("Sending :%s: %d\n",msg, numhandles);
1224
1225   /***************************************************************************/
1226   /* Create the memory chunk to be used for the response to the post.  The   */
1227   /* will be realloced.                                                      */
1228   /***************************************************************************/
1229 for (i=0;i<numhandles;i++)
1230 {
1231   rx_chunk[i].memory = malloc(1);
1232   assert(rx_chunk[i].memory != NULL);
1233   rx_chunk[i].size = 0;
1234
1235   /***************************************************************************/
1236   /* Create the memory chunk to be sent as the body of the post.             */
1237   /***************************************************************************/
1238   tx_chunk[i].memory = msg;
1239   tx_chunk[i].size = size;
1240   EVEL_DEBUG("Sending chunk of size %d", tx_chunk[i].size);
1241 }
1242
1243   /***************************************************************************/
1244   /* Point to the data to be received.                                       */
1245   /***************************************************************************/
1246   curl_rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, &rx_chunk[0]);
1247   if (curl_rc != CURLE_OK)
1248   {
1249     rc = EVEL_CURL_LIBRARY_FAIL;
1250     log_error_state("Failed to initialize libCURL rx to upload. "
1251                     "Error code=%d (%s)", curl_rc, curl_err_string);
1252     goto exit_label;
1253   }
1254
1255   /***************************************************************************/
1256   /* Pointer to pass to our read function                                    */
1257   /***************************************************************************/
1258   curl_rc = curl_easy_setopt(handle, CURLOPT_READDATA, &tx_chunk[0]);
1259   if (curl_rc != CURLE_OK)
1260   {
1261     rc = EVEL_CURL_LIBRARY_FAIL;
1262     log_error_state("Failed to set upload data for libCURL tx to upload. "
1263                     "Error code=%d (%s)", curl_rc, curl_err_string);
1264     goto exit_label;
1265   }
1266   /***************************************************************************/
1267   /* Size of the data to transmit.                                           */
1268   /***************************************************************************/
1269   curl_rc = curl_easy_setopt(handle,
1270                              CURLOPT_POSTFIELDSIZE,
1271                              tx_chunk[0].size);
1272   if (curl_rc != CURLE_OK)
1273   {
1274     rc = EVEL_CURL_LIBRARY_FAIL;
1275     log_error_state("Failed to set length of upload data for libCURL to "
1276                     "upload.  Error code=%d (%s)", curl_rc, curl_err_string);
1277     goto exit_label;
1278   }
1279
1280 if(numhandles == 2)
1281 {
1282
1283   /***************************************************************************/
1284   /* Point to the data to be received.                                       */
1285   /***************************************************************************/
1286   curl_rc = curl_easy_setopt(bhandle, CURLOPT_WRITEDATA, &rx_chunk[1]);
1287   if (curl_rc != CURLE_OK)
1288   {
1289     rc = EVEL_CURL_LIBRARY_FAIL;
1290     log_error_state("Failed to initialize libCURL2 rx to upload. "
1291                     "Error code=%d (%s)", curl_rc, curl_err_string2);
1292     goto exit_label;
1293   }
1294
1295   /***************************************************************************/
1296   /* Pointer to pass to our read function                                    */
1297   /***************************************************************************/
1298   curl_rc = curl_easy_setopt(bhandle, CURLOPT_READDATA, &tx_chunk[1]);
1299   if (curl_rc != CURLE_OK)
1300   {
1301     rc = EVEL_CURL_LIBRARY_FAIL;
1302     log_error_state("Failed to set upload data for libCURL2 tx to upload. "
1303                     "Error code=%d (%s)", curl_rc, curl_err_string2);
1304     goto exit_label;
1305   }
1306   /***************************************************************************/
1307   /* Size of the data to transmit.                                           */
1308   /***************************************************************************/
1309   curl_rc = curl_easy_setopt(bhandle,
1310                              CURLOPT_POSTFIELDSIZE,
1311                              tx_chunk[1].size);
1312   if (curl_rc != CURLE_OK)
1313   {
1314     rc = EVEL_CURL_LIBRARY_FAIL;
1315     log_error_state("Failed to set length of upload data for libCURL2 to "
1316                     "upload.  Error code=%d (%s)", curl_rc, curl_err_string);
1317     goto exit_label;
1318   }
1319
1320 }
1321
1322   /***************************************************************************/
1323   /* Now run off and do what you've been told!                               */
1324   /***************************************************************************/
1325   curl_rc = curl_multi_perform(multi_handle, still);
1326   if (curl_rc != CURLE_OK)
1327   {
1328     rc = EVEL_CURL_LIBRARY_FAIL;
1329     log_error_state("Failed to transfer an multi event to Vendor Event Listener! "
1330                     "Error code=%d (%s)", curl_rc, curl_multi_strerror(curl_rc
1331 ));
1332     EVEL_ERROR("Dropped event: %s", msg);
1333     goto exit_label;
1334   }
1335
1336   /***************************************************************************/
1337   /* See what response we got - any 2XX response is good.                    */
1338   /***************************************************************************/
1339
1340 exit_label:
1341  for (i=0;i<numhandles;i++)
1342     free(rx_chunk[i].memory);
1343   EVEL_EXIT();
1344
1345   return(rc);
1346 }
1347
1348
1349 /**************************************************************************//**
1350  * Event Multi Post Handler.
1351  *
1352  * Watch for messages coming on the internal queue and send them to the
1353  * listener.
1354  *
1355  * param[in]  jsonmsg  json message to be sent.
1356  * param[in]  size     size of json message
1357  * param[in]  currhandle Primary handle
1358  * param[in]  url1     pimary url
1359  * param[in]  bakkhandle  Backup handle
1360  * param[in]  url2     secondary url
1361  *****************************************************************************/
1362 static int evel_post_multiapi(char *jsonmsg, size_t size,CURL *currhandle, char *url1,
1363                                    CURL *bakkhandle, char *url2)
1364 {
1365       int rc = EVEL_SUCCESS;
1366       CURLcode curl_rc = 0;
1367       int nhandles = 1;
1368       int still_running,i;
1369       CURLMsg *msg; /* for picking up messages with the transfer status */ 
1370       int msgs_left; /* how many messages are left */
1371
1372       /***************************************************************************/
1373       /* Set the URL for the API.                                                */
1374       /***************************************************************************/
1375       curl_rc = curl_easy_setopt(currhandle, CURLOPT_URL, url1);
1376       if (curl_rc != CURLE_OK )
1377       {
1378         rc = EVEL_CURL_LIBRARY_FAIL;
1379         log_error_state("Failed to initialize libCURL with the multi API URL. "
1380                     "%s Error code=%d (%s)", url1, curl_rc, curl_err_string);
1381       }
1382
1383       if( url2 != NULL && activmode == 1 )
1384       {
1385         curl_rc = curl_easy_setopt(bakkhandle, CURLOPT_URL, url2);
1386         if (curl_rc != CURLE_OK)
1387         {
1388            rc = EVEL_CURL_LIBRARY_FAIL;
1389            log_error_state("Failed to initialize libCURL with the API URL. "
1390                     "%s Error code=%d (%s)", url2, curl_rc, curl_err_string2);
1391         }
1392         nhandles = 2;
1393       }
1394
1395       /* we start some action by calling perform right away */
1396       curl_multi_add_handle(multi_handle, currhandle);
1397       if(nhandles==2){
1398         curl_multi_add_handle(multi_handle, bakkhandle);
1399       }
1400
1401       /* we start some action by calling perform right away */
1402       curl_multi_perform(multi_handle, &still_running);
1403
1404   do {
1405     struct timeval timeout;
1406     int rc; /* select() return code */ 
1407     CURLMcode mc; /* curl_multi_fdset() return code */ 
1408  
1409     fd_set fdread;
1410     fd_set fdwrite;
1411     fd_set fdexcep;
1412     int maxfd = -1;
1413  
1414     long curl_timeo = -1;
1415  
1416     FD_ZERO(&fdread);
1417     FD_ZERO(&fdwrite);
1418     FD_ZERO(&fdexcep);
1419  
1420     /* set a suitable timeout to play around with */ 
1421     timeout.tv_sec = 1;
1422     timeout.tv_usec = 0;
1423  
1424     curl_multi_timeout(multi_handle, &curl_timeo);
1425     if(curl_timeo >= 0) {
1426       timeout.tv_sec = curl_timeo / 1000;
1427       if(timeout.tv_sec > 1)
1428         timeout.tv_sec = 1;
1429       else
1430         timeout.tv_usec = (curl_timeo % 1000) * 1000;
1431     }
1432  
1433     /* get file descriptors from the transfers */ 
1434     mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
1435  
1436     if(mc != CURLM_OK) {
1437       EVEL_ERROR("curl_multi_fdset() failed, code %d.\n", mc);
1438       break;
1439     }
1440  
1441     /* On success the value of maxfd is guaranteed to be >= -1. We call
1442        select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
1443        no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
1444        to sleep 100ms, which is the minimum suggested value in the
1445        curl_multi_fdset() doc. */ 
1446  
1447     if(maxfd == -1) {
1448 #ifdef _WIN32
1449       Sleep(100);
1450       rc = 0;
1451 #else
1452       /* Portable sleep for platforms other than Windows. */ 
1453       struct timeval wait = { 0, 300000 }; /* 250ms */ 
1454       rc = select(0, NULL, NULL, NULL, &wait);
1455 #endif
1456     }
1457     else {
1458       /* Note that on some platforms 'timeout' may be modified by select().
1459          If you need access to the original value save a copy beforehand. */ 
1460       rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
1461     }
1462  
1463     switch(rc) {
1464     case -1:
1465       /* select error */ 
1466       break;
1467     case 0: /* timeout */ 
1468     default: /* action */ 
1469       //curl_multi_perform(multi_handle, &still_running);
1470       evel_postmulti_message(jsonmsg, size, &still_running, currhandle, bakkhandle, nhandles);
1471     }
1472   } while(still_running);
1473  
1474   /* See how the transfers went */ 
1475   while((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
1476     if(msg->msg == CURLMSG_DONE) {
1477       int idx, found = 0;
1478       EVEL_DEBUG("Transfer status - %s\n", curl_multi_strerror(msg->data.result));
1479
1480       /* Find out which handle this message is about */ 
1481       for(idx = 0; idx<nhandles; idx++) {
1482         if (msg->easy_handle == currhandle) break;
1483         else if(msg->easy_handle == bakkhandle) break;
1484       }
1485  
1486       switch(idx) {
1487       case 0:
1488         curl_rc = msg->data.result;
1489         break;
1490       case 1:
1491         curl_rc = msg->data.result;
1492         break;
1493       }
1494     }
1495   }
1496
1497   /* we start some action by calling perform right away */
1498   curl_multi_remove_handle(multi_handle, currhandle);
1499   if(nhandles==2){
1500         curl_multi_remove_handle(multi_handle, bakkhandle);
1501   }
1502
1503   EVEL_DEBUG("Transfer completed with status %s\n", curl_multi_strerror(curl_rc));
1504   if( curl_rc == 0 || curl_rc == 55 )
1505      return EVEL_SUCCESS;
1506   else
1507      return EVEL_CURL_LIBRARY_FAIL;
1508
1509 }
1510 /**************************************************************************//**
1511  * Event Handler.
1512  *
1513  * Watch for messages coming on the internal queue and send them to the
1514  * listener.
1515  *
1516  * param[in]  arg  Argument - unused.
1517  *****************************************************************************/
1518 static void * event_multi_handler(void * arg __attribute__ ((unused)))
1519 {
1520   int old_type = 0;
1521   EVENT_HEADER * msg = NULL;
1522   EVENT_INTERNAL * internal_msg = NULL;
1523   int json_size = 0;
1524   char json_body[EVEL_MAX_JSON_BODY];
1525   int rc = EVEL_SUCCESS;
1526   CURLcode curl_rc;
1527   CURL *currhandler = NULL;
1528   CURL *bakhandler = NULL;
1529   char *send_url = NULL;
1530   char *send_url2 = NULL;
1531
1532   EVEL_INFO("Event multi handler thread started");
1533
1534   /***************************************************************************/
1535   /* Set this thread to be cancellable immediately.                          */
1536   /***************************************************************************/
1537   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
1538
1539   /***************************************************************************/
1540   /* Set the handler as active, defending against weird situations like      */
1541   /* immediately shutting down after initializing the library so the         */
1542   /* handler never gets started up properly.                                 */
1543   /***************************************************************************/
1544   if (evt_handler_state == EVT_HANDLER_INACTIVE)
1545   {
1546     evt_handler_state = EVT_HANDLER_ACTIVE;
1547   }
1548   else
1549   {
1550     EVEL_ERROR("Event Handler State was not INACTIVE at start-up - "
1551                "Handler will exit immediately!");
1552   }
1553
1554   currhandler = curl_handle;
1555   while (evt_handler_state == EVT_HANDLER_ACTIVE)
1556   {
1557     /*************************************************************************/
1558     /* Wait for a message to be received.                                    */
1559     /*************************************************************************/
1560     msg = ring_buffer_read(&event_buffer);
1561
1562     /*************************************************************************/
1563     /* Internal events get special treatment while regular events get posted */
1564     /* to the far side.                                                      */
1565     /*************************************************************************/
1566     if (msg->event_domain == EVEL_DOMAIN_BATCH )
1567     {
1568       EVEL_DEBUG("Batch event received");
1569
1570       /***********************************************************************/
1571       /* Encode the event in JSON.                                           */
1572       /***********************************************************************/
1573       json_size = evel_json_encode_batch_event(json_body, EVEL_MAX_JSON_BODY, msg);
1574
1575       /***************************************************************************/
1576       /* Set the URL for the API.                                                */
1577       /***************************************************************************/
1578       if( currhandler == curl_handle){
1579          send_url = evel_batch_api_url;
1580          send_url2 = evel_bbatch_api_url;
1581          bakhandler = curl_handle2;
1582       } else if(currhandler == curl_handle2) {
1583          send_url = evel_bbatch_api_url;
1584          send_url2 = evel_batch_api_url;
1585          bakhandler = curl_handle;
1586       }
1587
1588       /***********************************************************************/
1589       /* Send the JSON across the API.                                       */
1590       /***********************************************************************/
1591       EVEL_DEBUG("Sending Batch JSON of size %d is: %s", json_size, json_body);
1592       rc = evel_post_multiapi(json_body, json_size, currhandler, send_url, bakhandler, send_url2);
1593       if (rc != EVEL_SUCCESS)
1594       {
1595         EVEL_ERROR("Failed to transfer the data to %s. Error code=%d", send_url, rc);
1596         EVEL_INFO("Switched Collector ...");
1597         if( currhandler == curl_handle){
1598           currhandler = curl_handle2;
1599           bakhandler = curl_handle;
1600         } else if(currhandler == curl_handle2) {
1601           currhandler = curl_handle;
1602           bakhandler = curl_handle2;
1603         }
1604         rc = evel_post_multiapi(json_body, json_size, currhandler, send_url2, bakhandler,send_url);
1605         if (rc != EVEL_SUCCESS)
1606            EVEL_ERROR("Failed to transfer the data to failover %s. Error code=%d", send_url2, rc);
1607       }
1608     }
1609     else if (msg->event_domain != EVEL_DOMAIN_INTERNAL )
1610     {
1611       EVEL_DEBUG("External event received");
1612
1613       /***********************************************************************/
1614       /* Encode the event in JSON.                                           */
1615       /***********************************************************************/
1616       json_size = evel_json_encode_event(json_body, EVEL_MAX_JSON_BODY, msg);
1617
1618       /***************************************************************************/
1619       /* Set the URL for the API.                                                */
1620       /***************************************************************************/
1621       if( currhandler == curl_handle){
1622          send_url = evel_event_api_url;
1623          send_url2 = evel_bevent_api_url;
1624          bakhandler = curl_handle2;
1625       } else if(currhandler == curl_handle2) {
1626          send_url = evel_bevent_api_url;
1627          send_url2 = evel_event_api_url;
1628          bakhandler = curl_handle;
1629       }
1630
1631       /***********************************************************************/
1632       /* Send the JSON across the API.                                       */
1633       /***********************************************************************/
1634       EVEL_DEBUG("Sending Batch JSON of size %d is: %s", json_size, json_body);
1635       rc = evel_post_multiapi(json_body, json_size, currhandler, send_url, bakhandler, send_url2);
1636       if (rc != EVEL_SUCCESS)
1637       {
1638         EVEL_ERROR("Failed to transfer the data to %s. Error code=%d", send_url, rc);
1639         EVEL_INFO("Switched Collector ...");
1640         if( currhandler == curl_handle){
1641           currhandler = curl_handle2;
1642           bakhandler = curl_handle;
1643         } else if(currhandler == curl_handle2) {
1644           currhandler = curl_handle;
1645           bakhandler = curl_handle2;
1646         }
1647         rc = evel_post_multiapi(json_body, json_size, currhandler, send_url2, bakhandler,send_url);
1648         if (rc != EVEL_SUCCESS)
1649            EVEL_ERROR("Failed to transfer the data to failover %s. Error code=%d", send_url2, rc);
1650       }
1651
1652     }
1653     else
1654     {
1655       EVEL_DEBUG("Internal event received");
1656       internal_msg = (EVENT_INTERNAL *) msg;
1657       assert(internal_msg->command == EVT_CMD_TERMINATE);
1658       evt_handler_state = EVT_HANDLER_TERMINATING;
1659     }
1660
1661     /*************************************************************************/
1662     /* We are responsible for freeing the memory.                            */
1663     /*************************************************************************/
1664     evel_free_event(msg);
1665     msg = NULL;
1666
1667     /*************************************************************************/
1668     /* There may be a single priority post to be sent.                       */
1669     /*************************************************************************/
1670     if (priority_post.memory != NULL)
1671     {
1672       EVEL_DEBUG("Priority Post");
1673
1674       /***********************************************************************/
1675       /* Set the URL for the throttling API.                                 */
1676       /***********************************************************************/
1677       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url);
1678       if (curl_rc != CURLE_OK)
1679       {
1680         /*********************************************************************/
1681         /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
1682         /* case we carry on regardless.                                      */
1683         /*********************************************************************/
1684         EVEL_ERROR("Failed to set throttling URL. Error code=%d", rc);
1685       }
1686       else
1687       {
1688         rc = evel_post_api(priority_post.memory, priority_post.size);
1689         if (rc != EVEL_SUCCESS)
1690         {
1691           EVEL_ERROR("Failed to transfer priority post. Error code=%d", rc);
1692         }
1693       }
1694
1695       /***********************************************************************/
1696       /* Reinstate the URL for the event API.                                */
1697       /***********************************************************************/
1698       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1699       if (curl_rc != CURLE_OK)
1700       {
1701         /*********************************************************************/
1702         /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
1703         /* case we carry on regardless.                                      */
1704         /*********************************************************************/
1705         EVEL_ERROR("Failed to reinstate events URL. Error code=%d", rc);
1706       }
1707
1708       /***********************************************************************/
1709       /* We are responsible for freeing the memory.                          */
1710       /***********************************************************************/
1711       free(priority_post.memory);
1712       priority_post.memory = NULL;
1713     }
1714   }
1715
1716   /***************************************************************************/
1717   /* The event handler is now exiting. The ring-buffer could contain events  */
1718   /* which have not been processed, so deplete those.  Because we've been    */
1719   /* asked to exit we can be confident that the foreground will have stopped */
1720   /* sending events in so we know that this process will conclude!           */
1721   /***************************************************************************/
1722   evt_handler_state = EVT_HANDLER_TERMINATING;
1723   while (!ring_buffer_is_empty(&event_buffer))
1724   {
1725     EVEL_DEBUG("Reading event from buffer");
1726     msg = ring_buffer_read(&event_buffer);
1727     evel_free_event(msg);
1728   }
1729   evt_handler_state = EVT_HANDLER_TERMINATED;
1730   EVEL_INFO("Event handler thread stopped");
1731
1732   return (NULL);
1733 }
1734
1735
1736 /**************************************************************************//**
1737  * Event Handler.
1738  *
1739  * Watch for messages coming on the internal queue and send them to the
1740  * listener.
1741  *
1742  * param[in]  arg  Argument - unused.
1743  *****************************************************************************/
1744 static void * event_handler(void * arg __attribute__ ((unused)))
1745 {
1746   int old_type = 0;
1747   EVENT_HEADER * msg = NULL;
1748   EVENT_INTERNAL * internal_msg = NULL;
1749   int json_size = 0;
1750   char json_body[EVEL_MAX_JSON_BODY];
1751   int rc = EVEL_SUCCESS;
1752   CURLcode curl_rc;
1753
1754   EVEL_INFO("Event handler thread started");
1755
1756   /***************************************************************************/
1757   /* Set this thread to be cancellable immediately.                          */
1758   /***************************************************************************/
1759   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
1760
1761   /***************************************************************************/
1762   /* Set the handler as active, defending against weird situations like      */
1763   /* immediately shutting down after initializing the library so the         */
1764   /* handler never gets started up properly.                                 */
1765   /***************************************************************************/
1766   if (evt_handler_state == EVT_HANDLER_INACTIVE)
1767   {
1768     evt_handler_state = EVT_HANDLER_ACTIVE;
1769   }
1770   else
1771   {
1772     EVEL_ERROR("Event Handler State was not INACTIVE at start-up - "
1773                "Handler will exit immediately!");
1774   }
1775
1776   while (evt_handler_state == EVT_HANDLER_ACTIVE)
1777   {
1778     /*************************************************************************/
1779     /* Wait for a message to be received.                                    */
1780     /*************************************************************************/
1781     EVEL_DEBUG("Event handler getting any messages");
1782     msg = ring_buffer_read(&event_buffer);
1783
1784     /*************************************************************************/
1785     /* Internal events get special treatment while regular events get posted */
1786     /* to the far side.                                                      */
1787     /*************************************************************************/
1788     if (msg->event_domain == EVEL_DOMAIN_BATCH )
1789     {
1790       EVEL_DEBUG("Batch event received");
1791
1792       /***********************************************************************/
1793       /* Encode the event in JSON.                                           */
1794       /***********************************************************************/
1795       json_size = evel_json_encode_batch_event(json_body, EVEL_MAX_JSON_BODY, msg);
1796
1797       /***************************************************************************/
1798       /* Set the URL for the API.                                                */
1799       /***************************************************************************/
1800       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_batch_api_url);
1801       if (curl_rc != CURLE_OK)
1802       {
1803         rc = EVEL_CURL_LIBRARY_FAIL;
1804         log_error_state("Failed to initialize libCURL with the Batch API URL. "
1805                     "Error code=%d (%s)", curl_rc, curl_err_string);
1806       }
1807
1808       /***********************************************************************/
1809       /* Send the JSON across the API.                                       */
1810       /***********************************************************************/
1811       EVEL_DEBUG("Sending Batch JSON of size %d is: %s", json_size, json_body);
1812       rc = evel_post_api(json_body, json_size);
1813       if (rc != EVEL_SUCCESS)
1814       {
1815         EVEL_ERROR("Failed to transfer the data %s. Error code=%d", evel_batch_api_url, rc);
1816       }
1817     }
1818     else if (msg->event_domain != EVEL_DOMAIN_INTERNAL )
1819     {
1820       EVEL_DEBUG("External event received");
1821
1822       /***********************************************************************/
1823       /* Encode the event in JSON.                                           */
1824       /***********************************************************************/
1825       json_size = evel_json_encode_event(json_body, EVEL_MAX_JSON_BODY, msg);
1826
1827       /***************************************************************************/
1828       /* Set the URL for the API.                                                */
1829       /***************************************************************************/
1830       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1831       if (curl_rc != CURLE_OK)
1832       {
1833         rc = EVEL_CURL_LIBRARY_FAIL;
1834         log_error_state("Failed to initialize libCURL with the API URL. "
1835                     "Error code=%d (%s)", curl_rc, curl_err_string);
1836       }
1837
1838       /***********************************************************************/
1839       /* Send the JSON across the API.                                       */
1840       /***********************************************************************/
1841       EVEL_DEBUG("Sending JSON of size %d is: %s", json_size, json_body);
1842       rc = evel_post_api(json_body, json_size);
1843       if (rc != EVEL_SUCCESS)
1844       {
1845         EVEL_ERROR("Failed to transfer the data %s. Error code=%d",evel_event_api_url, rc);
1846       }
1847     }
1848     else
1849     {
1850       EVEL_DEBUG("Internal event received");
1851       internal_msg = (EVENT_INTERNAL *) msg;
1852       assert(internal_msg->command == EVT_CMD_TERMINATE);
1853       evt_handler_state = EVT_HANDLER_TERMINATING;
1854     }
1855
1856     /*************************************************************************/
1857     /* We are responsible for freeing the memory.                            */
1858     /*************************************************************************/
1859     evel_free_event(msg);
1860     msg = NULL;
1861
1862     /*************************************************************************/
1863     /* There may be a single priority post to be sent.                       */
1864     /*************************************************************************/
1865     if (priority_post.memory != NULL)
1866     {
1867       EVEL_DEBUG("Priority Post");
1868
1869       /***********************************************************************/
1870       /* Set the URL for the throttling API.                                 */
1871       /***********************************************************************/
1872       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url);
1873       if (curl_rc != CURLE_OK)
1874       {
1875         /*********************************************************************/
1876         /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
1877         /* case we carry on regardless.                                      */
1878         /*********************************************************************/
1879         EVEL_ERROR("Failed to set throttling URL. Error code=%d", rc);
1880       }
1881       else
1882       {
1883         rc = evel_post_api(priority_post.memory, priority_post.size);
1884         if (rc != EVEL_SUCCESS)
1885         {
1886           EVEL_ERROR("Failed to transfer priority post. Error code=%d", rc);
1887         }
1888       }
1889
1890       /***********************************************************************/
1891       /* Reinstate the URL for the event API.                                */
1892       /***********************************************************************/
1893       curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1894       if (curl_rc != CURLE_OK)
1895       {
1896         /*********************************************************************/
1897         /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
1898         /* case we carry on regardless.                                      */
1899         /*********************************************************************/
1900         EVEL_ERROR("Failed to reinstate events URL. Error code=%d", rc);
1901       }
1902
1903       /***********************************************************************/
1904       /* We are responsible for freeing the memory.                          */
1905       /***********************************************************************/
1906       free(priority_post.memory);
1907       priority_post.memory = NULL;
1908     }
1909   }
1910
1911   /***************************************************************************/
1912   /* The event handler is now exiting. The ring-buffer could contain events  */
1913   /* which have not been processed, so deplete those.  Because we've been    */
1914   /* asked to exit we can be confident that the foreground will have stopped */
1915   /* sending events in so we know that this process will conclude!           */
1916   /***************************************************************************/
1917   evt_handler_state = EVT_HANDLER_TERMINATING;
1918   while (!ring_buffer_is_empty(&event_buffer))
1919   {
1920     EVEL_DEBUG("Reading event from buffer");
1921     msg = ring_buffer_read(&event_buffer);
1922     evel_free_event(msg);
1923   }
1924   evt_handler_state = EVT_HANDLER_TERMINATED;
1925   EVEL_INFO("Event handler thread stopped");
1926
1927   return (NULL);
1928 }
1929
1930 /**************************************************************************//**
1931  * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK.
1932  *
1933  * Tokenize the response, and decode any tokens found.
1934  *
1935  * @param chunk         The memory chunk containing the response.
1936  * @param post          The memory chunk in which to place any resulting POST.
1937  *****************************************************************************/
1938 void evel_handle_event_response(const MEMORY_CHUNK * const chunk,
1939                                 MEMORY_CHUNK * const post)
1940 {
1941   jsmn_parser json_parser;
1942   jsmntok_t json_tokens[EVEL_MAX_RESPONSE_TOKENS];
1943   int num_tokens = 0;
1944
1945   EVEL_ENTER();
1946
1947   /***************************************************************************/
1948   /* Check preconditions.                                                    */
1949   /***************************************************************************/
1950   assert(chunk != NULL);
1951   assert(priority_post.memory == NULL);
1952
1953   EVEL_DEBUG("Response size = %d", chunk->size);
1954   EVEL_DEBUG("Response = %s", chunk->memory);
1955
1956   /***************************************************************************/
1957   /* Initialize the parser and tokenize the response.                        */
1958   /***************************************************************************/
1959   jsmn_init(&json_parser);
1960   num_tokens = jsmn_parse(&json_parser,
1961                           chunk->memory,
1962                           chunk->size,
1963                           json_tokens,
1964                           EVEL_MAX_RESPONSE_TOKENS);
1965
1966   if (num_tokens < 0)
1967   {
1968     EVEL_ERROR("Failed to parse JSON response.  "
1969                "Error code=%d", num_tokens);
1970   }
1971   else if (num_tokens == 0)
1972   {
1973     EVEL_DEBUG("No tokens found in JSON response");
1974   }
1975   else
1976   {
1977     //EVEL_DEBUG("Decode JSON response tokens");
1978     //if (!evel_handle_response_tokens(chunk, json_tokens, num_tokens, post))
1979     //{
1980     //  EVEL_ERROR("Failed to handle JSON response.");
1981     //}
1982   }
1983
1984   EVEL_EXIT();
1985 }
1986
1987 /**************************************************************************//**
1988  * Handle a JSON response from the listener, as a list of tokens from JSMN.
1989  *
1990  * @param chunk         Memory chunk containing the JSON buffer.
1991  * @param json_tokens   Array of tokens to handle.
1992  * @param num_tokens    The number of tokens to handle.
1993  * @param post          The memory chunk in which to place any resulting POST.
1994  * @return true if we handled the response, false otherwise.
1995  *****************************************************************************/
1996 bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
1997                                  const jsmntok_t * const json_tokens,
1998                                  const int num_tokens,
1999                                  MEMORY_CHUNK * const post)
2000 {
2001   bool json_ok = false;
2002
2003   EVEL_ENTER();
2004
2005   /***************************************************************************/
2006   /* Check preconditions.                                                    */
2007   /***************************************************************************/
2008   assert(chunk != NULL);
2009   assert(json_tokens != NULL);
2010   assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
2011
2012   /***************************************************************************/
2013   /* Peek at the tokens to decide what the response it, then call the        */
2014   /* appropriate handler to handle it.  There is only one handler at this    */
2015   /* point.                                                                  */
2016   /***************************************************************************/
2017   if (evel_tokens_match_command_list(chunk, json_tokens, num_tokens))
2018   {
2019     json_ok = evel_handle_command_list(chunk, json_tokens, num_tokens, post);
2020   }
2021
2022   EVEL_EXIT();
2023
2024   return json_ok;
2025 }
2026
2027 /**************************************************************************//**
2028  * Determine whether a list of tokens looks like a "commandList" response.
2029  *
2030  * @param chunk         Memory chunk containing the JSON buffer.
2031  * @param json_tokens   Token to check.
2032  * @param num_tokens    The number of tokens to handle.
2033  * @return true if the tokens look like a "commandList" match, or false.
2034  *****************************************************************************/
2035 bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
2036                                     const jsmntok_t * const json_tokens,
2037                                     const int num_tokens)
2038 {
2039   bool result = false;
2040
2041   EVEL_ENTER();
2042
2043   /***************************************************************************/
2044   /* Make some checks on the basic layout of the commandList.                */
2045   /***************************************************************************/
2046   if ((num_tokens > 3) &&
2047       (json_tokens[0].type == JSMN_OBJECT) &&
2048       (json_tokens[1].type == JSMN_STRING) &&
2049       (json_tokens[2].type == JSMN_ARRAY) &&
2050       (evel_token_equals_string(chunk, &json_tokens[1], "commandList")))
2051   {
2052     result = true;
2053   }
2054
2055   EVEL_EXIT();
2056
2057   return result;
2058 }
2059
2060 /**************************************************************************//**
2061  * Check that a string token matches a given input string.
2062  *
2063  * @param chunk         Memory chunk containing the JSON buffer.
2064  * @param json_token    Token to check.
2065  * @param check_string  String to check it against.
2066  * @return true if the strings match, or false.
2067  *****************************************************************************/
2068 bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
2069                               const jsmntok_t * json_token,
2070                               const char * check_string)
2071 {
2072   bool result = false;
2073
2074   EVEL_ENTER();
2075
2076   const int token_length = json_token->end - json_token->start;
2077   const char * const token_string = chunk->memory + json_token->start;
2078
2079   if (token_length == (int)strlen(check_string))
2080   {
2081     result = (strncmp(token_string, check_string, token_length) == 0);
2082   }
2083
2084   EVEL_EXIT();
2085
2086   return result;
2087 }