summaryrefslogtreecommitdiffstats
path: root/pceplib/pcep_msg_tools.c
diff options
context:
space:
mode:
Diffstat (limited to 'pceplib/pcep_msg_tools.c')
-rw-r--r--pceplib/pcep_msg_tools.c484
1 files changed, 484 insertions, 0 deletions
diff --git a/pceplib/pcep_msg_tools.c b/pceplib/pcep_msg_tools.c
new file mode 100644
index 0000000..f7c25f4
--- /dev/null
+++ b/pceplib/pcep_msg_tools.c
@@ -0,0 +1,484 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_tools.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+static const char *message_type_strs[] = {"NOT_IMPLEMENTED0",
+ "OPEN",
+ "KEEPALIVE",
+ "PCREQ",
+ "PCREP",
+ "PCNOTF",
+ "ERROR",
+ "CLOSE",
+ "NOT_IMPLEMENTED8",
+ "NOT_IMPLEMENTED9",
+ "REPORT",
+ "UPDATE",
+ "INITIATE",
+ "UNKOWN_MESSAGE_TYPE"};
+
+static const char *object_class_strs[] = {"NOT_IMPLEMENTED0",
+ "OPEN",
+ "RP",
+ "NOPATH",
+ "ENDPOINTS",
+ "BANDWIDTH",
+ "METRIC",
+ "ERO",
+ "RRO",
+ "LSPA",
+ "IRO",
+ "SVEC",
+ "NOTF",
+ "ERROR",
+ "NOT_IMPLEMENTED14",
+ "CLOSE",
+ "NOT_IMPLEMENTED16",
+ "NOT_IMPLEMENTED17",
+ "NOT_IMPLEMENTED18",
+ "NOT_IMPLEMENTED19",
+ "NOT_IMPLEMENTED20",
+ "OBJECTIVE_FUNCTION",
+ "NOT_IMPLEMENTED22",
+ "NOT_IMPLEMENTED23",
+ "NOT_IMPLEMENTED24",
+ "NOT_IMPLEMENTED25",
+ "NOT_IMPLEMENTED26",
+ "NOT_IMPLEMENTED27",
+ "NOT_IMPLEMENTED28",
+ "NOT_IMPLEMENTED29",
+ "NOT_IMPLEMENTED30",
+ "NOT_IMPLEMENTED31",
+ "LSP",
+ "SRP",
+ "VENDOR_INFO",
+ "NOT_IMPLEMENTED35",
+ "INTER_LAYER",
+ "SWITCH_LAYER",
+ "REQ_ADAP_CAP",
+ "SERVER_IND",
+ "ASSOCIATION", /* 40 */
+ "UNKNOWN_MESSAGE_TYPE"};
+
+
+double_linked_list *pcep_msg_read(int sock_fd)
+{
+ int ret;
+ uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0};
+ uint16_t buffer_read = 0;
+
+
+ ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH);
+
+ if (ret < 0) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]",
+ __func__, sock_fd, errno, strerror(errno));
+ return NULL;
+ } else if (ret == 0) {
+ pcep_log(LOG_INFO, "%s: pcep_msg_read: Remote shutdown fd [%d]",
+ __func__, sock_fd);
+ return NULL;
+ }
+
+ double_linked_list *msg_list = dll_initialize();
+ struct pcep_message *msg = NULL;
+
+ while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) {
+
+ /* Get the Message header, validate it, and return the msg
+ * length */
+ int32_t msg_length =
+ pcep_decode_validate_msg_header(buffer + buffer_read);
+ if (msg_length < 0 || msg_length > PCEP_MESSAGE_LENGTH) {
+ /* If the message header is invalid, we cant keep
+ * reading since the length may be invalid */
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Received an invalid message fd [%d]",
+ __func__, sock_fd);
+ return msg_list;
+ }
+
+ /* Check if the msg_length is longer than what was read,
+ * in which case, we need to read the rest of the message. */
+ if ((ret - buffer_read) < msg_length) {
+ int read_len = (msg_length - (ret - buffer_read));
+ int read_ret = 0;
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]",
+ __func__, read_len, sock_fd);
+
+ if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len)
+ read_ret =
+ read(sock_fd, &buffer[ret], read_len);
+ else {
+ pcep_log(
+ LOG_ERR,
+ "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)",
+ __func__, read_len, ret,
+ PCEP_MESSAGE_LENGTH);
+ return msg_list;
+ }
+
+ if (read_ret != read_len) {
+ pcep_log(
+ LOG_INFO,
+ "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
+ __func__, read_ret, read_len, sock_fd);
+ return msg_list;
+ }
+ }
+
+ msg = pcep_decode_message(buffer + buffer_read);
+ buffer_read += msg_length;
+
+ if (msg == NULL) {
+ return msg_list;
+ } else {
+ dll_append(msg_list, msg);
+ }
+ }
+
+ return msg_list;
+}
+
+struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type)
+{
+ if (msg_list == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = msg_list->head; node != NULL; node = node->next_node) {
+ if (((struct pcep_message *)node->data)->msg_header->type
+ == type) {
+ return (struct pcep_message *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_message *pcep_msg_get_next(double_linked_list *list,
+ struct pcep_message *current,
+ uint8_t type)
+{
+ if (list == NULL || current == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = list->head; node != NULL; node = node->next_node) {
+ if (node->data == current) {
+ continue;
+ }
+
+ if (((struct pcep_message *)node->data)->msg_header->type
+ == type) {
+ return (struct pcep_message *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get(double_linked_list *list,
+ uint8_t object_class)
+{
+ if (list == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *obj_item;
+ for (obj_item = list->head; obj_item != NULL;
+ obj_item = obj_item->next_node) {
+ if (((struct pcep_object_header *)obj_item->data)->object_class
+ == object_class) {
+ return (struct pcep_object_header *)obj_item->data;
+ }
+ }
+
+ return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
+ struct pcep_object_header *current,
+ uint8_t object_class)
+{
+ if (list == NULL || current == NULL) {
+ return NULL;
+ }
+
+ if (list->head == NULL) {
+ return NULL;
+ }
+
+ double_linked_list_node *node;
+ for (node = list->head; node != NULL; node = node->next_node) {
+ if (node->data == current) {
+ continue;
+ }
+
+ if (((struct pcep_object_header *)node->data)->object_class
+ == object_class) {
+ return (struct pcep_object_header *)node->data;
+ }
+ }
+
+ return NULL;
+}
+
+void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv)
+{
+ /* Specific TLV freeing */
+ switch (tlv->type) {
+ case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+ if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv)
+ ->speaker_entity_id_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_speaker_entity_identifier *)
+ tlv)
+ ->speaker_entity_id_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+ if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+ ->pst_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_path_setup_type_capability *)
+ tlv)
+ ->pst_list,
+ PCEPLIB_MESSAGES);
+ }
+
+ if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+ ->sub_tlv_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_object_tlv_path_setup_type_capability *)
+ tlv)
+ ->sub_tlv_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, tlv);
+}
+
+void pcep_obj_free_object(struct pcep_object_header *obj)
+{
+ /* Iterate the TLVs and free each one */
+ if (obj->tlv_list != NULL) {
+ struct pcep_object_tlv_header *tlv;
+ while ((tlv = (struct pcep_object_tlv_header *)
+ dll_delete_first_node(obj->tlv_list))
+ != NULL) {
+ pcep_obj_free_tlv(tlv);
+ }
+
+ dll_destroy(obj->tlv_list);
+ }
+
+ /* Specific object freeing */
+ switch (obj->object_class) {
+ case PCEP_OBJ_CLASS_ERO:
+ case PCEP_OBJ_CLASS_IRO:
+ case PCEP_OBJ_CLASS_RRO: {
+ if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
+ double_linked_list_node *node =
+ ((struct pcep_object_ro *)obj)
+ ->sub_objects->head;
+ for (; node != NULL; node = node->next_node) {
+ struct pcep_object_ro_subobj *ro_subobj =
+ (struct pcep_object_ro_subobj *)
+ node->data;
+ if (ro_subobj->ro_subobj_type
+ == RO_SUBOBJ_TYPE_SR) {
+ if (((struct pcep_ro_subobj_sr *)
+ ro_subobj)
+ ->nai_list
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct
+ pcep_ro_subobj_sr *)
+ ro_subobj)
+ ->nai_list,
+ PCEPLIB_MESSAGES);
+ }
+ }
+ }
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_ro *)obj)->sub_objects,
+ PCEPLIB_MESSAGES);
+ }
+ } break;
+
+ case PCEP_OBJ_CLASS_SVEC:
+ if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_svec *)obj)
+ ->request_id_list,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ case PCEP_OBJ_CLASS_SWITCH_LAYER:
+ if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
+ != NULL) {
+ dll_destroy_with_data_memtype(
+ ((struct pcep_object_switch_layer *)obj)
+ ->switch_layer_rows,
+ PCEPLIB_MESSAGES);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, obj);
+}
+
+void pcep_msg_free_message(struct pcep_message *message)
+{
+ /* Iterate the objects and free each one */
+ if (message->obj_list != NULL) {
+ struct pcep_object_header *obj;
+ while ((obj = (struct pcep_object_header *)
+ dll_delete_first_node(message->obj_list))
+ != NULL) {
+ pcep_obj_free_object(obj);
+ }
+
+ dll_destroy(message->obj_list);
+ }
+
+ if (message->msg_header != NULL) {
+ pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
+ }
+
+ if (message->encoded_message != NULL) {
+ pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
+ }
+
+ pceplib_free(PCEPLIB_MESSAGES, message);
+}
+
+void pcep_msg_free_message_list(double_linked_list *list)
+{
+ /* Iterate the messages and free each one */
+ struct pcep_message *msg;
+ while ((msg = (struct pcep_message *)dll_delete_first_node(list))
+ != NULL) {
+ pcep_msg_free_message(msg);
+ }
+
+ dll_destroy(list);
+}
+
+const char *get_message_type_str(uint8_t type)
+{
+ uint8_t msg_type =
+ (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
+
+ return message_type_strs[msg_type];
+}
+
+const char *get_object_class_str(uint8_t class)
+{
+ uint8_t object_class =
+ (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
+
+ return object_class_strs[object_class];
+}
+
+/* Expecting a list of struct pcep_message pointers */
+void pcep_msg_print(double_linked_list *msg_list)
+{
+ double_linked_list_node *node;
+ for (node = msg_list->head; node != NULL; node = node->next_node) {
+ struct pcep_message *msg = (struct pcep_message *)node->data;
+ pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
+ get_message_type_str(msg->msg_header->type));
+
+ double_linked_list_node *obj_node =
+ (msg->obj_list == NULL ? NULL : msg->obj_list->head);
+ for (; obj_node != NULL; obj_node = obj_node->next_node) {
+ struct pcep_object_header *obj_header =
+ ((struct pcep_object_header *)obj_node->data);
+ pcep_log(
+ LOG_INFO, "%s: PCEP_OBJ %s", __func__,
+ get_object_class_str(obj_header->object_class));
+ }
+ }
+}
+
+int pcep_msg_send(int sock_fd, struct pcep_message *msg)
+{
+ if (msg == NULL) {
+ return 0;
+ }
+ int msg_length = ntohs(msg->encoded_message_length);
+ if (msg_length > PCEP_MESSAGE_LENGTH) {
+ pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ",
+ __func__, msg_length, PCEP_MESSAGE_LENGTH);
+ return 0;
+ }
+
+ return write(sock_fd, msg->encoded_message, msg_length);
+}