From 027305c2447b05de2c576e3f5ee32ced400f439f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 28 Feb 2017 19:58:57 +0100
Subject: Defined abstract packed buffers to transfert data.

---
 ChangeLog                        |  30 ++++
 src/analysis/binary.c            |  24 +++-
 src/analysis/db/cdb.c            |  92 ++++++++----
 src/analysis/db/client.c         |  99 ++++++++-----
 src/analysis/db/collection.c     |  55 +++----
 src/analysis/db/collection.h     |   9 +-
 src/analysis/db/item-int.h       |   8 +-
 src/analysis/db/item.c           |  79 +++++------
 src/analysis/db/item.h           |   5 +-
 src/analysis/db/items/bookmark.c |  48 +++----
 src/analysis/db/items/comment.c  |  92 ++++++------
 src/analysis/db/items/move.c     |  53 ++++---
 src/analysis/db/items/switcher.c |  74 +++++-----
 src/analysis/db/misc/rlestr.c    |  56 +++-----
 src/analysis/db/misc/rlestr.h    |   5 +-
 src/analysis/db/misc/timestamp.c |  31 ++--
 src/analysis/db/misc/timestamp.h |   5 +-
 src/analysis/db/server.c         |  50 +++++--
 src/arch/vmpa.c                  |  44 +++---
 src/arch/vmpa.h                  |   5 +-
 src/common/Makefile.am           |   1 +
 src/common/packed.c              | 300 +++++++++++++++++++++++++++++++++++++++
 src/common/packed.h              |  72 ++++++++++
 23 files changed, 856 insertions(+), 381 deletions(-)
 create mode 100644 src/common/packed.c
 create mode 100644 src/common/packed.h

diff --git a/ChangeLog b/ChangeLog
index 7a15588..09e5a32 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+17-02-28  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/binary.c:
+	* src/analysis/db/cdb.c:
+	* src/analysis/db/client.c:
+	* src/analysis/db/collection.c:
+	* src/analysis/db/collection.h:
+	* src/analysis/db/item-int.h:
+	* src/analysis/db/item.c:
+	* src/analysis/db/item.h:
+	* src/analysis/db/items/bookmark.c:
+	* src/analysis/db/items/comment.c:
+	* src/analysis/db/items/move.c:
+	* src/analysis/db/items/switcher.c:
+	* src/analysis/db/misc/rlestr.c:
+	* src/analysis/db/misc/rlestr.h:
+	* src/analysis/db/misc/timestamp.c:
+	* src/analysis/db/misc/timestamp.h:
+	* src/analysis/db/server.c:
+	* src/arch/vmpa.c:
+	* src/arch/vmpa.h:
+	Update code.
+
+	* src/common/Makefile.am:
+	Add the 'packed.[ch]' files to libcommon_la_SOURCES.
+
+	* src/common/packed.c:
+	* src/common/packed.h:
+	New entries: define abstract packed buffers to transfert data.
+
 17-02-25  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/panels/welcome.c:
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 8c03dcf..603c519 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -1250,6 +1250,7 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
     GDbCollection *collec;                  /* Collection visée au final   */
     DBStorage storage;                      /* Forme d'enregistrement      */
     GDbClient *client;                      /* Liaison à utiliser          */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
     int fd;                                 /* Identifiant du canal de com.*/
 
     feature = g_db_item_get_feature(item);
@@ -1271,12 +1272,21 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
         client = binary->local;
 
 
+        init_packed_buffer(&out_pbuf);
+
         fd = g_db_client_get_fd(client);
 
-        result = g_db_collection_send(collec, fd, DBA_ADD_ITEM, item);
+        result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
 
         g_db_client_put_fd(client);
 
+        if (result)
+            result = send_packed_buffer(&out_pbuf, fd);
+
+        exit_packed_buffer(&out_pbuf);
+
+
+
     }
 
     g_object_unref(G_OBJECT(collec));
@@ -1312,6 +1322,7 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
     GDbCollection *collec;                  /* Collection visée au final   */
     DBStorage storage;                      /* Forme d'enregistrement      */
     GDbClient *client;                      /* Liaison à utiliser          */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
     int fd;                                 /* Identifiant du canal de com.*/
 
     collec = g_loaded_binary_find_collection(binary, feature);
@@ -1331,12 +1342,21 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
         client = binary->local;
 
 
+        init_packed_buffer(&out_pbuf);
+
         fd = g_db_client_get_fd(client);
 
-        result = g_db_collection_send(collec, fd, DBA_REM_ITEM, item);
+        result = g_db_collection_pack(collec, &out_pbuf, DBA_REM_ITEM, item);
 
         g_db_client_put_fd(client);
 
+        if (result)
+            result = send_packed_buffer(&out_pbuf, fd);
+
+        exit_packed_buffer(&out_pbuf);
+
+
+
     }
 
     g_object_unref(G_OBJECT(collec));
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 75a8714..167fa0c 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -803,28 +803,38 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive)
 
 static void on_collection_changed(GDbCollection *collec, DBAction action, GDbItem *item, GCdbArchive *archive)
 {
+    packed_buffer pbuf;                     /* Tampon d'émission           */
     size_t i;                               /* Boucle de parcours          */
     bool status;                            /* Bilan d'un envoi de retour  */
 
-    g_mutex_lock(&archive->clients_access);
+    init_packed_buffer(&pbuf);
 
-    for (i = 0; i < archive->count; i++)
-    {
-        status = g_db_collection_send(collec, archive->clients[i].fd, action, item);
+    status = true;
 
-        if (!status)
-        {
-            /* TODO : close() */
-        }
+    g_mutex_lock(&archive->clients_access);
 
-    }
+    for (i = 0; i < archive->count && status; i++)
+        status = g_db_collection_pack(collec, &pbuf, action, item);
 
     g_mutex_unlock(&archive->clients_access);
 
+    if (status)
+        status = send_packed_buffer(&pbuf, archive->clients[i].fd);
+
+    exit_packed_buffer(&pbuf);
+
+    if (!status)
+        goto occ_error;
+
+
     printf("CHANGED for %d clients !!\n", (int)archive->count);
 
 
 
+ occ_error:
+
+    /* TODO : close() */
+    ;
 
 }
 
@@ -847,10 +857,12 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
     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          */
+    packed_buffer 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           */
     GDbCollection *collec;                  /* Collection visée au final   */
 
     void interrupt_poll_with_sigusr1(int sig) { };
@@ -907,10 +919,13 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
             /* Données présentes en entrée */
             if (fds[i].revents & (POLLIN | POLLPRI))
             {
-                status = safe_recv(fds[i].fd, &val32, sizeof(uint32_t), 0);
+                status = recv_packed_buffer(&in_pbuf, fds[i].fd);
                 if (!status) goto gcap_bad_exchange;
 
-                command = be32toh(val32);
+                status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
+                if (!status) goto gcap_bad_exchange;
+
+                command = tmp32;
 
                 switch (command)
                 {
@@ -918,23 +933,31 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 
                         error = g_cdb_archive_write(archive);
 
-                        if (!safe_send(fds[i].fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t), 0))
-                            goto gcap_bad_exchange;
+                        init_packed_buffer(&out_pbuf);
+
+                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE },
+                                                      sizeof(uint32_t), true);
+                        if (!status) goto gcap_bad_reply;
+
+                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
+                        if (!status) goto gcap_bad_reply;
 
-                        if (!safe_send(fds[i].fd, (uint32_t []) { htobe32(error) }, sizeof(uint32_t), 0))
-                            goto gcap_bad_exchange;
+                        status = send_packed_buffer(&out_pbuf, fds[i].fd);
+                        if (!status) goto gcap_bad_reply;
+
+                        exit_packed_buffer(&out_pbuf);
 
                         break;
 
                     case DBC_COLLECTION:
 
-                        status = safe_recv(fds[i].fd, &val32, sizeof(uint32_t), 0);
+                        status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
                         if (!status) goto gcap_bad_exchange;
 
-                        collec = find_collection_in_list(archive->collections, be32toh(val32));
+                        collec = find_collection_in_list(archive->collections, tmp32);
                         if (collec == NULL) goto gcap_bad_exchange;
 
-                        status = g_db_collection_recv(collec, fds[i].fd, archive->db);
+                        status = g_db_collection_unpack(collec, &in_pbuf, archive->db);
                         if (!status) goto gcap_bad_exchange;
 
                         printf("## CDB ## Got something for collection %p...\n", collec);
@@ -947,7 +970,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 
                     case DBC_SET_LAST_ACTIVE:
 
-                        status = update_activity_in_collections(archive->collections, fds[i].fd, archive->db);
+                        status = update_activity_in_collections(archive->collections, &in_pbuf, archive->db);
                         if (!status) goto gcap_bad_exchange;
 
                         break;
@@ -959,12 +982,20 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 
                 }
 
+                exit_packed_buffer(&in_pbuf);
+
                 continue;
 
+ gcap_bad_reply:
+
+                exit_packed_buffer(&out_pbuf);
+
  gcap_bad_exchange:
 
                 printf("Bad exchange...\n");
 
+                exit_packed_buffer(&in_pbuf);
+
                 /* TODO : close conn */
 
                 ;
@@ -1018,6 +1049,8 @@ DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string
     GDbCollection *collec;                  /* Collection visée manipulée  */
     volatile pthread_t *process_id;         /* Identifiant de la procédure */
 
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    bool status;                            /* Bilan d'un envoi de retour  */
 
 
 
@@ -1056,20 +1089,27 @@ DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string
 
     /* Envoi des mises à jour au nouveau client... */
 
