| /************************************************************************* |
| * |
| * Copyright 2019 highstreet technologies GmbH and others |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| ***************************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <signal.h> |
| #include <inttypes.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <time.h> |
| #include <math.h> |
| #include <sys/time.h> |
| |
| #include <pthread.h> |
| |
| #include "heartbeat.h" |
| #include "sysrepo.h" |
| #include "sysrepo/values.h" |
| |
| #include "utils.h" |
| |
| #define LINE_BUFSIZE 128 |
| #define SLEEP_BEFORE_PNF_AUTOREG 60 |
| |
| volatile int exit_application = 0; |
| |
| pthread_mutex_t lock; |
| |
| static CURL *curl; |
| |
| int _init_curl() |
| { |
| curl = curl_easy_init(); |
| |
| if (curl == NULL) { |
| printf("cURL initialization error! Aborting call!\n"); |
| return SR_ERR_OPERATION_FAILED; |
| } |
| |
| return SR_ERR_OK; |
| } |
| |
| int cleanup_curl() |
| { |
| if (curl != NULL) |
| { |
| curl_easy_cleanup(curl); |
| } |
| |
| return SR_ERR_OK; |
| } |
| |
| //static void prepare_ves_message_curl(void) |
| //{ |
| // curl_easy_reset(curl); |
| // set_curl_common_info(); |
| // |
| // char *ves_ip = getVesIpFromConfigJson(); |
| // int ves_port = getVesPortFromConfigJson(); |
| // |
| // char url[100]; |
| // sprintf(url, "http://%s:%d/eventListener/v7", ves_ip, ves_port); |
| // curl_easy_setopt(curl, CURLOPT_URL, url); |
| // |
| // free(ves_ip); |
| // |
| //// curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); |
| // |
| // return; |
| //} |
| /* |
| * Heartbeat payload example |
| * |
| * { |
| "event": { |
| "commonEventHeader": { |
| "domain": "heartbeat", |
| "eventId": "parallels-Parallels-Virtual-Platform_2019-10-24T10:25:25.514Z", |
| "eventName": "heartbeat_Controller", |
| "eventType": "Controller", |
| "sequence": 0, |
| "priority": "Low", |
| "reportingEntityId": "", |
| "reportingEntityName": "parallels-Parallels-Virtual-Platform", |
| "sourceId": "", |
| "sourceName": "parallels-Parallels-Virtual-Platform", |
| "startEpochMicrosec": 1571912725514, |
| "lastEpochMicrosec": 1571912725514, |
| "nfNamingCode": "sdn controller", |
| "nfVendorName": "sdn", |
| "timeZoneOffset": "+00:00", |
| "version": "4.0.1", |
| "vesEventListenerVersion":"7.0.1" |
| }, |
| "heartbeatFields": { |
| "heartbeatFieldsVersion": "3.0", |
| "heartbeatInterval": 20, |
| "additionalFields": { |
| "eventTime": "2019-10-24T10:25:25.514Z" |
| } |
| } |
| } |
| } |
| * |
| * */ |
| |
| static int send_heartbeat(int heartbeat_interval) |
| { |
| CURLcode res; |
| static int sequence_number = 0; |
| |
| prepare_ves_message_curl(curl); |
| |
| cJSON *postDataJson = cJSON_CreateObject(); |
| |
| cJSON *event = cJSON_CreateObject(); |
| if (event == NULL) |
| { |
| printf("Could not create JSON object: event\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(postDataJson, "event", event); |
| |
| char hostname[100]; |
| sprintf(hostname, "%s", getenv("HOSTNAME")); |
| |
| cJSON *commonEventHeader = vesCreateCommonEventHeader("heartbeat", "Controller", hostname, sequence_number++); |
| if (commonEventHeader == NULL) |
| { |
| printf("Could not create JSON object: commonEventHeader\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(event, "commonEventHeader", commonEventHeader); |
| |
| cJSON *heartbeatFields = vesCreateHeartbeatFields(heartbeat_interval); |
| if (heartbeatFields == NULL) |
| { |
| printf("Could not create JSON object: heartbeatFields\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(event, "heartbeatFields", heartbeatFields); |
| |
| char *post_data_string = NULL; |
| |
| post_data_string = cJSON_PrintUnformatted(postDataJson); |
| |
| printf("Post data JSON:\n%s\n", post_data_string); |
| |
| if (postDataJson != NULL) |
| { |
| cJSON_Delete(postDataJson); |
| } |
| |
| curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string); |
| |
| res = curl_easy_perform(curl); |
| |
| if (res != CURLE_OK) |
| { |
| printf("Failed to send cURL...\n"); |
| return SR_ERR_OPERATION_FAILED; |
| } |
| |
| return SR_ERR_OK; |
| } |
| |
| static void |
| sigint_handler(int signum) |
| { |
| exit_application = 1; |
| } |
| |
| static int send_pnf_registration_instance(char *hostname, int port, bool is_tls) |
| { |
| CURLcode res; |
| static int sequence_number = 0; |
| |
| prepare_ves_message_curl(curl); |
| |
| cJSON *postDataJson = cJSON_CreateObject(); |
| |
| cJSON *event = cJSON_CreateObject(); |
| if (event == NULL) |
| { |
| printf("Could not create JSON object: event\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(postDataJson, "event", event); |
| |
| char source_name[100]; |
| sprintf(source_name, "%s_%d", hostname, port); |
| |
| cJSON *commonEventHeader = vesCreateCommonEventHeader("pnfRegistration", "EventType5G", source_name, sequence_number++); |
| if (commonEventHeader == NULL) |
| { |
| printf("Could not create JSON object: commonEventHeader\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(event, "commonEventHeader", commonEventHeader); |
| |
| cJSON *pnfRegistrationFields = vesCreatePnfRegistrationFields(port, is_tls); |
| if (pnfRegistrationFields == NULL) |
| { |
| printf("Could not create JSON object: pnfRegistrationFields\n"); |
| return 1; |
| } |
| cJSON_AddItemToObject(event, "pnfRegistrationFields", pnfRegistrationFields); |
| |
| char *post_data_string = NULL; |
| |
| post_data_string = cJSON_PrintUnformatted(postDataJson); |
| |
| printf("Post data JSON:\n%s\n", post_data_string); |
| |
| if (postDataJson != NULL) |
| { |
| cJSON_Delete(postDataJson); |
| } |
| |
| curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data_string); |
| |
| res = curl_easy_perform(curl); |
| |
| if (res != CURLE_OK) |
| { |
| printf("Failed to send cURL...\n"); |
| return SR_ERR_OPERATION_FAILED; |
| } |
| |
| return SR_ERR_OK; |
| } |
| |
| static void pnf_registration(void) |
| { |
| // delay the PNF Registration VES message, until anything else is initialized |
| printf("delay the PNF Registration VES message, until anything else is initialized"); |
| sleep(SLEEP_BEFORE_PNF_AUTOREG); |
| |
| int is_reg = getVesRegistrationFromConfigJson(); |
| |
| if (!is_reg) |
| { |
| //ves-registration object is set to False, we do not make an automatic PNF registration |
| printf("ves-registration object is set to False, we do not make an automatic PNF registration"); |
| return; |
| } |
| |
| int rc = SR_ERR_OK, netconf_port_base = 0; |
| char *netconf_base_string = getenv("NETCONF_BASE"); |
| char *hostname_string = getenv("HOSTNAME"); |
| |
| if (netconf_base_string != NULL) |
| { |
| rc = sscanf(netconf_base_string, "%d", &netconf_port_base); |
| if (rc != 1) |
| { |
| printf("Could not find the NETCONF base port, aborting the PNF registration...\n"); |
| return; |
| } |
| } |
| |
| //TODO This is where we hardcoded: 7 devices will have SSH connections and 3 devices will have TLS connections |
| for (int port = 0; port < NETCONF_CONNECTIONS_PER_DEVICE - 3; ++port) |
| { |
| pthread_mutex_lock(&lock); |
| rc = send_pnf_registration_instance(hostname_string, netconf_port_base + port, FALSE); |
| if (rc != SR_ERR_OK) |
| { |
| printf("Could not send PNF Registration SSH message...\n"); |
| } |
| pthread_mutex_unlock(&lock); |
| } |
| for (int port = NETCONF_CONNECTIONS_PER_DEVICE - 3; port < NETCONF_CONNECTIONS_PER_DEVICE; ++port) |
| { |
| pthread_mutex_lock(&lock); |
| rc = send_pnf_registration_instance(hostname_string, netconf_port_base + port, TRUE); |
| pthread_mutex_unlock(&lock); |
| if (rc != SR_ERR_OK) |
| { |
| printf("Could not send PNF Registration TLS message...\n"); |
| } |
| } |
| |
| return; |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| int rc = SR_ERR_OK; |
| |
| int heartbeat_interval = 120; //seconds |
| |
| setbuf(stdout, NULL); |
| |
| if (pthread_mutex_init(&lock, NULL) != 0) |
| { |
| printf("Mutex init failed...\n"); |
| goto cleanup; |
| } |
| |
| pthread_t pnf_autoregistration_thread; |
| if(pthread_create(&pnf_autoregistration_thread, NULL, pnf_registration, NULL)) |
| { |
| fprintf(stderr, "Could not create thread for pnf auto registration\n"); |
| goto cleanup; |
| } |
| |
| rc = _init_curl(); |
| if (rc != SR_ERR_OK) |
| { |
| fprintf(stderr, "Could not initialize cURL: %s\n", sr_strerror(rc)); |
| goto cleanup; |
| } |
| |
| /* loop until ctrl-c is pressed / SIGINT is received */ |
| signal(SIGINT, sigint_handler); |
| signal(SIGTERM, sigint_handler); |
| signal(SIGPIPE, SIG_IGN); |
| |
| while (!exit_application) |
| { |
| heartbeat_interval = getVesHeartbeatPeriodFromConfigJson(); |
| |
| if (heartbeat_interval > 0) |
| { |
| pthread_mutex_lock(&lock); |
| send_heartbeat(heartbeat_interval); |
| pthread_mutex_unlock(&lock); |
| sleep(heartbeat_interval); |
| } |
| else |
| { |
| sleep(1); |
| } |
| } |
| |
| printf("Application exit requested, exiting.\n"); |
| |
| cleanup: |
| |
| rc = cleanup_curl(); |
| |
| return rc; |
| } |
| |