summaryrefslogtreecommitdiffstats
path: root/ffi
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2018-09-10 11:00:31 +0200
committerNeal H. Walfield <neal@pep.foundation>2018-09-10 11:17:00 +0200
commitda075409e3d0632ee113f4a9c988151799a455da (patch)
treee351d793fcbf14d98712bff46137336a07af4c9d /ffi
parent7818f0b843153ff8d681c78a92cde2bb331934fc (diff)
ffi: Provide an FFI to work with sq_packet_parser_result_t's.
- 4486871 added the sq_packet_parser_result_t to the FFI and fixed sq_packet_parser_from_reader, etc. to return it instead of a sq_packet_parser_t. That change didn't provide any methods for working with sq_packet_parser_result_t's, and it made ffi/examples/parser.c no longer compile (although parser.c no longer worked since we changed the PacketParser code to work with PacketParserResults's in c9ee0ac). - Add sq_packet_parser_result_packet_parser, sq_packet_parser_result_eof, and sq_packet_parser_result_free to be able to work with sq_packet_parser_result_t's. - Fix parser.c so that it not only compiles, but also works again.
Diffstat (limited to 'ffi')
-rw-r--r--ffi/examples/parser.c42
-rw-r--r--ffi/include/sequoia/openpgp.h63
-rw-r--r--ffi/src/openpgp.rs88
3 files changed, 166 insertions, 27 deletions
diff --git a/ffi/examples/parser.c b/ffi/examples/parser.c
index 798f01cf..3cceea26 100644
--- a/ffi/examples/parser.c
+++ b/ffi/examples/parser.c
@@ -23,7 +23,8 @@ main (int argc, char **argv)
sq_status_t rc;
sq_error_t err;
sq_context_t ctx;
- sq_packet_parser_t pp, ppo;
+ sq_packet_parser_result_t ppr;
+ sq_packet_parser_t pp;
if (argc != 2)
error (1, 0, "Usage: %s <file>", argv[0]);
@@ -45,30 +46,38 @@ main (int argc, char **argv)
if (b == MAP_FAILED)
error (1, errno, "mmap");
- pp = sq_packet_parser_from_bytes (ctx, b, st.st_size);
- if (pp == NULL)
- {
- err = sq_context_last_error (ctx);
- error (1, 0, "sq_packet_parser_from_bytes: %s", sq_error_string (err));
- }
-
size_t n = 0;
time_t start = time (NULL);
time_t elapsed;
size_t tens_of_s = 0;
- while (pp)
+
+ ppr = sq_packet_parser_from_bytes (ctx, b, st.st_size);
+ while (ppr && (pp = sq_packet_parser_result_packet_parser (ppr)))
{
- sq_packet_t p;
- rc = sq_packet_parser_next (ctx, pp, &p, NULL, &ppo, NULL);
+ // Get a reference to the packet that is currently being parsed.
+ sq_packet_t p = sq_packet_parser_packet (pp);
+
+ if (sq_packet_tag(p) == SQ_TAG_LITERAL)
+ {
+ // Stream the packet here.
+ }
+
+ // Finish parsing the current packet (returned in p), and read
+ // the header of the next packet (returned in ppr).
+ rc = sq_packet_parser_next (ctx, pp, &p, NULL, &ppr, NULL);
if (rc)
{
err = sq_context_last_error (ctx);
error (1, 0, "sq_packet_parser_from_bytes: %s",
sq_error_string (err));
}
- pp = ppo;
+
+ // We now own p. If we want, we can save it in some structure.
+ // This would be useful when collecting PKESK packets. Either
+ // way, we need to free it when we are done.
n += 1;
+
sq_packet_free (p);
elapsed = time (NULL) - start;
@@ -81,10 +90,17 @@ main (int argc, char **argv)
tens_of_s = elapsed / 10;
}
}
+ if (ppr == NULL)
+ {
+ err = sq_context_last_error (ctx);
+ error (1, 0, "sq_packet_parser_from_bytes: %s", sq_error_string (err));
+ }
+
fprintf (stderr, "Parsed %ld packets in %ld seconds, %.2f packets/s.\n",
n, elapsed, (double) n / (double) elapsed);
- sq_packet_parser_free (pp);
+ sq_packet_parser_result_free (ppr);
+
sq_context_free (ctx);
munmap (b, st.st_size);
return 0;
diff --git a/ffi/include/sequoia/openpgp.h b/ffi/include/sequoia/openpgp.h
index 54a8d864..37b84211 100644
--- a/ffi/include/sequoia/openpgp.h
+++ b/ffi/include/sequoia/openpgp.h
@@ -715,37 +715,71 @@ sq_status_t sq_skesk_decrypt (sq_context_t ctx, sq_skesk_t skesk,
typedef struct sq_packet_parser *sq_packet_parser_t;
/*/
-/// Like an `Option<PacketParser>`, but the `None` variant contains
-/// some summary information.
+/// Like an `Option<PacketParser>`, but the `None` variant
+/// (`PacketParserEOF`) contains some summary information.
/*/
typedef struct sq_packet_parser_result *sq_packet_parser_result_t;
/*/
+/// The `None` variant of a `PacketParserResult`.
+/*/
+typedef struct sq_packet_parser_eof *sq_packet_parser_eof_t;
+
+/*/
/// Starts parsing an OpenPGP message stored in a `sq_reader_t` object.
-///
-/// This function returns a `PacketParser` for the first packet in
-/// the stream.
/*/
sq_packet_parser_result_t sq_packet_parser_from_reader (sq_context_t ctx,
sq_reader_t reader);
/*/
/// Starts parsing an OpenPGP message stored in a file named `path`.
-///
-/// This function returns a `PacketParser` for the first packet in
-/// the stream.
/*/
sq_packet_parser_result_t sq_packet_parser_from_file (sq_context_t ctx,
const char *filename);
/*/
/// Starts parsing an OpenPGP message stored in a buffer.
-///
-/// This function returns a `PacketParserResult` for the first packet in
-/// the stream.
/*/
sq_packet_parser_result_t sq_packet_parser_from_bytes (sq_context_t ctx,
- const uint8_t *b, size_t len);
+ const uint8_t *b,
+ size_t len);
+
+/*/
+/// If the `PacketParserResult` contains a `PacketParser`, returns it,
+/// otherwise, returns NULL.
+///
+/// If the `PacketParser` reached EOF, then the `PacketParserResult`
+/// contains a `PacketParserEOF` and you should use
+/// `sq_packet_parser_result_eof` to get it.
+///
+/// If this function returns a `PacketParser`, then it consumes the
+/// `PacketParserResult` and ownership of the `PacketParser` is
+/// returned to the caller, i.e., the caller is responsible for
+/// ensuring that the `PacketParser` is freed.
+/*/
+sq_packet_parser_t sq_packet_parser_result_packet_parser (
+ sq_packet_parser_result_t ppr);
+
+/*/
+/// If the `PacketParserResult` contains a `PacketParserEOF`, returns
+/// it, otherwise, returns NULL.
+///
+/// If the `PacketParser` did not yet reach EOF, then the
+/// `PacketParserResult` contains a `PacketParser` and you should use
+/// `sq_packet_parser_result_packet_parser` to get it.
+///
+/// If this function returns a `PacketParserEOF`, then it consumes the
+/// `PacketParserResult` and ownership of the `PacketParserEOF` is
+/// returned to the caller, i.e., the caller is responsible for
+/// ensuring that the `PacketParserEOF` is freed.
+/*/
+sq_packet_parser_eof_t sq_packet_parser_result_eof (
+ sq_packet_parser_result_t ppr);
+
+/*/
+/// Frees the packet parser result.
+/*/
+void sq_packet_parser_result_free (sq_packet_parser_result_t ppr);
/*/
/// Frees the packet parser.
@@ -753,6 +787,11 @@ sq_packet_parser_result_t sq_packet_parser_from_bytes (sq_context_t ctx,
void sq_packet_parser_free (sq_packet_parser_t pp);
/*/
+/// Frees the packet parser EOF object.
+/*/
+void sq_packet_parser_eof_free (sq_packet_parser_eof_t eof);
+
+/*/
/// Returns a reference to the packet that is being parsed.
/*/
sq_packet_t sq_packet_parser_packet (sq_packet_parser_t pp);
diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs
index 8bb40aa9..f17f9db7 100644
--- a/ffi/src/openpgp.rs
+++ b/ffi/src/openpgp.rs
@@ -3,7 +3,7 @@
use failure;
use std::ffi::{CString, CStr};
use std::hash::{Hash, Hasher};
-use std::mem::size_of;
+use std::mem::{size_of, forget};
use std::ptr;
use std::slice;
use std::io::{Read, Write};
@@ -13,7 +13,7 @@ extern crate openpgp;
use self::openpgp::{armor, Fingerprint, KeyID, PacketPile, TPK, TSK, Packet};
use self::openpgp::tpk::{CipherSuite, TPKBuilder};
-use self::openpgp::parse::{PacketParser, PacketParserResult};
+use self::openpgp::parse::{PacketParserResult, PacketParser, PacketParserEOF};
use self::openpgp::serialize::Serialize;
use self::openpgp::constants::{
DataFormat,
@@ -1192,6 +1192,17 @@ pub extern "system" fn sq_packet_parser_from_bytes
fry_box!(ctx, PacketParser::from_bytes(buf))
}
+/// Frees the packet parser result
+#[no_mangle]
+pub extern "system" fn sq_packet_parser_result_free(
+ ppr: *mut PacketParserResult)
+{
+ if ppr.is_null() { return }
+ unsafe {
+ drop(Box::from_raw(ppr));
+ }
+}
+
/// Frees the packet parser.
#[no_mangle]
pub extern "system" fn sq_packet_parser_free(pp: *mut PacketParser) {
@@ -1201,6 +1212,15 @@ pub extern "system" fn sq_packet_parser_free(pp: *mut PacketParser) {
}
}
+/// Frees the packet parser EOF object.
+#[no_mangle]
+pub extern "system" fn sq_packet_parser_eof_free(eof: *mut PacketParserEOF) {
+ if eof.is_null() { return }
+ unsafe {
+ drop(Box::from_raw(eof));
+ }
+}
+
/// Returns a reference to the packet that is being parsed.
#[no_mangle]
pub extern "system" fn sq_packet_parser_packet
@@ -1450,6 +1470,70 @@ pub extern "system" fn sq_packet_parser_decrypt<'a>
fry_status!(ctx, pp.decrypt((algo as u8).into(), key))
}
+
+/* PacketParserResult. */
+
+/// If the `PacketParserResult` contains a `PacketParser`, returns it,
+/// otherwise, returns NULL.
+///
+/// If the `PacketParser` reached EOF, then the `PacketParserResult`
+/// contains a `PacketParserEOF` and you should use
+/// `sq_packet_parser_result_eof` to get it.
+///
+/// If this function returns a `PacketParser`, then it consumes the
+/// `PacketParserResult` and ownership of the `PacketParser` is
+/// returned to the caller, i.e., the caller is responsible for
+/// ensuring that the `PacketParser` is freed.
+#[no_mangle]
+pub extern "system" fn sq_packet_parser_result_packet_parser<'a>
+ (ppr: *mut PacketParserResult<'a>)
+ -> *mut PacketParser<'a>
+{
+ assert!(! ppr.is_null());
+ let ppr = unsafe {
+ Box::from_raw(ppr)
+ };
+
+ match *ppr {
+ PacketParserResult::Some(pp) => box_raw!(pp),
+ PacketParserResult::EOF(_) => {
+ // Don't free ppr!
+ forget(ppr);
+ ptr::null_mut()
+ }
+ }
+}
+
+/// If the `PacketParserResult` contains a `PacketParserEOF`, returns
+/// it, otherwise, returns NULL.
+///
+/// If the `PacketParser` did not yet reach EOF, then the
+/// `PacketParserResult` contains a `PacketParser` and you should use
+/// `sq_packet_parser_result_packet_parser` to get it.
+///
+/// If this function returns a `PacketParserEOF`, then it consumes the
+/// `PacketParserResult` and ownership of the `PacketParserEOF` is
+/// returned to the caller, i.e., the caller is responsible for
+/// ensuring that the `PacketParserEOF` is freed.
+#[no_mangle]
+pub extern "system" fn sq_packet_parser_result_eof<'a>
+ (ppr: *mut PacketParserResult<'a>)
+ -> *mut PacketParserEOF
+{
+ assert!(! ppr.is_null());
+ let ppr = unsafe {
+ Box::from_raw(ppr)
+ };
+
+ match *ppr {
+ PacketParserResult::Some(_) => {
+ forget(ppr);
+ ptr::null_mut()
+ }
+ PacketParserResult::EOF(eof) => box_raw!(eof),
+ }
+}
+
use self::openpgp::serialize::{
writer,
stream::{