+    init_packed_buffer(&out_pbuf);
+
+    status = true;
+
+
+    /* TODO : lock ? */
+
     for (iter = g_list_first(archive->collections);
-         iter != NULL;
+         iter != NULL && status;
          iter = g_list_next(iter))
     {
         collec = G_DB_COLLECTION(iter->data);
 
-        if (!g_db_collection_send_all_updates(collec, fd))
-            /* TODO */;
-
-
+        status = g_db_collection_pack_all_updates(collec, &out_pbuf);
 
+    }
 
+    if (status)
+        status = send_packed_buffer(&out_pbuf, fd);
 
-    }
+    exit_packed_buffer(&out_pbuf);
 
 
 
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 2a7aa03..309d9ed 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -353,11 +353,14 @@ bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned shor
 
 static bool g_db_client_start_common(GDbClient *client, const char *desc)
 {
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    bool status;                            /* Bilan d'une opération       */
     rle_string user;                        /* Nom d'utilisateur associé   */
     GChecksum *checksum;                    /* Empreinte MD5 à signer      */
     unsigned char md5_digest[16];           /* Empreinte MD5 calculée      */
     RSA *key;                               /* Clef pour la signature      */
     unsigned char sig[RSA_USED_SIZE];       /* Signature effectuée         */
+    packed_buffer in_pbuf;                  /* Tampon de réception         */
     uint32_t data;                          /* Mot de données lues         */
     DBError error;                          /* Validation de la connexion  */
 
@@ -372,19 +375,21 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
      * Tout ceci est à synchroniser avec la fonction g_db_server_listener().
      */
 
-    if (!safe_send(client->fd, (uint32_t []) { htobe32(DBC_HELO) }, sizeof(uint32_t), MSG_MORE))
-        goto gdcs_error;
+    init_packed_buffer(&out_pbuf);
 
-    if (!safe_send(client->fd, (uint32_t []) { htobe32(CDB_PROTOCOL_VERSION) }, sizeof(uint32_t), MSG_MORE))
-        goto gdcs_error;
+    status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_HELO }, sizeof(uint32_t), true);
+    if (!status) goto gdcs_error;
 
-    if (!send_rle_string(&client->hash, client->fd, MSG_MORE))
-        goto gdcs_error;
+    status = extend_packed_buffer(&out_pbuf, (uint32_t []) { CDB_PROTOCOL_VERSION }, sizeof(uint32_t), true);
+    if (!status) goto gdcs_error;
+
+    status = pack_rle_string(&client->hash, &out_pbuf);
+    if (!status) goto gdcs_error;
 
     init_rle_string(&user, client->author);
 
-    if (!send_rle_string(&user, client->fd, MSG_MORE))
-        goto gdcs_error;
+    status = pack_rle_string(&user, &out_pbuf);
+    if (!status) goto gdcs_error;
 
     checksum = g_checksum_new(G_CHECKSUM_MD5);
     g_checksum_update(checksum, (guchar *)get_rle_string(&user), get_rle_length(&user));
@@ -399,8 +404,11 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
 
     RSA_free(key);
 
-    if (!safe_send(client->fd, sig, RSA_USED_SIZE, 0))
-        goto gdcs_error;
+    status = extend_packed_buffer(&out_pbuf, sig, RSA_USED_SIZE, false);
+    if (!status) goto gdcs_error;
+
+    status = send_packed_buffer(&out_pbuf, client->fd);
+    if (!status) goto gdcs_error;
 
     /**
      * Le serveur doit répondre pour un message type :
@@ -409,19 +417,22 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
      *      ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR').
      */
 
-    if (!safe_recv(client->fd, &data, sizeof(uint32_t), 0))
-        goto gdcs_error;
+    status = recv_packed_buffer(&in_pbuf, client->fd);
+    if (!status) goto gdsc_error;
 
-    if (be32toh(data) != DBC_WELCOME)
+    status = extract_packed_buffer(&in_pbuf, &data, sizeof(uint32_t), true);
+    if (!status) goto gdsc_error;
+
+    if (data != DBC_WELCOME)
     {
         log_variadic_message(LMT_ERROR, _("The server '%s' did not welcome us!"), desc);
-        goto gdcs_error;
+        goto gdsc_error;
     }
 
-    if (!safe_recv(client->fd, &data, sizeof(uint32_t), 0))
-        goto gdcs_error;
+    status = extract_packed_buffer(&in_pbuf, &data, sizeof(uint32_t), true);
+    if (!status) goto gdsc_error;
 
-    error = be32toh(data);
+    error = data;
 
     switch (error)
     {
@@ -432,25 +443,25 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
         case DBE_WRONG_VERSION:
             log_variadic_message(LMT_ERROR, _("The server '%s' does not use our protocol version (0x%08x)..."),
                                  desc, CDB_PROTOCOL_VERSION);
-            goto gdcs_error;
+            goto gdsc_error;
             break;
 
         case DBE_XML_VERSION_ERROR:
             log_variadic_message(LMT_ERROR, _("The archive from the server '%s' does not use our protocol version (0x%08x)..."),
                                  desc, CDB_PROTOCOL_VERSION);
-            goto gdcs_error;
+            goto gdsc_error;
             break;
 
         case DBE_DB_LOADING_ERROR:
             log_variadic_message(LMT_ERROR, _("The server '%s' got into troubles while loading the database...."),
                                  desc);
-            goto gdcs_error;
+            goto gdsc_error;
             break;
 
         default:
             log_variadic_message(LMT_ERROR, _("The server '%s' has run into an error (%u)..."),
                                  desc, error);
-            goto gdcs_error;
+            goto gdsc_error;
             break;
 
     }
@@ -460,13 +471,22 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
     {
         log_variadic_message(LMT_ERROR, _("Failed to start a listening thread for the server '%s'!"),
                              desc);
-        goto gdcs_error;
+        goto gdsc_error;
     }
 
+    exit_packed_buffer(&out_pbuf);
+    exit_packed_buffer(&in_pbuf);
+
     return true;
 
+ gdsc_error:
+
+    exit_packed_buffer(&in_pbuf);
+
  gdcs_error:
 
+    exit_packed_buffer(&out_pbuf);
+
     unset_rle_string(&user);
 
     close(client->fd);
@@ -493,7 +513,8 @@ static void *g_db_client_update(GDbClient *client)
 {
     struct pollfd fds;                      /* Surveillance des flux       */
     int ret;                                /* Bilan d'un appel            */
-    uint32_t val32;                         /* Valeur sur 32 bits          */
+    packed_buffer in_pbuf;                  /* Tampon de réception         */
+    uint32_t tmp32;                         /* Valeur sur 32 bits          */
     bool status;                            /* Bilan d'une opération       */
     uint32_t command;                       /* Commande de la requête      */
     DBError error;                          /* Bilan d'une commande passée */
@@ -515,19 +536,20 @@ static void *g_db_client_update(GDbClient *client)
 
         if (fds.revents & (POLLIN | POLLPRI))
         {
-            status = safe_recv(fds.fd, &val32, sizeof(uint32_t), 0);
+            status = recv_packed_buffer(&in_pbuf, fds.fd);
             if (!status) goto gdcu_bad_exchange;
 
-            command = be32toh(val32);
+            status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
+            if (!status) goto gdcu_bad_exchange;
 
             switch (command)
             {
                 case DBC_SAVE:
 
-                    status = safe_recv(fds.fd, &val32, sizeof(uint32_t), 0);
+                    status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
                     if (!status) goto gdcu_bad_exchange;
 
-                    error = be32toh(val32);
+                    error = tmp32;
 
                     if (error == DBE_NONE)
                         log_variadic_message(LMT_INFO, _("Archive saved for binary '%s'"),
@@ -540,13 +562,13 @@ static void *g_db_client_update(GDbClient *client)
 
                 case DBC_COLLECTION:
 
-                    status = safe_recv(fds.fd, &val32, sizeof(uint32_t), 0);
+                    status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
                     if (!status) goto gdcu_bad_exchange;
 
-                    collec = find_collection_in_list(client->collections, be32toh(val32));
+                    collec = find_collection_in_list(client->collections, tmp32);
                     if (collec == NULL) goto gdcu_bad_exchange;
 
-                    status = g_db_collection_recv(collec, fds.fd, NULL);
+                    status = g_db_collection_unpack(collec, &in_pbuf, NULL);
                     if (!status) goto gdcu_bad_exchange;
 
 
@@ -558,12 +580,16 @@ static void *g_db_client_update(GDbClient *client)
 
             }
 
+            exit_packed_buffer(&in_pbuf);
+
             continue;
 
  gdcu_bad_exchange:
 
                 printf("Bad reception...\n");
 
+                exit_packed_buffer(&in_pbuf);
+
                 /* TODO : close conn */
 
                 ;
@@ -689,15 +715,24 @@ bool g_db_client_save(GDbClient *client)
 bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp)
 {
     bool result;                            /* Bilan partiel à remonter    */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+
+    init_packed_buffer(&out_pbuf);
 
     g_db_client_get_fd(client);
 
-    result = safe_send(client->fd, (uint32_t []) { htobe32(DBC_SET_LAST_ACTIVE) }, sizeof(uint32_t), 0);
+    result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
 
-    result &= send_timestamp(&timestamp, client->fd, MSG_MORE);
+    if (result)
+        result = pack_timestamp(&timestamp, &out_pbuf);
 
     g_db_client_put_fd(client);
 
+    if (result)
+        result = send_packed_buffer(&out_pbuf, client->fd);
+
+    exit_packed_buffer(&out_pbuf);
+
     return result;
 
 }
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index ebf7eb8..12194ca 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -33,7 +33,6 @@
 #include "collection-int.h"
 #include "misc/rlestr.h"
 #include "../../common/extstr.h"
-#include "../../common/io.h"
 #include "../../glibext/chrysamarshal.h"
 
 
@@ -258,7 +257,7 @@ uint32_t g_db_collection_get_feature(const GDbCollection *collec)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : collec = ensemble d'éléments à considérer.                   *
-*                fd     = flux ouvert en lecture pour la réception de données.*
+*                pbuf   = paquet de données où venir puiser les infos.        *
 *                db     = base de données à mettre à jour.                    *
 *                                                                             *
 *  Description : Réceptionne et traite une requête réseau pour collection.    *
@@ -271,25 +270,28 @@ uint32_t g_db_collection_get_feature(const GDbCollection *collec)
 *                                                                             *
 ******************************************************************************/
 
-bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
+bool g_db_collection_unpack(GDbCollection *collec, packed_buffer *pbuf, sqlite3 *db)
 {
     bool result;                            /* Bilan à faire remonter      */
-    uint32_t val32;                         /* Valeur sur 32 bits          */
+    uint32_t tmp32;                         /* Valeur sur 32 bits          */
     bool status;                            /* Bilan de lecture initiale   */
     DBAction action;                        /* Commande de la requête      */
     GDbItem *item;                          /* Définition d'élément visé   */
     GList *found;                           /* Test de présence existante  */
     timestamp_t inactive;                   /* Horodatage de désactivation */
 
-    status = safe_recv(fd, &val32, sizeof(uint32_t), 0);
-    if (!status) return false;
+    result = extend_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
+    action = tmp32;
+
+    if (action < 0 || action >= DBA_COUNT)
+        result = false;
 
-    action = be32toh(val32);
-    if (action < 0 || action >= DBA_COUNT) return false;
+    if (!result)
+        return result;
 
     item = g_object_new(collec->type, NULL);
 
-    status = g_db_item_recv(item, fd, 0);
+    status = g_db_item_unpack(item, pbuf);
     if (!status) return false;
 
     result = false;
@@ -380,7 +382,7 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : collec = ensemble d'éléments à considérer.                   *
-*                fd     = flux ouvert en écriture pour l'émission de données. *
+*                pbuf   = paquet de données où venir inscrire les infos.      *
 *                action = avenir de l'élément fourni.                         *
 *                item   = élément de collection à sérialiser.                 *
 *                                                                             *
@@ -392,23 +394,22 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
 *                                                                             *
 ******************************************************************************/
 
-bool g_db_collection_send(GDbCollection *collec, int fd, DBAction action, GDbItem *item)
+bool g_db_collection_pack(GDbCollection *collec, packed_buffer *pbuf, DBAction action, GDbItem *item)
 {
-    bool status;                            /* Bilan de lecture initiale   */
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_send(fd, (uint32_t []) { htobe32(DBC_COLLECTION) }, sizeof(uint32_t), MSG_MORE);
-    if (!status) return false;
+    result = extend_packed_buffer(pbuf, (uint32_t []) { DBC_COLLECTION }, sizeof(uint32_t), true);
 
-    status = safe_send(fd, (uint32_t []) { htobe32(collec->featuring) }, sizeof(uint32_t), MSG_MORE);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint32_t []) { collec->featuring }, sizeof(uint32_t), true);
 
-    status = safe_send(fd, (uint32_t []) { htobe32(action) }, sizeof(uint32_t), MSG_MORE);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint32_t []) { action }, sizeof(uint32_t), true);
 
