summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2022-02-21 06:54:10 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2022-02-21 06:54:10 (GMT)
commit8bf77ba6e5ef40d8bb936dc952ac2c8cc30aab3e (patch)
tree934661f2f30e0b8d23793f52084c736052e85f7c /src
parent8ce244d136b32b43d8553866747c68b503b2d10a (diff)
Make the server drive the network exchanges.
Diffstat (limited to 'src')
-rw-r--r--src/analysis/db/analyst.c140
-rw-r--r--src/analysis/db/analyst.h14
-rw-r--r--src/analysis/db/cdb.c133
-rw-r--r--src/analysis/db/protocol.h31
-rw-r--r--src/analysis/db/server.c4
5 files changed, 290 insertions, 32 deletions
diff --git a/src/analysis/db/analyst.c b/src/analysis/db/analyst.c
index ab12cc1..2e1cc23 100644
--- a/src/analysis/db/analyst.c
+++ b/src/analysis/db/analyst.c
@@ -35,6 +35,17 @@
+
+
+
+
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+
+
+
+
/* Description de client à l'écoute (instance) */
struct _GAnalystClient
{
@@ -65,6 +76,8 @@ struct _GAnalystClientClass
/* Signaux */
+ void (* ready) (GAnalystClient *);
+ void (* server_status_changed) (GAnalystClient *, LoadingStatusHint);
void (* snapshots_updated) (GAnalystClient *);
void (* snapshot_changed) (GAnalystClient *);
@@ -97,6 +110,56 @@ static bool g_analyst_client_update_current_snapshot(GAnalystClient *, packed_bu
+/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
+
+
+/* Prend en compte une évolution du statut côté serveur. */
+static bool g_analyst_client_handle_loading_hints(GAnalystClient *, packed_buffer_t *);
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GLUES POUR LA GLIB */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Définit un type GLib pour l'énumération "LoadingStatusHint". *
+* *
+* Retour : Type GLib enregistré. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GType g_loading_status_hint_type(void)
+{
+ static GType result = 0;
+
+ static const GEnumValue values[] = {
+ { LSH_READY, "LSH_READY", "ready" },
+ { LSH_ON_WAIT_LIST, "LSH_ON_WAIT_LIST", "on_wait_list" },
+ { LSH_NEED_CONTENT, "LSH_NEED_CONTENT", "need_content" },
+ { LSH_NEED_FORMAT, "LSH_NEED_FORMAT", "need_format" },
+ { LSH_NEED_ARCH, "LSH_NEED_ARCH", "need_arch" },
+ { 0, NULL, NULL }
+ };
+
+ if (result == 0)
+ result = g_enum_register_static(g_intern_static_string("LoadingStatusHint"), values);
+
+ return result;
+
+}
+
+
+
+
+
/* Indique le type défini pour une description de client à l'écoute. */
G_DEFINE_TYPE(GAnalystClient, g_analyst_client, G_TYPE_HUB_CLIENT);
@@ -129,6 +192,22 @@ static void g_analyst_client_class_init(GAnalystClientClass *klass)
client->complete_hello = (complete_client_hello_fc)g_analyst_client_complete_hello;
client->recv_func = (GThreadFunc)g_analyst_client_update;
+ g_signal_new("ready",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_signal_new("server-status-changed",
+ G_TYPE_ANALYST_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAnalystClientClass, server_status_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1, G_TYPE_LOADING_STATUS_HINT);
+
g_signal_new("snapshots-updated",
G_TYPE_ANALYST_CLIENT,
G_SIGNAL_RUN_LAST,
@@ -430,6 +509,11 @@ static void *g_analyst_client_update(GAnalystClient *client)
switch (command)
{
+ case DBC_LOADING_STATUS:
+ status = g_analyst_client_handle_loading_hints(client, &in_pbuf);
+ if (!status) goto gdcu_bad_exchange;
+ break;
+
case DBC_SAVE:
status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
@@ -1285,3 +1369,59 @@ bool g_analyst_client_remove_snapshot(GAnalystClient *client, const snapshot_id_
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* PRISES EN COMPTE DES COMMANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* in_pbuf = paquet à consulter. *
+* *
+* Description : Prend en compte une évolution du statut côté serveur. *
+* *
+* Retour : Indication pour le maintien de la communication. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_analyst_client_handle_loading_hints(GAnalystClient *client, packed_buffer_t *in_pbuf)
+{
+ bool result; /* Bilan à retourner */
+ uleb128_t hint; /* Indication du serveur */
+
+ result = unpack_uleb128(&hint, in_pbuf);
+
+ switch (hint)
+ {
+ case LSH_READY:
+ g_signal_emit_by_name(client, "ready");
+ break;
+
+ case LSH_ON_WAIT_LIST:
+ log_simple_message(LMT_INFO, _("Waiting for content from server..."));
+ break;
+
+ case LSH_NEED_CONTENT:
+ case LSH_NEED_FORMAT:
+ case LSH_NEED_ARCH:
+ g_signal_emit_by_name(client, "server-status-changed", hint);
+ break;
+
+ default:
+ log_variadic_message(LMT_ERROR,
+ _("Unknown loaded hint received (%x); unsupported newer protocol?"),
+ hint);
+ result = false;
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/src/analysis/db/analyst.h b/src/analysis/db/analyst.h
index 9f7b32b..459034e 100644
--- a/src/analysis/db/analyst.h
+++ b/src/analysis/db/analyst.h
@@ -38,6 +38,20 @@
+
+/* ------------------------------- GLUES POUR LA GLIB ------------------------------- */
+
+
+#define G_TYPE_LOADING_STATUS_HINT g_loading_status_hint_type()
+
+
+/* Définit un type GLib pour l'énumération "LoadingStatusHint". */
+GType g_loading_status_hint_type(void);
+
+
+
+
+
#define G_TYPE_ANALYST_CLIENT g_analyst_client_get_type()
#define G_ANALYST_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ANALYST_CLIENT, GAnalystClient))
#define G_IS_ANALYST_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ANALYST_CLIENT))
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index c5d3af7..b1e47bc 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -101,9 +101,13 @@ struct _GCdbArchive
char *filename; /* Chemin d'accès à l'archive */
char *tmpdir; /* Répertoire de travail */
- char *cnt_file; /* Fichier de contenu binaire */
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 */
@@ -189,8 +193,8 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *, packed_buffer_t *)
/* ------------------------- PRISES EN COMPTE DES COMMANDES ------------------------- */
-/* Prépare la réponse à envoyer à un client connecté. */
-static bool setup_server_answer(DBCommand, DBError, packed_buffer_t *);
+/* 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 *);
@@ -218,7 +222,7 @@ static cdb_client *create_cdb_client(SSL *fd, const char *peer_name, const char
{
cdb_client *result; /* Fiche d'entité à retourner */
- result = malloc(sizeof(cdb_client *));
+ result = malloc(sizeof(cdb_client));
result->tls_fd = fd;
@@ -358,9 +362,11 @@ static void g_cdb_archive_init(GCdbArchive *archive)
archive->filename = NULL;
archive->tmpdir = NULL;
- archive->cnt_file = NULL;
archive->xml_desc = NULL;
+ archive->cnt_file = NULL;
+ g_mutex_init(&archive->loading_access);
+
archive->collections = create_collections_list();
archive->snapshot = NULL;
@@ -387,9 +393,11 @@ static void g_cdb_archive_dispose(GCdbArchive *archive)
{
g_server_backend_stop(G_SERVER_BACKEND(archive));
+ g_mutex_clear(&archive->clients_access);
+
g_clear_object(&archive->snapshot);
- g_mutex_clear(&archive->clients_access);
+ g_mutex_clear(&archive->loading_access);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->dispose(G_OBJECT(archive));
@@ -1459,38 +1467,100 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
* *
******************************************************************************/
+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);
/**
- * 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.
+ * Le verrou encadrant les évolutions des contenus initiaux doit englober
+ * l'extension de la liste des clients.
*
- * - soit on intègre le client et celui ci demande des mises à jour
- * collection par collection ; c'est également à lui que revient le rejet
- * des éléments envoyés en solitaires avant la réception de la base
- * complète.
+ * 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).
*
- * 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.
+ * 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.
*/
- client = create_cdb_client(fd, peer_name, user);
+ g_mutex_lock(&archive->loading_access);
g_mutex_lock(&archive->clients_access);
- archive->clients = realloc(archive->clients, ++archive->count * sizeof(cdb_client *));
+ 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;
- archive->clients[archive->count - 1] = client;
+ }
g_mutex_unlock(&archive->clients_access);
+ g_mutex_unlock(&archive->loading_access);
+
}
@@ -1694,10 +1764,10 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff
/******************************************************************************
* *
* Paramètres : cmd = commande à l'origine d'un traitement. *
-* error = bilan de traitement à communiquer. *
+* value = valeur à communiquer. *
* out_pbuf = paquet à consituer pour un retour au client. [OUT]*
* *
-* Description : Prépare la réponse à envoyer à un client connecté. *
+* Description : Prépare une courte réponse à envoyer à un client connecté. *
* *
* Retour : Indication pour le maintien de la communication. *
* *
@@ -1705,7 +1775,7 @@ static bool g_cdb_archive_send_snapshot_change(GCdbArchive *archive, packed_buff
* *
******************************************************************************/
-static bool setup_server_answer(DBCommand cmd, DBError error, packed_buffer_t *out_pbuf)
+static bool craft_server_short_answer(DBCommand cmd, uleb128_t value, packed_buffer_t *out_pbuf)
{
bool result; /* Bilan à retourner */
@@ -1714,7 +1784,7 @@ static bool setup_server_answer(DBCommand cmd, DBError error, packed_buffer_t *o
result = extend_packed_buffer(out_pbuf, (uint32_t []) { cmd }, sizeof(uint32_t), true);
if (result)
- result = extend_packed_buffer(out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
+ result = pack_uleb128((uleb128_t []){ value }, out_pbuf);
return result;
@@ -1748,6 +1818,7 @@ static bool g_cdb_archive_set_content(GCdbArchive *archive, packed_buffer_t *in_
const gchar *hash; /* Empreinte de ce contenu */
int fd; /* Flux ouvert en écriture */
bool status; /* Bilan d'une écriture */
+ LoadingStatusHint hint; /* Statut de chargement */
result = true;
error = DBE_NONE;
@@ -1848,7 +1919,15 @@ static bool g_cdb_archive_set_content(GCdbArchive *archive, packed_buffer_t *in_
/* Formulation de la réponse */
- result = setup_server_answer(DBC_SET_CONTENT, error, out_pbuf);
+ 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:
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 17263c8..7707058 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -76,14 +76,21 @@ typedef enum _ServerPrivLevels
+/**
+ * Précisions pour la commande DBC_LOADING_STATUS.
+ */
+
+
/* Eléments de base nécessaires */
-typedef enum _RequiredBasics
+typedef enum _LoadingStatusHint
{
- RBS_NONE = 0x0, /* (Plus) rien n'est requis */
- RBS_CONTENT = 0x1, /* Contenu binaire à analyser */
- RBS_LOADED = 0x2, /* Contenu binaire analysé */
+ LSH_READY = 0, /* (Plus) rien n'est requis */
+ LSH_ON_WAIT_LIST = 1, /* Concurrence des connexions */
+ LSH_NEED_CONTENT = 2, /* Suppléments nécessaires */
+ LSH_NEED_FORMAT = 3, /* Suppléments nécessaires */
+ LSH_NEED_ARCH = 4, /* Suppléments nécessaires */
-} RequiredBasics;
+} LoadingStatusHint;
@@ -135,6 +142,8 @@ typedef enum _DBAction
*/
typedef enum _DBCommand
{
+ /* ------------------------- Commandes à portée générale ------------------------- */
+
/**
* Le client envoie un tout premier paquet de la forme suivante :
*
@@ -176,6 +185,18 @@ typedef enum _DBCommand
/* ------------------------ Commandes pour analyste ------------------------ */
/**
+ * Gestion de la commande 'DBC_LOADING_STATUS'.
+ *
+ * Le serveur envoie un statut de prise en charge au début d'une connexion :
+ *
+ * [ Indication du serveur : DBC_LOADING_STATUS]
+ * [ Statut courant ; cf. LoadingStatusHint ]
+ *
+ */
+
+ DBC_LOADING_STATUS, /* Indications initiales */
+
+ /**
* Gestion de la commande 'DBC_SET_CONTENT'.
*
* Le client connecté envoie un paquet de la forme suivante :
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index 5c6fd18..79d5df1 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -1088,6 +1088,8 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
/* Fin de réception des données envoyées */
+ setup_empty_rle_string(&hash);
+
status = unpack_rle_string(&hash, in_pbuf);
if (!status)
{
@@ -1101,6 +1103,8 @@ static GServerBackend *g_hub_server_handle_analyst(GHubServer *server, packed_bu
goto wrong_receiving_0;
}
+ setup_empty_rle_string(&class);
+
status = unpack_rle_string(&class, in_pbuf);
if (!status)
{