45 #include <curl/curl.h> 56 static const int EVEL_API_TIMEOUT = 5;
61 static size_t read_callback(
void *ptr,
size_t size,
size_t nmemb,
void *userp);
62 static void * event_handler(
void *arg);
63 static bool evel_handle_response_tokens(
const MEMORY_CHUNK *
const chunk,
67 static bool evel_tokens_match_command_list(
const MEMORY_CHUNK *
const chunk,
69 const int num_tokens);
70 static bool evel_token_equals_string(
const MEMORY_CHUNK *
const chunk,
72 const char * check_string);
77 static char curl_err_string[CURL_ERROR_SIZE] =
"<NULL>";
82 static CURL * curl_handle = NULL;
87 static struct curl_slist * hdr_chunk = NULL;
104 static pthread_t evt_handler_thread;
115 static char * evel_event_api_url;
116 static char * evel_throt_api_url;
134 const char *
const throt_api_url,
135 const char *
const username,
136 const char *
const password,
140 CURLcode curl_rc = CURLE_OK;
147 assert(event_api_url != NULL);
148 assert(throt_api_url != NULL);
149 assert(username != NULL);
150 assert(password != NULL);
155 evel_event_api_url = strdup(event_api_url);
156 assert(evel_event_api_url != NULL);
157 evel_throt_api_url = strdup(throt_api_url);
158 assert(evel_throt_api_url != NULL);
165 curl_rc = curl_global_init(CURL_GLOBAL_SSL);
166 if (curl_rc != CURLE_OK)
169 log_error_state(
"Failed to initialize libCURL. Error code=%d", curl_rc);
176 curl_handle = curl_easy_init();
177 if (curl_handle == NULL)
187 curl_rc = curl_easy_setopt(curl_handle,
190 if (curl_rc != CURLE_OK)
193 log_error_state(
"Failed to initialize libCURL to provide friendly errors. " 194 "Error code=%d", curl_rc);
203 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
204 if (curl_rc != CURLE_OK)
208 "Error code=%d", curl_rc);
216 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, event_api_url);
217 if (curl_rc != CURLE_OK)
221 "Error code=%d (%s)", curl_rc, curl_err_string);
224 EVEL_INFO(
"Initializing CURL to send events to: %s", event_api_url);
229 curl_rc = curl_easy_setopt(curl_handle,
230 CURLOPT_WRITEFUNCTION,
232 if (curl_rc != CURLE_OK)
235 log_error_state(
"Failed to initialize libCURL with the write callback. " 236 "Error code=%d (%s)", curl_rc, curl_err_string);
244 curl_rc = curl_easy_setopt(curl_handle,
246 "libcurl-agent/1.0");
247 if (curl_rc != CURLE_OK)
251 "Error code=%d (%s)", curl_rc, curl_err_string);
258 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
259 if (curl_rc != CURLE_OK)
263 "Error code=%d (%s)", curl_rc, curl_err_string);
270 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback);
271 if (curl_rc != CURLE_OK)
275 "function. Error code=%d (%s)", curl_rc, curl_err_string);
286 hdr_chunk = curl_slist_append(hdr_chunk,
"Content-type: application/json");
287 hdr_chunk = curl_slist_append(hdr_chunk,
"Expect:");
292 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hdr_chunk);
293 if (curl_rc != CURLE_OK)
297 "Error code=%d (%s)", curl_rc, curl_err_string);
304 curl_rc = curl_easy_setopt(curl_handle,
307 if (curl_rc != CURLE_OK)
311 "Error code=%d (%s)", curl_rc, curl_err_string);
319 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
320 if (curl_rc != CURLE_OK)
323 log_error_state(
"Failed to initialize libCURL for Basic Authentication. " 324 "Error code=%d (%s)", curl_rc, curl_err_string);
327 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_USERNAME, username);
328 if (curl_rc != CURLE_OK)
332 "Error code=%d (%s)", curl_rc, curl_err_string);
335 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password);
336 if (curl_rc != CURLE_OK)
340 "Error code=%d (%s)", curl_rc, curl_err_string);
353 priority_post.
memory = NULL;
382 pthread_rc = pthread_create(&evt_handler_thread, NULL, event_handler, NULL);
387 "Error code=%d", pthread_rc);
432 EVEL_ERROR(
"Failed to get internal event - perform dirty exit instead!");
440 EVEL_DEBUG(
"Sending event to Event Hander to request it to exit.");
443 pthread_join(evt_handler_thread, NULL);
444 EVEL_DEBUG(
"Event Handler thread has exited.");
449 EVEL_DEBUG(
"Event handler was not initialized, so no need to kill it");
455 if (curl_handle != NULL)
457 curl_easy_cleanup(curl_handle);
460 if (hdr_chunk != NULL)
462 curl_slist_free_all(hdr_chunk);
469 if (evel_event_api_url != NULL)
471 free(evel_event_api_url);
472 evel_event_api_url = NULL;
474 if (evel_throt_api_url != NULL)
476 free(evel_throt_api_url);
477 evel_throt_api_url = NULL;
506 assert(event != NULL);
548 CURLcode curl_rc = CURLE_OK;
551 int http_response_code = 0;
559 rx_chunk.
memory = malloc(1);
560 assert(rx_chunk.
memory != NULL);
567 tx_chunk.
size = size;
573 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &rx_chunk);
574 if (curl_rc != CURLE_OK)
578 "Error code=%d (%s)", curl_rc, curl_err_string);
586 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READDATA, &tx_chunk);
587 if (curl_rc != CURLE_OK)
591 "Error code=%d (%s)", curl_rc, curl_err_string);
599 curl_rc = curl_easy_setopt(curl_handle,
600 CURLOPT_POSTFIELDSIZE,
602 if (curl_rc != CURLE_OK)
606 "upload. Error code=%d (%s)", curl_rc, curl_err_string);
609 EVEL_DEBUG(
"Initialized length of data to send");
614 curl_rc = curl_easy_perform(curl_handle);
615 if (curl_rc != CURLE_OK)
618 log_error_state(
"Failed to transfer an event to Vendor Event Listener! " 619 "Error code=%d (%s)", curl_rc, curl_err_string);
627 curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
628 EVEL_DEBUG(
"HTTP response code: %d", http_response_code);
629 if ((http_response_code / 100) == 2)
635 if ((rx_chunk.
size > 0) && (rx_chunk.
memory != NULL))
644 if (priority_post.
memory != NULL)
646 EVEL_ERROR(
"Ignoring priority post response");
656 EVEL_ERROR(
"Unexpected HTTP response code: %d with data size %d (%s)",
659 rx_chunk.
size > 0 ? rx_chunk.
memory :
"NONE");
660 EVEL_ERROR(
"Potentially dropped event: %s", msg);
677 static size_t read_callback(
void *ptr,
size_t size,
size_t nmemb,
void *userp)
680 size_t bytes_to_write = 0;
685 bytes_to_write =
min(size*nmemb, tx_chunk->
size);
687 if (bytes_to_write > 0)
689 EVEL_DEBUG(
"Going to try to write %d bytes", bytes_to_write);
690 strncpy((
char *)ptr, tx_chunk->
memory, bytes_to_write);
691 tx_chunk->
memory += bytes_to_write;
692 tx_chunk->
size -= bytes_to_write;
693 rtn = bytes_to_write;
717 size_t realsize = size * nmemb;
722 EVEL_DEBUG(
"Called with %d chunks of %d size = %d", nmemb, size, realsize);
725 rx_chunk->
memory = realloc(rx_chunk->
memory, rx_chunk->
size + realsize + 1);
726 if(rx_chunk->
memory == NULL) {
728 printf(
"not enough memory (realloc returned NULL)\n");
732 memcpy(&(rx_chunk->
memory[rx_chunk->
size]), contents, realsize);
733 rx_chunk->
size += realsize;
751 static void * event_handler(
void * arg __attribute__ ((unused)))
761 EVEL_INFO(
"Event handler thread started");
766 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
779 EVEL_ERROR(
"Event Handler State was not INACTIVE at start-up - " 780 "Handler will exit immediately!");
788 EVEL_DEBUG(
"Event handler getting any messages");
807 EVEL_DEBUG(
"Sending JSON of size %d is: %s", json_size, json_body);
808 rc = evel_post_api(json_body, json_size);
811 EVEL_ERROR(
"Failed to transfer the data. Error code=%d", rc);
831 if (priority_post.
memory != NULL)
838 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url);
839 if (curl_rc != CURLE_OK)
845 EVEL_ERROR(
"Failed to set throttling URL. Error code=%d", rc);
849 rc = evel_post_api(priority_post.
memory, priority_post.
size);
852 EVEL_ERROR(
"Failed to transfer priority post. Error code=%d", rc);
859 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
860 if (curl_rc != CURLE_OK)
866 EVEL_ERROR(
"Failed to reinstate events URL. Error code=%d", rc);
872 free(priority_post.
memory);
873 priority_post.
memory = NULL;
891 EVEL_INFO(
"Event handler thread stopped");
916 assert(chunk != NULL);
917 assert(priority_post.
memory == NULL);
935 "Error code=%d", num_tokens);
937 else if (num_tokens == 0)
939 EVEL_DEBUG(
"No tokens found in JSON response");
944 if (!evel_handle_response_tokens(chunk, json_tokens, num_tokens, post))
946 EVEL_ERROR(
"Failed to handle JSON response.");
962 bool evel_handle_response_tokens(
const MEMORY_CHUNK *
const chunk,
964 const int num_tokens,
967 bool json_ok =
false;
974 assert(chunk != NULL);
975 assert(json_tokens != NULL);
983 if (evel_tokens_match_command_list(chunk, json_tokens, num_tokens))
1001 bool evel_tokens_match_command_list(
const MEMORY_CHUNK *
const chunk,
1003 const int num_tokens)
1005 bool result =
false;
1012 if ((num_tokens > 3) &&
1016 (evel_token_equals_string(chunk, &json_tokens[1],
"commandList")))
1034 bool evel_token_equals_string(
const MEMORY_CHUNK *
const chunk,
1036 const char * check_string)
1038 bool result =
false;
1042 const int token_length = json_token->
end - json_token->
start;
1043 const char *
const token_string = chunk->
memory + json_token->
start;
1045 if (token_length == (
int)strlen(check_string))
1047 result = (strncmp(token_string, check_string, token_length) == 0);
#define EVEL_DEBUG(FMT,...)
void * ring_buffer_read(ring_buffer *buffer)
Read an element from a ring_buffer.
#define EVEL_INFO(FMT,...)
void evel_free_event(void *event)
Free an event.
EVT_HANDLER_COMMAND command
A chunk of memory used in the cURL functions.
The event handler thread not started.
A memory allocation failure occurred.
The event handler thread is started.
Initial stages of shutdown.
int ring_buffer_write(ring_buffer *buffer, void *msg)
Write an element into a ring_buffer.
EVEL_ERR_CODES evel_post_event(EVENT_HEADER *event)
Post an event.
int evel_json_encode_event(char *json, int max_size, EVENT_HEADER *event)
Encode the event as a JSON event object according to AT&T's schema.
EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command)
Create a new internal event.
void ring_buffer_initialize(ring_buffer *buffer, int size)
Ring buffer initialization.
Too many events in the ring-buffer.
A cURL library operation failed.
#define EVEL_ERROR(FMT,...)
int ring_buffer_is_empty(ring_buffer *buffer)
Tests whether there is data in the ring_buffer.
EVEL_ERR_CODES
Error codes.
EVEL_ERR_CODES event_handler_initialize(const char *const event_api_url, const char *const throt_api_url, const char *const username, const char *const password, int verbosity)
Initialize the event handler.
EVEL_ERR_CODES event_handler_terminate()
Terminate the event handler.
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
Parse JSON string and fill tokens.
The library cannot handle events.
void log_error_state(char *format,...)
void jsmn_init(jsmn_parser *parser)
Creates a new parser based over a given buffer with an array of tokens available. ...
EVT_HANDLER_STATE
State of the Event Handler thread.
bool evel_handle_command_list(const MEMORY_CHUNK *const chunk, const jsmntok_t *const json_tokens, const int num_tokens, MEMORY_CHUNK *const post)
Handle a JSON response from the listener, as a list of tokens from JSMN.
size_t evel_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
Callback function to provide returned data.
EVEL_ERR_CODES event_handler_run()
Run the event handler.
EVEL throttle definitions.
EVEL internal definitions.
The ring-buffer is being depleted.
#define EVEL_MAX_JSON_BODY
#define EVEL_MAX_RESPONSE_TOKENS
Maximum number of tokens that we allow for in a JSON response.
void evel_handle_event_response(const MEMORY_CHUNK *const chunk, MEMORY_CHUNK *const post)
Handle a JSON response from the listener, contained in a MEMORY_CHUNK.