summaryrefslogtreecommitdiff
path: root/src/analysis/db/cdb.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2014-08-18 21:55:24 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2014-08-18 21:55:24 (GMT)
commita0a7b6c1e05c78ae433f353d15e3366107b67d03 (patch)
treebca0b187778cf016c6131bfc982b08c67a38442b /src/analysis/db/cdb.c
parent161c0f8ab227af5033b1b6456607b9b9c3bc60df (diff)
Inserted storages and collections into loaded binaries (first steps).
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@389 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r--src/analysis/db/cdb.c427
1 files changed, 398 insertions, 29 deletions
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 7e530ac..563aa40 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -28,7 +28,11 @@
#include <archive_entry.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <malloc.h>
+#include <poll.h>
+#include <pthread.h>
+#include <signal.h>
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
@@ -39,8 +43,9 @@
#include <config.h>
-#include "bookmark.h"
+#include "collection.h"
#include "protocol.h"
+#include "items/bookmark.h"
#include "../../common/cpp.h"
#include "../../common/extstr.h"
#include "../../common/io.h"
@@ -53,13 +58,26 @@
#define ARCHIVE_RBUF_SIZE 2048
+
+
+
+/* Informations relatives à un client */
+typedef struct _cdb_client
+{
+ int fd; /* Canal de communication */
+ rle_string user; /* Utilisateur à l'autre bout */
+
+ uint64_t last_time; /* Date de dernier envoi */
+
+} cdb_client;
+
+
/* Description d'une archive d'éléments utilisateur (instance) */
struct _GCdbArchive
{
GObject parent; /* A laisser en premier */
- char hash[65]; /* Empreinte SHA256 */
-
+ rle_string hash; /* Empreinte cryptographique */
char *filename; /* Chemin d'accès à l'archive */
@@ -71,6 +89,15 @@ struct _GCdbArchive
sqlite3 *db; /* Base de données à manipuler */
+ GList *collections; /* Ensemble de modifications */
+
+ 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 */
+ pthread_t process_id; /* Identifiant de la procédure */
+
};
/* Description d'une archive d'éléments utilisateur (classe) */
@@ -101,7 +128,8 @@ static bool g_cdb_archive_read(GCdbArchive *);
/* Crée la description XML correspondant à l'archive. */
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *, const core_db_info *);
+static bool g_cdb_archive_create_xml_desc(GCdbArchive *, const rle_string *);
+
@@ -112,6 +140,22 @@ static bool g_cdb_archive_create_db(const GCdbArchive *, const core_db_info *);
+/////////////////////////:
+
+
+/* Crée et remplit les collections à partir de leurs bases. */
+static bool g_cdb_archive_load_collections(GCdbArchive *);
+
+/* Réagit à une modification au sein d'une collection donnée. */
+static void on_collection_changed(GDbCollection *, DBAction, GDbItem *, GCdbArchive *);
+
+/* Assure le traitement des requêtes de clients. */
+static void *g_cdb_archive_process(GCdbArchive *);
+
+
+
+
+
/* Indique le type défini pour une une archive d'éléments utilisateur. */
G_DEFINE_TYPE(GCdbArchive, g_cdb_archive, G_TYPE_OBJECT);
@@ -155,6 +199,7 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
static void g_cdb_archive_init(GCdbArchive *archive)
{
+ g_mutex_init(&archive->clients_access);
}
@@ -203,19 +248,21 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
/******************************************************************************
* *
-* Paramètres : local = indique si l'enregistrement est local ou non. *
-* client = flux ouvert en lecture pour les informations utiles.*
-* info = informations de base associées à la requête. *
+* Paramètres : owner = description humaine du serveur d'accueil. *
+* hash = empreinte du binaire à représenter. *
+* user = désignation d'un éventuel nouveau créateur. *
+* error = indication éventuelle en cas d'échec. [OUT] *
* *
* Description : Définit ou ouvre une archive d'éléments utilisateur. *
* *
* Retour : Structure mise en plae ou NULL en cas d'échec. *
* *
-* Remarques : - *
+* Remarques : Les chaînes sont assurées d'être non vides ; la procédure *
+* assume un transfert de propriété. *
* *
******************************************************************************/
-GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info *info)
+GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const rle_string *user, DBError *error)
{
GCdbArchive *result; /* Adresse à retourner */
char *suffix; /* Fin du nom de fichier */
@@ -224,19 +271,14 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL);
-
-
- strcpy(result->hash, info->hash);
-
-
-
+ dup_rle_string(&result->hash, hash);
/* Chemin de l'archive */
suffix = strdup("chrysalide" G_DIR_SEPARATOR_S);
- suffix = stradd(suffix, local ? "local" : "server");
+ suffix = stradd(suffix, owner);
suffix = stradd(suffix, G_DIR_SEPARATOR_S);
- suffix = stradd(suffix, result->hash);
+ suffix = stradd(suffix, hash->data);
suffix = stradd(suffix, ".tar.xz");
result->filename = get_xdg_config_dir(suffix);
@@ -253,7 +295,7 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
if (result->xml_desc[strlen(result->xml_desc) - 1] != G_DIR_SEPARATOR)
result->xml_desc = stradd(result->xml_desc, G_DIR_SEPARATOR_S);
- result->xml_desc = stradd(result->xml_desc, result->hash);
+ result->xml_desc = stradd(result->xml_desc, result->hash.data);
result->xml_desc = stradd(result->xml_desc, "_desc.xml");
result->sql_db = strdup(g_get_tmp_dir());
@@ -261,7 +303,7 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
if (result->sql_db[strlen(result->sql_db) - 1] != G_DIR_SEPARATOR)
result->sql_db = stradd(result->sql_db, G_DIR_SEPARATOR_S);
- result->sql_db = stradd(result->sql_db, result->hash);
+ result->sql_db = stradd(result->sql_db, result->hash.data);
result->sql_db = stradd(result->sql_db, "_db.sql");
/* Création de l'archive si elle n'existe pas */
@@ -273,8 +315,8 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
/* Le soucis ne vient pas de l'absence du fichier... */
if (errno != ENOENT) goto gcan_error;
- g_cdb_archive_create_xml_desc(result, info);
- g_cdb_archive_create_db(result, info);
+ g_cdb_archive_create_xml_desc(result, user);
+ g_cdb_archive_create_db(result, NULL);
if (!g_cdb_archive_write(result))
goto gcan_error;
@@ -288,6 +330,11 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
if (!g_cdb_archive_read(result) && 0)
goto gcan_error;
+ /* Chargement des éléments sauvegardés */
+
+ if (!g_cdb_archive_load_collections(result))
+ goto gcan_error;
+
return result;
gcan_error:
@@ -301,7 +348,7 @@ GCdbArchive *g_cdb_archive_new(bool local, GDbClient *client, const core_db_info
/******************************************************************************
* *
-* Paramètres : archive = information quant à l'archive à interpréter. *
+* Paramètres : archive = informations quant à l'archive à interpréter. *
* *
* Description : Ouvre une archive avec tous les éléments à conserver. *
* *
@@ -416,7 +463,7 @@ static bool g_cdb_archive_read(GCdbArchive *archive)
/******************************************************************************
* *
-* Paramètres : archive = information quant à l'archive à créer. *
+* Paramètres : archive = informations quant à l'archive à créer. *
* *
* Description : Enregistre une archive avec tous les éléments à conserver. *
* *
@@ -497,9 +544,24 @@ bool g_cdb_archive_write(const GCdbArchive *archive)
}
+/******************************************************************************
+* *
+* Paramètres : archive = informations quant à l'archive à consulter. *
+* hash = empreinte extérieure à comparer. *
+* *
+* Description : Détermine si une empreinte correspond à celle d'une archive. *
+* *
+* Retour : Résultat de la comparaison : -1, 0 ou 1. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *hash)
+{
+ return cmp_rle_string(&archive->hash, hash);
-
+}
@@ -514,7 +576,7 @@ bool g_cdb_archive_write(const GCdbArchive *archive)
/******************************************************************************
* *
* Paramètres : archive = archive à constituer. *
-* info = informations de base associées à la requête. *
+* user = désignation d'un éventuel nouveau créateur. *
* *
* Description : Crée la description XML correspondant à l'archive. *
* *
@@ -524,7 +586,7 @@ bool g_cdb_archive_write(const GCdbArchive *archive)
* *
******************************************************************************/
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const core_db_info *info)
+static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string *user)
{
bool result; /* Bilan à retourner */
char tmp[sizeof(STR(ULLONG_MAX))]; /* Stockage temporaire */
@@ -536,12 +598,15 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const core_db_in
"/ChrysalideBinary/Version", PACKAGE_VERSION);
result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Hash", archive->hash);
+ "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION));
result &= add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Creation/Author", "**me**");
+ "/ChrysalideBinary/Hash", archive->hash.data);
- snprintf(tmp, sizeof(tmp), "%" PRIu64, (uint64_t)10ull);
+ result &= add_content_to_node(archive->xdoc, archive->context,
+ "/ChrysalideBinary/Creation/Author", user->data);
+
+ snprintf(tmp, sizeof(tmp), "%" PRIu64, (uint64_t)time(NULL));
result &= add_content_to_node(archive->xdoc, archive->context,
"/ChrysalideBinary/Creation/Date", tmp);
@@ -600,3 +665,307 @@ static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_in
return result;
}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ACCES A LA BASE DE DONNEES SQL */
+/* ACCES A LA BASE DE DONNEES SQL */
+/* ---------------------------------------------------------------------------------- */
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive dont les collections sont à initialiser. *
+* *
+* Description : Crée et remplit les collections à partir de leurs bases. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_cdb_archive_load_collections(GCdbArchive *archive)
+{
+ GList *iter; /* Boucle de parcours */
+
+ archive->collections = create_collections_list();
+
+ for (iter = g_list_first(archive->collections);
+ iter != NULL;
+ iter = g_list_next(iter))
+ {
+ g_signal_connect(iter->data, "content-changed", G_CALLBACK(on_collection_changed), archive);
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = collection dont le contenu a évolué. *
+* action = type d'évolution rencontrée. *
+* item = élément ajouté, modifié ou supprimé. *
+* archive = centralisation de tous les savoirs. *
+* *
+* Description : Réagit à une modification au sein d'une collection donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_collection_changed(GDbCollection *collec, DBAction action, GDbItem *item, GCdbArchive *archive)
+{
+ size_t i; /* Boucle de parcours */
+ bool status; /* Bilan d'un envoi de retour */
+
+ g_mutex_lock(&archive->clients_access);
+
+ for (i = 0; i < archive->count; i++)
+ {
+ status = g_db_collection_send(collec, archive->clients[i].fd, action, item);
+
+ if (!status)
+ {
+ /* TODO : close() */
+ }
+
+ }
+
+ g_mutex_unlock(&archive->clients_access);
+
+ printf("CHANGED !!\n");
+
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = centralisation de tous les savoirs. *
+* *
+* Description : Assure le traitement des requêtes de clients. *
+* *
+* Retour : NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *g_cdb_archive_process(GCdbArchive *archive)
+{
+ 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 */
+ uint32_t val32; /* Valeur sur 32 bits */
+ bool status; /* Bilan de lecture initiale */
+ uint32_t command; /* Commande de la requête */
+ GDbCollection *collec; /* Collection visée au final */
+
+ void interrupt_poll_with_sigusr1(int sig) { };
+
+ signal(SIGUSR1, interrupt_poll_with_sigusr1);
+
+ archive->process_id = pthread_self();
+
+ fds = NULL;
+
+ while (1)
+ {
+ /* Reconstitution d'une liste à jour */
+
+ g_mutex_lock(&archive->clients_access);
+
+ nfds = archive->count;
+ fds = (struct pollfd *)realloc(fds, nfds * sizeof(struct pollfd));
+
+ for (i = 0; i < nfds; i++)
+ {
+ fds[i].fd = archive->clients[i].fd;
+ fds[i].events = POLLIN | POLLPRI;
+ }
+
+ if (nfds == 0)
+ goto gcap_no_more_clients;
+
+ g_mutex_unlock(&archive->clients_access);
+
+ /* Lancement d'une phase de surveillance */
+
+ printf("(%p) POLL %d\n", archive, nfds);
+
+ ret = poll(fds, nfds, -1);
+ if (ret == -1)
+ {
+ if (errno == EINTR) continue;
+
+ perror("poll");
+ break;
+
+ }
+
+ /* Traitement des requêtes reçues */
+
+ for (i = 0; i < nfds; i++)
+ {
+ /* Le canal est fermé, une sortie doit être demandée... */
+ if (fds[i].revents & POLLNVAL)
+ goto gcap_bad_exchange;
+
+ /* Données présentes en entrée */
+ if (fds[i].revents & (POLLIN | POLLPRI))
+ {
+ status = safe_recv(fds[i].fd, &val32, sizeof(uint32_t), 0);
+ if (!status) goto gcap_bad_exchange;
+
+ command = be32toh(val32);
+
+ switch (command)
+ {
+ case DBC_COLLECTION:
+
+ status = safe_recv(fds[i].fd, &val32, sizeof(uint32_t), 0);
+ if (!status) goto gcap_bad_exchange;
+
+ collec = find_collection_in_list(archive->collections, be32toh(val32));
+ if (collec == NULL) goto gcap_bad_exchange;
+
+ status = g_db_collection_recv(collec, fds[i].fd);
+ if (!status) goto gcap_bad_exchange;
+
+ printf("## CDB ## Got something for collection %p...\n", collec);
+
+ //GDbCollection *find_collection_in_list(GList *, uint32_t);
+
+ //static GGenConfig *find_collection_in_list(GList *list, uint32_t id)
+
+ break;
+
+ default:
+ printf("bad command :: 0x%08x\n", command);
+ goto gcap_bad_exchange;
+ break;
+
+ }
+
+ continue;
+
+ gcap_bad_exchange:
+
+ printf("Bad exchange...\n");
+
+ /* TODO : close conn */
+
+ ;
+
+
+ }
+
+ }
+
+ }
+
+ /* On disparaît des écrans... */
+
+ g_mutex_lock(&archive->clients_access);
+
+ gcap_no_more_clients:
+
+ archive->process = NULL;
+ archive->process_id = 0;
+
+ g_mutex_unlock(&archive->clients_access);
+
+ if (fds != NULL)
+ free(fds);
+
+
+ return NULL;
+
+}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : archive = archive à connecter avec un utilisateur. *
+* fd = canal de communication réseau ouvert. *
+* user = désignation de l'utilisateur associé. *
+* *
+* Description : Associe un nouvel utilisateur à l'archive. *
+* *
+* Retour : Indication d'une éventuelle erreur lors de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string *user)
+{
+
+ volatile pthread_t *process_id; /* Identifiant de la procédure */
+
+
+
+
+ printf("Add '%s' for archive...\n", user->data);
+
+
+ g_mutex_lock(&archive->clients_access);
+
+ /* Ajout dans la liste officielle */
+
+ archive->clients = (cdb_client *)realloc(archive->clients, ++archive->count * sizeof(cdb_client));
+
+ archive->clients[archive->count - 1].fd = fd;
+ dup_rle_string(&archive->clients[archive->count - 1].user, user);
+
+ /* Démarrage ou redémarrage du processus d'écoute */
+
+ if (archive->process == NULL)
+ {
+ archive->process = g_thread_new("cdb_process", (GThreadFunc)g_cdb_archive_process, archive);
+
+ /* On attend que le processus parallèle soit prêt */
+ for (process_id = &archive->process_id; *process_id == 0; );
+
+ }
+ else
+ pthread_kill(archive->process_id, SIGUSR1);
+
+ g_mutex_unlock(&archive->clients_access);
+
+ /* Envoi des mises à jour au nouveau client... */
+
+
+ /* TODO */
+
+
+
+ return DBE_NONE;
+
+}
+
+
+