-    status = g_db_item_send(item, fd, 0);
-    if (!status) return false;
+    if (result)
+        result = g_db_item_pack(item, pbuf);
 
-    return true;
+    return result;
 
 }
 
@@ -416,7 +417,7 @@ bool g_db_collection_send(GDbCollection *collec, int fd, DBAction action, GDbIte
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : collec = ensemble d'éléments à considérer.                   *
-*                fd     = flux ouvert en écriture pour l'émission de données. *
+*                pbuf   = paquet de données où venir inscrire les infos.      *
 *                                                                             *
 *  Description : Envoie pour mise à jour tous les éléments courants.          *
 *                                                                             *
@@ -426,7 +427,7 @@ bool g_db_collection_send(GDbCollection *collec, int fd, DBAction action, GDbIte
 *                                                                             *
 ******************************************************************************/
 
-bool g_db_collection_send_all_updates(GDbCollection *collec, int fd)
+bool g_db_collection_pack_all_updates(GDbCollection *collec, packed_buffer *pbuf)
 {
     bool result;                            /* Bilan à renvoyer            */
     GList *iter;                            /* Boucle de parcours          */
@@ -439,7 +440,7 @@ bool g_db_collection_send_all_updates(GDbCollection *collec, int fd)
          iter != NULL && result;
          iter = g_list_next(iter))
     {
-        result = g_db_collection_send(collec, fd, DBA_ADD_ITEM, G_DB_ITEM(iter->data));
+        result = g_db_collection_pack(collec, pbuf, DBA_ADD_ITEM, G_DB_ITEM(iter->data));
 
     }
 
@@ -1495,7 +1496,7 @@ void lock_unlock_collections(GList *list, bool write, bool lock)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : list = ensemble de collectons à traiter.                     *
-*                fd   = canal de communication ouvert en lecture.             *
+*                pbuf = paquet de données où venir puiser les infos.          *
 *                db   = base de données à mettre à jour.                      *
 *                                                                             *
 *  Description : Met à jour les statuts d'activité des éléments.              *
@@ -1506,7 +1507,7 @@ void lock_unlock_collections(GList *list, bool write, bool lock)
 *                                                                             *
 ******************************************************************************/
 
-bool update_activity_in_collections(GList *list, int fd, sqlite3 *db)
+bool update_activity_in_collections(GList *list, packed_buffer *pbuf, sqlite3 *db)
 {
     bool result;                            /* Résultat global à renvoyer  */
     bool status;                            /* Bilan de lecture initiale   */
@@ -1521,7 +1522,7 @@ bool update_activity_in_collections(GList *list, int fd, sqlite3 *db)
 
     /* TODO : lock ? */
 
-    status = recv_timestamp(&timestamp, fd, 0);
+    status = unpack_timestamp(&timestamp, pbuf);
     if (!status) return false;
 
     inactive = TIMESTAMP_ALL_ACTIVE;
diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h
index 79787e3..1eb297c 100644
--- a/src/analysis/db/collection.h
+++ b/src/analysis/db/collection.h
@@ -33,6 +33,7 @@
 
 #include "item.h"
 #include "protocol.h"
+#include "../../common/packed.h"
 
 
 
@@ -70,13 +71,13 @@ uint32_t g_db_collection_get_feature(const GDbCollection *);
 
 
 /* Réceptionne et traite une requête réseau pour collection. */
-bool g_db_collection_recv(GDbCollection *, int, sqlite3 *);
+bool g_db_collection_unpack(GDbCollection *, packed_buffer *, sqlite3 *);
 
 /* Envoie pour traitement une requête réseau pour collection. */
-bool g_db_collection_send(GDbCollection *, int, DBAction, GDbItem *);
+bool g_db_collection_pack(GDbCollection *, packed_buffer *, DBAction, GDbItem *);
 
 /* Envoie pour mise à jour tous les éléments courants. */
-bool g_db_collection_send_all_updates(GDbCollection *, int);
+bool g_db_collection_pack_all_updates(GDbCollection *, packed_buffer *);
 
 
 
@@ -154,7 +155,7 @@ void lock_unlock_collections(GList *, bool, bool);
 #define runlock_collections(lst) lock_unlock_collections(lst, false, false);
 
 /* Met à jour les statuts d'activité des éléments. */
-bool update_activity_in_collections(GList *, int, sqlite3 *);
+bool update_activity_in_collections(GList *, packed_buffer *, sqlite3 *);
 
 
 
diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h
index a116ac2..38ad444 100644
--- a/src/analysis/db/item-int.h
+++ b/src/analysis/db/item-int.h
@@ -40,10 +40,10 @@
 typedef gint (* cmp_db_item_fc) (GDbItem *, GDbItem *, bool);
 
 /* Importe la définition d'une base d'éléments pour collection. */
-typedef bool (* recv_db_item_fc) (GDbItem *, int, int);
+typedef bool (* unpack_db_item_fc) (GDbItem *, packed_buffer *);
 
 /* Exporte la définition d'une base d'éléments pour collection. */
-typedef bool (* send_db_item_fc) (const GDbItem *, int, int);
+typedef bool (* pack_db_item_fc) (const GDbItem *, packed_buffer *);
 
 /* Construit la description humaine d'un signet sur un tampon. */
 typedef void (* build_item_label_fc) (GDbItem *);
@@ -84,8 +84,8 @@ struct _GDbItemClass
 
     cmp_db_item_fc cmp;                     /* Comparaison entre éléments  */
 
-    recv_db_item_fc recv;                   /* Réception depuis le réseau  */
-    send_db_item_fc send;                   /* Emission depuis le réseau   */
+    unpack_db_item_fc unpack;               /* Réception depuis le réseau  */
+    pack_db_item_fc pack;                   /* Emission depuis le réseau   */
 
     build_item_label_fc build_label;        /* Construction de description */
     run_item_fc apply;                      /* Application de l'élément    */
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index ce08339..20276d6 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -31,7 +31,6 @@
 
 
 #include "item-int.h"
-#include "../../common/io.h"
 #include "../../core/params.h"
 
 
@@ -49,10 +48,10 @@ static void g_db_item_dispose(GDbItem *);
 static void g_db_item_finalize(GDbItem *);
 
 /* Importe la définition d'une base d'éléments pour collection. */
-static bool g_db_item_recv_from_fd(GDbItem *, int, int);
+static bool _g_db_item_unpack(GDbItem *, packed_buffer *);
 
 /* Exporte la définition d'une base d'éléments pour collection. */
-static bool g_db_item_send_to_fd(const GDbItem *, int, int);
+static bool _g_db_item_pack(const GDbItem *, packed_buffer *);
 
 
 
@@ -94,8 +93,8 @@ static void g_db_item_class_init(GDbItemClass *klass)
 
     klass->cmp = (cmp_db_item_fc)g_db_item_cmp;
 
-    klass->recv = (recv_db_item_fc)g_db_item_recv_from_fd;
-    klass->send = (send_db_item_fc)g_db_item_send_to_fd;
+    klass->unpack = (unpack_db_item_fc)_g_db_item_unpack;
+    klass->pack = (pack_db_item_fc)_g_db_item_pack;
 
     klass->prepare_stmt = (prepare_db_statement)_g_db_item_prepare_db_statement;
     klass->load = (load_db_item_fc)_g_db_item_load;
@@ -290,9 +289,8 @@ gint g_db_item_compare_without_timestamp(GDbItem *a, GDbItem *b)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : item   = base d'éléments à charger. [OUT]                    *
-*                fd     = flux ouvert en lecture pour l'importation.          *
-*                flags  = éventuelles options d'envoi supplémentaires.        *
+*  Paramètres  : item = base d'éléments à charger. [OUT]                      *
+*                pbuf = paquet de données où venir puiser les infos.          *
 *                                                                             *
 *  Description : Importe la définition d'une base d'éléments pour collection. *
 *                                                                             *
@@ -302,32 +300,30 @@ gint g_db_item_compare_without_timestamp(GDbItem *a, GDbItem *b)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
+static bool _g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'une réception       */
+    bool result;                            /* Bilan à retourner           */
 
-    status = recv_timestamp(&item->created, fd, flags);
-    if (!status) return false;
+    result = unpack_timestamp(&item->created, pbuf);
 
-    status = recv_timestamp(&item->timestamp, fd, flags);
-    if (!status) return false;
+    if (result)
+        result = unpack_timestamp(&item->timestamp, pbuf);
 
-    status = recv_rle_string(&item->author, fd, flags);
-    if (!status) return false;
+    if (result)
+        result = unpack_rle_string(&item->author, pbuf);
 
-    status = recv_rle_string(&item->tool, fd, flags);
-    if (!status) return false;
+    if (result)
+        result = unpack_rle_string(&item->tool, pbuf);
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : item  = base d'éléments à charger. [OUT]                     *
-*                fd    = flux ouvert en lecture pour l'importation.           *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : item = base d'éléments à charger. [OUT]                      *
+*                pbuf = paquet de données où venir puiser les infos.          *
 *                                                                             *
 *  Description : Importe la définition d'une base d'éléments pour collection. *
 *                                                                             *
@@ -337,11 +333,11 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-bool g_db_item_recv(GDbItem *item, int fd, int flags)
+bool g_db_item_unpack(GDbItem *item, packed_buffer *pbuf)
 {
     bool result;                            /* Bilan à retourner           */
 
-    result = G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags);
+    result = G_DB_ITEM_GET_CLASS(item)->unpack(item, pbuf);
 
     return result;
 
@@ -350,9 +346,8 @@ bool g_db_item_recv(GDbItem *item, int fd, int flags)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : item  = informations à sauvegarer.                           *
-*                fd    = flux ouvert en écriture pour l'exportation.          *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : item = informations à sauvegarer.                            *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Exporte la définition d'une base d'éléments pour collection. *
 *                                                                             *
@@ -362,32 +357,30 @@ bool g_db_item_recv(GDbItem *item, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags)
+static bool _g_db_item_pack(const GDbItem *item, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'une émission        */
+    bool result;                            /* Bilan à retourner           */
 
-    status = send_timestamp(&item->created, fd, MSG_MORE | flags);
-    if (!status) return false;
+    result = pack_timestamp(&item->created, pbuf);
 
-    status = send_timestamp(&item->timestamp, fd, MSG_MORE | flags);
-    if (!status) return false;
+    if (result)
+        result = pack_timestamp(&item->timestamp, pbuf);
 
-    status = send_rle_string(&item->author, fd, MSG_MORE | flags);
-    if (!status) return false;
+    if (result)
+        result = pack_rle_string(&item->author, pbuf);
 
-    status = send_rle_string(&item->tool, fd, flags);
-    if (!status) return false;
+    if (result)
+        result = pack_rle_string(&item->tool, pbuf);
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : item  = informations à sauvegarer.                           *
-*                fd    = flux ouvert en écriture pour l'exportation.          *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : item = informations à sauvegarer.                            *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Exporte la définition d'une base d'éléments pour collection. *
 *                                                                             *
@@ -397,9 +390,9 @@ static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-bool g_db_item_send(const GDbItem *item, int fd, int flags)
+bool g_db_item_pack(const GDbItem *item, packed_buffer *pbuf)
 {
-    return G_DB_ITEM_GET_CLASS(item)->send(item, fd, flags);
+    return G_DB_ITEM_GET_CLASS(item)->pack(item, pbuf);
 
 }
 
diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h
index e31814c..286f907 100644
--- a/src/analysis/db/item.h
+++ b/src/analysis/db/item.h
@@ -31,6 +31,7 @@
 
 #include "protocol.h"
 #include "misc/timestamp.h"
+#include "../../common/packed.h"
 #include "../../common/sqlite.h"
 
 
@@ -73,10 +74,10 @@ gint g_db_item_compare_with_timestamp(GDbItem *, GDbItem *);
 gint g_db_item_compare_without_timestamp(GDbItem *, GDbItem *);
 
 /* Importe la définition d'une base d'éléments pour collection. */
-bool g_db_item_recv(GDbItem *, int, int);
+bool g_db_item_unpack(GDbItem *, packed_buffer *);
 
 /* Exporte la définition d'une base d'éléments pour collection. */
-bool g_db_item_send(const GDbItem *, int, int);
+bool g_db_item_pack(const GDbItem *, packed_buffer *);
 
 /* Applique un élément de collection sur un binaire. */
 bool g_db_item_apply(GDbItem *, GLoadedBinary *);
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 6289588..9d3b691 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -76,10 +76,10 @@ static void g_db_bookmark_finalize(GDbBookmark *);
 static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *, bool);
 
 /* Importe la définition d'un signet dans un flux réseau. */
-static bool g_db_bookmark_recv_from_fd(GDbBookmark *, int, int);
+static bool g_db_bookmark_unpack(GDbBookmark *, packed_buffer *);
 
 /* Exporte la définition d'un signet dans un flux réseau. */
-static bool g_db_bookmark_send_to_fd(const GDbBookmark *, int, int);
+static bool g_db_bookmark_pack(const GDbBookmark *, packed_buffer *);
 
 /* Construit la description humaine d'un signet sur un tampon. */
 static void g_db_bookmark_build_label(GDbBookmark *);
@@ -179,8 +179,8 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass)
 
     item->cmp = (cmp_db_item_fc)g_db_bookmark_cmp;
 
-    item->recv = (recv_db_item_fc)g_db_bookmark_recv_from_fd;
-    item->send = (send_db_item_fc)g_db_bookmark_send_to_fd;
+    item->unpack = (unpack_db_item_fc)g_db_bookmark_unpack;
+    item->pack = (pack_db_item_fc)g_db_bookmark_pack;
 
     item->build_label = (build_item_label_fc)g_db_bookmark_build_label;
     item->apply = (run_item_fc)g_db_bookmark_apply;
@@ -312,8 +312,7 @@ static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b, bool with)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : bookmark = signet dont les informations sont à charger. [OUT]*
-*                fd       = flux ouvert en lecture pour l'importation.        *
-*                flags    = éventuelles options d'envoi supplémentaires.      *
+*                pbuf     = paquet de données où venir inscrire les infos.    *
 *                                                                             *
 *  Description : Importe la définition d'un signet dans un flux réseau.       *
 *                                                                             *
@@ -323,20 +322,19 @@ static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b, bool with)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_bookmark_recv_from_fd(GDbBookmark *bookmark, int fd, int flags)
+static bool g_db_bookmark_unpack(GDbBookmark *bookmark, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->recv(G_DB_ITEM(bookmark), fd, flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->unpack(G_DB_ITEM(bookmark), pbuf);
 
-    if (!recv_vmpa(&bookmark->addr, fd, flags))
-        return false;
+    if (result)
+        result = unpack_vmpa(&bookmark->addr, pbuf);
 
-    if (!recv_rle_string(&bookmark->comment, fd, flags))
-        return false;
+    if (result)
+        result = unpack_rle_string(&bookmark->comment, pbuf);
 
-    return true;
+    return result;
 
 }
 
@@ -344,8 +342,7 @@ static bool g_db_bookmark_recv_from_fd(GDbBookmark *bookmark, int fd, int flags)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : bookmark = informations à sauvegarder.                       *
-*                fd       = flux ouvert en écriture pour l'exportation.       *
-*                flags    = éventuelles options d'envoi supplémentaires.      *
+*                pbuf     = paquet de données où venir inscrire les infos.    *
 *                                                                             *
 *  Description : Exporte la définition d'un signet dans un flux réseau.       *
 *                                                                             *
@@ -355,20 +352,19 @@ static bool g_db_bookmark_recv_from_fd(GDbBookmark *bookmark, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int flags)
+static bool g_db_bookmark_pack(const GDbBookmark *bookmark, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->send(G_DB_ITEM(bookmark), fd, MSG_MORE | flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->pack(G_DB_ITEM(bookmark), pbuf);
 
-    if (!send_vmpa(&bookmark->addr, fd, MSG_MORE | flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&bookmark->addr, pbuf);
 
-    if (!send_rle_string(&bookmark->comment, fd, flags))
-        return false;
+    if (result)
+        result = pack_rle_string(&bookmark->comment, pbuf);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index c021e44..15d541b 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -36,7 +36,6 @@
 #include "../collection-int.h"
 #include "../item-int.h"
 #include "../../human/asm/lang.h"
-#include "../../../common/io.h"
 #include "../../../common/extstr.h"
 #include "../../../glibext/linegen-int.h"
 
@@ -97,10 +96,10 @@ static void g_db_comment_finalize(GDbComment *);
 static gint g_db_comment_cmp(GDbComment *, GDbComment *, bool);
 
 /* Importe la définition d'un commentaire dans un flux réseau. */
-static bool g_db_comment_recv_from_fd(GDbComment *, int, int);
+static bool g_db_comment_unpack(GDbComment *, packed_buffer *);
 
 /* Exporte la définition d'un commentaire dans un flux réseau. */
-static bool g_db_comment_send_to_fd(const GDbComment *, int, int);
+static bool g_db_comment_pack(const GDbComment *, packed_buffer *);
 
 /* Construit la description humaine d'un commentaire. */
 static void g_db_comment_build_label(GDbComment *);
@@ -227,8 +226,8 @@ static void g_db_comment_class_init(GDbCommentClass *klass)
 
     item->cmp = (cmp_db_item_fc)g_db_comment_cmp;
 
-    item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd;
-    item->send = (send_db_item_fc)g_db_comment_send_to_fd;
+    item->unpack = (unpack_db_item_fc)g_db_comment_unpack;
+    item->pack = (pack_db_item_fc)g_db_comment_pack;
 
     item->build_label = (build_item_label_fc)g_db_comment_build_label;
     item->apply = (run_item_fc)g_db_comment_apply;
@@ -443,8 +442,7 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : comment = commentaire avec informations sont à charger. [OUT]*
-*                fd      = flux ouvert en lecture pour l'importation.         *
-*                flags   = éventuelles options d'envoi supplémentaires.       *
+*                pbuf    = paquet de données où venir inscrire les infos.     *
 *                                                                             *
 *  Description : Importe la définition d'un commentaire dans un flux réseau.  *
 *                                                                             *
@@ -454,37 +452,39 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
+static bool g_db_comment_unpack(GDbComment *comment, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
-    uint32_t val32;                         /* Valeur sur 32 bits          */
-    uint8_t val8;                           /* Valeur sur 8 bits           */
-
-    status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->recv(G_DB_ITEM(comment), fd, flags);
-    if (!status) return false;
-
-    if (!recv_vmpa(&comment->addr, fd, flags))
-        return false;
+    bool result;                            /* Bilan à retourner           */
+    uint32_t tmp32;                         /* Valeur sur 32 bits          */
+    uint8_t tmp8;                           /* Valeur sur 8 bits           */
 
-    status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
-    if (!status) return false;
-
-    comment->flags = be32toh(val32);
+    result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->unpack(G_DB_ITEM(comment), pbuf);
 
-    if (!recv_rle_string(&comment->text, fd, flags))
-        return false;
+    if (result)
+        result = unpack_vmpa(&comment->addr, pbuf);
 
-    status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    if (result)
+    {
+        result = extend_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
+        comment->flags = tmp32;
+    }
 
-    comment->inlined = val8;
+    if (result)
+        result = unpack_rle_string(&comment->text, pbuf);
 
-    status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    if (result)
+    {
+        result = extend_packed_buffer(pbuf, &tmp8, sizeof(uint8_t), true);
+        comment->inlined = tmp8;
+    }
 
-    comment->repeatable = val8;
+    if (result)
+    {
+        result = extend_packed_buffer(pbuf, &tmp8, sizeof(uint8_t), true);
+        comment->repeatable = tmp8;
+    }
 
-    return true;
+    return result;
 
 }
 
@@ -492,8 +492,7 @@ static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : comment = informations à sauvegarder.                        *
-*                fd      = flux ouvert en écriture pour l'exportation.        *
-*                flags   = éventuelles options d'envoi supplémentaires.       *
+*                pbuf    = paquet de données où venir inscrire les infos.     *
 *                                                                             *
 *  Description : Exporte la définition d'un commentaire dans un flux réseau.  *
 *                                                                             *
@@ -503,29 +502,28 @@ static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags)
+static bool g_db_comment_pack(const GDbComment *comment, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->send(G_DB_ITEM(comment), fd, MSG_MORE | flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->pack(G_DB_ITEM(comment), pbuf);
 
-    if (!send_vmpa(&comment->addr, fd, MSG_MORE | flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&comment->addr, pbuf);
 
-    status = safe_send(fd, (uint32_t []) { htobe32(comment->flags) }, sizeof(uint32_t), MSG_MORE | flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint32_t []) { comment->flags }, sizeof(uint32_t), true);
 
-    if (!send_rle_string(&comment->text, fd, MSG_MORE | flags))
-        return false;
+    if (result)
+        result = pack_rle_string(&comment->text, pbuf);
 
-    status = safe_send(fd, (uint8_t []) { (uint8_t)comment->inlined }, sizeof(uint8_t), MSG_MORE | flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint8_t []) { comment->inlined }, sizeof(uint8_t), true);
 
-    status = safe_send(fd, (uint8_t []) { (uint8_t)comment->repeatable }, sizeof(uint8_t), flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint8_t []) { comment->repeatable }, sizeof(uint8_t), true);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/items/move.c b/src/analysis/db/items/move.c
index c781170..ddbcab1 100644
--- a/src/analysis/db/items/move.c
+++ b/src/analysis/db/items/move.c
@@ -35,7 +35,6 @@
 
 #include "../collection-int.h"
 #include "../item-int.h"
-#include "../../../common/io.h"
 #include "../../../gui/editem.h"
 #include "../../../gtkext/gtkdisplaypanel.h"
 
@@ -81,10 +80,10 @@ static void g_db_move_finalize(GDbMove *);
 static gint g_db_move_cmp(GDbMove *, GDbMove *, bool);
 
 /* Importe la définition d'un déplacement depuis un flux réseau. */
-static bool g_db_move_recv_from_fd(GDbMove *, int, int);
+static bool g_db_move_unpack(GDbMove *, packed_buffer *);
 
 /* Exporte la définition d'un déplacement dans un flux réseau. */
-static bool g_db_move_send_to_fd(const GDbMove *, int, int);
+static bool g_db_move_pack(const GDbMove *, packed_buffer *);
 
 /* Construit la description humaine d'un déplacement. */
 static void g_db_move_build_label(GDbMove *);
@@ -185,8 +184,8 @@ static void g_db_move_class_init(GDbMoveClass *klass)
 
     item->cmp = (cmp_db_item_fc)g_db_move_cmp;
 
-    item->recv = (recv_db_item_fc)g_db_move_recv_from_fd;
-    item->send = (send_db_item_fc)g_db_move_send_to_fd;
+    item->unpack = (unpack_db_item_fc)g_db_move_unpack;
+    item->pack = (pack_db_item_fc)g_db_move_pack;
 
     item->build_label = (build_item_label_fc)g_db_move_build_label;
     item->apply = (run_item_fc)g_db_move_apply;
@@ -314,9 +313,8 @@ static gint g_db_move_cmp(GDbMove *a, GDbMove *b, bool with)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : move  = bascule d'affichage aux infos à charger. [OUT]       *
-*                fd    = flux ouvert en lecture pour l'importation.           *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : move = bascule d'affichage aux infos à charger. [OUT]        *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Importe la définition d'un déplacement depuis un flux réseau.*
 *                                                                             *
@@ -326,29 +324,27 @@ static gint g_db_move_cmp(GDbMove *a, GDbMove *b, bool with)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_move_recv_from_fd(GDbMove *move, int fd, int flags)
+static bool g_db_move_unpack(GDbMove *move, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_move_parent_class)->recv(G_DB_ITEM(move), fd, flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_move_parent_class)->unpack(G_DB_ITEM(move), pbuf);
 
-    if (!recv_vmpa(&move->src, fd, flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&move->src, pbuf);
 
-    if (!recv_vmpa(&move->dest, fd, flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&move->dest, pbuf);
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : move  = bascule d'affichage aux infos à sauvegarder.         *
-*                fd    = flux ouvert en écriture pour l'exportation.          *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : move = bascule d'affichage aux infos à sauvegarder.          *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Exporte la définition d'un déplacement dans un flux réseau.  *
 *                                                                             *
@@ -358,20 +354,19 @@ static bool g_db_move_recv_from_fd(GDbMove *move, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_move_send_to_fd(const GDbMove *move, int fd, int flags)
+static bool g_db_move_pack(const GDbMove *move, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_move_parent_class)->send(G_DB_ITEM(move), fd, MSG_MORE | flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_move_parent_class)->pack(G_DB_ITEM(move), pbuf);
 
-    if (!send_vmpa(&move->src, fd, MSG_MORE | flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&move->src, pbuf);
 
-    if (!send_vmpa(&move->dest, fd, flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&move->dest, pbuf);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 5a03e8e..01c1910 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -34,9 +34,6 @@
 
 #include "../collection-int.h"
 #include "../item-int.h"
-#include "../../../common/io.h"
-
-
 
 
 
@@ -81,10 +78,10 @@ static void g_db_switcher_finalize(GDbSwitcher *);
 static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *, bool);
 
 /* Importe la définition d'un signet depuis un flux réseau. */
-static bool g_db_switcher_recv_from_fd(GDbSwitcher *, int, int);
+static bool g_db_switcher_unpack(GDbSwitcher *, packed_buffer *);
 
 /* Exporte la définition d'un signet dans un flux réseau. */
-static bool g_db_switcher_send_to_fd(const GDbSwitcher *, int, int);
+static bool g_db_switcher_pack(const GDbSwitcher *, packed_buffer *);
 
 /* Construit la description humaine d'un signet sur un tampon. */
 static void g_db_switcher_build_label(GDbSwitcher *);
@@ -185,8 +182,8 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass)
 
     item->cmp = (cmp_db_item_fc)g_db_switcher_cmp;
 
-    item->recv = (recv_db_item_fc)g_db_switcher_recv_from_fd;
-    item->send = (send_db_item_fc)g_db_switcher_send_to_fd;
+    item->unpack = (unpack_db_item_fc)g_db_switcher_unpack;
+    item->pack = (pack_db_item_fc)g_db_switcher_pack;
 
     item->build_label = (build_item_label_fc)g_db_switcher_build_label;
     item->apply = (run_item_fc)g_db_switcher_apply;
@@ -358,8 +355,7 @@ static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b, bool with)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : switcher = bascule d'affichage aux infos à charger. [OUT]    *
-*                fd       = flux ouvert en lecture pour l'importation.        *
-*                flags    = éventuelles options d'envoi supplémentaires.      *
+*                pbuf     = paquet de données où venir inscrire les infos.    *
 *                                                                             *
 *  Description : Importe la définition d'un signet depuis un flux réseau.     *
 *                                                                             *
@@ -369,31 +365,33 @@ static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b, bool with)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_switcher_recv_from_fd(GDbSwitcher *switcher, int fd, int flags)
+static bool g_db_switcher_unpack(GDbSwitcher *switcher, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
-    uint32_t val32;                         /* Valeur sur 32 bits          */
+    bool result;                            /* Bilan à retourner           */
+    uint32_t tmp32;                         /* Valeur sur 32 bits          */
 
-    status = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->recv(G_DB_ITEM(switcher), fd, flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->unpack(G_DB_ITEM(switcher), pbuf);
 
-    if (!recv_vmpa(&switcher->addr, fd, flags))
-        return false;
-
-    status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    if (result)
+        result = unpack_vmpa(&switcher->addr, pbuf);
 
-    switcher->index = be32toh(val32);
+    if (result)
+    {
+        result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
+        switcher->index = tmp32;
+    }
 
-    status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    if (result)
+    {
+        result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
+        switcher->display = tmp32;
 
-    switcher->display = be32toh(val32);
+        if (switcher->display > IOD_COUNT)
+            result = false;
 
-    if (switcher->display > IOD_COUNT)
-        return false;
+    }
 
-    return true;
+    return result;
 
 }
 
@@ -401,8 +399,7 @@ static bool g_db_switcher_recv_from_fd(GDbSwitcher *switcher, int fd, int flags)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : switcher = bascule d'affichage aux infos à sauvegarder.      *
-*                fd       = flux ouvert en écriture pour l'exportation.       *
-*                flags    = éventuelles options d'envoi supplémentaires.      *
+*                pbuf     = paquet de données où venir inscrire les infos.    *
 *                                                                             *
 *  Description : Exporte la définition d'une bascule d'affichage d'opérande.  *
 *                                                                             *
@@ -412,23 +409,22 @@ static bool g_db_switcher_recv_from_fd(GDbSwitcher *switcher, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_db_switcher_send_to_fd(const GDbSwitcher *switcher, int fd, int flags)
+static bool g_db_switcher_pack(const GDbSwitcher *switcher, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'opération initiale  */
+    bool result;                            /* Bilan à retourner           */
 
-    status = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->send(G_DB_ITEM(switcher), fd, MSG_MORE | flags);
-    if (!status) return false;
+    result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->pack(G_DB_ITEM(switcher), pbuf);
 
-    if (!send_vmpa(&switcher->addr, fd, MSG_MORE | flags))
-        return false;
+    if (result)
+        result = pack_vmpa(&switcher->addr, pbuf);
 
-    status = safe_send(fd, (uint32_t []) { htobe32(switcher->index) }, sizeof(uint32_t), MSG_MORE | flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint32_t []) { switcher->index }, sizeof(uint32_t), true);
 
-    status = safe_send(fd, (uint32_t []) { htobe32(switcher->display) }, sizeof(uint32_t), flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint32_t []) { switcher->display }, sizeof(uint32_t), true);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/misc/rlestr.c b/src/analysis/db/misc/rlestr.c
index 2f06542..39e2d99 100644
--- a/src/analysis/db/misc/rlestr.c
+++ b/src/analysis/db/misc/rlestr.c
@@ -24,15 +24,11 @@
 #include "rlestr.h"
 
 
-#include <endian.h>
 #include <malloc.h>
 #include <sqlite3.h>
 #include <string.h>
 
 
-#include "../../../common/io.h"
-
-
 
 /******************************************************************************
 *                                                                             *
@@ -162,9 +158,8 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : str   = informations à constituer. [OUT]                     *
-*                fd    = flux ouvert en lecture pour l'importation.           *
-*                flags = éventuelles options de réception supplémentaires.    *
+*  Paramètres  : str  = informations à constituer. [OUT]                      *
+*                pbuf = paquet de données où venir puiser les infos.          *
 *                                                                             *
 *  Description : Importe la définition d'une chaîne de caractères.            *
 *                                                                             *
@@ -174,44 +169,41 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2)
 *                                                                             *
 ******************************************************************************/
 
-bool recv_rle_string(rle_string *str, int fd, int flags)
+bool unpack_rle_string(rle_string *str, packed_buffer *pbuf)
 {
-    uint32_t val32;                         /* Valeur sur 32 bits          */
-    bool status;                            /* Bilan d'une opération       */
+    bool result;                            /* Bilan à retourner           */
+    uint32_t tmp32;                         /* Valeur sur 32 bits          */
 
     str->data = NULL;
     str->length = 0;
 
-    status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true);
 
-    str->length = be32toh(val32);
+    str->length = tmp32;
 
-    if (str->length > 0)
+    if (result && str->length > 0)
     {
         str->data = (char *)malloc(str->length + 1);
 
-        status = safe_recv(fd, str->data, str->length + 1, MSG_WAITALL | flags);
-        if (!status)
-        {
+        result = extract_packed_buffer(pbuf, str->data, str->length + 1, false);
+
+        if (!result)
             unset_rle_string(str);
-            return false;
-        }
 
-        str->data[str->length] = '\0';
+        else
+            str->data[str->length] = '\0';
 
     }
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : str   = informations à sauvegarer.                           *
-*                fd    = flux ouvert en écriture pour l'exportation.          *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : str  = informations à sauvegarer.                            *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Exporte la définition d'une chaîne de caractères.            *
 *                                                                             *
@@ -221,20 +213,16 @@ bool recv_rle_string(rle_string *str, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-bool send_rle_string(const rle_string *str, int fd, int flags)
+bool pack_rle_string(const rle_string *str, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'une opération       */
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_send(fd, (uint32_t []) { htobe32(str->length) }, sizeof(uint32_t), MSG_MORE | flags);
-    if (!status) return false;
+    result = extend_packed_buffer(pbuf, (uint32_t []) { str->length }, sizeof(uint32_t), true);
 
-    if (str->length > 0)
-    {
-        status = safe_send(fd, str->data, str->length + 1, flags);
-        if (!status) return false;
-    }
+    if (result && str->length > 0)
+        result = extend_packed_buffer(pbuf, str->data, str->length + 1, false);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/misc/rlestr.h b/src/analysis/db/misc/rlestr.h
index 01f37e6..be76f17 100644
--- a/src/analysis/db/misc/rlestr.h
+++ b/src/analysis/db/misc/rlestr.h
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 
 
+#include "../../../common/packed.h"
 #include "../../../common/sqlite.h"
 
 
@@ -66,10 +67,10 @@ void unset_rle_string(rle_string *);
 int cmp_rle_string(const rle_string *, const rle_string *);
 
 /* Importe la définition d'une chaîne de caractères. */
-bool recv_rle_string(rle_string *, int, int);
+bool unpack_rle_string(rle_string *, packed_buffer *);
 
 /* Exporte la définition d'une chaîne de caractères. */
-bool send_rle_string(const rle_string *, int, int);
+bool pack_rle_string(const rle_string *, packed_buffer *);
 
 
 
diff --git a/src/analysis/db/misc/timestamp.c b/src/analysis/db/misc/timestamp.c
index 6c7a47f..aa9f758 100644
--- a/src/analysis/db/misc/timestamp.c
+++ b/src/analysis/db/misc/timestamp.c
@@ -24,15 +24,11 @@
 #include "timestamp.h"
 
 
-#include <endian.h>
 #include <malloc.h>
 #include <sqlite3.h>
 #include <time.h>
 
 
-#include "../../../common/io.h"
-
-
 
 /******************************************************************************
 *                                                                             *
@@ -117,8 +113,7 @@ int cmp_timestamp(const timestamp_t *t1, const timestamp_t *t2)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : timestamp = informations à constituer. [OUT]                 *
-*                fd        = flux ouvert en lecture pour l'importation.       *
-*                flags     = éventuelles options de réception supplémentaires.*
+*                pbuf      = paquet de données où venir puiser les infos.     *
 *                                                                             *
 *  Description : Importe la définition d'un horodatage.                       *
 *                                                                             *
@@ -128,17 +123,13 @@ int cmp_timestamp(const timestamp_t *t1, const timestamp_t *t2)
 *                                                                             *
 ******************************************************************************/
 
-bool recv_timestamp(timestamp_t *timestamp, int fd, int flags)
+bool unpack_timestamp(timestamp_t *timestamp, packed_buffer *pbuf)
 {
-    uint64_t val64;                         /* Valeur sur 64 bits          */
-    bool status;                            /* Bilan d'une opération       */
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    result = extract_packed_buffer(pbuf, (uint64_t *)timestamp, sizeof(uint64_t), true);
 
-    *timestamp = be64toh(val64);
-
-    return true;
+    return result;
 
 }
 
@@ -146,8 +137,7 @@ bool recv_timestamp(timestamp_t *timestamp, int fd, int flags)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : timestamp = informations à sauvegarer.                       *
-*                fd        = flux ouvert en écriture pour l'exportation.      *
-*                flags     = éventuelles options d'envoi supplémentaires.     *
+*                pbuf      = paquet de données où venir inscrire les infos.   *
 *                                                                             *
 *  Description : Exporte la définition d'un horodatage.                       *
 *                                                                             *
@@ -157,14 +147,13 @@ bool recv_timestamp(timestamp_t *timestamp, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-bool send_timestamp(const timestamp_t *timestamp, int fd, int flags)
+bool pack_timestamp(const timestamp_t *timestamp, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'une opération       */
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_send(fd, (uint64_t []) { htobe64(*timestamp) }, sizeof(uint64_t), flags);
-    if (!status) return false;
+    result = extend_packed_buffer(pbuf, (uint64_t *)timestamp, sizeof(uint64_t), true);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/analysis/db/misc/timestamp.h b/src/analysis/db/misc/timestamp.h
index 5d4f2f1..14a1fb5 100644
--- a/src/analysis/db/misc/timestamp.h
+++ b/src/analysis/db/misc/timestamp.h
@@ -29,6 +29,7 @@
 #include <stdint.h>
 
 
+#include "../../../common/packed.h"
 #include "../../../common/sqlite.h"
 
 
@@ -52,10 +53,10 @@ bool timestamp_is_younger(timestamp_t, timestamp_t);
 int cmp_timestamp(const timestamp_t *, const timestamp_t *);
 
 /* Importe la définition d'un horodatage. */
-bool recv_timestamp(timestamp_t *, int, int);
+bool unpack_timestamp(timestamp_t *, packed_buffer *);
 
 /* Exporte la définition d'un horodatage. */
-bool send_timestamp(const timestamp_t *, int, int);
+bool pack_timestamp(const timestamp_t *, packed_buffer *);
 
 
 
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index 1621ed7..748af4e 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -478,12 +478,15 @@ static void *g_db_server_listener(GDbServer *server)
     char *peer_name;                        /* Désignation du correspondant*/
     DBError error;                          /* Validation de la connexion  */
     GCdbArchive *archive;                   /* Destinataire final du client*/
+    packed_buffer in_pbuf;                  /* Tampon de réception         */
+    bool status;                            /* Bilan d'une opération       */
     uint32_t cmd;                           /* Commande initiale lue       */
     uint32_t version;                       /* Version du client lue       */
     rle_string hash;                        /* Empreinte du binaire visé   */
     rle_string user;                        /* Nom d'utilisateur du client */
     unsigned char sig[RSA_USED_SIZE];       /* Signature effectuée         */
     GList *iter;                            /* Boucle de parcours          */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
 
     fds.fd = server->fd;
     fds.events = POLLIN | POLLPRI;
@@ -540,7 +543,17 @@ static void *g_db_server_listener(GDbServer *server)
              * Tout ceci est à synchroniser avec la fonction g_db_client_start().
              */
 
-            if (!safe_recv(fd, &cmd, sizeof(uint32_t), 0))
+            status = recv_packed_buffer(&in_pbuf, fd);
+            if (!status)
+            {
+                log_variadic_message(LMT_ERROR, _("Error while getting the initial packet from '%s'..."),
+                                     peer_name);
+                error = DBE_BAD_EXCHANGE;
+                goto gdsl_error_sending;
+            }
+
+            status = extract_packed_buffer(&in_pbuf, &cmd, sizeof(uint32_t), true);
+            if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s'..."),
                                      peer_name);
@@ -548,7 +561,8 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (!safe_recv(fd, &version, sizeof(uint32_t), 0))
+            status = extract_packed_buffer(&in_pbuf, &version, sizeof(uint32_t), true);
+            if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s'..."),
                                      peer_name);
@@ -556,7 +570,8 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (!recv_rle_string(&hash, fd, 0))
+            status = unpack_rle_string(&hash, &in_pbuf);
+            if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."),
                                      peer_name);
@@ -564,7 +579,8 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (!recv_rle_string(&user, fd, 0))
+            status = unpack_rle_string(&user, &in_pbuf);
+            if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s'..."),
                                      peer_name);
@@ -572,7 +588,8 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (!safe_recv(fd, sig, RSA_USED_SIZE, 0))
+            status = extract_packed_buffer(&in_pbuf, sig, RSA_USED_SIZE, false);
+            if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s'..."),
                                      peer_name);
@@ -580,7 +597,7 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (be32toh(cmd) != DBC_HELO)
+            if (cmd != DBC_HELO)
             {
                 log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"),
                                      peer_name);
@@ -588,7 +605,7 @@ static void *g_db_server_listener(GDbServer *server)
                 goto gdsl_error_sending;
             }
 
-            if (be32toh(version) != CDB_PROTOCOL_VERSION)
+            if (version != CDB_PROTOCOL_VERSION)
             {
                 log_variadic_message(LMT_ERROR, _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
                                      peer_name, be32toh(version), CDB_PROTOCOL_VERSION);
@@ -647,11 +664,20 @@ static void *g_db_server_listener(GDbServer *server)
 
  gdsl_error_sending:
 
-            if (!safe_send(fd, (uint32_t []) { htobe32(DBC_WELCOME) }, sizeof(uint32_t), MSG_MORE))
-                goto gdsl_error;
+            exit_packed_buffer(&in_pbuf);
 
-            if (!safe_send(fd, (uint32_t []) { htobe32(error) }, sizeof(uint32_t), 0))
-                goto gdsl_error;
+            init_packed_buffer(&out_pbuf);
+
+            status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_WELCOME }, sizeof(uint32_t), true);
+            if (!status) goto gdsl_error;
+
+            status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
+            if (!status) goto gdsl_error;
+
+            status = send_packed_buffer(&out_pbuf, fd);
+            if (!status) goto gdsl_error;
+
+            exit_packed_buffer(&out_pbuf);
 
             /**
              * L'ajout dans la liste des clients connectés provoque un envoie de mises à jour.
@@ -679,6 +705,8 @@ static void *g_db_server_listener(GDbServer *server)
 
  gdsl_error:
 
+            exit_packed_buffer(&out_pbuf);
+
             free(peer_name);
 
             exit_rle_string(&hash);
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index c32c836..27262d1 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -34,9 +34,6 @@
 #include <i18n.h>
 
 
-#include "../common/io.h"
-
-
 
 /* ---------------------- DEFINITION D'UNE POSITION EN MEMOIRE ---------------------- */
 
@@ -347,9 +344,8 @@ phys_t compute_vmpa_diff(const vmpa2t *a, const vmpa2t *b)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : addr  = élément à venir lire. [OUT]                          *
-*                fd    = flux ouvert en lecture pour l'importation.           *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : addr = élément à venir lire. [OUT]                           *
+*                pbuf = paquet de données où venir puiser les infos.          *
 *                                                                             *
 *  Description : Lit la définition d'une adresse depuis un flux réseau.       *
 *                                                                             *
@@ -359,31 +355,24 @@ phys_t compute_vmpa_diff(const vmpa2t *a, const vmpa2t *b)
 *                                                                             *
 ******************************************************************************/
 
-bool recv_vmpa(vmpa2t *addr, int fd, int flags)
+bool unpack_vmpa(vmpa2t *addr, packed_buffer *pbuf)
 {
-    virt_t val64;                           /* Valeur sur 64 bits          */
-    bool status;                            /* Bilan d'une réception       */
-
-    status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
-    if (!status) return false;
-
-    addr->physical = be64toh(val64);
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
-    if (!status) return false;
+    result = extract_packed_buffer(pbuf, (uint64_t *)&addr->physical, sizeof(uint64_t), true);
 
-    addr->virtual = be64toh(val64);
+    if (result)
+        result = extract_packed_buffer(pbuf, (uint64_t *)&addr->virtual, sizeof(uint64_t), true);
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : addr  = élément à venir écrire.                              *
-*                fd    = flux ouvert en écriture pour l'exportation.          *
-*                flags = éventuelles options d'envoi supplémentaires.         *
+*  Paramètres  : addr = élément à venir écrire.                               *
+*                pbuf = paquet de données où venir inscrire les infos.        *
 *                                                                             *
 *  Description : Ecrit la définition d'une adresse dans un flux réseau.       *
 *                                                                             *
@@ -393,17 +382,16 @@ bool recv_vmpa(vmpa2t *addr, int fd, int flags)
 *                                                                             *
 ******************************************************************************/
 
-bool send_vmpa(const vmpa2t *addr, int fd, int flags)
+bool pack_vmpa(const vmpa2t *addr, packed_buffer *pbuf)
 {
-    bool status;                            /* Bilan d'une émission        */
+    bool result;                            /* Bilan à retourner           */
 
-    status = safe_send(fd, (uint64_t []) { htobe64(addr->physical) }, sizeof(uint64_t), MSG_MORE | flags);
-    if (!status) return false;
+    result = extend_packed_buffer(pbuf, (uint64_t *)&addr->physical, sizeof(uint64_t), true);
 
-    status = safe_send(fd, (uint64_t []) { htobe64(addr->virtual) }, sizeof(uint64_t), flags);
-    if (!status) return false;
+    if (result)
+        result = extend_packed_buffer(pbuf, (uint64_t *)&addr->virtual, sizeof(uint64_t), true);
 
-    return true;
+    return result;
 
 }
 
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 6305f79..3bfb40c 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -33,6 +33,7 @@
 
 #include "archbase.h"
 #include "../common/cpp.h"
+#include "../common/packed.h"
 #include "../common/sqlite.h"
 
 
@@ -122,10 +123,10 @@ void align_vmpa(vmpa2t *, phys_t);
 phys_t compute_vmpa_diff(const vmpa2t *, const vmpa2t *);
 
 /* Lit la définition d'une adresse depuis un flux réseau. */
-bool recv_vmpa(vmpa2t *, int, int);
+bool unpack_vmpa(vmpa2t *, packed_buffer *);
 
 /* Ecrit la définition d'une adresse dans un flux réseau. */
-bool send_vmpa(const vmpa2t *, int, int);
+bool pack_vmpa(const vmpa2t *, packed_buffer *);
 
 /* Transforme une adresse physique en chaîne de caractères. */
 char *vmpa2_phys_to_string(const vmpa2t *, MemoryDataSize, char [VMPA_MAX_LEN], size_t *);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 02c1718..b4d1a5b 100755
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -15,6 +15,7 @@ libcommon_la_SOURCES =					\
 	leb128.h leb128.c					\
 	macros.h							\
 	net.h net.c							\
+	packed.h packed.c					\
 	pathname.h pathname.c				\
 	shuffle.h shuffle.c					\
 	sort.h sort.c						\
diff --git a/src/common/packed.c b/src/common/packed.c
new file mode 100644
index 0000000..39df330
--- /dev/null
+++ b/src/common/packed.c
@@ -0,0 +1,300 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * packed.c - regroupement de bribes de paquets réseau
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "packed.h"
+
+
+#include <assert.h>
+#include <endian.h>
+#include <malloc.h>
+#include <string.h>
+
+
+
+/* Taille d'allocation en cas de besoin */
+#define PACKET_BLOCK_SIZE 1000
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à initialiser. [OUT]                *
+*                                                                             *
+*  Description : Intialise un paquet réseau pour une constitution.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void init_packed_buffer(packed_buffer *pbuf)
+{
+    pbuf->allocated = PACKET_BLOCK_SIZE;
+    pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t));
+
+    pbuf->used = 0;
+    pbuf->pos = sizeof(uint32_t);
+
+    assert(pbuf->pos <= pbuf->allocated);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à libérer.                          *
+*                                                                             *
+*  Description : Efface les données contenues par un paquet réseau.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void exit_packed_buffer(packed_buffer *pbuf)
+{
+    free(pbuf->data);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à compléter.                        *
+*                buf  = nouvelles données à ajouter.                          *
+*                len  = quantité de ces données.                              *
+*                hton = indique si une conversion est à réaliser.             *
+*                                                                             *
+*  Description : Ajoute des données à un paquet en amont à un envoi.          *
+*                                                                             *
+*  Retour      : true.                                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool hton)
+{
+    uint16_t tmp16;                         /* Valeur intermédiaire 16b    */
+    uint32_t tmp32;                         /* Valeur intermédiaire 32b    */
+    uint64_t tmp64;                         /* Valeur intermédiaire 64b    */
+
+    /* Réallocation nécessaire ? */
+
+    while ((pbuf->pos + len) > pbuf->allocated)
+    {
+        pbuf->allocated += PACKET_BLOCK_SIZE;
+        pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t));
+    }
+
+    /* Conversion au formalisme du réseau */
+
+    if (!hton)
+        goto skip_conversion;
+
+    switch (len)
+    {
+        case 1:
+            *((uint8_t *)(pbuf->data + pbuf->pos)) = *((uint8_t *)buf);
+            break;
+
+        case 2:
+            tmp16 = htobe16(*(uint16_t *)buf);
+            *((uint16_t *)(pbuf->data + pbuf->pos)) = tmp16;
+            break;
+
+        case 4:
+            tmp32 = htobe32(*(uint32_t *)buf);
+            *((uint32_t *)(pbuf->data + pbuf->pos)) = tmp32;
+            break;
+
+        case 8:
+            tmp64 = htobe64(*(uint64_t *)buf);
+            *((uint64_t *)(pbuf->data + pbuf->pos)) = tmp64;
+            break;
+
+        default:
+
+ skip_conversion:
+
+            /**
+             * Dans ce cas de figure, c'est à l'appelant de s'assurer que la
+             * conversion a bien été réalisée.
+             */
+            assert(!hton);
+
+            memcpy(pbuf->data + pbuf->pos, buf, len);
+            break;
+
+    }
+
+    pbuf->used += len;
+    pbuf->pos += len;
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à consulter.                        *
+*                buf  = nouvelles données à définir.                          *
+*                len  = quantité de ces données.                              *
+*                ntoh = indique si une conversion est à réaliser.             *
+*                                                                             *
+*  Description : Récupère des données depuis un paquet après une réception.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool extract_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh)
+{
+    bool result;                            /* Bilan à retourner           */
+    uint16_t tmp16;                         /* Valeur intermédiaire 16b    */
+    uint32_t tmp32;                         /* Valeur intermédiaire 32b    */
+    uint64_t tmp64;                         /* Valeur intermédiaire 64b    */
+
+    result = ((pbuf->pos + len - sizeof(uint32_t)) <= pbuf->used);
+
+    /* Conversion au formalisme du réseau */
+
+    if (!ntoh)
+        goto skip_conversion;
+
+    if (result)
+    {
+        switch (len)
+        {
+            case 1:
+                *((uint8_t *)buf) = *((uint8_t *)(pbuf->data + pbuf->pos));
+                break;
+
+            case 2:
+                tmp16 = be16toh(*(uint16_t *)(pbuf->data + pbuf->pos));
+                *((uint16_t *)buf) = tmp16;
+                break;
+
+            case 4:
+                tmp32 = be32toh(*(uint32_t *)(pbuf->data + pbuf->pos));
+                *((uint32_t *)buf) = tmp32;
+                break;
+
+            case 8:
+                tmp64 = be64toh(*(uint64_t *)(pbuf->data + pbuf->pos));
+                *((uint64_t *)buf) = tmp64;
+                break;
+
+            default:
+
+ skip_conversion:
+
+                /**
+                 * Dans ce cas de figure, c'est à l'appelant de s'assurer que la
+                 * conversion a bien été réalisée.
+                 */
+                assert(!ntoh);
+
+                memcpy(buf, pbuf->data + pbuf->pos, len);
+                break;
+
+        }
+
+        pbuf->pos += len;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à constituer. [OUT]                 *
+*                fd   = flux ouvert en lecture.                               *
+*                                                                             *
+*  Description : Réceptionne des données depuis un flux réseau.               *
+*                                                                             *
+*  Retour      : true si toutes les données ont été reçues, false sinon.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool recv_packed_buffer(packed_buffer *pbuf, int fd)
+{
+    bool result;                            /* Bilan à retourner           */
+    uint32_t used;                          /* Taille de charge utile      */
+
+    result = safe_recv(fd, &used, sizeof(uint32_t), 0);
+
+    if (!result)
+        init_packed_buffer(pbuf);
+
+    else
+    {
+        pbuf->allocated = sizeof(uint32_t) + used;
+        pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t));
+
+        pbuf->used = used;
+        pbuf->pos = sizeof(uint32_t);
+
+        result = safe_recv(fd, pbuf->data + pbuf->pos, used, 0);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à émettre.                          *
+*                fd   = flux ouvert en écriture.                              *
+*                                                                             *
+*  Description : Envoie des données au travers un flux réseau.                *
+*                                                                             *
+*  Retour      : true si toutes les données ont été émises, false sinon.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool send_packed_buffer(packed_buffer *pbuf, int fd)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    *((uint32_t *)pbuf->data) = pbuf->used;
+
+    result = safe_send(fd, pbuf->data, sizeof(uint32_t) + pbuf->used, 0);
+
+    return result;
+
+}
diff --git a/src/common/packed.h b/src/common/packed.h
new file mode 100644
index 0000000..bc038d8
--- /dev/null
+++ b/src/common/packed.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * packed.h - prototypes pour le regroupement de bribes de paquets réseau
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _COMMON_PACKED_H
+#define _COMMON_PACKED_H
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+
+#include "io.h"
+
+
+
+/* Rassemblement de données d'un paquet */
+typedef struct _packed_buffer
+{
+    uint8_t *data;                          /* Données à traiter           */
+    size_t allocated;                       /* Taille allouée              */
+
+    size_t used;                            /* Quantité de données utiles  */
+    size_t pos;                             /* Tête de lecture/écriture    */
+
+} packed_buffer;
+
+
+/* Intialise un paquet réseau pour une constitution. */
+void init_packed_buffer(packed_buffer *);
+
+/* Efface les données contenues par un paquet réseau. */
+void exit_packed_buffer(packed_buffer *);
+
+/* Ajoute des données à un paquet en amont à un envoi. */
+bool extend_packed_buffer(packed_buffer *, const void *, size_t, bool);
+
+/* Récupère des données depuis un paquet après une réception. */
+bool extract_packed_buffer(packed_buffer *, void *, size_t, bool);
+
+/* Réceptionne des données depuis un flux réseau. */
+bool recv_packed_buffer(packed_buffer *, int);
+
+/* Réceptionne des données depuis un flux réseau. */
+bool recv_packed_buffer(packed_buffer *, int);
+
+/* Envoie des données au travers un flux réseau. */
+bool send_packed_buffer(packed_buffer *, int);
+
+
+
+#endif  /* _COMMON_PACKED_H */
-- 
cgit v0.11.2-87-g4458