Skip to content

Commit

Permalink
build abi3 wheels
Browse files Browse the repository at this point in the history
 - change c extensions to use the limited ABI
 - update `setup.py` to build abi3 wheels
 - add Python 3.11 to build matrix
 - rebased 2023may08

Co-authored-by: Kelsey Gilbert <[email protected]>
Co-authored-by: Jeremy Lainé <[email protected]>
  • Loading branch information
3 people committed Jul 4, 2023
1 parent 61eca01 commit 20eaa61
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 130 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools"]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
Expand Down
17 changes: 17 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sys

import setuptools
from wheel.bdist_wheel import bdist_wheel

if sys.platform == "win32":
extra_compile_args = []
Expand All @@ -9,18 +10,34 @@
extra_compile_args = ["-std=c99"]
libraries = ["crypto"]


class bdist_wheel_abi3(bdist_wheel):
def get_tag(self):
python, abi, plat = super().get_tag()

if python.startswith("cp"):
return "cp37", "abi3", plat

return python, abi, plat


setuptools.setup(
ext_modules=[
setuptools.Extension(
"aioquic._buffer",
extra_compile_args=extra_compile_args,
sources=["src/aioquic/_buffer.c"],
define_macros=[("Py_LIMITED_API", "0x03070000")],
py_limited_api=True,
),
setuptools.Extension(
"aioquic._crypto",
extra_compile_args=extra_compile_args,
libraries=libraries,
sources=["src/aioquic/_crypto.c"],
define_macros=[("Py_LIMITED_API", "0x03070000")],
py_limited_api=True,
),
],
cmdclass={"bdist_wheel": bdist_wheel_abi3},
)
71 changes: 28 additions & 43 deletions src/aioquic/_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ typedef struct {
uint8_t *pos;
} BufferObject;

static PyObject *BufferType;

