diff options
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r-- | src/analysis/db/cdb.c | 427 |
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; + +} + + + |