summaryrefslogtreecommitdiffstats
path: root/python/libknot/__init__.py.in
blob: 554cbe6f6922a7ca75a8ffae3930a4504678f771 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Python libknot interface."""

import ctypes
import sys


class KnotLookup(ctypes.Structure):
    """Libknot lookup return structure."""

    _fields_ = [('id', ctypes.c_int), ('name', ctypes.c_char_p)]


class KnotRdataDescriptor(ctypes.Structure):
    """Rdata descriptor structure."""

    _fields_ = [('block_types', ctypes.c_int * 8), ('name', ctypes.c_char_p)]


class Knot(object):
    """Basic libknot interface."""

    LIBKNOT = None
    LIBKNOT_VERSION = "@libknot_SOVERSION@"

    RCODE_NAMES = None

    STRERROR = None
    RDATA_DESC = None

    @classmethod
    def __init__(cls, path: str = None) -> None:
        """Loads shared libknot library.
           An explicit library path can be specified.
        """

        if cls.LIBKNOT:
            return

        if path is None:
            version = ""
            try:
                version = ".%u" % int(cls.LIBKNOT_VERSION)
            except Exception:
                pass

            if sys.platform == "darwin":
                path = "libknot%s.dylib" % version
            else:
                path = "libknot.so%s" % version

        cls.LIBKNOT = ctypes.cdll.LoadLibrary(path)

        cls.RCODE_NAMES = (KnotLookup * 32).in_dll(cls.LIBKNOT, "knot_rcode_names")

        cls.STRERROR = cls.LIBKNOT.knot_strerror
        cls.STRERROR.restype = ctypes.c_char_p
        cls.STRERROR.argtypes = [ctypes.c_int]

        cls.RDATA_DESC = cls.LIBKNOT.knot_get_rdata_descriptor
        cls.RDATA_DESC.restype = ctypes.POINTER(KnotRdataDescriptor)
        cls.RDATA_DESC.argtypes = [ctypes.c_ushort]

    @classmethod
    def rclass_str(cls, rclass: int) -> str:
        """Returns RRCLASS in text form."""

        if (rclass == 1):
            return "IN"
        elif (rclass == 3):
            return "CH"
        elif (rclass == 254):
            return "NONE"
        elif (rclass == 255):
            return "ANY"
        else:
            return "CLASS%i" % rclass

    @classmethod
    def rtype_str(cls, rtype: int) -> str:
        """Returns RRTYPE in text form."""

        descr = cls.RDATA_DESC(rtype).contents.name
        if descr:
            return descr.decode()
        else:
            return "TYPE%i" % rtype

    @classmethod
    def rcode_str(cls, rcode: int) -> str:
        """Returns RCODE in text form."""

        for item in cls.RCODE_NAMES:
            if item.name and item.id == rcode:
                return item.name.decode()
        return "RCODE%i" % rcode