s4-python: Move dnspython to lib/, like the other Python modules
[kai/samba-autobuild/.git] / lib / dnspython / dns / edns.py
1 # Copyright (C) 2009 Nominum, Inc.
2 #
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose with or without fee is hereby granted,
5 # provided that the above copyright notice and this permission notice
6 # appear in all copies.
7 #
8 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16 """EDNS Options"""
17
18 NSID = 3
19
20 class Option(object):
21     """Base class for all EDNS option types.
22     """
23
24     def __init__(self, otype):
25         """Initialize an option.
26         @param rdtype: The rdata type
27         @type rdtype: int
28         """
29         self.otype = otype
30
31     def to_wire(self, file):
32         """Convert an option to wire format.
33         """
34         raise NotImplementedError
35
36     def from_wire(cls, otype, wire, current, olen):
37         """Build an EDNS option object from wire format
38
39         @param otype: The option type
40         @type otype: int
41         @param wire: The wire-format message
42         @type wire: string
43         @param current: The offet in wire of the beginning of the rdata.
44         @type current: int
45         @param olen: The length of the wire-format option data
46         @type olen: int
47         @rtype: dns.ends.Option instance"""
48         raise NotImplementedError
49
50     from_wire = classmethod(from_wire)
51
52     def _cmp(self, other):
53         """Compare an ENDS option with another option of the same type.
54         Return < 0 if self < other, 0 if self == other, and > 0 if self > other.
55         """
56         raise NotImplementedError
57
58     def __eq__(self, other):
59         if not isinstance(other, Option):
60             return False
61         if self.otype != other.otype:
62             return False
63         return self._cmp(other) == 0
64
65     def __ne__(self, other):
66         if not isinstance(other, Option):
67             return False
68         if self.otype != other.otype:
69             return False
70         return self._cmp(other) != 0
71
72     def __lt__(self, other):
73         if not isinstance(other, Option) or \
74                self.otype != other.otype:
75             return NotImplemented
76         return self._cmp(other) < 0
77
78     def __le__(self, other):
79         if not isinstance(other, Option) or \
80                self.otype != other.otype:
81             return NotImplemented
82         return self._cmp(other) <= 0
83
84     def __ge__(self, other):
85         if not isinstance(other, Option) or \
86                self.otype != other.otype:
87             return NotImplemented
88         return self._cmp(other) >= 0
89
90     def __gt__(self, other):
91         if not isinstance(other, Option) or \
92                self.otype != other.otype:
93             return NotImplemented
94         return self._cmp(other) > 0
95
96
97 class GenericOption(Option):
98     """Generate Rdata Class
99
100     This class is used for EDNS option types for which we have no better
101     implementation.
102     """
103
104     def __init__(self, otype, data):
105         super(GenericOption, self).__init__(otype)
106         self.data = data
107
108     def to_wire(self, file):
109         file.write(self.data)
110
111     def from_wire(cls, otype, wire, current, olen):
112         return cls(otype, wire[current : current + olen])
113
114     from_wire = classmethod(from_wire)
115
116     def _cmp(self, other):
117         return cmp(self.data, other.data)
118
119 _type_to_class = {
120 }
121
122 def get_option_class(otype):
123     cls = _type_to_class.get(otype)
124     if cls is None:
125         cls = GenericOption
126     return cls
127
128 def option_from_wire(otype, wire, current, olen):
129     """Build an EDNS option object from wire format
130
131     @param otype: The option type
132     @type otype: int
133     @param wire: The wire-format message
134     @type wire: string
135     @param current: The offet in wire of the beginning of the rdata.
136     @type current: int
137     @param olen: The length of the wire-format option data
138     @type olen: int
139     @rtype: dns.ends.Option instance"""
140
141     cls = get_option_class(otype)
142     return cls.from_wire(otype, wire, current, olen)