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 them static, 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 the static 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 croaks), 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:

-boot_section => $c_code

Adds $c_code to the BOOT section of the generated .so module.

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".

SEE ALSO

Inline::C, perlxstut, perlguts, perlapi.