diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2022-02-21 06:54:10 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2022-02-21 06:54:10 (GMT) |
commit | 8bf77ba6e5ef40d8bb936dc952ac2c8cc30aab3e (patch) | |
tree | 934661f2f30e0b8d23793f52084c736052e85f7c /src | |
parent | 8ce244d136b32b43d8553866747c68b503b2d10a (diff) |
Make the server drive the network exchanges.
Diffstat (limited to 'src')
-rw-r--r-- | src/analysis/db/analyst.c | 140 | ||||
-rw-r--r-- | src/analysis/db/analyst.h | 14 | ||||
-rw-r--r-- | src/analysis/db/cdb.c | 133 | ||||
-rw-r--r-- | src/analysis/db/protocol.h | 31 | ||||
-rw-r--r-- | src/analysis/db/server.c | 4 |
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) { |