#define RTR_V0 0
#define RTR_V1 1
-#define CACHE_RESPONSE_PDU_TYPE 3
-#define IPV4_PREFIX_PDU_TYPE 4
-#define IPV6_PREFIX_PDU_TYPE 6
-#define END_OF_DATA_PDU_TYPE 7
-#define CACHE_RESET_PDU_TYPE 8
+#define PDU_TYPE_CACHE_RESPONSE 3
+#define PDU_TYPE_IPV4_PREFIX 4
+#define PDU_TYPE_IPV6_PREFIX 6
+#define PDU_TYPE_END_OF_DATA 7
+#define PDU_TYPE_CACHE_RESET 8
+#define PDU_TYPE_ERROR_REPORT 10
+
+#define ERR_CORRUPT_DATA 0
+#define ERR_INTERNAL_ERROR 1
+#define ERR_NO_DATA_AVAILABLE 2
+#define ERR_INVALID_REQUEST 3
+#define ERR_UNSUP_PROTO_VERSION 4
+#define ERR_UNSUP_PDU_TYPE 5
+#define ERR_WITHDRAWAL_UNKNOWN 6
+#define ERR_DUPLICATE_ANNOUNCE 7
+#define UNEXPECTED_PROTO_VERSION 8
struct pdu_header {
u_int8_t protocol_version;
struct error_report_pdu {
struct pdu_header header;
- void *erroneous_pdu;
+ u_int32_t error_pdu_length;
+ void *erroneous_pdu;
+ u_int32_t error_message_length;
rtr_char *error_message;
};
updates = deltas_db_status(common.start_serial);
switch (updates) {
- /* TODO Implement error */
-// case NO_DATA_AVAILABLE:
+ case NO_DATA_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.4 */
-// return send_error_pdu;
+ return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL);
case DIFF_UNDETERMINED:
/* https://tools.ietf.org/html/rfc8210#section-8.3 */
return send_cache_reset_pdu(&common);
updates = deltas_db_status(common.start_serial);
switch (updates) {
- /* TODO Implement error */
-// case NO_DATA_AVAILABLE:
+ case NO_DATA_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.4 */
-// return send_error_pdu;
+ return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL);
case DIFF_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.1 */
return send_commmon_exchange(&common);
return len;
}
+static u_int32_t
+length_error_report_pdu(struct error_report_pdu *pdu)
+{
+ return HEADER_LENGTH +
+ pdu->error_pdu_length + sizeof(pdu->error_pdu_length) +
+ pdu->error_message_length + sizeof(pdu->error_message_length);
+}
+
static int
send_response(int fd, char *data, size_t data_len)
{
size_t len;
/* This PDU has only the header */
- set_header_values(&pdu.header, common->version, CACHE_RESET_PDU_TYPE, 0);
+ set_header_values(&pdu.header, common->version, PDU_TYPE_CACHE_RESET, 0);
pdu.header.length = HEADER_LENGTH;
len = serialize_cache_reset_pdu(&pdu, data);
size_t len;
/* This PDU has only the header */
- set_header_values(&pdu.header, common->version,
- CACHE_RESPONSE_PDU_TYPE, *common->session_id);
+ set_header_values(&pdu.header, common->version, PDU_TYPE_CACHE_RESPONSE,
+ *common->session_id);
pdu.header.length = HEADER_LENGTH;
len = serialize_cache_response_pdu(&pdu, data);
char data[BUFFER_SIZE];
size_t len;
- set_header_values(&pdu.header, common->version, IPV4_PREFIX_PDU_TYPE, 0);
+ set_header_values(&pdu.header, common->version, PDU_TYPE_IPV4_PREFIX, 0);
pdu.flags = vrp->flags;
pdu.prefix_length = vrp->prefix_length;
char data[BUFFER_SIZE];
size_t len;
- set_header_values(&pdu.header, common->version, IPV6_PREFIX_PDU_TYPE, 0);
+ set_header_values(&pdu.header, common->version, PDU_TYPE_IPV6_PREFIX, 0);
pdu.flags = vrp->flags;
pdu.prefix_length = vrp->prefix_length;
char data[BUFFER_SIZE];
size_t len;
- set_header_values(&pdu.header, common->version, END_OF_DATA_PDU_TYPE, *common->session_id);
+ set_header_values(&pdu.header, common->version, PDU_TYPE_END_OF_DATA,
+ *common->session_id);
pdu.serial_number = *common->end_serial;
if (common->version == RTR_V1) {
pdu.refresh_interval = config_get_refresh_interval();
return send_response(common->fd, data, len);
}
+
+int
+send_error_report_pdu(struct sender_common *common, u_int16_t code,
+ void *err_pdu, char *message)
+{
+ struct error_report_pdu pdu;
+ char data[BUFFER_SIZE];
+ size_t len;
+
+ set_header_values(&pdu.header, common->version, PDU_TYPE_ERROR_REPORT,
+ code);
+ if (err_pdu == NULL) {
+ pdu.error_pdu_length = 0;
+ pdu.erroneous_pdu = NULL;
+ } else {
+ /* TODO Really? Or get the PDU header length field */
+ pdu.error_pdu_length = sizeof(*err_pdu);
+ pdu.erroneous_pdu = err_pdu;
+ }
+ if (message == NULL) {
+ pdu.error_message_length = 0;
+ pdu.error_message = NULL;
+ } else {
+ pdu.error_message = malloc(strlen(message) + 1);
+ if (pdu.error_message == NULL) {
+ warn("Error message couldn't be allocated, removed from PDU");
+ pdu.error_message_length = 0;
+ } else {
+ pdu.error_message_length = strlen(message) + 1;
+ strcpy(pdu.error_message, message);
+ }
+ }
+
+ /* Calculate lengths */
+ pdu.header.length = length_error_report_pdu(&pdu);
+
+ len = serialize_error_report_pdu(&pdu, data);
+ return send_response(common->fd, data, len);
+}
#include "pdu_serializer.h"
#include <stdlib.h>
+#include <string.h>
#include "primitive_writer.h"
void
size_t
serialize_error_report_pdu(struct error_report_pdu *pdu, char *buf)
{
- // FIXME Complete me!
- return 0;
+ size_t head_size;
+ char *ptr, *tmp_ptr;
+ int i;
+
+ head_size = serialize_pdu_header(&pdu->header, pdu->header.error_code, buf);
+
+ ptr = buf + head_size;
+
+ ptr = write_int32(ptr, pdu->error_pdu_length);
+ if (pdu->error_pdu_length > 0) {
+ tmp_ptr = pdu->erroneous_pdu;
+ /* TODO Set only the header of err PDU */
+ while (*tmp_ptr != '\0') {
+ ptr = write_int8(ptr, *tmp_ptr);
+ tmp_ptr++;
+ }
+ }
+
+ ptr = write_int32(ptr, pdu->error_message_length);
+ tmp_ptr = pdu->error_message;
+ for (i = 0; i < pdu->error_message_length; i++)
+ ptr = write_int8(ptr, tmp_ptr[i]);
+
+ return ptr - buf;
}