Send Unexpected Protocol Version when needed.
Simplify 'send_error_report_pdu' call.
Remove error codes definitions from 'pdu.h'.
Send Unsupported PDU error when such PDUs arrive to the server.
Try to close socket when a fatal Error PDU is received.
Log errno when there's an error sending a response.
return clientsdb_add(clients_db, client);
}
-static struct client
-*get_client(struct sockaddr_storage *addr, u_int8_t rtr_version)
+static struct client *
+get_client(struct sockaddr_storage *addr)
{
struct client *ptr;
ARRAYLIST_FOREACH(clients_db, ptr)
- if (ptr->rtr_version == rtr_version &&
- ptr->sin_family == addr->ss_family) {
+ if (ptr->sin_family == addr->ss_family) {
if (ptr->sin_family == AF_INET) {
if (ptr->sin_addr.s_addr == SADDR_IN(addr)->sin_addr.s_addr &&
ptr->sin_port == SADDR_IN(addr)->sin_port)
return clients_db_add_client(client);
}
+/*
+ * If the ADDR isn't already stored, store it; otherwise update its file
+ * descriptor.
+ *
+ * Return the creation/update result.
+ *
+ * Code error -EINVAL will be returned when a client exists but its RTR version
+ * isn't the same as in the DB.
+ */
int
update_client(int fd, struct sockaddr_storage *addr, u_int8_t rtr_version)
{
struct client *client;
- client = get_client(addr, rtr_version);
+ client = get_client(addr);
if (client == NULL)
return create_client(fd, addr, rtr_version);
+
+ /* TODO Isn't ready to handle distinct version on clients reconnection */
+ if (client->rtr_version != rtr_version)
+ return -EINVAL;
+
client->fd = fd;
return 0;
}
return error;
}
- warnx("Error report received from stream. Code %d. Message %s.",
- pdu->header.error_code,
- strlen(pdu->error_message) == 0 ? "**empty**" : pdu->error_message);
return 0;
}
#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;
u_int8_t pdu_type;
#include <err.h>
#include <errno.h>
#include <stddef.h>
+#include <unistd.h>
+#include "err_pdu.h"
#include "pdu.h"
#include "pdu_sender.h"
#include "vrps.h"
-static int warn_unexpected_pdu(char *);
-
static int
-warn_unexpected_pdu(char *pdu_name)
+warn_unexpected_pdu(int fd, void *pdu, char *pdu_name)
{
- warnx("RTR servers are not expected to receive %s PDUs, but we got one anyway (Closing socket.)",
- pdu_name);
+ struct pdu_header *pdu_header = pdu;
+ warnx("Unexpected %s PDU received", pdu_name);
+ err_pdu_send(fd, pdu_header->protocol_version, ERR_PDU_UNSUP_PDU_TYPE,
+ pdu_header, "Unexpected PDU received");
return -EINVAL;
}
int
handle_serial_notify_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("Serial Notify");
+ return warn_unexpected_pdu(fd, pdu, "Serial Notify");
}
static int
version = received->header.protocol_version;
session_id = current_session_id(version);
if (received->header.session_id != session_id)
- return send_error_report_pdu(&common, ERR_CORRUPT_DATA, NULL, NULL);
+ return err_pdu_send(fd, version, ERR_PDU_CORRUPT_DATA, NULL, NULL);
current_serial = last_serial_number();
init_sender_common(&common, fd, version, &session_id,
switch (updates) {
case NO_DATA_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.4 */
- return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL);
+ return err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE, NULL,
+ NULL);
case DIFF_UNDETERMINED:
/* https://tools.ietf.org/html/rfc8210#section-8.3 */
return send_cache_reset_pdu(&common);
switch (updates) {
case NO_DATA_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.4 */
- return send_error_report_pdu(&common, ERR_NO_DATA_AVAILABLE, NULL, NULL);
+ return err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE, NULL,
+ NULL);
case DIFF_AVAILABLE:
/* https://tools.ietf.org/html/rfc8210#section-8.1 */
return send_commmon_exchange(&common);
int
handle_cache_response_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("Cache Response");
+ return warn_unexpected_pdu(fd, pdu, "Cache Response");
}
int
handle_ipv4_prefix_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("IPv4 Prefix");
+ return warn_unexpected_pdu(fd, pdu, "IPv4 Prefix");
}
int
handle_ipv6_prefix_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("IPv6 Prefix");
+ return warn_unexpected_pdu(fd, pdu, "IPv6 Prefix");
}
int
handle_end_of_data_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("End of Data");
+ return warn_unexpected_pdu(fd, pdu, "End of Data");
}
int
handle_cache_reset_pdu(int fd, void *pdu)
{
- return warn_unexpected_pdu("Cache Reset");
+ return warn_unexpected_pdu(fd, pdu, "Cache Reset");
}
int
handle_error_report_pdu(int fd, void *pdu)
{
struct error_report_pdu *received = pdu;
- struct sender_common common;
- init_sender_common(&common, fd, received->header.protocol_version,
- NULL, NULL, NULL);
+ if (err_pdu_is_fatal(received->header.error_code)) {
+ warnx("Fatal error report PDU received, closing socket.");
+ close(fd);
+ }
+ err_pdu_log(received->header.error_code, received->error_message);
- /* TODO complete handler */
return 0;
}
error = write(fd, buffer.data, buffer.len);
free_buffer(&buffer);
if (error < 0) {
- err(error, "Error sending response");
- /*
- * TODO Send error PDU here depending on error type?
- */
+ err(errno, "Error sending response");
return error;
}
}
int
-send_error_report_pdu(struct sender_common *common, u_int16_t code,
- struct pdu_header *err_pdu_header, char *message)
+send_error_report_pdu(int fd, u_int8_t version, u_int16_t code,
+struct pdu_header *err_pdu_header, 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,
+ set_header_values(&pdu.header, version, PDU_TYPE_ERROR_REPORT,
code);
pdu.error_pdu_length = 0;
len = serialize_error_report_pdu(&pdu, data);
free(pdu.error_message);
- return send_response(common->fd, data, len);
+ return send_response(fd, data, len);
}
int send_cache_response_pdu(struct sender_common *);
int send_payload_pdus(struct sender_common *);
int send_end_of_data_pdu(struct sender_common *);
-int send_error_report_pdu(struct sender_common *, u_int16_t,
- struct pdu_header *, char *);
+int send_error_report_pdu(int, u_int8_t, u_int16_t, struct pdu_header *,
+ char *);
#endif /* SRC_RTR_PDU_SENDER_H_ */
#include "clients.h"
#include "configuration.h"
+#include "err_pdu.h"
#include "pdu.h"
/*
if (err)
return NULL;
+ /* Protocol Version Negotiation isn't necessary (for now) */
/* RTR Version ready, now update client */
err = update_client(param.client_fd, ¶m.client_addr, rtr_version);
- if (err)
+ if (err) {
+ if (err == -EINVAL) {
+ err_pdu_send(param.client_fd, rtr_version,
+ ERR_PDU_UNEXPECTED_PROTO_VERSION,
+ (struct pdu_header *) pdu, NULL);
+ }
return NULL;
+ }
err = meta->handle(param.client_fd, pdu);
meta->destructor(pdu);