For certain reasons I have to extend python's ssl module. In particular I need a second version of load_cert_chain() in C.
My problem is not related to openssl but rather how to cope with "clinic": In front of the original function there is a clinic-input:
/*[clinic input]
_ssl._SSLContext.load_cert_chain
certfile: object
keyfile: object = NULL
password: object = NULL
[clinic start generated code]*/
static PyObject *
_ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
PyObject *keyfile, PyObject *password)
/*[clinic end generated code: output=9480bc1c380e2095 input=7cf9ac673cbee6fc]*/
{
PyObject *certfile_bytes = NULL, *keyfile_bytes = NULL;
pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback;
...
So far I know, that the _ssl__SSLContext_load_cert_chain_impl is the implementation of load_cert_chain and called within _ssl__SSLContext_load_cert_chain, which is defined within the header file _ssl.c.h This, however, is auto-generated by clinic- isn't it?
So where do I start to define my new function load_cert_chain2 as a copy of the original, since everything is auto-created?
To clear some misunderstanding:
No, the argument clinic has nothing to do with linking C functions to Python functions!
The argument clinic just creates a function signature for a C function. In your example
/*[clinic input]
_ssl._SSLContext.load_cert_chain
certfile: object
keyfile: object = NULL
password: object = NULL
The _ssl__SSLContext_load_cert_chain_impl
C function will be exposed in the signature as _ssl._SSLContext.load_cert_chain
with the three arguments expecting a python object
: certfile
as positional argument and keyfile, password
as optional arguments with a default of NULL
.
How or when the function is called isn't linked to the argument clinic. The method declaration is done in Modules/clinic/_ssl.c.h
:
#define _SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF \
{"load_cert_chain", (PyCFunction)_ssl__SSLContext_load_cert_chain, METH_FASTCALL, _ssl__SSLContext_load_cert_chain__doc__}
static PyObject *
_ssl__SSLContext_load_cert_chain(PySSLContext *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
[...]
return_value = _ssl__SSLContext_load_cert_chain_impl(self, certfile, keyfile, password);
}
and it's explicitly added as method to the _SSLContext
class in Modules/_ssl.c
:
static struct PyMethodDef context_methods[] = {
[...]
_SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF
[...]
{NULL, NULL} /* sentinel */
};
[...]
static PyTypeObject PySSLContext_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ssl._SSLContext", /*tp_name*/
sizeof(PySSLContext), /*tp_basicsize*/
[...]
context_methods, /*tp_methods*/
[...]
};
So the argument clinic isn't responsible for assigning the method to a class. That's done with a wrapper function _ssl__SSLContext_load_cert_chain
around _ssl__SSLContext_load_cert_chain_impl
and assigned to the class using a PyMethodDef
struct that's assigned to the class.
Now you know that there is no auto-generated linking, I don't know if that helps when you want to replace that function. I don't know how you could easily do that (argument clinic or no clinic) without recompiling Python or copying all relevant files into your extension.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments