diff options
author | Neal H. Walfield <neal@pep.foundation> | 2018-09-10 11:00:31 +0200 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2018-09-10 11:17:00 +0200 |
commit | da075409e3d0632ee113f4a9c988151799a455da (patch) | |
tree | e351d793fcbf14d98712bff46137336a07af4c9d /ffi | |
parent | 7818f0b843153ff8d681c78a92cde2bb331934fc (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.c | 42 | ||||
-rw-r--r-- | ffi/include/sequoia/openpgp.h | 63 | ||||
-rw-r--r-- | ffi/src/openpgp.rs | 88 |
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::{ |