Use sockaddr_storage to fetch both IPv4 & 6 socket info.
Fetch the RTR version when the PDU is loaded.
Expose client data for later use (Serial Notify PDU).
rtr_server_SOURCES = main.c
rtr_server_SOURCES += address.c address.h
rtr_server_SOURCES += array_list.h
+rtr_server_SOURCES += clients.c clients.h
rtr_server_SOURCES += common.c common.h
rtr_server_SOURCES += configuration.c configuration.h
rtr_server_SOURCES += csv.c csv.h
--- /dev/null
+#include "clients.h"
+
+#include "array_list.h"
+
+#define SADDR_IN(addr) ((struct sockaddr_in *)addr)
+#define SADDR_IN6(addr) ((struct sockaddr_in6 *)addr)
+
+ARRAY_LIST(clientsdb, struct client)
+
+struct clientsdb *clients_db;
+
+int
+clients_db_init(void)
+{
+ int error;
+
+ clients_db = malloc(sizeof(struct clientsdb));
+ if (clients_db == NULL) {
+ err(-ENOMEM, "Clients DB couldn't be allocated");
+ return -ENOMEM;
+ }
+ error = clientsdb_init(clients_db);
+ if (error)
+ err(error, "Clients DB couldn't be initialized");
+
+ return error;
+}
+
+static int
+clients_db_add_client(struct client *client)
+{
+ return clientsdb_add(clients_db, client);
+}
+
+static struct client
+*get_client(struct sockaddr_storage *addr, u_int8_t rtr_version)
+{
+ struct client *ptr;
+
+ ARRAYLIST_FOREACH(clients_db, ptr)
+ if (ptr->rtr_version == rtr_version &&
+ 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 ptr;
+ } else if (ptr->sin_family == AF_INET6)
+ if (IN6_ARE_ADDR_EQUAL(ptr->sin6_addr.s6_addr32, SADDR_IN6(addr)->sin6_addr.s6_addr32) &&
+ ptr->sin_port == SADDR_IN6(addr)->sin6_port)
+ return ptr;
+ }
+
+ return NULL;
+}
+
+static int
+create_client(struct sockaddr_storage *addr, u_int8_t rtr_version,
+ time_t ttl)
+{
+ struct client *client;
+
+ client = malloc(sizeof(struct client));
+ if (client == NULL) {
+ err(-ENOMEM, "Couldn't allocate client");
+ return -ENOMEM;
+ }
+
+ client->sin_family = addr->ss_family;
+ if (addr->ss_family == AF_INET) {
+ client->sin_addr = SADDR_IN(addr)->sin_addr;
+ client->sin_port = SADDR_IN(addr)->sin_port;
+ } else if (addr->ss_family == AF_INET6) {
+ client->sin6_addr = SADDR_IN6(addr)->sin6_addr;
+ client->sin_port = SADDR_IN6(addr)->sin6_port;
+ }
+ client->rtr_version = rtr_version;
+ client->expiration = time(NULL) + ttl;
+
+ return clients_db_add_client(client);
+}
+
+int
+update_client(struct sockaddr_storage *addr, u_int8_t rtr_version,
+ time_t ttl)
+{
+ struct client *client;
+ client = get_client(addr, rtr_version);
+
+ if (client == NULL)
+ return create_client(addr, rtr_version, ttl);
+ client->expiration = time(NULL) + ttl;
+ return 0;
+}
+
+static void
+client_destroy(struct client *client)
+{
+ free(client);
+}
+
+void
+clients_db_destroy(void)
+{
+ clientsdb_cleanup(clients_db, client_destroy);
+ free(clients_db);
+}
--- /dev/null
+#ifndef SRC_CLIENTS_H_
+#define SRC_CLIENTS_H_
+
+#include <arpa/inet.h>
+#include <time.h>
+
+struct client {
+ sa_family_t sin_family;
+ union {
+ struct in_addr sin_addr;
+ struct in6_addr sin6_addr;
+ };
+ in_port_t sin_port;
+ u_int8_t rtr_version;
+ /* TODO forget clients when the expiration time is reached */
+ time_t expiration;
+};
+
+int clients_db_init(void);
+int update_client(struct sockaddr_storage *, u_int8_t, time_t);
+void clients_db_destroy(void);
+
+#endif /* SRC_CLIENTS_H_ */
#include <unistd.h>
#include "rtr/rtr.h"
+#include "clients.h"
#include "configuration.h"
#include "csv.h"
#include "updates_daemon.h"
if (err)
goto end1;
- err = csv_parse_vrps_file();
+ err = clients_db_init();
if (err)
goto end2;
+ err = csv_parse_vrps_file();
+ if (err)
+ goto end3;
+
err = updates_daemon_init();
if (err)
- goto end2;
+ goto end3;
err = rtr_listen();
+end3:
+ clients_db_destroy();
end2:
deltas_db_destroy();
end1:
static void error_report_destroy(void *);
int
-pdu_load(int fd, void **pdu, struct pdu_metadata const **metadata)
+pdu_load(int fd, void **pdu, struct pdu_metadata const **metadata,
+ u_int8_t *rtr_version)
{
struct pdu_header header;
struct pdu_metadata const *meta;
free(*pdu);
return err;
}
+ *rtr_version = header.protocol_version;
if (metadata)
*metadata = meta;
{
struct error_report_pdu *pdu = pdu_void;
u_int32_t sub_pdu_len; /* TODO use this for something */
+ u_int8_t rtr_version;
int error;
memcpy(&pdu->header, header, sizeof(*header));
if (error)
return error;
- error = pdu_load(fd, &pdu->erroneous_pdu, NULL);
+ error = pdu_load(fd, &pdu->erroneous_pdu, NULL, &rtr_version);
if (error)
return -EINVAL;
};
__BEGIN_DECLS
-int pdu_load(int, void **, struct pdu_metadata const **);
+int pdu_load(int, void **, struct pdu_metadata const **, u_int8_t *);
struct pdu_metadata const *pdu_get_metadata(u_int8_t);
struct pdu_header *pdu_get_header(void *);
__END_DECLS
#include <unistd.h>
#include <arpa/inet.h>
+#include "clients.h"
#include "configuration.h"
#include "pdu.h"
*/
struct thread_param {
int client_fd;
+ struct sockaddr_storage client_addr;
};
enum verdict {
struct pdu_metadata const *meta;
void *pdu;
int err;
+ u_int8_t rtr_version;
memcpy(¶m, param_void, sizeof(param));
free(param_void); /* Ha. */
while (true) { /* For each PDU... */
- err = pdu_load(param.client_fd, &pdu, &meta);
+ err = pdu_load(param.client_fd, &pdu, &meta, &rtr_version);
+ if (err)
+ return NULL;
+
+ /* RTR Version ready, now update client */
+ err = update_client(¶m.client_addr, rtr_version, 3600);
if (err)
return NULL;
handle_client_connections(int server_fd)
{
int client_fd;
- struct sockaddr_in client_addr;
+ struct sockaddr_storage client_addr;
socklen_t sizeof_client_addr;
struct thread_param *arg;
pthread_t thread;
continue;
}
arg->client_fd = client_fd;
+ arg->client_addr = client_addr;
/*
* FIXME Handle session IDs, serial IDs, protocol version