summaryrefslogtreecommitdiff
path: root/src/analysis/db/cdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r--src/analysis/db/cdb.c822
1 files changed, 646 insertions, 176 deletions
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 9e24f84..6d4b84d 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * cdb.h - prototypes pour la manipulation des archives au format CDB
+ * cdb.c - manipulation des archives au format CDB
*
* Copyright (C) 2014-2019 Cyrille Bagard
*
@@ -26,10 +26,10 @@
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <pthread.h>
-#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,16 +38,20 @@
#include <sys/stat.h>
-#include <i18n.h>
#include <config.h>
+#include <i18n.h>
+#include "backend-int.h"
#include "collection.h"
#include "protocol.h"
#include "snapshot.h"
+#include "../content.h"
+#include "../storage/storage.h"
#include "../../common/compression.h"
#include "../../common/cpp.h"
#include "../../common/extstr.h"
+#include "../../common/io.h"
#include "../../common/pathname.h"
#include "../../common/xml.h"
#include "../../core/collections.h"
@@ -55,51 +59,70 @@
-/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+/* -------------------------- LIEN VERS UN CLIENT CONNECTE -------------------------- */
/* Informations relatives à un client */
typedef struct _cdb_client
{
- SSL *ssl_fd; /* Canal de communication */
+ SSL *tls_fd; /* Canal de communication */
+ char *peer_name; /* Désignation du correspondant*/
char *user; /* Utilisateur à l'autre bout */
- uint64_t last_time; /* Date de dernier envoi */
+ gint ref_count; /* Décompte d'utilisation */
} cdb_client;
+/* Met en place le suivi d'une connexion de client. */
+static cdb_client *create_cdb_client(SSL *, const char *, const char *);
+
+/* Supprime le suivi d'une connexion de client. */
+static void delete_cdb_client(cdb_client *);
+
+/* Augmente le décompte d'utilisation d'un suivi de connexion. */
+static void ref_cdb_client(cdb_client *);
+
+/* Diminue le décompte d'utilisation d'un suivi de connexion. */
+static void unref_cdb_client(cdb_client *);
+
+
+
+/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+
+
/* Description d'une archive d'éléments utilisateur (instance) */
struct _GCdbArchive
{
- GObject parent; /* A laisser en premier */
+ GServerBackend parent; /* A laisser en premier */
rle_string hash; /* Empreinte cryptographique */
+ rle_string class; /* Nature du contenu analysé */
char *filename; /* Chemin d'accès à l'archive */
char *tmpdir; /* Répertoire de travail */
char *xml_desc; /* Fichier de description */
+ char *cnt_file; /* Fichier de contenu binaire */
+
+ GMutex loading_access; /* Verrou pour l'accès */
+
+
GList *collections; /* Ensemble de modifications */
GDbSnapshot *snapshot; /* Instantanés de bases SQL */
sqlite3 *db; /* Base de données à manipuler */
- cdb_client *clients; /* Connexions en place */
+ cdb_client **clients; /* Connexions en place */
size_t count; /* Quantité de clients */
GMutex clients_access; /* Verrou pour l'accès */
- GThread *process; /* Procédure de traitement */
- GMutex id_access; /* Accès à l'identifiant */
- GCond id_cond; /* Condition d'attente */
- pthread_t process_id; /* Identifiant de la procédure */
-
};
/* Description d'une archive d'éléments utilisateur (classe) */
struct _GCdbArchiveClass
{
- GObjectClass parent; /* A laisser en premier */
+ GServerBackendClass parent; /* A laisser en premier */
};
@@ -147,20 +170,135 @@ static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *);
/* Assure le traitement des requêtes de clients. */
static void *g_cdb_archive_process(GCdbArchive *);
+/* Prend en compte une connexion nouvelle d'un utilisateur. */
+static void g_cdb_archive_add_client(GCdbArchive *, SSL *, const char *, const char *);
+
+/* Dissocie un utilisateur de l'archive. */
+static void _g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
+/* Dissocie un utilisateur de l'archive. */
+static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
/* Envoie un paquet de données constitué à tous les clients. */
-static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer *);
+static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *, packed_buffer_t *);
/* Envoie à tous les clients la nouvelle liste d'instantanés. */
-static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer *);
+static bool g_cdb_archive_send_snapshot_update(GCdbArchive *, packed_buffer_t *);
/* Envoie à tous les clients le nouvel instantané courant. */
-static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer *);
+static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer_t *);
-/* Dissocie un utilisateur de l'archive. */
-static void _g_cdb_archive_remove_client(GCdbArchive *, size_t);
-/* Dissocie un utilisateur de l'archive. */
-static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
+
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+/* Prépare une courte réponse à envoyer à un client connecté. */
+static bool craft_server_short_answer(DBCommand, uleb128_t, packed_buffer_t *);
+
+/* Enregistre le contenu binaire lié à une analyse. */
+static bool g_cdb_archive_set_content(GCdbArchive *, packed_buffer_t *, packed_buffer_t *);
+
+
+
+/* -------------------------- LIEN VERS UN CLIENT CONNECTE -------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Met en place le suivi d'une connexion de client. *
+* *
+* Retour : Structure dédiée construite. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static cdb_client *create_cdb_client(SSL *fd, const char *peer_name, const char *user)
+{
+ cdb_client *result; /* Fiche d'entité à retourner */
+
+ result = malloc(sizeof(cdb_client));
+
+ result->tls_fd = fd;
+
+ result->peer_name = strdup(peer_name);
+ result->user = strdup(user);
+
+ g_atomic_int_set(&result->ref_count, 1);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Supprime le suivi d'une connexion de client. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_cdb_client(cdb_client *client)
+{
+ assert(g_atomic_int_get(&client->ref_count) == 0);
+
+ SSL_free(client->tls_fd);
+
+ free(client->peer_name);
+ free(client->user);
+
+ free(client);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Augmente le décompte d'utilisation d'un suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void ref_cdb_client(cdb_client *client)
+{
+ g_atomic_int_inc(&client->ref_count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = informations de suivi à libérer de la mémoire. *
+* *
+* Description : Diminue le décompte d'utilisation d'un suivi de connexion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void unref_cdb_client(cdb_client *client)
+{
+ if (g_atomic_int_dec_and_test(&client->ref_count))
+ delete_cdb_client(client);
+
+}
@@ -170,7 +308,7 @@ static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
/* Indique le type défini pour une une archive d'éléments utilisateur. */
-G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_SERVER_BACKEND);
/******************************************************************************
@@ -188,12 +326,20 @@ G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT);
static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GServerBackendClass *backend; /* Classe parente */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_cdb_archive_dispose;
object->finalize = (GObjectFinalizeFunc)g_cdb_archive_finalize;
+ backend = G_SERVER_BACKEND_CLASS(klass);
+
+ backend->thread_name = "cdb_archiver";
+ backend->thread_func = (GThreadFunc)g_cdb_archive_process;
+
+ backend->add_client = (add_backend_client_fc)g_cdb_archive_add_client;
+
}
@@ -212,18 +358,22 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
static void g_cdb_archive_init(GCdbArchive *archive)
{
setup_empty_rle_string(&archive->hash);
+ setup_empty_rle_string(&archive->class);
+ archive->filename = NULL;
archive->tmpdir = NULL;
+ archive->xml_desc = NULL;
+
+ archive->cnt_file = NULL;
+ g_mutex_init(&archive->loading_access);
archive->collections = create_collections_list();
archive->snapshot = NULL;
+ archive->db = NULL;
g_mutex_init(&archive->clients_access);
- g_mutex_init(&archive->id_access);
- g_cond_init(&archive->id_cond);
-
}
@@ -241,13 +391,14 @@ static void g_cdb_archive_init(GCdbArchive *archive)
static void g_cdb_archive_dispose(GCdbArchive *archive)
{
- g_clear_object(&archive->snapshot);
-
- g_cond_clear(&archive->id_cond);
- g_mutex_clear(&archive->id_access);
+ g_server_backend_stop(G_SERVER_BACKEND(archive));
g_mutex_clear(&archive->clients_access);
+ g_clear_object(&archive->snapshot);
+
+ g_mutex_clear(&archive->loading_access);
+
G_OBJECT_CLASS(g_cdb_archive_parent_class)->dispose(G_OBJECT(archive));
}
@@ -281,14 +432,19 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
#endif
}
+ if (archive->cnt_file != NULL)
+ free(archive->cnt_file);
+
if (archive->xml_desc != NULL)
free(archive->xml_desc);
- free(archive->filename);
-
if (archive->tmpdir != NULL)
free(archive->tmpdir);
+ if (archive->filename != NULL)
+ free(archive->filename);
+
+ exit_rle_string(&archive->class);
exit_rle_string(&archive->hash);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->finalize(G_OBJECT(archive));
@@ -301,6 +457,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
* Paramètres : basedir = répertoire de stockage des enregistrements. *
* tmpdir = répertoire de travail temporaire. *
* hash = empreinte du binaire à représenter. *
+* class = nature du contenu analysé associé. *
* error = indication éventuelle en cas d'échec. [OUT] *
* *
* Description : Définit ou ouvre une archive d'éléments utilisateur. *
@@ -312,7 +469,7 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
* *
******************************************************************************/
-GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, DBError *error)
+GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rle_string *hash, const rle_string *class, DBError *error)
{
GCdbArchive *result; /* Adresse à retourner */
int ret; /* Retour d'un appel */
@@ -321,13 +478,16 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL);
dup_into_rle_string(&result->hash, get_rle_string(hash));
+ dup_into_rle_string(&result->class, get_rle_string(class));
*error = DBE_SYS_ERROR;
/* Chemin de l'archive */
result->filename = strdup(basedir);
- result->filename = stradd(result->filename, hash->data);
+ result->filename = stradd(result->filename, get_rle_string(hash));
+ result->filename = stradd(result->filename, "-");
+ result->filename = stradd(result->filename, get_rle_string(class));
result->filename = stradd(result->filename, ".cdb.tar.xz");
if (!mkpath(result->filename))
@@ -340,11 +500,8 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
if (!mkpath(tmpdir))
goto error;
- ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, get_rle_string(hash));
- if (ret == -1) goto no_tmp;
-
- ret = ensure_path_exists(result->xml_desc);
- if (ret == -1) goto no_tmp;
+ result->xml_desc = g_cdb_archive_get_tmp_filename(result, "desc.xml");
+ if (result->xml_desc == NULL) goto no_tmp;
/* Création de l'archive si elle n'existe pas */
@@ -355,7 +512,7 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
/* Le soucis ne vient pas de l'absence du fichier... */
if (errno != ENOENT) goto error;
- result->snapshot = g_db_snapshot_new_empty(tmpdir, get_rle_string(hash), result->collections);
+ result->snapshot = g_db_snapshot_new_empty(result, result->collections);
if (result->snapshot == NULL)
goto error;
@@ -426,6 +583,47 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
/******************************************************************************
* *
* Paramètres : archive = informations quant à l'archive à interpréter. *
+* suffix = fin du nom de fichier à définir. *
+* *
+* Description : Construit un chemin pour un fichier propre à l'archive. *
+* *
+* Retour : Chemin de fichier à utiliser ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_cdb_archive_get_tmp_filename(const GCdbArchive *archive, const char *suffix)
+{
+ char *result; /* Chemin à retourner */
+ int ret; /* Retour d'un appel */
+
+ ret = asprintf(&result, "%s" G_DIR_SEPARATOR_S "%s_%s",
+ archive->tmpdir, get_rle_string(&archive->hash), suffix);
+
+ if (ret == -1)
+ result = NULL;
+
+ else
+ {
+ ret = ensure_path_exists(result);
+
+ if (ret == -1)
+ {
+ free(result);
+ result = NULL;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = informations quant à l'archive à interpréter. *
* *
* Description : Ouvre une archive avec tous les éléments à conserver. *
* *
@@ -475,8 +673,7 @@ static DBError g_cdb_archive_read(GCdbArchive *archive)
goto load_error;
}
- archive->snapshot = g_db_snapshot_new_from_xml(archive->tmpdir, get_rle_string(&archive->hash),
- xdoc, context);
+ archive->snapshot = g_db_snapshot_new_from_xml(archive, xdoc, context);
close_xml_file(xdoc, context);
@@ -503,7 +700,7 @@ static DBError g_cdb_archive_read(GCdbArchive *archive)
ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */);
if (ret != ARCHIVE_OK) goto bad_archive;
- status = g_db_snapshot_fill(archive->snapshot, in);
+ status = g_db_snapshot_fill(archive->snapshot, in, archive);
if (!status) goto load_error;
result = DBE_NONE;
@@ -616,18 +813,26 @@ DBError g_cdb_archive_write(const GCdbArchive *archive)
* *
* Paramètres : archive = informations quant à l'archive à consulter. *
* hash = empreinte extérieure à comparer. *
+* class = nature du contenu analysé. *
* *
-* Description : Détermine si une empreinte correspond à celle d'une archive. *
+* Description : Détermine l'archive correspond à une cible recherchée. *
* *
-* Retour : Résultat de la comparaison : -1, 0 ou 1. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *hash)
+bool g_cdb_archive_compare_is_suitable_for(const GCdbArchive *archive, const rle_string *hash, const rle_string *class)
{
- return cmp_rle_string(&archive->hash, hash);
+ bool result; /* Bilan à retourner */
+
+ result = (cmp_rle_string(&archive->hash, hash) == 0);
+
+ if (result)
+ result = (cmp_rle_string(&archive->class, class) == 0);
+
+ return result;
}
@@ -792,7 +997,7 @@ static void g_cdb_archive_register_signals(GCdbArchive *archive)
static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArchive *archive)
{
- packed_buffer pbuf; /* Tampon d'émission */
+ packed_buffer_t pbuf; /* Tampon d'émission */
size_t i; /* Boucle de parcours */
bool status; /* Bilan d'un envoi de retour */
@@ -804,7 +1009,7 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc
for (i = 0; i < archive->count && status; i++)
{
- status = ssl_send_packed_buffer(&pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&pbuf, archive->clients[i]->tls_fd);
if (!status)
LOG_ERROR(LMT_ERROR, _("Failed to send some DB update"));
@@ -832,66 +1037,91 @@ static void on_collection_extended(GDbCollection *collec, GDbItem *item, GCdbArc
static void *g_cdb_archive_process(GCdbArchive *archive)
{
+ GServerBackend *base; /* Base de l'instance */
+ cdb_client **clients; /* Clients surveillés */
+ size_t last_count; /* Quantité de ces clients */
struct pollfd *fds; /* Surveillance des flux */
nfds_t nfds; /* Quantité de ces flux */
nfds_t i; /* Boucle de parcours */
int ret; /* Bilan d'un appel */
- packed_buffer in_pbuf; /* Tampon de réception */
+ packed_buffer_t in_pbuf; /* Tampon de réception */
uint32_t tmp32; /* Valeur sur 32 bits */
bool status; /* Bilan de lecture initiale */
uint32_t command; /* Commande de la requête */
DBError error; /* Bilan d'une opération */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
GDbCollection *collec; /* Collection visée au final */
bool reload; /* Besoin de rechargement */
char *msg; /* Erreur à faire remonter */
- void interrupt_poll_with_sigusr1(int sig) { };
+ base = G_SERVER_BACKEND(archive);
- signal(SIGUSR1, interrupt_poll_with_sigusr1);
-
- g_mutex_lock(&archive->id_access);
- archive->process_id = pthread_self();
- g_cond_signal(&archive->id_cond);
- g_mutex_unlock(&archive->id_access);
+ clients = NULL;
+ last_count = 0;
fds = NULL;
while (1)
{
+ /* Réinitialisation ? */
+
+ for (i = 0; i < last_count; i++)
+ unref_cdb_client(clients[i]);
+
/* Reconstitution d'une liste à jour */
g_mutex_lock(&archive->clients_access);
- nfds = archive->count;
+ last_count = archive->count;
+
+ clients = realloc(clients, last_count * sizeof(cdb_client));
+
+ for (i = 0; i < last_count; i++)
+ {
+ clients[i] = archive->clients[i];
+ ref_cdb_client(clients[i]);
+ }
+
+ nfds = last_count + 2;
fds = realloc(fds, nfds * sizeof(struct pollfd));
- for (i = 0; i < nfds; i++)
+ for (i = 0; i < (nfds - 2); i++)
{
- fds[i].fd = SSL_get_fd(archive->clients[i].ssl_fd);
+ fds[i].fd = SSL_get_fd(clients[i]->tls_fd);
fds[i].events = POLLIN | POLLPRI;
}
g_mutex_unlock(&archive->clients_access);
- if (nfds == 0)
+ if (nfds == 2)
goto gcap_no_more_clients;
+ fds[nfds - 2].fd = base->stop_ctrl[0];
+ fds[nfds - 2].events = POLLIN | POLLPRI;
+
+ fds[nfds - 1].fd = base->refresh_ctrl[0];
+ fds[nfds - 1].events = POLLIN | POLLPRI;
+
/* Lancement d'une phase de surveillance */
ret = poll(fds, nfds, -1);
if (ret == -1)
{
- if (errno == EINTR) continue;
-
LOG_ERROR_N("poll");
break;
-
}
+ /* Demande expresse d'arrêt des procédures */
+ if (fds[nfds - 2].revents)
+ break;
+
+ /* Demande d'actualisation */
+ if (fds[nfds - 1].revents)
+ continue;
+
/* Traitement des requêtes reçues */
- for (i = 0; i < nfds; i++)
+ for (i = 0; i < (nfds - 1); i++)
{
/* Le canal est fermé, une sortie doit être demandée... */
if (fds[i].revents & POLLNVAL)
@@ -910,7 +1140,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
{
init_packed_buffer(&in_pbuf);
- status = ssl_recv_packed_buffer(&in_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_recv_packed_buffer(&in_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_exchange;
next_command:
@@ -920,13 +1150,21 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
command = tmp32;
+ init_packed_buffer(&out_pbuf);
+
switch (command)
{
+ case DBC_SET_CONTENT:
+ status = g_cdb_archive_set_content(archive, &in_pbuf, &out_pbuf);
+ break;
+
+
+
case DBC_SAVE:
error = g_cdb_archive_write(archive);
- init_packed_buffer(&out_pbuf);
+ //init_packed_buffer(&out_pbuf);
status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE },
sizeof(uint32_t), true);
@@ -935,7 +1173,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -976,10 +1214,10 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
status = extend_packed_buffer(&out_pbuf, (uint8_t []) { 0x0 }, sizeof(uint8_t), true);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
- exit_packed_buffer(&out_pbuf);
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -998,7 +1236,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
&in_pbuf, &out_pbuf, archive->db);
if (!status) goto gcap_bad_reply;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
if (!status) goto gcap_bad_reply;
exit_packed_buffer(&out_pbuf);
@@ -1010,10 +1248,12 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
if (!g_cdb_archive_send_snapshot_update(archive, &out_pbuf))
goto critical_error;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ status = true;
- exit_packed_buffer(&out_pbuf);
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
+
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -1022,10 +1262,10 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
if (!g_cdb_archive_send_snapshot_change(archive, &out_pbuf))
goto critical_error;
- status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
- if (!status) goto gcap_bad_reply;
+ //status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ //if (!status) goto gcap_bad_reply;
- exit_packed_buffer(&out_pbuf);
+ //exit_packed_buffer(&out_pbuf);
break;
@@ -1100,7 +1340,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
case DBC_CREATE_SNAPSHOT:
- error = g_db_snapshot_create(archive->snapshot, archive->db);
+ error = g_db_snapshot_create(archive->snapshot, archive->db, archive);
if (error == DBE_NONE)
{
@@ -1144,6 +1384,17 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
}
+ if (!status)
+ goto gcap_bad_reply;
+
+ if (get_packed_buffer_payload_length(&out_pbuf) > 0)
+ {
+ status = ssl_send_packed_buffer(&out_pbuf, clients[i]->tls_fd);
+ if (!status) goto gcap_bad_reply;
+ }
+
+ exit_packed_buffer(&out_pbuf);
+
if (has_more_data_in_packed_buffer(&in_pbuf))
goto next_command;
@@ -1185,12 +1436,13 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
gcap_no_more_clients:
- archive->process = NULL;
+ g_server_backend_stop(G_SERVER_BACKEND(archive));
+
+ for (i = 0; i < last_count; i++)
+ unref_cdb_client(clients[i]);
- g_mutex_lock(&archive->id_access);
- archive->process_id = 0;
- g_cond_signal(&archive->id_cond);
- g_mutex_unlock(&archive->id_access);
+ if (clients != NULL)
+ free(clients);
if (fds != NULL)
free(fds);
@@ -1202,6 +1454,170 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
/******************************************************************************
* *
+* Paramètres : archive = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static LoadingStatusHint g_cdb_archive_compute_loading_hint(GCdbArchive *archive)
+{
+ LoadingStatusHint result; /* Statut à retourner */
+
+
+ // Try
+ // g_mutex_lock(&archive->loading_access);
+
+
+
+ // cnt_file
+
+ if (archive->cnt_file == NULL)
+ result = LSH_NEED_CONTENT;
+
+ else
+ result = LSH_NEED_FORMAT;
+
+
+
+
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = support pour le suivi d'une connexion. *
+* fd = canal de communication réseau ouvert. *
+* peer_name = désignation de la connexion. *
+* user = désignation de l'utilisateur de la connexion. *
+* *
+* Description : Prend en compte une connexion nouvelle d'un utilisateur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const char *peer_name, const char *user)
+{
+ cdb_client *client; /* Nouvelle fiche d'entité */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
+ LoadingStatusHint hint; /* Statut de chargement */
+ bool status; /* Bilan de lecture initiale */
+
+ client = create_cdb_client(fd, peer_name, user);
+
+ /**
+ * Le verrou encadrant les évolutions des contenus initiaux doit englober
+ * l'extension de la liste des clients.
+ *
+ * En effet, une évolution partielle peut intervenir dans la fonction
+ * g_cdb_archive_process(), à un moment au seul le verrou dans les
+ * évolutions sera posé (g_cdb_archive_set_content() par exemple).
+ *
+ * Or g_cdb_archive_compute_loading_hint() doit fournir ici un état qui ne
+ * varie pas entre le calcul et l'envoi. Donc verrous sur les clients et
+ * l'état de l'archive doivent englover l'ensemble des traitements ci-après.
+ */
+
+ g_mutex_lock(&archive->loading_access);
+
+ g_mutex_lock(&archive->clients_access);
+
+ hint = g_cdb_archive_compute_loading_hint(archive);
+
+ if (hint != LSH_READY)
+ hint = (archive->count == 0 ? hint : LSH_ON_WAIT_LIST);
+
+ init_packed_buffer(&out_pbuf);
+
+ status = craft_server_short_answer(DBC_LOADING_STATUS, hint, &out_pbuf);
+
+ if (status)
+ status = ssl_send_packed_buffer(&out_pbuf, fd);
+
+ exit_packed_buffer(&out_pbuf);
+
+ if (status)
+ {
+ archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client *));
+
+ archive->clients[archive->count - 1] = client;
+
+ }
+
+ g_mutex_unlock(&archive->clients_access);
+
+ g_mutex_unlock(&archive->loading_access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* index = indice de l'utilisateur concerné. *
+* *
+* Description : Dissocie un utilisateur de l'archive. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
+{
+ assert(!g_mutex_trylock(&archive->clients_access));
+
+ unref_cdb_client(archive->clients[index]);
+
+ if ((index + 1) < archive->count)
+ memmove(&archive->clients[index], &archive->clients[index + 1],
+ (archive->count - index - 1) * sizeof(cdb_client *));
+
+ archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client *));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* index = indice de l'utilisateur concerné. *
+* *
+* Description : Dissocie un utilisateur de l'archive. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
+{
+ g_mutex_lock(&archive->clients_access);
+
+ _g_cdb_archive_remove_client(archive, index);
+
+ g_mutex_unlock(&archive->clients_access);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : archive = archive à connecter avec un utilisateur. *
* pbuf = paquet de données à émettre. *
* *
@@ -1213,7 +1629,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
******************************************************************************/
-static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed_buffer *pbuf)
+static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed_buffer_t *pbuf)
{
size_t i; /* Boucle de parcours */
bool status; /* Bilan d'une émission */
@@ -1222,7 +1638,7 @@ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed
for (i = 0; i < archive->count; i++)
{
- status = ssl_send_packed_buffer(pbuf, archive->clients[i].ssl_fd);
+ status = ssl_send_packed_buffer(pbuf, archive->clients[i]->tls_fd);
if (!status)
{
log_variadic_message(LMT_ERROR, _("Error while replying to client %zu"), i);
@@ -1252,11 +1668,11 @@ static void g_cdb_archive_send_reply_to_all_clients(GCdbArchive *archive, packed
* *
******************************************************************************/
-static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buffer *pbuf)
+static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
bool do_send; /* Réalisation de l'émission */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
do_send = (pbuf == NULL);
@@ -1301,11 +1717,11 @@ static bool g_cdb_archive_send_snapshot_update(GCdbArchive *archive, packed_buff
* *
******************************************************************************/
-static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buffer *pbuf)
+static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
bool do_send; /* Réalisation de l'émission */
- packed_buffer out_pbuf; /* Tampon d'émission */
+ packed_buffer_t out_pbuf; /* Tampon d'émission */
snapshot_id_t id; /* Identifiant d'instantané */
do_send = (pbuf == NULL);
@@ -1339,132 +1755,186 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff
}
+
+/* ---------------------------------------------------------------------------------- */
+/* PRISES EN COMPTE DES COMMANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* fd = canal de communication réseau ouvert. *
+* Paramètres : cmd = commande à l'origine d'un traitement. *
+* value = valeur à communiquer. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
* *
-* Description : Associe un nouvel utilisateur à l'archive. *
+* Description : Prépare une courte réponse à envoyer à un client connecté. *
* *
-* Retour : - *
+* Retour : Indication pour le maintien de la communication. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd)
+static bool craft_server_short_answer(DBCommand cmd, uleb128_t value, packed_buffer_t *out_pbuf)
{
- X509 *peer_cert; /* Certificat présenté */
- volatile pthread_t *process_id; /* Identifiant de la procédure */
+ bool result; /* Bilan à retourner */
- /**
- * La situation est un peu compliquée lors de l'accueil d'un nouveau client :
- *
- * - soit on envoie tous les éléments à prendre en compte, mais on doit
- * bloquer la base de données jusqu'à l'intégration pleine et entière
- * du client, afin que ce dernier ne loupe pas l'envoi d'un nouvel
- * élément entre temps.
- *
- * - soit on intègre le client et celui ci demande des mises à jour
- * collection par collection ; c'est également à lui qui revient le rejet
- * des éléments envoyés en solitaires avant la réception de la base
- * complète.
- *
- * On fait le choix du second scenario ici, du fait de la difficulté
- * de maîtriser facilement la reconstitution d'une liste de clients dans
- * g_cdb_archive_process() depuis un autre flot d'exécution.
- */
+ init_packed_buffer(out_pbuf);
- /* Ajout dans la liste officielle */
+ result = extend_packed_buffer(out_pbuf, (uint32_t []) { cmd }, sizeof(uint32_t), true);
- g_mutex_lock(&archive->clients_access);
+ if (result)
+ result = pack_uleb128((uleb128_t []){ value }, out_pbuf);
- archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client));
+ return result;
- archive->clients[archive->count - 1].ssl_fd = fd;
+}
- peer_cert = SSL_get_peer_certificate(fd);
- archive->clients[archive->count - 1].user = X509_NAME_oneline(X509_get_subject_name(peer_cert), NULL, -1);
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* in_pbuf = paquet à consulter. *
+* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
+* *
+* Description : Enregistre le contenu binaire lié à une analyse. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- X509_free(peer_cert);
+static bool g_cdb_archive_set_content(GCdbArchive *archive, packed_buffer_t *in_pbuf, packed_buffer_t *out_pbuf)
+{
+ bool result; /* Bilan à retourner */
+ DBError error; /* Bilan d'une opération */
+ uleb128_t data_length; /* Taille du contenu stocké */
+ void *data; /* Données du stockage */
+ packed_buffer_t test_pbuf; /* Copie des données pour test */
+ uleb128_t pos; /* Position du contenu */
+ GObjectStorage *storage; /* Gestionnaire de stockage */
+ GSerializableObject *content; /* Contenu restitué */
+ const gchar *hash; /* Empreinte de ce contenu */
+ int fd; /* Flux ouvert en écriture */
+ bool status; /* Bilan d'une écriture */
+ LoadingStatusHint hint; /* Statut de chargement */
- /* Démarrage ou redémarrage du processus d'écoute */
+ result = true;
+ error = DBE_NONE;
- if (archive->process == NULL)
- {
- archive->process = g_thread_new("cdb_process", (GThreadFunc)g_cdb_archive_process, archive);
+ /* Récupération de la charge utile */
+
+ result = unpack_uleb128(&data_length, in_pbuf);
+ if (!result) goto exit;
+
+ data = malloc(data_length);
+
+ result = extract_packed_buffer(in_pbuf, data, data_length, false);
+ if (!result) goto free_and_exit;
+
+ /* Validation de l'empreinte du contenu */
+
+ init_packed_buffer(&test_pbuf);
- /* On attend que le processus parallèle soit prêt */
+ result = extend_packed_buffer(&test_pbuf, data, data_length, false);
+ if (!result) goto check_failure;
- process_id = &archive->process_id;
+ rewind_packed_buffer(&test_pbuf);
- g_mutex_lock(&archive->id_access);
- while (process_id == 0)
- g_cond_wait(&archive->id_cond, &archive->id_access);
- g_mutex_unlock(&archive->id_access);
+ result = unpack_uleb128(&pos, &test_pbuf);
+ if (!result) goto check_failure;
+ storage = g_object_storage_load(&test_pbuf);
+ if (storage == NULL)
+ {
+ result = false;
+ goto check_failure;
}
- else
- pthread_kill(archive->process_id, SIGUSR1);
- g_mutex_unlock(&archive->clients_access);
+ content = g_object_storage_load_object(storage, "contents", pos);
+ if (!G_IS_BIN_CONTENT(content))
+ {
+ result = false;
+ goto storage_check_failure;
+ }
-}
+ hash = g_binary_content_get_checksum(G_BIN_CONTENT(content));
+ if (strcmp(hash, get_rle_string(&archive->hash)) != 0)
+ error = DBE_WRONG_HASH;
-/******************************************************************************
-* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* index = indice de l'utilisateur concerné. *
-* *
-* Description : Dissocie un utilisateur de l'archive. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ g_object_unref(G_OBJECT(content));
-static void _g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
-{
- cdb_client *client; /* Client à traiter */
+ storage_check_failure:
- assert(!g_mutex_trylock(&archive->clients_access));
+ g_object_unref(G_OBJECT(storage));
- client = &archive->clients[index];
+ check_failure:
- SSL_free(client->ssl_fd);
- free(client->user);
+ exit_packed_buffer(&test_pbuf);
- if ((index + 1) < archive->count)
- memmove(&archive->clients[index], &archive->clients[index + 1],
- (archive->count - index - 1) * sizeof(cdb_client));
+ if (!result) goto free_and_exit;
- archive->clients = realloc(archive->clients, --archive->count * sizeof(cdb_client));
+ /* Enregistrement sur disque */
-}
+ if (error == DBE_NONE)
+ {
+ if (archive->cnt_file != NULL)
+ free(archive->cnt_file);
+ archive->cnt_file = g_cdb_archive_get_tmp_filename(archive, "storedcontent.bin");
+ if (archive->cnt_file == NULL)
+ {
+ error = DBE_SYS_ERROR;
+ goto save_error;
+ }
-/******************************************************************************
-* *
-* Paramètres : archive = archive à connecter avec un utilisateur. *
-* index = indice de l'utilisateur concerné. *
-* *
-* Description : Dissocie un utilisateur de l'archive. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ fd = open(archive->cnt_file, O_WRONLY | O_CREAT, 0600);
+ if (fd == -1)
+ {
+ error = DBE_SYS_ERROR;
+ goto save_error;
+ }
-static void g_cdb_archive_remove_client(GCdbArchive *archive, size_t index)
-{
- g_mutex_lock(&archive->clients_access);
+ status = safe_write(fd, data, data_length);
- _g_cdb_archive_remove_client(archive, index);
+ if (!status)
+ {
+ unlink(archive->cnt_file);
+ free(archive->cnt_file);
+ archive->cnt_file = NULL;
- g_mutex_unlock(&archive->clients_access);
+ error = DBE_SYS_ERROR;
+
+ }
+
+ close(fd);
+
+ save_error:
+
+ ;
+
+ }
+
+ /* Formulation de la réponse */
+
+ result = craft_server_short_answer(DBC_SET_CONTENT, error, out_pbuf);
+
+ if (result && error == DBE_NONE)
+ {
+ hint = g_cdb_archive_compute_loading_hint(archive);
+
+ result = craft_server_short_answer(DBC_LOADING_STATUS, hint, out_pbuf);
+
+ }
+
+ free_and_exit:
+
+ free(data);
+
+ exit:
+
+ return result;
}