NAME
Crypt::OpenSSL::CA::Inline::C - A bag of XS and Inline::C tricks
SYNOPSIS
package Crypt::OpenSSL::CA::Foo;
use Crypt::OpenSSL::CA::Inline::C <<"C_CODE_SAMPLE";
#include <openssl/x509.h>
static
SV* mysub() {
// Your C code here
}
C_CODE_SAMPLE
# Lots and lots of the same...
use Crypt::OpenSSL::CA::Inline::C "__END__";
DESCRIPTION
This package provides Inline::C goodness to Crypt::OpenSSL::CA during development, plus a few tricks of our own. The idiom in "SYNOPSIS", used throughout the source code of Crypt::OpenSSL::CA, recaps them all; noteworthy points are:
- the
static
-newline trick -
Because the C language doesn't have namespaces, we don't want symbols named e.g.
new
appearing in the .so's symbol tables: they could clash with other symbols defined by Perl, or with each other. Therefore we have to declare themstatic
, but doing this in the naïve way would cause Inline::C to purposefully not bind them with Perl... The winning trick is to put thestatic
word alone on its line, as demonstrated. - the "__END__" pragma
-
In order to accomodate hypothetical future extensions, the code in Crypt::OpenSSL::CA should use the following pragma to signal that it won't attempt to add any Inline::C code after this point:
use Crypt::OpenSSL::CA::Inline::C "__END__";
Standard Library
In addition to the standard library available to XS C code described in Inline::C, perlxstut, perlguts and perlapi, C code that compiles itself through Crypt::OpenSSL::CA::Inline::C has access to the following C functions:
- static inline char* char0_value(SV* string)
-
Returns the string value of a Perl SV, making sure that it exists and is zero-terminated beforehand. See "Working with SVs" in perlguts, look for the word "Nevertheless". I'm pretty sure there is a macro in Perl's convenience stuff that does exactly that already, but I don't know it...
- static inline SV* perl_wrap(class, pointer)
-
Creates read-only SV containing the integral value of
pointer
, blesses it into classclass
and returns it as a SV*. The return value is an adequate Perl wrapper to stand forpointer
, as demonstrated in "Object Oriented Inline" in Inline::C-Cookbook. - perl_unwrap(class, typename, SV*)
-
The reverse of "perl_wrap". Given a "perl_wrap"ped SV*, asserts that it actually contains an object blessed in class
class
(lest itcroak
s), extracts the pointer within same, casts it intotypename
and returns it. This is a macro instead of a static inline, so as to be able to perform the polymorphic cast. - static inline SV* openssl_string_to_SV(char* string)
-
Copies over
string
to a newly-allocatedSV*
Perl scalar, and then freesstring
usingOPENSSL_free()
. Used to transfer ownership of strings from OpenSSL to Perl, and thereby ensure proper memory management.Note to Crypt::OpenSSL::CA hackers: if
string
is on an OpenSSL static buffer instead of having been allocated by OpenSSL, this will SEGV in trying to free()string
that was not malloc()'d; in this case you want to use "XSRETURN_PV" in perlapi instead or some such. Check the OpenSSL documentation carefully, and make use of "leaks_bytes_ok" in Crypt::OpenSSL::CA::Test to ascertain experimentally that your code doesn't leak memory. - static inline SV* openssl_buf_to_SV(char* string, int length)
-
Like "openssl_string_to_SV" except that the length is specified, which allows for
string
to not contain null characters or not be zero-terminated. Use this form e.g. for ASN.1 buffers returned byi2d_foobar
OpenSSL functions. - static inline SV* BIO_mem_to_SV(BIO *bio)
-
This inline function is intended to be used to return scalar values (e.g. PEM strings and RSA moduli) constructed by OpenSSL. Should be invoked thusly, after having freed all temporary resources except *bio:
return BIO_mem_to_SV(bio);
BIO_mem_to_SV() turns bio into a Perl scalar and returns it, or
croak()
s trying (hence the requirement not to have any outstanding memory resources allocated in the caller). Regardless of the outcome,bio
will beBIO_free
()d. - static void ensure_openssl_stuff_loaded()
-
Ensures that various stuff is loaded inside OpenSSL, such as
ERR_load_crypto_strings()
,OpenSSL_add_all_digests()
and all that jazz. After this function returns,$Crypt::OpenSSL::CA::openssl_stuff_loaded
will be 1. Calling it several times has no effect. - static void sslcroak(char *format, ...)
-
Like "croak" in perlapi, except that a blessed exception of class Crypt::OpenSSL::CA::Error is generated. The OpenSSL error stack, if any, gets recorded as an array reference inside the exception structure.
Note to Crypt::OpenSSL::CA hackers: please select the appropriate routine between sslcroak and croak, depending on whether the current error condition is being caused by OpenSSL or not; in this way callers are able to discriminate errors. Also, don't be fooled into thinking that
sslcroak
(or, for that matter,croak
) is the same thing in C and in Perl! Because callingsslcroak
will return control directly to Perl without running any C code, any and all temporary variables that have been allocated from C will fail to be de-allocated, thereby causing a memory leak.Internally, sslcroak works by invoking "_ssl_croak_callback" several times, using a rough equivalent of the following pseudo-code:
_sslcroak_callback("-message", $formattedstring); _sslcroak_callback("-openssl", $openssl_errorstring_1); _sslcroak_callback("-openssl", $openssl_errorstring_2); ... _sslcroak_callback("DONE");
where $formattedstring is the
sprintf
-formatted version of the arguments passed to sslcroak, and the OpenSSL error strings are retrieved using ERR_get_error(3) and ERR_error_string(3).
INTERNALS
The use Crypt::OpenSSL::CA::Inline::C
idiom described in "SYNOPSIS" is implemented in terms of Inline.
DOCUMENTME
- import()
-
Called whenever one of the
use Crypt::OpenSSL::CA::Inline::C "foo"
pragmas (listed in "SYNOPSIS") is seen by Perl; performs the actual magic of the module. Mostly delegates to "import" in Inline, with the following tweaks:Inline::C is configured to compile with all warnings turned into errors (i.e.
-Wall -Werror
) and to link with the OpenSSL libraries;the C code that implements the "Standard Library" is prepended to the caller-provided C code.
- compile_everything()
-
Called when "the "__END__" pragma" is seen. Currently does nothing.
- installed_version
-
Returns what the source code of this module will look like (with POD and everything) after it is installed. The installed version is a dud stub; its "import" method only loads the XS DLL, and it is no longer possible to alter the C code once the module has been installed. The upside is that in thanks to that, Inline is a dependency only at compile time.
TODO
Right now it is not possible to invoke Crypt::OpenSSL::CA::Inline::C several times from the same package, yet allowing that would be straightforward. the immediate benefit of that would be to allow to intermingle POD and C code freely.
TEST SUITE
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 49:
Non-ASCII character seen before =encoding in 'naïve'. Assuming UTF-8