internals.rst 3.1 KB

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