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
# Then maybe some Perl...
use Crypt::OpenSSL::CA::Inline::C <<"MORE_C_CODE";
static
void another() {
// ...
}
MORE_C_CODE
use Crypt::OpenSSL::CA::Inline::C "__END__";
DESCRIPTION
This documentation is only useful for people who want to hack Crypt::OpenSSL::CA. It is of no interest for people who just want to use the module.
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
-
The code in Crypt::OpenSSL::CA must 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:
char0_value
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. If string
is undef, returns the empty string (not NULL; see "char0_value_or_null"). If string
is tainted, that makes no difference; return it, or the empty string, just the same. See "Working with SVs" in perlguts, look for the word "Nevertheless" - I assume there is a macro in Perl's convenience stuff that does exactly that already, but I don't know it...
char0_value_or_null
static inline char* char0_value_or_null(SV* string);
Like "char0_value", except that NULL is returned if string
is undef.
perl_wrap
static inline SV* perl_wrap(class, pointer);
Creates read-only SV containing the integral value of pointer
, blesses it into class class
and returns it as a SV*. The return value is an adequate Perl wrapper to stand for pointer
, 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 it croak
s), extracts the pointer within same, casts it into typename
and returns it. This is a macro instead of a static inline, so as to be able to perform the polymorphic cast.
openssl_string_to_SV
static inline SV* openssl_string_to_SV(char* string);
Copies over string
to a newly-allocated SV*
Perl scalar, and then frees string
using OPENSSL_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.
openssl_buf_to_SV
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 by i2d_foobar
OpenSSL functions.
BIO_mem_to_SV
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 be BIO_free
()d.
sslcroak
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 croak
-style error management acts in the same way in C and Perl! Because calling sslcroak
(or, for that matter, "croak" in perlapi) 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 "_sslcroak_callback" in Crypt::OpenSSL::CA 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).
BOOT-time effect
Each .so
XS module will be fitted with a BOOT
section (see "BOOT" in Inline::C which automatically gets executed upon loading it with DynaLoader or XSLoader. The BOOT
section is the same for all subpackages in Crypt::OpenSSL::CA; it ensures that various stuff is loaded inside OpenSSL, such as ERR_load_crypto_strings()
, OpenSSL_add_all_algorithms()
and all that jazz. After the boot code completes, $Crypt::OpenSSL::CA::openssl_stuff_loaded
will be 1, so that the following XS modules can skip that when they in turn get loaded.
INTERNALS
The use Crypt::OpenSSL::CA::Inline::C
idiom described in "SYNOPSIS" is implemented in terms of Inline.
%c_code
A lexical variable that "import" uses to accumulate all the C code submitted by Crypt::OpenSSL::CA. Keys are package names, and values are snippets of C.
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. Stashes everything into "%c_code", and invokes "compile_everything" at the end.
compile_everything ()
Called when "the "__END__" pragma" is seen. Invokes compile_namespace once for every package (that is, every key in "%c_code"), prepending _c_boilerplate each time.
compile_into ($package, $c_code, %named_options)
Compile $c_code and make its functions available as part of $package's namespace, courtesy to Inline::C magic. Works by invoking "import" in Inline in a tweaked fashion, so as to compile with all warnings turned into errors (i.e. -Wall -Werror
) and to link with the OpenSSL libraries. The environment variables are taken into account (see "ENVIRONMENT VARIABLES").
Available named options are:
full_debugging
Returns true iff the environment variable "FULL_DEBUGGING" is set.
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.
ENVIRONMENT VARIABLES
FULL_DEBUGGING
Setting this variable to 1 causes the C code to be compiled without optimization, allowing gdb to dump symbols of static functions with only one call site (which comprises most of the C code in Crypt::OpenSSL::CA). Also, the temporary build files are left intact if FULL_DEBUGGING
is set.
Developpers, please note that in the absence of FULL_DEBUGGING
, the default compiler flags are -g -O2
, still allowing for a range of debugging strategies. FULL_DEBUGGING
should therefore only be set on a one-shot basis by developpers who have a specific need for it.
BUILD_OPENSSL_CFLAGS
Contains the CFLAGS to pass so as to compile C code that links against OpenSSL; eg -I/usr/lib/openssl/include
or something. Passed on to "INC" in Inline::C by "compile_everything".
BUILD_OPENSSL_LDFLAGS
Contains the LDFLAGS to pass so as to link with the OpenSSL libraries; eg -L/usr/lib/openssl/lib
or something. Passed on to "LIBS" in Inline::C by "compile_everything".