From e46b64a20f9d4499ddd6665dd8d016f400124b27 Mon Sep 17 00:00:00 2001 From: Luca Saiu Date: Wed, 12 Apr 2023 16:57:42 +0200 Subject: [PATCH] lots of progress, including changes to be discussed with Heck: Blob copy constructor, Blob internal data accessor --- src/pEp/_pEp/message.cc | 82 ++++++++++++++++++++++++++++++++++++++- src/pEp/_pEp/message.hh | 15 ++++++- src/pEp/_pEp/pEpmodule.cc | 23 ++++++++++- 3 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/pEp/_pEp/message.cc b/src/pEp/_pEp/message.cc index 51e8dce..90744c5 100644 --- a/src/pEp/_pEp/message.cc +++ b/src/pEp/_pEp/message.cc @@ -29,6 +29,8 @@ namespace pEp { if (!_bl) { throw std::bad_alloc(); } + std::cerr << "Built a blob at " << this << " from a C bloblist (chained? " << chained << ")\n"; + std::cerr << " its _bl is at " << _bl << "\n"; } Message::Blob::Blob(object data, string mime_type, string filename) : @@ -52,23 +54,52 @@ namespace pEp { } memcpy(mem, src.buf, src.len); + std::cerr << " copied old cd " << src.buf << " ...\n"; + std::cerr << " ... to " << mem << " ...\n"; free(_bl->value); + std::cerr << " keeping _bl " << _bl << "\n"; + std::cerr << " freed value " << (void*) _bl->value << "\n"; _bl->size = src.len; _bl->value = mem; + std::cerr << " replaced with " << (void*) _bl->value << "\n"; PyBuffer_Release(&src); this->mime_type(mime_type); this->filename(filename); + std::cerr << "Built a blob at " << this << " from a C++ data object\n"; + std::cerr << " its _bl is at " << _bl << "\n"; + } + + Message::Blob::Blob(const Message::Blob &second) : _bl(second._bl), part_of_chain(second.part_of_chain) { + std::cerr << "Built a blob at " << this << " as a copy of " << & second << " which " << (second.part_of_chain ? "WAS" : "was NOT") << " part of a chain\n"; + if (! part_of_chain) { + assert(second._bl->next == NULL); + // Replace _bc with a copy. + char *data_c = NULL; + data_c = (char*) malloc(_bl->size); + if (data_c == NULL) + throw std::bad_alloc(); + memcpy(data_c, _bl->value, _bl->size); + ::bloblist_t *_new_bl = ::new_bloblist(data_c, _bl->size, _bl->mime_type, NULL); + if (_new_bl == NULL) { + free(data_c); + throw std::bad_alloc(); + } + _bl = _new_bl; + } + std::cerr << " its _bl is at " << _bl << "\n"; } - Message::Blob::Blob(const Message::Blob &second) : _bl(second._bl), part_of_chain(true) {} - Message::Blob::~Blob() { + std::cerr << "Destroy blob at " << this << "\n"; + std::cerr << " its _bl was at" << _bl << (part_of_chain ? " (NOT destroying it)" : "(DESTROYING it)") << "\n"; if (!part_of_chain) { free(_bl->value); + std::cerr << " freed c_data " << (void*) _bl->value << "\n"; free(_bl); + std::cerr << " freed _bl " << (void*) _bl << "\n"; } } @@ -79,6 +110,9 @@ namespace pEp { if (!_bl) { build << "b'', '', ''"; } else { +build << "@ " << this << " _bl " << (void*) _bl << " c_data " << (void*) _bl->value << " " ; +//build << "\"" << (char *)_bl->value << "\""; // only for debugging, of course: dangerous unless '\0'-terminated +build << " "; build << "bytes(" << _bl->size << "), "; string mime_type; if (_bl->mime_type) @@ -461,6 +495,50 @@ namespace pEp { return copy(); } + Message::Blob Message::serialize() + { + std::cerr << "Message::serialize this is " << this << "\n"; + size_t length_in_bytes_c; + char *data_c = NULL; + ::bloblist_t *blob_c; + + /* Serialise the message into a memory buffer. */ + PEP_STATUS status = onion_serialize_message(Adapter::session(), *this, &data_c, &length_in_bytes_c); + _throw_status(status); + + /* Turn the memory buffer into a blob. */ + blob_c = new_bloblist(data_c, length_in_bytes_c, PEP_ONION_MESSAGE_MIME_TYPE, NULL); + if (blob_c == NULL) { + ::free(data_c); + throw std::bad_alloc(); + } + return Message::Blob(blob_c, false); + /* + char *data_c = strdup("foo!"); + size_t length_in_bytes_c = strlen(data_c); + ::bloblist_t *blob_c = NULL; + blob_c = ::new_bloblist(data_c, length_in_bytes_c, PEP_ONION_MESSAGE_MIME_TYPE, NULL); + if (blob_c == NULL) { + ::free(data_c); + throw std::bad_alloc(); + } + std::cerr << "Message::serialize data_c is " << (void*) data_c << "\n"; + std::cerr << "Message::serialize blob_c is " << blob_c << "\n"; + return Message::Blob(blob_c, false); + */ + } + + Message deserialize(const Message::Blob &blob) + { + const char *data_c = blob.c_data(); + size_t length_in_bytes_c = blob.size(); + message *msg = NULL; + PEP_STATUS status = onion_deserialize_message(Adapter::session(), data_c, length_in_bytes_c, &msg); + _throw_status(status); + + return Message(msg); + } + Message outgoing_message(Identity me) { if (me.address().empty() || me.user_id().empty()) { diff --git a/src/pEp/_pEp/message.hh b/src/pEp/_pEp/message.hh index 75fe00d..f438660 100644 --- a/src/pEp/_pEp/message.hh +++ b/src/pEp/_pEp/message.hh @@ -68,11 +68,20 @@ namespace pEp { str_attr(_bl->filename, value); } - size_t size() + size_t size() const { return _bl->size; } + // Return an initial to the internal data, without copying the + // buffer. + // This method is of course unsafe, as the resulting pointer + // must not be dereferenced past the bloblist's destruction. + const char* c_data() const + { + return _bl->value; + } + string decode(string encoding); string decode() @@ -323,8 +332,12 @@ namespace pEp { Message deepcopy(dict &memo); Message copy(); + + Message::Blob serialize(); }; + Message deserialize(const Message::Blob &blob); + Message outgoing_message(Identity me); Message incoming_message(string mime_text); diff --git a/src/pEp/_pEp/pEpmodule.cc b/src/pEp/_pEp/pEpmodule.cc index 4be96e7..633b210 100644 --- a/src/pEp/_pEp/pEpmodule.cc +++ b/src/pEp/_pEp/pEpmodule.cc @@ -407,7 +407,7 @@ namespace pEp { (void(Message::Blob::*)(string)) & Message::Blob::filename, "filename of object in Blob"); - //((PyTypeObject *)(void *)blob_class.ptr())->tp_as_buffer = &Message::Blob::bp; + ((PyTypeObject *)(void *)blob_class.ptr())->tp_as_buffer = &Message::Blob::bp; auto message_class = class_( "Message", @@ -594,6 +594,17 @@ namespace pEp { " keys a list of keys being used\n" " rating the rating of the message as integer\n" " flags flags set while decryption\n") + .def( + "serialize", + &Message::serialize, + "b = msg.serialize()\n" + "\n" + "serialises a p≡p message into a blob (which can be converted into\n" + "a bytes object). The blob can be deserialised back into a message\n" + "through pEp.deserialize\n" + "\n" + " msg a message, encrypted or not\n" + " b the resultint blob\n") .def( "onionize", (Message(Message::*)(boost::python::list)) & @@ -747,6 +758,16 @@ namespace pEp { "The returned identities are all distinct and in random order.\n" "\n" "identities = onion_identities(2, 5)\n"); + def("deserialize", + &deserialize, + "msg = deserialize(blob)\n" + "\n" + "Return the message obtained by the deserialisation of the given blob.\n" + "The blob must be obtained from Message.serialize.\n" + "\n" + "msg the returned message\n" + "blob a blob returned by Message.serialize\n" + "\n"); // message API