/*
* 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 .
*
* Author : Brady Johnson
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
#include
#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);
}