#define CHECK_READ_BOUNDS(self, len) \
if (len < 0 || self->pos + len > self->end) { \
PyErr_SetString(BufferReadError, "Read out of bounds"); \
Expand Down Expand Up @@ -54,7 +56,10 @@ static void
Buffer_dealloc(BufferObject *self)
{
free(self->base);
Py_TYPE(self)->tp_free((PyObject *) self);
PyTypeObject *tp = Py_TYPE(self);
freefunc free = PyType_GetSlot(tp, Py_tp_free);
free(self);
Py_DECREF(tp);
}

static PyObject *
Expand Down Expand Up @@ -360,44 +365,21 @@ static PyGetSetDef Buffer_getset[] = {
{NULL}
};

static PyTypeObject BufferType = {
PyVarObject_HEAD_INIT(NULL, 0)
MODULE_NAME ".Buffer", /* tp_name */
sizeof(BufferObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)Buffer_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Buffer objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Buffer_methods, /* tp_methods */
0, /* tp_members */
Buffer_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Buffer_init, /* tp_init */
0, /* tp_alloc */
static PyType_Slot BufferType_slots[] = {
{Py_tp_dealloc, Buffer_dealloc},
{Py_tp_methods, Buffer_methods},
{Py_tp_doc, "Buffer objects"},
{Py_tp_getset, Buffer_getset},
{Py_tp_init, Buffer_init},
{0, 0},
};

static PyType_Spec BufferType_spec = {
MODULE_NAME ".Buffer",
sizeof(BufferObject),
0,
Py_TPFLAGS_DEFAULT,
BufferType_slots
};


Expand Down Expand Up @@ -431,11 +413,14 @@ PyInit__buffer(void)
Py_INCREF(BufferWriteError);
PyModule_AddObject(m, "BufferWriteError", BufferWriteError);

BufferType.tp_new = PyType_GenericNew;
if (PyType_Ready(&BufferType) < 0)
BufferType = PyType_FromSpec(&BufferType_spec);
if (BufferType == NULL)
return NULL;

PyObject *o = PyType_FromSpec(&BufferType_spec);
if (o == NULL)
return NULL;
Py_INCREF(&BufferType);
PyModule_AddObject(m, "Buffer", (PyObject *)&BufferType);
PyModule_AddObject(m, "Buffer", o);

return m;
}
140 changes: 54 additions & 86 deletions src/aioquic/_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ typedef struct {
unsigned char nonce[AEAD_NONCE_LENGTH];
} AEADObject;

static PyObject *AEADType;

static EVP_CIPHER_CTX *
create_ctx(const EVP_CIPHER *cipher, int key_length, int operation)
{
Expand Down Expand Up @@ -104,7 +106,10 @@ AEAD_dealloc(AEADObject *self)
{
EVP_CIPHER_CTX_free(self->decrypt_ctx);
EVP_CIPHER_CTX_free(self->encrypt_ctx);
Py_TYPE(self)->tp_free((PyObject *) self);
PyTypeObject *tp = Py_TYPE(self);
freefunc free = PyType_GetSlot(tp, Py_tp_free);
free(self);
Py_DECREF(tp);
}

static PyObject*
Expand Down Expand Up @@ -195,44 +200,20 @@ static PyMethodDef AEAD_methods[] = {
{NULL}
};

static PyTypeObject AEADType = {
PyVarObject_HEAD_INIT(NULL, 0)
MODULE_NAME ".AEAD", /* tp_name */
sizeof(AEADObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)AEAD_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"AEAD objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
AEAD_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)AEAD_init, /* tp_init */
0, /* tp_alloc */
static PyType_Slot AEADType_slots[] = {
{Py_tp_dealloc, AEAD_dealloc},
{Py_tp_methods, AEAD_methods},
{Py_tp_doc, "AEAD objects"},
{Py_tp_init, AEAD_init},
{0, 0},
};

static PyType_Spec AEADType_spec = {
MODULE_NAME ".AEADType",
sizeof(AEADObject),
0,
Py_TPFLAGS_DEFAULT,
AEADType_slots
};

/* HeaderProtection */
Expand All @@ -246,6 +227,8 @@ typedef struct {
unsigned char zero[5];
} HeaderProtectionObject;

static PyObject *HeaderProtectionType;

static int
HeaderProtection_init(HeaderProtectionObject *self, PyObject *args, PyObject *kwargs)
{
Expand Down Expand Up @@ -286,7 +269,10 @@ static void
HeaderProtection_dealloc(HeaderProtectionObject *self)
{
EVP_CIPHER_CTX_free(self->ctx);
Py_TYPE(self)->tp_free((PyObject *) self);
PyTypeObject *tp = Py_TYPE(self);
freefunc free = PyType_GetSlot(tp, Py_tp_free);
free(self);
Py_DECREF(tp);
}

static int HeaderProtection_mask(HeaderProtectionObject *self, const unsigned char* sample)
Expand Down Expand Up @@ -369,46 +355,21 @@ static PyMethodDef HeaderProtection_methods[] = {
{NULL}
};

static PyTypeObject HeaderProtectionType = {
PyVarObject_HEAD_INIT(NULL, 0)
MODULE_NAME ".HeaderProtection", /* tp_name */
sizeof(HeaderProtectionObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)HeaderProtection_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"HeaderProtection objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
HeaderProtection_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)HeaderProtection_init, /* tp_init */
0, /* tp_alloc */
static PyType_Slot HeaderProtectionType_slots[] = {
{Py_tp_dealloc, HeaderProtection_dealloc},
{Py_tp_methods, HeaderProtection_methods},
{Py_tp_doc, "HeaderProtection objects"},
{Py_tp_init, HeaderProtection_init},
{0, 0},
};

static PyType_Spec HeaderProtectionType_spec = {
MODULE_NAME ".HeaderProtectionType",
sizeof(HeaderProtectionObject),
0,
Py_TPFLAGS_DEFAULT,
HeaderProtectionType_slots
};

static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
Expand All @@ -426,6 +387,7 @@ PyMODINIT_FUNC
PyInit__crypto(void)
{
PyObject* m;
PyObject *o;

m = PyModule_Create(&moduledef);
if (m == NULL)
Expand All @@ -435,17 +397,23 @@ PyInit__crypto(void)
Py_INCREF(CryptoError);
PyModule_AddObject(m, "CryptoError", CryptoError);

AEADType.tp_new = PyType_GenericNew;
if (PyType_Ready(&AEADType) < 0)
AEADType = PyType_FromSpec(&AEADType_spec);
if (AEADType == NULL)
return NULL;

o = PyType_FromSpec(&AEADType_spec);
if (o == NULL)
return NULL;
PyModule_AddObject(m, "AEAD", o);

HeaderProtectionType = PyType_FromSpec(&HeaderProtectionType_spec);
if (HeaderProtectionType == NULL)
return NULL;
Py_INCREF(&AEADType);
PyModule_AddObject(m, "AEAD", (PyObject *)&AEADType);

HeaderProtectionType.tp_new = PyType_GenericNew;
if (PyType_Ready(&HeaderProtectionType) < 0)
o = PyType_FromSpec(&HeaderProtectionType_spec);
if (o == NULL)
return NULL;
Py_INCREF(&HeaderProtectionType);
PyModule_AddObject(m, "HeaderProtection", (PyObject *)&HeaderProtectionType);
PyModule_AddObject(m, "HeaderProtection", o);

// ensure required ciphers are initialised
EVP_add_cipher(EVP_aes_128_ecb());
Expand Down

0 comments on commit 20eaa61

Please sign in to comment.