1.. _internals:
2
3Internals
4=========
5
6We ran into three main problems developing this: Exceptions, callbacks and
7accessing socket methods. This is what this chapter is about.
8
9
10.. _exceptions:
11
12Exceptions
13----------
14
15We realized early that most of the exceptions would be raised by the I/O
16functions of OpenSSL, so it felt natural to mimic OpenSSL's error code system,
17translating them into Python exceptions. This naturally gives us the exceptions
18:py:exc:`.SSL.ZeroReturnError`, :py:exc:`.SSL.WantReadError`,
19:py:exc:`.SSL.WantWriteError`, :py:exc:`.SSL.WantX509LookupError` and
20:py:exc:`.SSL.SysCallError`.
21
22For more information about this, see section :ref:`openssl-ssl`.
23
24
25.. _callbacks:
26
27Callbacks
28---------
29
30Callbacks were more of a problem when pyOpenSSL was written in C.
31Having switched to being written in Python using cffi, callbacks are now straightforward.
32The problems that originally existed no longer do
33(if you are interested in the details you can find descriptions of those problems in the version control history for this document).
34
35.. _socket-methods:
36
37Accessing Socket Methods
38------------------------
39
40We quickly saw the benefit of wrapping socket methods in the
41:py:class:`.SSL.Connection` class, for an easy transition into using SSL. The
42problem here is that the :py:mod:`socket` module lacks a C API, and all the
43methods are declared static. One approach would be to have :py:mod:`.OpenSSL` as
44a submodule to the :py:mod:`socket` module, placing all the code in
45``socketmodule.c``, but this is obviously not a good solution, since you
46might not want to import tonnes of extra stuff you're not going to use when
47importing the :py:mod:`socket` module. The other approach is to somehow get a
48pointer to the method to be called, either the C function, or a callable Python
49object. This is not really a good solution either, since there's a lot of
50lookups involved.
51
52The way it works is that you have to supply a :py:class:`socket`- **like** transport
53object to the :py:class:`.SSL.Connection`. The only requirement of this object is
54that it has a :py:meth:`fileno()` method that returns a file descriptor that's
55valid at the C level (i.e. you can use the system calls read and write). If you
56want to use the :py:meth:`connect()` or :py:meth:`accept()` methods of the
57:py:class:`.SSL.Connection` object, the transport object has to supply such
58methods too. Apart from them, any method lookups in the :py:class:`.SSL.Connection`
59object that fail are passed on to the underlying transport object.
60
61Future changes might be to allow Python-level transport objects, that instead
62of having :py:meth:`fileno()` methods, have :py:meth:`read()` and :py:meth:`write()`
63methods, so more advanced features of Python can be used. This would probably
64entail some sort of OpenSSL **BIOs**, but converting Python strings back and
65forth is expensive, so this shouldn't be used unless necessary. Other nice
66things would be to be able to pass in different transport objects for reading
67and writing, but then the :py:meth:`fileno()` method of :py:class:`.SSL.Connection`
68becomes virtually useless. Also, should the method resolution be used on the
69read-transport or the write-transport?
70