Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #include <Python.h>
16 : :
17 : : #include <dns/serial.h>
18 : : #include <util/python/pycppwrapper_util.h>
19 : :
20 : : #include "serial_python.h"
21 : : #include "pydnspp_common.h"
22 : :
23 : : using namespace std;
24 : : using namespace isc::dns;
25 : : using namespace isc::dns::python;
26 : : using namespace isc::util;
27 : : using namespace isc::util::python;
28 : :
29 : : namespace {
30 : : // The s_* Class simply covers one instantiation of the object
31 : : class s_Serial : public PyObject {
32 : : public:
33 : : s_Serial() : cppobj(NULL) {};
34 : : isc::dns::Serial* cppobj;
35 : : };
36 : :
37 : : typedef CPPPyObjectContainer<s_Serial, Serial> SerialContainer;
38 : :
39 : : PyObject* Serial_str(PyObject* self);
40 : : PyObject* Serial_getValue(s_Serial* self);
41 : : PyObject* Serial_richcmp(s_Serial* self, s_Serial* other, int op);
42 : : PyObject* Serial_add(PyObject *right, PyObject *left);
43 : :
44 : : // This list contains the actual set of functions we have in
45 : : // python. Each entry has
46 : : // 1. Python method name
47 : : // 2. Our static function here
48 : : // 3. Argument type
49 : : // 4. Documentation
50 : : PyMethodDef Serial_methods[] = {
51 : : { "get_value", reinterpret_cast<PyCFunction>(Serial_getValue), METH_NOARGS,
52 : : "Returns the Serial value as an integer" },
53 : : { NULL, NULL, 0, NULL }
54 : : };
55 : :
56 : : // For overriding the + operator. We do not define any other operators for
57 : : // this type.
58 : : PyNumberMethods Serial_NumberMethods = {
59 : : Serial_add, //nb_add;
60 : : NULL, //nb_subtract;
61 : : NULL, //nb_multiply;
62 : : NULL, //nb_remainder;
63 : : NULL, //nb_divmod;
64 : : NULL, //nb_power;
65 : : NULL, //nb_negative;
66 : : NULL, //nb_positive;
67 : : NULL, //nb_absolute;
68 : : NULL, //nb_bool;
69 : : NULL, //nb_invert;
70 : : NULL, //nb_lshift;
71 : : NULL, //nb_rshift;
72 : : NULL, //nb_and;
73 : : NULL, //nb_xor;
74 : : NULL, //nb_or;
75 : : NULL, //nb_int;
76 : : NULL, //nb_reserved;
77 : : NULL, //nb_float;
78 : :
79 : : NULL, //nb_inplace_add;
80 : : NULL, //nb_inplace_subtract;
81 : : NULL, //nb_inplace_multiply;
82 : : NULL, //nb_inplace_remainder;
83 : : NULL, //nb_inplace_power;
84 : : NULL, //nb_inplace_lshift;
85 : : NULL, //nb_inplace_rshift;
86 : : NULL, //nb_inplace_and;
87 : : NULL, //nb_inplace_xor;
88 : : NULL, //nb_inplace_or;
89 : :
90 : : NULL, //nb_floor_divide;
91 : : NULL, //nb_true_divide;
92 : : NULL, //nb_inplace_floor_divide;
93 : : NULL, //nb_inplace_true_divide;
94 : :
95 : : NULL, //nb_index;
96 : : };
97 : :
98 : : int
99 : 323 : Serial_init(s_Serial* self, PyObject* args) {
100 : : long long i;
101 [ + - ]: 323 : if (PyArg_ParseTuple(args, "L", &i)) {
102 : 323 : PyErr_Clear();
103 [ + + ]: 323 : if (i < 0 || i > 0xffffffff) {
104 : 4 : PyErr_SetString(PyExc_ValueError, "Serial number out of range");
105 : 4 : return (-1);
106 : : }
107 : 319 : self->cppobj = new Serial(i);
108 : 323 : return (0);
109 : : } else {
110 : : return (-1);
111 : : }
112 : : }
113 : :
114 : : void
115 : 336 : Serial_destroy(s_Serial* self) {
116 : 336 : delete self->cppobj;
117 : 336 : self->cppobj = NULL;
118 : 336 : Py_TYPE(self)->tp_free(self);
119 : 336 : }
120 : :
121 : : PyObject*
122 : 38 : Serial_getValue(s_Serial* self) {
123 : 38 : return (Py_BuildValue("I", self->cppobj->getValue()));
124 : : }
125 : :
126 : : PyObject*
127 : 52 : Serial_str(PyObject* po_self) {
128 : 52 : const s_Serial* const self = static_cast<s_Serial*>(po_self);
129 : 52 : return (PyUnicode_FromFormat("%u", self->cppobj->getValue()));
130 : : }
131 : :
132 : : PyObject*
133 : 127 : Serial_richcmp(s_Serial* self, s_Serial* other, int op) {
134 : 127 : bool c = false;
135 : :
136 : : // Check for null and if the types match. If different type,
137 : : // simply return False
138 [ + - ][ - + ]: 127 : if (!other || (self->ob_type != other->ob_type)) {
139 : 0 : Py_RETURN_FALSE;
140 : : }
141 : :
142 [ + + + + : 127 : switch (op) {
+ + - ]
143 : : case Py_LT:
144 : 6 : c = *self->cppobj < *other->cppobj;
145 : 6 : break;
146 : : case Py_LE:
147 : 24 : c = *self->cppobj <= *other->cppobj;
148 : 24 : break;
149 : : case Py_EQ:
150 : 37 : c = *self->cppobj == *other->cppobj;
151 : 37 : break;
152 : : case Py_NE:
153 : 37 : c = *self->cppobj != *other->cppobj;
154 : 37 : break;
155 : : case Py_GT:
156 : 2 : c = *self->cppobj > *other->cppobj;
157 : 2 : break;
158 : : case Py_GE:
159 : 21 : c = *self->cppobj >= *other->cppobj;
160 : 21 : break;
161 : : }
162 [ + + ]: 127 : if (c) {
163 : 69 : Py_RETURN_TRUE;
164 : : } else {
165 : 127 : Py_RETURN_FALSE;
166 : : }
167 : : }
168 : :
169 : : PyObject *
170 : 16 : Serial_add(PyObject *left, PyObject *right) {
171 : : // Either can be either a serial or a long, as long as one of them is a
172 : : // serial
173 [ + + ][ + + ]: 16 : if (PySerial_Check(left) && PySerial_Check(right)) {
[ + + ]
174 : 7 : return (createSerialObject(PySerial_ToSerial(left) +
175 : 14 : PySerial_ToSerial(right)));
176 [ + + ][ + + ]: 9 : } else if (PySerial_Check(left) && PyLong_Check(right)) {
[ + + ]
177 : 5 : return (createSerialObject(PySerial_ToSerial(left) +
178 : 10 : PyLong_AsLong(right)));
179 [ + + ][ - + ]: 4 : } else if (PyLong_Check(left) && PySerial_Check(right)) {
[ + + ]
180 : 1 : return (createSerialObject(PySerial_ToSerial(right) +
181 : 2 : PyLong_AsLong(left)));
182 : : } else {
183 : 3 : Py_INCREF(Py_NotImplemented);
184 : 16 : return Py_NotImplemented;
185 : : }
186 : : }
187 : :
188 : : } // end anonymous namespace
189 : :
190 : : namespace isc {
191 : : namespace dns {
192 : : namespace python {
193 : : // This defines the complete type for reflection in python and
194 : : // parsing of PyObject* to s_Serial
195 : : // Most of the functions are not actually implemented and NULL here.
196 : : PyTypeObject serial_type = {
197 : : PyVarObject_HEAD_INIT(NULL, 0)
198 : : "pydnspp.Serial",
199 : : sizeof(s_Serial), // tp_basicsize
200 : : 0, // tp_itemsize
201 : : (destructor)Serial_destroy, // tp_dealloc
202 : : NULL, // tp_print
203 : : NULL, // tp_getattr
204 : : NULL, // tp_setattr
205 : : NULL, // tp_reserved
206 : : NULL, // tp_repr
207 : : &Serial_NumberMethods, // tp_as_number
208 : : NULL, // tp_as_sequence
209 : : NULL, // tp_as_mapping
210 : : NULL, // tp_hash
211 : : NULL, // tp_call
212 : : Serial_str, // tp_str
213 : : NULL, // tp_getattro
214 : : NULL, // tp_setattro
215 : : NULL, // tp_as_buffer
216 : : Py_TPFLAGS_DEFAULT, // tp_flags
217 : : "The Serial class encapsulates Serials used in DNS SOA records.\n\n"
218 : : "This is a straightforward class; an Serial object simply maintains a "
219 : : "32-bit unsigned integer corresponding to the SOA SERIAL value. The "
220 : : "main purpose of this class is to provide serial number arithmetic, as "
221 : : "described in RFC 1892. Objects of this type can be compared and added "
222 : : "to each other, as described in RFC 1892. Apart from str(), get_value(), "
223 : : "comparison operators, and the + operator, no other operations are "
224 : : "defined for this type.",
225 : : NULL, // tp_traverse
226 : : NULL, // tp_clear
227 : : (richcmpfunc)Serial_richcmp, // tp_richcompare
228 : : 0, // tp_weaklistoffset
229 : : NULL, // tp_iter
230 : : NULL, // tp_iternext
231 : : Serial_methods, // tp_methods
232 : : NULL, // tp_members
233 : : NULL, // tp_getset
234 : : NULL, // tp_base
235 : : NULL, // tp_dict
236 : : NULL, // tp_descr_get
237 : : NULL, // tp_descr_set
238 : : 0, // tp_dictoffset
239 : : (initproc)Serial_init, // tp_init
240 : : NULL, // tp_alloc
241 : : PyType_GenericNew, // tp_new
242 : : NULL, // tp_free
243 : : NULL, // tp_is_gc
244 : : NULL, // tp_bases
245 : : NULL, // tp_mro
246 : : NULL, // tp_cache
247 : : NULL, // tp_subclasses
248 : : NULL, // tp_weaklist
249 : : NULL, // tp_del
250 : : 0 // tp_version_tag
251 : : };
252 : :
253 : : PyObject*
254 : 13 : createSerialObject(const Serial& source) {
255 : 13 : SerialContainer container(PyObject_New(s_Serial, &serial_type));
256 [ + - ][ + - ]: 13 : container.set(new Serial(source));
257 : 13 : return (container.release());
258 : : }
259 : :
260 : : bool
261 : 40 : PySerial_Check(PyObject* obj) {
262 [ - + ]: 40 : if (obj == NULL) {
263 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException,
264 : : "obj argument NULL in Serial typecheck");
265 : : }
266 [ + + ][ + - ]: 40 : return (PyObject_TypeCheck(obj, &serial_type));
267 : : }
268 : :
269 : : const Serial&
270 : 20 : PySerial_ToSerial(const PyObject* serial_obj) {
271 [ - + ]: 20 : if (serial_obj == NULL) {
272 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException,
273 : : "obj argument NULL in Serial PyObject conversion");
274 : : }
275 : 20 : const s_Serial* serial = static_cast<const s_Serial*>(serial_obj);
276 : 20 : return (*serial->cppobj);
277 : : }
278 : :
279 : : } // namespace python
280 : : } // namespace dns
281 : 123 : } // namespace isc
|