You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
3.1 KiB
70 lines
3.1 KiB
7 months ago
|
.. _internals:
|
||
|
|
||
|
Internals
|
||
|
=========
|
||
|
|
||
|
We ran into three main problems developing this: Exceptions, callbacks and
|
||
|
accessing socket methods. This is what this chapter is about.
|
||
|
|
||
|
|
||
|
.. _exceptions:
|
||
|
|
||
|
Exceptions
|
||
|
----------
|
||
|
|
||
|
We realized early that most of the exceptions would be raised by the I/O
|
||
|
functions of OpenSSL, so it felt natural to mimic OpenSSL's error code system,
|
||
|
translating them into Python exceptions. This naturally gives us the exceptions
|
||
|
:py:exc:`.SSL.ZeroReturnError`, :py:exc:`.SSL.WantReadError`,
|
||
|
:py:exc:`.SSL.WantWriteError`, :py:exc:`.SSL.WantX509LookupError` and
|
||
|
:py:exc:`.SSL.SysCallError`.
|
||
|
|
||
|
For more information about this, see section :ref:`openssl-ssl`.
|
||
|
|
||
|
|
||
|
.. _callbacks:
|
||
|
|
||
|
Callbacks
|
||
|
---------
|
||
|
|
||
|
Callbacks were more of a problem when pyOpenSSL was written in C.
|
||
|
Having switched to being written in Python using cffi, callbacks are now straightforward.
|
||
|
The problems that originally existed no longer do
|
||
|
(if you are interested in the details you can find descriptions of those problems in the version control history for this document).
|
||
|
|
||
|
.. _socket-methods:
|
||
|
|
||
|
Accessing Socket Methods
|
||
|
------------------------
|
||
|
|
||
|
We quickly saw the benefit of wrapping socket methods in the
|
||
|
:py:class:`.SSL.Connection` class, for an easy transition into using SSL. The
|
||
|
problem here is that the :py:mod:`socket` module lacks a C API, and all the
|
||
|
methods are declared static. One approach would be to have :py:mod:`.OpenSSL` as
|
||
|
a submodule to the :py:mod:`socket` module, placing all the code in
|
||
|
``socketmodule.c``, but this is obviously not a good solution, since you
|
||
|
might not want to import tonnes of extra stuff you're not going to use when
|
||
|
importing the :py:mod:`socket` module. The other approach is to somehow get a
|
||
|
pointer to the method to be called, either the C function, or a callable Python
|
||
|
object. This is not really a good solution either, since there's a lot of
|
||
|
lookups involved.
|
||
|
|
||
|
The way it works is that you have to supply a :py:class:`socket`- **like** transport
|
||
|
object to the :py:class:`.SSL.Connection`. The only requirement of this object is
|
||
|
that it has a :py:meth:`fileno()` method that returns a file descriptor that's
|
||
|
valid at the C level (i.e. you can use the system calls read and write). If you
|
||
|
want to use the :py:meth:`connect()` or :py:meth:`accept()` methods of the
|
||
|
:py:class:`.SSL.Connection` object, the transport object has to supply such
|
||
|
methods too. Apart from them, any method lookups in the :py:class:`.SSL.Connection`
|
||
|
object that fail are passed on to the underlying transport object.
|
||
|
|
||
|
Future changes might be to allow Python-level transport objects, that instead
|
||
|
of having :py:meth:`fileno()` methods, have :py:meth:`read()` and :py:meth:`write()`
|
||
|
methods, so more advanced features of Python can be used. This would probably
|
||
|
entail some sort of OpenSSL **BIOs**, but converting Python strings back and
|
||
|
forth is expensive, so this shouldn't be used unless necessary. Other nice
|
||
|
things would be to be able to pass in different transport objects for reading
|
||
|
and writing, but then the :py:meth:`fileno()` method of :py:class:`.SSL.Connection`
|
||
|
becomes virtually useless. Also, should the method resolution be used on the
|
||
|
read-transport or the write-transport?
|