rtr_server_SOURCES += address.c address.h
rtr_server_SOURCES += array_list.h
rtr_server_SOURCES += clients.c clients.h
-rtr_server_SOURCES += common.h
+rtr_server_SOURCES += common.c common.h
rtr_server_SOURCES += configuration.c configuration.h
rtr_server_SOURCES += csv.c csv.h
rtr_server_SOURCES += line_file.c line_file.h
#include "clients.h"
#include "array_list.h"
+#include "common.h"
#define SADDR_IN(addr) ((struct sockaddr_in *)addr)
#define SADDR_IN6(addr) ((struct sockaddr_in6 *)addr)
struct clientsdb clients_db;
+/* Read and Write locks */
+sem_t rlock, wlock;
+
+/* Readers counter */
+unsigned int rcounter;
+
int
clients_db_init(void)
{
if (error)
warnx( "Clients DB couldn't be initialized");
- return error;
-}
+ sem_init(&rlock, 0, 1);
+ sem_init(&wlock, 0, 1);
+ rcounter = 0;
-static int
-clients_db_add_client(struct client *client)
-{
- return clientsdb_add(&clients_db, client);
+ return error;
}
static struct client *
{
struct client *ptr;
+ read_lock(&rlock, &wlock, &rcounter);
ARRAYLIST_FOREACH(&clients_db, ptr)
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)
+ ptr->sin_port ==
+ SADDR_IN(addr)->sin_port) {
+ read_unlock(&rlock, &wlock, &rcounter);
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)
+ SADDR_IN6(addr)->sin6_port) {
+ read_unlock(&rlock, &wlock, &rcounter);
return ptr;
+ }
}
-
+ read_unlock(&rlock, &wlock, &rcounter);
return NULL;
}
create_client(int fd, struct sockaddr_storage *addr, u_int8_t rtr_version)
{
struct client client;
+ int error;
client.fd = fd;
client.sin_family = addr->ss_family;
}
client.rtr_version = rtr_version;
- return clients_db_add_client(&client);
+ sem_wait(&wlock);
+ error = clientsdb_add(&clients_db, &client);
+ sem_post(&wlock);
+
+ return error;
}
/*
size_t
client_list(struct client **clients)
{
+ size_t len;
+
+ read_lock(&rlock, &wlock, &rcounter);
*clients = clients_db.array;
- return clients_db.len;
+ len = clients_db.len;
+ read_unlock(&rlock, &wlock, &rcounter);
+
+ return len;
}
static void
void
clients_db_destroy(void)
{
+ sem_wait(&wlock);
clientsdb_cleanup(&clients_db, client_destroy);
+ sem_post(&wlock);
+
+ sem_destroy(&wlock);
+ sem_destroy(&rlock);
}
--- /dev/null
+#include "common.h"
+
+void
+read_lock(sem_t *read, sem_t *write, unsigned int *reader_count)
+{
+ sem_wait(read);
+ (*reader_count)++;
+ if (*reader_count == 1)
+ sem_wait(write);
+ sem_post(read);
+}
+
+/*
+ * MUST NOT be called without previously called 'read_lock' or done the same
+ * things that such function does.
+ */
+void
+read_unlock(sem_t *read, sem_t *write, unsigned int *reader_count)
+{
+ sem_wait(read);
+ (*reader_count)--;
+ if (*reader_count == 0) {
+ sem_post(write);
+ }
+ sem_post(read);
+}
#ifndef _SRC_COMMON_H_
#define _SRC_COMMON_H_
-/* __BEGIN_DECLS should be used at the beginning of your declarations,
- so that C++ compilers don't mangle their names. Use __END_DECLS at
- the end of C declarations. */
-#undef __BEGIN_DECLS
-#undef __END_DECLS
-#ifdef __cplusplus
-# define __BEGIN_DECLS extern "C" {
-# define __END_DECLS }
-#else
-# define __BEGIN_DECLS /* empty */
-# define __END_DECLS /* empty */
-#endif
+#include <semaphore.h>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
* does not.
*/
+void read_lock(sem_t *, sem_t *, unsigned int *);
+void read_unlock(sem_t *, sem_t *, unsigned int *);
+
#endif /* _SRC_COMMON_H_ */