message_python.cc 59.9 KB
Newer Older
1
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
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
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $Id: message_python.cc 1711 2010-04-14 15:14:53Z jelte $

#include <dns/message.h>
using namespace isc::dns;

//
// Declaration of the custom exceptions
// Initialization and addition of these go in the initModulePart
// function at the end of this file
//
static PyObject* po_MessageTooShort;
static PyObject* po_InvalidMessageSection;
static PyObject* po_InvalidMessageOperation;
static PyObject* po_InvalidMessageUDPSize;
static PyObject* po_DNSMessageBADVERS;

//
// Definition of the classes
//

// For each class, we need a struct, a helper functions (init, destroy,
// and static wrappers around the methods we export), a list of methods,
// and a type description


//
// MessageFlag
//
43
44
class s_MessageFlag : public PyObject {
public:
45
    const MessageFlag* messageflag;
46
};
47
48
49
50
51
52
53
54
55
56
57
58
59
60

static int MessageFlag_init(s_MessageFlag* self, PyObject* args);
static void MessageFlag_destroy(s_MessageFlag* self);

static PyObject* MessageFlag_getBit(s_MessageFlag* self);
static PyObject* MessageFlag_QR(s_MessageFlag* self);
static PyObject* MessageFlag_AA(s_MessageFlag* self);
static PyObject* MessageFlag_TC(s_MessageFlag* self);
static PyObject* MessageFlag_RD(s_MessageFlag* self);
static PyObject* MessageFlag_RA(s_MessageFlag* self);
static PyObject* MessageFlag_AD(s_MessageFlag* self);
static PyObject* MessageFlag_CD(s_MessageFlag* self);

static PyMethodDef MessageFlag_methods[] = {
61
62
63
64
65
66
67
68
    { "get_bit", reinterpret_cast<PyCFunction>(MessageFlag_getBit), METH_NOARGS, "Returns the flag bit" },
    { "QR", reinterpret_cast<PyCFunction>(MessageFlag_QR), METH_NOARGS | METH_STATIC, "Creates a QR MessageFlag" },
    { "AA", reinterpret_cast<PyCFunction>(MessageFlag_AA), METH_NOARGS | METH_STATIC, "Creates a AA MessageFlag" },
    { "TC", reinterpret_cast<PyCFunction>(MessageFlag_TC), METH_NOARGS | METH_STATIC, "Creates a TC MessageFlag" },
    { "RD", reinterpret_cast<PyCFunction>(MessageFlag_RD), METH_NOARGS | METH_STATIC, "Creates a RD MessageFlag" },
    { "RA", reinterpret_cast<PyCFunction>(MessageFlag_RA), METH_NOARGS | METH_STATIC, "Creates a RA MessageFlag" },
    { "AD", reinterpret_cast<PyCFunction>(MessageFlag_AD), METH_NOARGS | METH_STATIC, "Creates a AD MessageFlag" },
    { "CD", reinterpret_cast<PyCFunction>(MessageFlag_CD), METH_NOARGS | METH_STATIC, "Creates a CD MessageFlag" },
69
70
71
72
73
74
    { NULL, NULL, 0, NULL }
};

static PyTypeObject messageflag_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "libdns_python.MessageFlag",
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    sizeof(s_MessageFlag),              // tp_basicsize
    0,                                  // tp_itemsize
    (destructor)MessageFlag_destroy,    // tp_dealloc
    NULL,                               // tp_print
    NULL,                               // tp_getattr
    NULL,                               // tp_setattr
    NULL,                               // tp_reserved
    NULL,                               // tp_repr
    NULL,                               // tp_as_number
    NULL,                               // tp_as_sequence
    NULL,                               // tp_as_mapping
    NULL,                               // tp_hash 
    NULL,                               // tp_call
    NULL,                               // tp_str
    NULL,                               // tp_getattro
    NULL,                               // tp_setattro
    NULL,                               // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                 // tp_flags
Jelte Jansen's avatar
Jelte Jansen committed
93
94
    "The MessageFlag class objects represent standard "
    "flag bits of the header section of DNS messages.",
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    NULL,                               // tp_traverse
    NULL,                               // tp_clear
    NULL,                               // tp_richcompare
    0,                                  // tp_weaklistoffset
    NULL,                               // tp_iter
    NULL,                               // tp_iternext
    MessageFlag_methods,                // tp_methods
    NULL,                               // tp_members
    NULL,                               // tp_getset
    NULL,                               // tp_base
    NULL,                               // tp_dict
    NULL,                               // tp_descr_get
    NULL,                               // tp_descr_set
    0,                                  // tp_dictoffset
    (initproc)MessageFlag_init,         // tp_init
    NULL,                               // tp_alloc
    PyType_GenericNew,                  // tp_new
    NULL,                               // tp_free
    NULL,                               // tp_is_gc
    NULL,                               // tp_bases
    NULL,                               // tp_mro
    NULL,                               // tp_cache
    NULL,                               // tp_subclasses
    NULL,                               // tp_weaklist
    NULL,                               // tp_del
    0                                   // tp_version_tag
121
122
123
124
};


static int
125
126
MessageFlag_init(s_MessageFlag* self UNUSED_PARAM,
                 PyObject* args UNUSED_PARAM)
127
128
129
{
    PyErr_SetString(PyExc_NotImplementedError,
                    "MessageFlag can't be built directly");
Jelte Jansen's avatar
Jelte Jansen committed
130
    return (-1);
131
132
133
}

static void
134
MessageFlag_destroy(s_MessageFlag* self) {
135
136
137
138
139
140
141
    // We only use the consts from MessageFlag, so don't
    // delete self->messageflag here
    self->messageflag = NULL;
    Py_TYPE(self)->tp_free(self);
}

static PyObject*
142
MessageFlag_getBit(s_MessageFlag* self) {
Jelte Jansen's avatar
Jelte Jansen committed
143
    return (Py_BuildValue("I", self->messageflag->getBit()));
144
145
146
}

static PyObject*
147
MessageFlag_createStatic(const MessageFlag& flag) {
148
149
    s_MessageFlag* ret = PyObject_New(s_MessageFlag, &messageflag_type);
    if (ret != NULL) {
150
        ret->messageflag = &flag;
151
    }
152
153
154
155
156
    return (ret);
}

static PyObject*
MessageFlag_QR(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
157
    return (MessageFlag_createStatic(MessageFlag::QR()));
158
159
160
}

static PyObject*
161
MessageFlag_AA(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
162
    return (MessageFlag_createStatic(MessageFlag::AA()));
163
164
165
}

static PyObject*
166
MessageFlag_TC(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
167
    return (MessageFlag_createStatic(MessageFlag::TC()));
168
169
170
}

static PyObject*
171
MessageFlag_RD(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
172
    return (MessageFlag_createStatic(MessageFlag::RD()));
173
174
175
}

static PyObject*
176
MessageFlag_RA(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
177
    return (MessageFlag_createStatic(MessageFlag::RA()));
178
179
180
}

static PyObject*
181
MessageFlag_AD(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
182
    return (MessageFlag_createStatic(MessageFlag::AD()));
183
184
185
}

static PyObject*
186
MessageFlag_CD(s_MessageFlag* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
187
    return (MessageFlag_createStatic(MessageFlag::CD()));
188
189
190
191
192
193
194
195
196
197
}

//
// End of MessageFlag wrapper
//


//
// Opcode
//
198
199
class s_Opcode : public PyObject {
public:
200
    const Opcode* opcode;
201
};
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227

static int Opcode_init(s_Opcode* self, PyObject* args);
static void Opcode_destroy(s_Opcode* self);

static PyObject* Opcode_getCode(s_Opcode* self);
static PyObject* Opcode_toText(s_Opcode* self);
static PyObject* Opcode_str(PyObject* self);
static PyObject* Opcode_QUERY(s_Opcode* self);
static PyObject* Opcode_IQUERY(s_Opcode* self);
static PyObject* Opcode_STATUS(s_Opcode* self);
static PyObject* Opcode_RESERVED3(s_Opcode* self);
static PyObject* Opcode_NOTIFY(s_Opcode* self);
static PyObject* Opcode_UPDATE(s_Opcode* self);
static PyObject* Opcode_RESERVED6(s_Opcode* self);
static PyObject* Opcode_RESERVED7(s_Opcode* self);
static PyObject* Opcode_RESERVED8(s_Opcode* self);
static PyObject* Opcode_RESERVED9(s_Opcode* self);
static PyObject* Opcode_RESERVED10(s_Opcode* self);
static PyObject* Opcode_RESERVED11(s_Opcode* self);
static PyObject* Opcode_RESERVED12(s_Opcode* self);
static PyObject* Opcode_RESERVED13(s_Opcode* self);
static PyObject* Opcode_RESERVED14(s_Opcode* self);
static PyObject* Opcode_RESERVED15(s_Opcode* self);
static PyObject* Opcode_richcmp(s_Opcode* self, s_Opcode* other, int op);

static PyMethodDef Opcode_methods[] = {
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    { "get_code", reinterpret_cast<PyCFunction>(Opcode_getCode), METH_NOARGS, "Returns the code value" },
    { "to_text", reinterpret_cast<PyCFunction>(Opcode_toText), METH_NOARGS, "Returns the text representation" },
    { "QUERY", reinterpret_cast<PyCFunction>(Opcode_QUERY), METH_NOARGS | METH_STATIC, "Creates a QUERY Opcode" },
    { "IQUERY", reinterpret_cast<PyCFunction>(Opcode_IQUERY), METH_NOARGS | METH_STATIC, "Creates a IQUERY Opcode" },
    { "STATUS", reinterpret_cast<PyCFunction>(Opcode_STATUS), METH_NOARGS | METH_STATIC, "Creates a STATUS Opcode" },
    { "RESERVED3", reinterpret_cast<PyCFunction>(Opcode_RESERVED3), METH_NOARGS | METH_STATIC, "Creates a RESERVED3 Opcode" },
    { "NOTIFY", reinterpret_cast<PyCFunction>(Opcode_NOTIFY), METH_NOARGS | METH_STATIC, "Creates a NOTIFY Opcode" },
    { "UPDATE", reinterpret_cast<PyCFunction>(Opcode_UPDATE), METH_NOARGS | METH_STATIC, "Creates a UPDATE Opcode" },
    { "RESERVED6", reinterpret_cast<PyCFunction>(Opcode_RESERVED6), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED7", reinterpret_cast<PyCFunction>(Opcode_RESERVED7), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED8", reinterpret_cast<PyCFunction>(Opcode_RESERVED8), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED9", reinterpret_cast<PyCFunction>(Opcode_RESERVED9), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED10", reinterpret_cast<PyCFunction>(Opcode_RESERVED10), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED11", reinterpret_cast<PyCFunction>(Opcode_RESERVED11), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED12", reinterpret_cast<PyCFunction>(Opcode_RESERVED12), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED13", reinterpret_cast<PyCFunction>(Opcode_RESERVED13), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED14", reinterpret_cast<PyCFunction>(Opcode_RESERVED14), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
    { "RESERVED15", reinterpret_cast<PyCFunction>(Opcode_RESERVED15), METH_NOARGS | METH_STATIC, "Creates a RESERVED Opcode" },
246
247
248
249
250
251
    { NULL, NULL, 0, NULL }
};

static PyTypeObject opcode_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "libdns_python.Opcode",
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    sizeof(s_Opcode),                   // tp_basicsize
    0,                                  // tp_itemsize
    (destructor)Opcode_destroy,         // tp_dealloc
    NULL,                               // tp_print
    NULL,                               // tp_getattr
    NULL,                               // tp_setattr
    NULL,                               // tp_reserved
    NULL,                               // tp_repr
    NULL,                               // tp_as_number
    NULL,                               // tp_as_sequence
    NULL,                               // tp_as_mapping
    NULL,                               // tp_hash 
    NULL,                               // tp_call
    Opcode_str,                         // tp_str
    NULL,                               // tp_getattro
    NULL,                               // tp_setattro
    NULL,                               // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                 // tp_flags
Jelte Jansen's avatar
Jelte Jansen committed
270
271
    "The Opcode class objects represent standard OPCODEs "
    "of the header section of DNS messages.",
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
    NULL,                               // tp_traverse
    NULL,                               // tp_clear
    (richcmpfunc)Opcode_richcmp,        // tp_richcompare
    0,                                  // tp_weaklistoffset
    NULL,                               // tp_iter
    NULL,                               // tp_iternext
    Opcode_methods,                     // tp_methods
    NULL,                               // tp_members
    NULL,                               // tp_getset
    NULL,                               // tp_base
    NULL,                               // tp_dict
    NULL,                               // tp_descr_get
    NULL,                               // tp_descr_set
    0,                                  // tp_dictoffset
    (initproc)Opcode_init,              // tp_init
    NULL,                               // tp_alloc
    PyType_GenericNew,                  // tp_new
    NULL,                               // tp_free
    NULL,                               // tp_is_gc
    NULL,                               // tp_bases
    NULL,                               // tp_mro
    NULL,                               // tp_cache
    NULL,                               // tp_subclasses
    NULL,                               // tp_weaklist
    NULL,                               // tp_del
    0                                   // tp_version_tag
298
299
300
301
};


static int
302
Opcode_init(s_Opcode* self UNUSED_PARAM, PyObject* args UNUSED_PARAM) {
303
304
    PyErr_SetString(PyExc_NotImplementedError,
                    "Opcode can't be built directly");
Jelte Jansen's avatar
Jelte Jansen committed
305
    return (-1);
306
307
308
}

static void
309
Opcode_destroy(s_Opcode* self) {
310
311
312
313
314
315
316
    // We only use the consts from Opcode, so don't
    // delete self->opcode here
    self->opcode = NULL;
    Py_TYPE(self)->tp_free(self);
}

static PyObject*
317
Opcode_getCode(s_Opcode* self) {
Jelte Jansen's avatar
Jelte Jansen committed
318
    return (Py_BuildValue("I", self->opcode->getCode()));
319
320
321
}

static PyObject*
322
Opcode_toText(s_Opcode* self) {
Jelte Jansen's avatar
Jelte Jansen committed
323
    return (Py_BuildValue("s", self->opcode->toText().c_str()));
324
325
326
}

static PyObject*
327
Opcode_str(PyObject* self) {
328
    // Simply call the to_text method we already defined
329
330
331
    return PyObject_CallMethod(self,
                               const_cast<char*>("to_text"),
                               const_cast<char*>(""));
332
333
334
}

static PyObject*
335
Opcode_createStatic(const Opcode& opcode) {
336
337
    s_Opcode* ret = PyObject_New(s_Opcode, &opcode_type);
    if (ret != NULL) {
338
        ret->opcode = &opcode;
339
    }
340
341
342
343
344
    return (ret);
}

static PyObject*
Opcode_QUERY(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
345
    return (Opcode_createStatic(Opcode::QUERY()));
346
347
348
}

static PyObject*
349
Opcode_IQUERY(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
350
    return (Opcode_createStatic(Opcode::IQUERY()));
351
352
353
}

static PyObject*
354
Opcode_STATUS(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
355
    return (Opcode_createStatic(Opcode::STATUS()));
356
357
358
}

static PyObject*
359
Opcode_RESERVED3(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
360
    return (Opcode_createStatic(Opcode::RESERVED3()));
361
362
363
}

static PyObject*
364
Opcode_NOTIFY(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
365
    return (Opcode_createStatic(Opcode::NOTIFY()));
366
367
368
}

static PyObject*
369
Opcode_UPDATE(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
370
    return (Opcode_createStatic(Opcode::UPDATE()));
371
372
373
}

static PyObject*
374
Opcode_RESERVED6(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
375
    return (Opcode_createStatic(Opcode::RESERVED6()));
376
377
378
}

static PyObject*
379
Opcode_RESERVED7(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
380
    return (Opcode_createStatic(Opcode::RESERVED7()));
381
382
383
}

static PyObject*
384
Opcode_RESERVED8(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
385
    return (Opcode_createStatic(Opcode::RESERVED8()));
386
387
388
}

static PyObject*
389
Opcode_RESERVED9(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
390
    return (Opcode_createStatic(Opcode::RESERVED9()));
391
392
393
}

static PyObject*
394
Opcode_RESERVED10(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
395
    return (Opcode_createStatic(Opcode::RESERVED10()));
396
397
398
}

static PyObject*
399
Opcode_RESERVED11(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
400
    return (Opcode_createStatic(Opcode::RESERVED11()));
401
402
403
}

static PyObject*
404
Opcode_RESERVED12(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
405
    return (Opcode_createStatic(Opcode::RESERVED12()));
406
407
408
}

static PyObject*
409
Opcode_RESERVED13(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
410
    return (Opcode_createStatic(Opcode::RESERVED13()));
411
412
413
}

static PyObject*
414
Opcode_RESERVED14(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
415
    return (Opcode_createStatic(Opcode::RESERVED14()));
416
417
418
}

static PyObject*
419
Opcode_RESERVED15(s_Opcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
420
    return (Opcode_createStatic(Opcode::RESERVED15()));
421
422
423
}

static PyObject* 
424
Opcode_richcmp(s_Opcode* self, s_Opcode* other, int op) {
Jelte Jansen's avatar
Jelte Jansen committed
425
    bool c = false;
426

427
428
    // Check for null and if the types match. If different type,
    // simply return False
Jelte Jansen's avatar
Jelte Jansen committed
429
    if (!other || (self->ob_type != other->ob_type)) {
430
431
432
        Py_RETURN_FALSE;
    }

433
434
435
436
    // Only equals and not equals here, unorderable type
    switch (op) {
    case Py_LT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
Jelte Jansen's avatar
Jelte Jansen committed
437
        return (NULL);
438
439
440
        break;
    case Py_LE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
Jelte Jansen's avatar
Jelte Jansen committed
441
        return (NULL);
442
443
444
445
446
447
448
449
450
        break;
    case Py_EQ:
        c = (*self->opcode == *other->opcode);
        break;
    case Py_NE:
        c = (*self->opcode != *other->opcode);
        break;
    case Py_GT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
Jelte Jansen's avatar
Jelte Jansen committed
451
        return (NULL);
452
453
454
        break;
    case Py_GE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
Jelte Jansen's avatar
Jelte Jansen committed
455
        return (NULL);
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
        break;
    }
    if (c)
        Py_RETURN_TRUE;
    else
        Py_RETURN_FALSE;
}

//
// End of Opcode wrapper
//

//
// Rcode
//
471
472
473
474
475
476
477
478

// We added a helper variable static_code here
// Since we can create Rcodes dynamically with Rcode(int), but also
// use the static globals (Rcode::NOERROR() etc), we use this
// variable to see if the code came from one of the latter, in which
// case Rcode_destroy should not free it (the other option is to
// allocate new Rcodes for every use of the static ones, but this
// seems more efficient).
479
480
class s_Rcode : public PyObject {
public:
481
    const Rcode* rcode;
482
    bool static_code;
483
};
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510

static int Rcode_init(s_Rcode* self, PyObject* args);
static void Rcode_destroy(s_Rcode* self);

static PyObject* Rcode_getCode(s_Rcode* self);
static PyObject* Rcode_toText(s_Rcode* self);
static PyObject* Rcode_str(PyObject* self);
static PyObject* Rcode_NOERROR(s_Rcode* self);
static PyObject* Rcode_FORMERR(s_Rcode* self);
static PyObject* Rcode_SERVFAIL(s_Rcode* self);
static PyObject* Rcode_NXDOMAIN(s_Rcode* self);
static PyObject* Rcode_NOTIMP(s_Rcode* self);
static PyObject* Rcode_REFUSED(s_Rcode* self);
static PyObject* Rcode_YXDOMAIN(s_Rcode* self);
static PyObject* Rcode_YXRRSET(s_Rcode* self);
static PyObject* Rcode_NXRRSET(s_Rcode* self);
static PyObject* Rcode_NOTAUTH(s_Rcode* self);
static PyObject* Rcode_NOTZONE(s_Rcode* self);
static PyObject* Rcode_RESERVED11(s_Rcode* self);
static PyObject* Rcode_RESERVED12(s_Rcode* self);
static PyObject* Rcode_RESERVED13(s_Rcode* self);
static PyObject* Rcode_RESERVED14(s_Rcode* self);
static PyObject* Rcode_RESERVED15(s_Rcode* self);
static PyObject* Rcode_BADVERS(s_Rcode* self);
static PyObject* Rcode_richcmp(s_Rcode* self, s_Rcode* other, int op);

static PyMethodDef Rcode_methods[] = {
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
    { "get_code", reinterpret_cast<PyCFunction>(Rcode_getCode), METH_NOARGS, "Returns the code value" },
    { "to_text", reinterpret_cast<PyCFunction>(Rcode_toText), METH_NOARGS, "Returns the text representation" },
    { "NOERROR", reinterpret_cast<PyCFunction>(Rcode_NOERROR), METH_NOARGS | METH_STATIC, "Creates a NOERROR Rcode" },
    { "FORMERR", reinterpret_cast<PyCFunction>(Rcode_FORMERR), METH_NOARGS | METH_STATIC, "Creates a FORMERR Rcode" },
    { "SERVFAIL", reinterpret_cast<PyCFunction>(Rcode_SERVFAIL), METH_NOARGS | METH_STATIC, "Creates a SERVFAIL Rcode" },
    { "NXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_NXDOMAIN), METH_NOARGS | METH_STATIC, "Creates a NXDOMAIN Rcode" },
    { "NOTIMP", reinterpret_cast<PyCFunction>(Rcode_NOTIMP), METH_NOARGS | METH_STATIC, "Creates a NOTIMP Rcode" },
    { "REFUSED", reinterpret_cast<PyCFunction>(Rcode_REFUSED), METH_NOARGS | METH_STATIC, "Creates a REFUSED Rcode" },
    { "YXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_YXDOMAIN), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "YXRRSET", reinterpret_cast<PyCFunction>(Rcode_YXRRSET), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "NXRRSET", reinterpret_cast<PyCFunction>(Rcode_NXRRSET), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "NOTAUTH", reinterpret_cast<PyCFunction>(Rcode_NOTAUTH), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "NOTZONE", reinterpret_cast<PyCFunction>(Rcode_NOTZONE), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "RESERVED11", reinterpret_cast<PyCFunction>(Rcode_RESERVED11), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "RESERVED12", reinterpret_cast<PyCFunction>(Rcode_RESERVED12), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "RESERVED13", reinterpret_cast<PyCFunction>(Rcode_RESERVED13), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "RESERVED14", reinterpret_cast<PyCFunction>(Rcode_RESERVED14), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "RESERVED15", reinterpret_cast<PyCFunction>(Rcode_RESERVED15), METH_NOARGS | METH_STATIC, "Creates a RESERVED Rcode" },
    { "BADVERS", reinterpret_cast<PyCFunction>(Rcode_BADVERS), METH_NOARGS | METH_STATIC, "Creates a BADVERS Rcode" },
530
531
532
533
534
535
    { NULL, NULL, 0, NULL }
};

static PyTypeObject rcode_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "libdns_python.Rcode",
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
    sizeof(s_Rcode),                    // tp_basicsize
    0,                                  // tp_itemsize
    (destructor)Rcode_destroy,          // tp_dealloc
    NULL,                               // tp_print
    NULL,                               // tp_getattr
    NULL,                               // tp_setattr
    NULL,                               // tp_reserved
    NULL,                               // tp_repr
    NULL,                               // tp_as_number
    NULL,                               // tp_as_sequence
    NULL,                               // tp_as_mapping
    NULL,                               // tp_hash 
    NULL,                               // tp_call
    Rcode_str,                          // tp_str
    NULL,                               // tp_getattro
    NULL,                               // tp_setattro
    NULL,                               // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                 // tp_flags
Jelte Jansen's avatar
Jelte Jansen committed
554
555
    "The Rcode class objects represent standard RCODEs"
    "of the header section of DNS messages.",
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
    NULL,                               // tp_traverse
    NULL,                               // tp_clear
    (richcmpfunc)Rcode_richcmp,         // tp_richcompare
    0,                                  // tp_weaklistoffset
    NULL,                               // tp_iter
    NULL,                               // tp_iternext
    Rcode_methods,                      // tp_methods
    NULL,                               // tp_members
    NULL,                               // tp_getset
    NULL,                               // tp_base
    NULL,                               // tp_dict
    NULL,                               // tp_descr_get
    NULL,                               // tp_descr_set
    0,                                  // tp_dictoffset
    (initproc)Rcode_init,               // tp_init
    NULL,                               // tp_alloc
    PyType_GenericNew,                  // tp_new
    NULL,                               // tp_free
    NULL,                               // tp_is_gc
    NULL,                               // tp_bases
    NULL,                               // tp_mro
    NULL,                               // tp_cache
    NULL,                               // tp_subclasses
    NULL,                               // tp_weaklist
    NULL,                               // tp_del
    0                                   // tp_version_tag
582
583
584
585
};


static int
586
Rcode_init(s_Rcode* self UNUSED_PARAM, PyObject* args UNUSED_PARAM) {
587
588
589
590
    uint16_t code = 0;
    if (PyArg_ParseTuple(args, "h", &code)) {
        try {
            self->rcode = new Rcode(code);
591
            self->static_code = false;
592
593
594
        } catch (isc::OutOfRange) {
            PyErr_SetString(PyExc_OverflowError,
                            "rcode out of range");
Jelte Jansen's avatar
Jelte Jansen committed
595
            return (-1);
596
        }
Jelte Jansen's avatar
Jelte Jansen committed
597
        return (0);
598
    } else {
Jelte Jansen's avatar
Jelte Jansen committed
599
        return (-1);
600
601
602
603
    }
}

static void
604
Rcode_destroy(s_Rcode* self) {
605
606
    // Depending on whether we created the rcode or are referring
    // to a global static one, we do or do not delete self->rcode here
607
608
609
    if (!self->static_code) {
        delete self->rcode;
    }
610
611
612
613
614
    self->rcode = NULL;
    Py_TYPE(self)->tp_free(self);
}

static PyObject*
615
Rcode_getCode(s_Rcode* self) {
Jelte Jansen's avatar
Jelte Jansen committed
616
    return (Py_BuildValue("I", self->rcode->getCode()));
617
618
619
}

static PyObject*
620
Rcode_toText(s_Rcode* self) {
Jelte Jansen's avatar
Jelte Jansen committed
621
    return (Py_BuildValue("s", self->rcode->toText().c_str()));
622
623
624
}

static PyObject*
625
Rcode_str(PyObject* self) {
626
    // Simply call the to_text method we already defined
627
628
629
    return PyObject_CallMethod(self,
                               const_cast<char*>("to_text"),
                               const_cast<char*>(""));
630
631
632
}

static PyObject*
633
Rcode_createStatic(const Rcode& rcode) {
634
635
    s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
    if (ret != NULL) {
636
        ret->rcode = &rcode;
637
        ret->static_code = true;
638
    }
639
640
641
642
643
    return (ret);
}

static PyObject*
Rcode_NOERROR(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
644
    return (Rcode_createStatic(Rcode::NOERROR()));
645
646
647
}

static PyObject*
648
Rcode_FORMERR(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
649
    return (Rcode_createStatic(Rcode::FORMERR()));
650
651
652
}

static PyObject*
653
Rcode_SERVFAIL(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
654
    return (Rcode_createStatic(Rcode::SERVFAIL()));
655
656
657
}

static PyObject*
658
Rcode_NXDOMAIN(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
659
    return (Rcode_createStatic(Rcode::NXDOMAIN()));
660
661
662
}

static PyObject*
663
Rcode_NOTIMP(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
664
    return (Rcode_createStatic(Rcode::NOTIMP()));
665
666
667
}

static PyObject*
668
Rcode_REFUSED(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
669
    return (Rcode_createStatic(Rcode::REFUSED()));
670
671
672
}

static PyObject*
673
Rcode_YXDOMAIN(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
674
    return (Rcode_createStatic(Rcode::YXDOMAIN()));
675
676
677
}

static PyObject*
678
Rcode_YXRRSET(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
679
    return (Rcode_createStatic(Rcode::YXRRSET()));
680
681
682
}

static PyObject*
683
Rcode_NXRRSET(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
684
    return (Rcode_createStatic(Rcode::NXRRSET()));
685
686
687
}

static PyObject*
688
Rcode_NOTAUTH(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
689
    return (Rcode_createStatic(Rcode::NOTAUTH()));
690
691
692
}

static PyObject*
693
Rcode_NOTZONE(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
694
    return (Rcode_createStatic(Rcode::NOTZONE()));
695
696
697
}

static PyObject*
698
Rcode_RESERVED11(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
699
    return (Rcode_createStatic(Rcode::RESERVED11()));
700
701
702
}

static PyObject*
703
Rcode_RESERVED12(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
704
    return (Rcode_createStatic(Rcode::RESERVED12()));
705
706
707
}

static PyObject*
708
Rcode_RESERVED13(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
709
    return (Rcode_createStatic(Rcode::RESERVED13()));
710
711
712
}

static PyObject*
713
Rcode_RESERVED14(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
714
    return (Rcode_createStatic(Rcode::RESERVED14()));
715
716
717
}

static PyObject*
718
Rcode_RESERVED15(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
719
    return (Rcode_createStatic(Rcode::RESERVED15()));
720
721
722
}

static PyObject*
723
Rcode_BADVERS(s_Rcode* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
724
    return (Rcode_createStatic(Rcode::BADVERS()));
725
726
727
}

static PyObject* 
728
Rcode_richcmp(s_Rcode* self, s_Rcode* other, int op) {
Jelte Jansen's avatar
Jelte Jansen committed
729
    bool c = false;
730

731
732
    // Check for null and if the types match. If different type,
    // simply return False
Jelte Jansen's avatar
Jelte Jansen committed
733
    if (!other || (self->ob_type != other->ob_type)) {
734
735
736
        Py_RETURN_FALSE;
    }

737
738
739
740
    // Only equals and not equals here, unorderable type
    switch (op) {
    case Py_LT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
Jelte Jansen's avatar
Jelte Jansen committed
741
        return (NULL);
742
743
744
        break;
    case Py_LE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
Jelte Jansen's avatar
Jelte Jansen committed
745
        return (NULL);
746
747
748
749
750
751
752
753
754
        break;
    case Py_EQ:
        c = (*self->rcode == *other->rcode);
        break;
    case Py_NE:
        c = (*self->rcode != *other->rcode);
        break;
    case Py_GT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
Jelte Jansen's avatar
Jelte Jansen committed
755
        return (NULL);
756
757
758
        break;
    case Py_GE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
Jelte Jansen's avatar
Jelte Jansen committed
759
        return (NULL);
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
        break;
    }
    if (c)
        Py_RETURN_TRUE;
    else
        Py_RETURN_FALSE;
}

//
// End of Rcode wrapper
//


//
// Section
//

// TODO: iterator?

779
780
class s_Section : public PyObject {
public:
781
    const Section* section;
782
};
783
784
785
786
787
788
789
790
791
792
793
794

static int Section_init(s_Section* self, PyObject* args);
static void Section_destroy(s_Section* self);

static PyObject* Section_getCode(s_Section* self);
static PyObject* Section_QUESTION(s_Section* self);
static PyObject* Section_ANSWER(s_Section* self);
static PyObject* Section_AUTHORITY(s_Section* self);
static PyObject* Section_ADDITIONAL(s_Section* self);
static PyObject* Section_richcmp(s_Section* self, s_Section* other, int op);

static PyMethodDef Section_methods[] = {
795
796
797
798
799
    { "get_code", reinterpret_cast<PyCFunction>(Section_getCode), METH_NOARGS, "Returns the code value" },
    { "QUESTION", reinterpret_cast<PyCFunction>(Section_QUESTION), METH_NOARGS | METH_STATIC, "Creates a QUESTION Section" },
    { "ANSWER", reinterpret_cast<PyCFunction>(Section_ANSWER), METH_NOARGS | METH_STATIC, "Creates an ANSWER Section" },
    { "AUTHORITY", reinterpret_cast<PyCFunction>(Section_AUTHORITY), METH_NOARGS | METH_STATIC, "Creates an AUTHORITY Section" },
    { "ADDITIONAL", reinterpret_cast<PyCFunction>(Section_ADDITIONAL), METH_NOARGS | METH_STATIC, "Creates an ADDITIONAL Section" },
800
801
802
803
804
805
    { NULL, NULL, 0, NULL }
};

static PyTypeObject section_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "libdns_python.Section",
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
    sizeof(s_Section),                  // tp_basicsize
    0,                                  // tp_itemsize
    (destructor)Section_destroy,        // tp_dealloc
    NULL,                               // tp_print
    NULL,                               // tp_getattr
    NULL,                               // tp_setattr
    NULL,                               // tp_reserved
    NULL,                               // tp_repr
    NULL,                               // tp_as_number
    NULL,                               // tp_as_sequence
    NULL,                               // tp_as_mapping
    NULL,                               // tp_hash 
    NULL,                               // tp_call
    NULL,                               // tp_str
    NULL,                               // tp_getattro
    NULL,                               // tp_setattro
    NULL,                               // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                 // tp_flags
Jelte Jansen's avatar
Jelte Jansen committed
824
825
    "The Section class objects represent DNS message sections such "
    "as the header, question, or answer.",
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
    NULL,                               // tp_traverse
    NULL,                               // tp_clear
    (richcmpfunc)Section_richcmp,       // tp_richcompare
    0,                                  // tp_weaklistoffset
    NULL,                               // tp_iter
    NULL,                               // tp_iternext
    Section_methods,                    // tp_methods
    NULL,                               // tp_members
    NULL,                               // tp_getset
    NULL,                               // tp_base
    NULL,                               // tp_dict
    NULL,                               // tp_descr_get
    NULL,                               // tp_descr_set
    0,                                  // tp_dictoffset
    (initproc)Section_init,             // tp_init
    NULL,                               // tp_alloc
    PyType_GenericNew,                  // tp_new
    NULL,                               // tp_free
    NULL,                               // tp_is_gc
    NULL,                               // tp_bases
    NULL,                               // tp_mro
    NULL,                               // tp_cache
    NULL,                               // tp_subclasses
    NULL,                               // tp_weaklist
    NULL,                               // tp_del
    0                                   // tp_version_tag
852
853
854
855
};


static int
856
857
Section_init(s_Section* self UNUSED_PARAM,
             PyObject* args UNUSED_PARAM)
858
859
860
{
    PyErr_SetString(PyExc_NotImplementedError,
                    "Section can't be built directly");
Jelte Jansen's avatar
Jelte Jansen committed
861
    return (-1);
862
863
864
}

static void
865
Section_destroy(s_Section* self) {
866
867
868
869
870
871
872
    // We only use the consts from Section, so don't
    // delete self->section here
    self->section = NULL;
    Py_TYPE(self)->tp_free(self);
}

static PyObject*
873
Section_getCode(s_Section* self) {
Jelte Jansen's avatar
Jelte Jansen committed
874
    return (Py_BuildValue("I", self->section->getCode()));
875
876
877
}

static PyObject*
Jelte Jansen's avatar
Jelte Jansen committed
878
Section_createStatic(const Section& section) {
879
880
    s_Section* ret = PyObject_New(s_Section, &section_type);
    if (ret != NULL) {
Jelte Jansen's avatar
Jelte Jansen committed
881
        ret->section = &section;
882
    }
Jelte Jansen's avatar
Jelte Jansen committed
883
884
885
886
887
888
889
    return (ret);
}


static PyObject*
Section_QUESTION(s_Section* self UNUSED_PARAM) {
    return Section_createStatic(Section::QUESTION());
890
891
892
}

static PyObject*
893
Section_ANSWER(s_Section* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
894
    return Section_createStatic(Section::ANSWER());
895
896
897
}

static PyObject*
898
Section_AUTHORITY(s_Section* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
899
    return Section_createStatic(Section::AUTHORITY());
900
901
902
}

static PyObject*
903
Section_ADDITIONAL(s_Section* self UNUSED_PARAM) {
Jelte Jansen's avatar
Jelte Jansen committed
904
    return Section_createStatic(Section::ADDITIONAL());
905
906
907
}

static PyObject* 
908
Section_richcmp(s_Section* self, s_Section* other, int op) {
Jelte Jansen's avatar
Jelte Jansen committed
909
    bool c = false;
910

911
912
    // Check for null and if the types match. If different type,
    // simply return False
Jelte Jansen's avatar
Jelte Jansen committed
913
    if (!other || (self->ob_type != other->ob_type)) {
914
915
916
        Py_RETURN_FALSE;
    }

917
918
919
920
    // Only equals and not equals here, unorderable type
    switch (op) {
    case Py_LT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Section");
Jelte Jansen's avatar
Jelte Jansen committed
921
        return (NULL);
922
923
924
        break;
    case Py_LE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Section");
Jelte Jansen's avatar
Jelte Jansen committed
925
        return (NULL);
926
927
928
929
930
931
932
933
934
        break;
    case Py_EQ:
        c = (*self->section == *other->section);
        break;
    case Py_NE:
        c = (*self->section != *other->section);
        break;
    case Py_GT:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Section");
Jelte Jansen's avatar
Jelte Jansen committed
935
        return (NULL);
936
937
938
        break;
    case Py_GE:
        PyErr_SetString(PyExc_TypeError, "Unorderable type; Section");
Jelte Jansen's avatar
Jelte Jansen committed
939
        return (NULL);
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
        break;
    }
    if (c)
        Py_RETURN_TRUE;
    else
        Py_RETURN_FALSE;
}

//
// End of Section wrapper
//



//
// Message
//

// The s_* Class simply coverst one instantiation of the object
959
960
class s_Message : public PyObject {
public:
961
    Message* message;
962
};
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994

//
// We declare the functions here, the definitions are below
// the type definition of the object, since both can use the other
//

// General creation and destruction
static int Message_init(s_Message* self, PyObject* args);
static void Message_destroy(s_Message* self);

static PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
static PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
static PyObject* Message_clearHeaderFlag(s_Message* self, PyObject* args);
static PyObject* Message_isDNSSECSupported(s_Message* self);
static PyObject* Message_setDNSSECSupported(s_Message* self, PyObject* args);
static PyObject* Message_getUDPSize(s_Message* self);
static PyObject* Message_setUDPSize(s_Message* self, PyObject* args);
static PyObject* Message_getQid(s_Message* self);
static PyObject* Message_setQid(s_Message* self, PyObject* args);
static PyObject* Message_getRcode(s_Message* self);
static PyObject* Message_setRcode(s_Message* self, PyObject* args);
static PyObject* Message_getOpcode(s_Message* self);
static PyObject* Message_setOpcode(s_Message* self, PyObject* args);
static PyObject* Message_getRRCount(s_Message* self, PyObject* args);
// use direct iterators for these? (or simply lists for now?)
static PyObject* Message_getQuestion(s_Message* self);
static PyObject* Message_getSection(s_Message* self, PyObject* args);
//static PyObject* Message_beginQuestion(s_Message* self, PyObject* args);
//static PyObject* Message_endQuestion(s_Message* self, PyObject* args);
//static PyObject* Message_beginSection(s_Message* self, PyObject* args);
//static PyObject* Message_endSection(s_Message* self, PyObject* args);

995
static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
static PyObject* Message_addRRset(s_Message* self, PyObject* args);
static PyObject* Message_clear(s_Message* self, PyObject* args);
static PyObject* Message_makeResponse(s_Message* self);
static PyObject* Message_toText(s_Message* self);
static PyObject* Message_str(PyObject* self);
static PyObject* Message_toWire(s_Message* self, PyObject* args);
static PyObject* Message_fromWire(s_Message* self, PyObject* args);

// This list contains the actual set of functions we have in
// python. Each entry has
// 1. Python method name
// 2. Our static function here
// 3. Argument type
// 4. Documentation
static PyMethodDef Message_methods[] = {
1011
    { "get_header_flag", reinterpret_cast<PyCFunction>(Message_getHeaderFlag), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1012
1013
      "Return whether the specified header flag bit is set in the "
      "header section. Takes a MessageFlag object as the only argument." },
1014
    { "set_header_flag", reinterpret_cast<PyCFunction>(Message_setHeaderFlag), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1015
1016
1017
      "Sets the specified header flag bit to 1. The message must be in "
      "RENDER mode. If not, an InvalidMessageOperation is raised. "
      "Takes a MessageFlag object as the only argument." },
1018
    { "clear_header_flag", reinterpret_cast<PyCFunction>(Message_clearHeaderFlag), METH_VARARGS, 
Jelte Jansen's avatar
Jelte Jansen committed
1019
1020
1021
      "Sets the specified header flag bit to 0. The message must be in "
      "RENDER mode. If not, an InvalidMessageOperation is raised. "
      "Takes a MessageFlag object as the only argument." },
1022
    { "is_dnssec_supported", reinterpret_cast<PyCFunction>(Message_isDNSSECSupported), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1023
1024
1025
      "Returns True if the message sender indicates DNSSEC is supported. "
      "If EDNS is included, this corresponds to the value of the DO bit. "
      "Otherwise, DNSSEC is considered not supported." },
1026
    { "set_dnssec_supported", reinterpret_cast<PyCFunction>(Message_setDNSSECSupported), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1027
1028
1029
1030
1031
      "Specify whether DNSSEC is supported in the message. "
      "The message must be in RENDER mode. If not, an "
      "InvalidMessageOperation is raised."
      "If EDNS is included in the message, the DO bit is set or cleared "
      "according to given argument (True or False) of this method."},
1032
    { "get_udp_size", reinterpret_cast<PyCFunction>(Message_getUDPSize), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1033
1034
1035
1036
1037
1038
1039
      "Return the maximum buffer size of UDP messages for the sender "
      "of the message.\n\n"
      "The semantics of this value is different based on the mode:\n"
      "In the PARSE mode, it means the buffer size of the remote node;\n"
      "in the RENDER mode, it means the buffer size of the local node.\n\n"
      "In either case, its value is the value of the UDP payload size field "
      "of EDNS (when it's included) or DEFAULT_MAX_UDPSIZE." },
1040
    { "set_udp_size", reinterpret_cast<PyCFunction>(Message_setUDPSize), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
      "Specify the maximum buffer size of UDP messages of the local "
      "node. If the message is not in RENDER mode, an "
      "InvalidMessageOperation is raised.\n\n"
      "If EDNS OPT RR is included in the message, its UDP payload size field "
      "will be set to the specified value.\n"
      "Unless explicitly specified, DEFAULT_MAX_UDPSIZE will be assumed "
      "for the maximum buffer size, regardless of whether EDNS OPT RR is "
      "included or not.  This means if an application wants to send a message "
      "with an EDNS OPT RR for specifying a larger UDP size, it must explicitly "
      "specify the value using this method. "},
1051
    { "get_qid", reinterpret_cast<PyCFunction>(Message_getQid), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1052
      "Returns the query id" },
1053
    { "set_qid", reinterpret_cast<PyCFunction>(Message_setQid), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1054
1055
1056
      "Sets the query id. If the message is not in RENDER mode, an "
      "InvalidMessageOperation is raised.\n"
      "The argument must be an integer" },
1057
    { "get_rcode", reinterpret_cast<PyCFunction>(Message_getRcode), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1058
      "Returns the message Response code (an Rcode object)" },
1059
    { "set_rcode", reinterpret_cast<PyCFunction>(Message_setRcode), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1060
1061
1062
      "Sets the message Response code (an Rcode object).\n"
      "If the message is not in RENDER mode, an "
      "InvalidMessageOperation is raised."},
1063
    { "get_opcode", reinterpret_cast<PyCFunction>(Message_getOpcode), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1064
      "Returns the message opcode (an Opcode object)" },
1065
    { "set_opcode", reinterpret_cast<PyCFunction>(Message_setOpcode), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1066
1067
1068
      "Sets the message opcode (an Opcode object).\n"
      "If the message is not in RENDER mode, an "
      "InvalidMessageOperation is raised."},
1069
    { "get_rr_count", reinterpret_cast<PyCFunction>(Message_getRRCount), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1070
      "Returns the number of RRs contained in the given section." },
1071
    { "get_question", reinterpret_cast<PyCFunction>(Message_getQuestion), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1072
1073
      "Returns a list of all Question objects in the message "
      "(should be either 0 or 1)" },
1074
    { "get_section", reinterpret_cast<PyCFunction>(Message_getSection), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1075
1076
      "Returns a list of all RRset objects in the given section of the message\n"
      "The argument must be of type Section" },
1077
    { "add_question", reinterpret_cast<PyCFunction>(Message_addQuestion), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1078
1079
1080
      "Add a Question to the message."
      "If the message is not in RENDER mode, an "
      "InvalidMessageOperation is raised."},
1081
    { "add_rrset", reinterpret_cast<PyCFunction>(Message_addRRset), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1082
1083
1084
1085
1086
      "Add an RRset to the given section of the message.\n"
      "The first argument is of type Section\n"
      "The second is of type RRset\n"
      "The third argument is an optional Boolean specifying whether "
      "the RRset is signed"},
1087
    { "clear", reinterpret_cast<PyCFunction>(Message_clear), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1088
1089
1090
      "Clears the message content (if any) and reinitialize the "
      "message in the given mode\n"
      "The argument must be either Message.PARSE or Message.RENDER"},
1091
    { "make_response", reinterpret_cast<PyCFunction>(Message_makeResponse), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1092
1093
1094
1095
      "Prepare for making a response from a request.\n"
      "This will clear the DNS header except those fields that should be kept "
      "for the response, and clear answer and the following sections. "
      "See also dns_message_reply() of BIND9."},
1096
    { "to_text", reinterpret_cast<PyCFunction>(Message_toText), METH_NOARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1097
      "Returns the string representation of the message" },
1098
    { "to_wire", reinterpret_cast<PyCFunction>(Message_toWire), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1099
1100
1101
1102
1103
      "Render the message in wire format.\n"
      "The argument must be a MessageRenderer.\n"
      "If the given message is not in RENDER mode, an "
      "InvalidMessageOperation is raised.\n"
       },
1104
    { "from_wire", reinterpret_cast<PyCFunction>(Message_fromWire), METH_VARARGS,
Jelte Jansen's avatar
Jelte Jansen committed
1105
1106
1107
1108
1109
1110
1111
      "Parses the given wire format to a Message object.\n"
      "The first argument is a Message to parse the data into.\n"
      "The second argument must implement the buffer interface.\n"
      "If the given message is not in PARSE mode, an "
      "InvalidMessageOperation is raised.\n"
      "Raises MessageTooShort, DNSMessageFORMERR or DNSMessageBADVERS "
      " if there is a problem parsing the message." },
1112
1113
1114
1115
1116
1117
1118
1119
1120
    { NULL, NULL, 0, NULL }
};

// This defines the complete type for reflection in python and
// parsing of PyObject* to s_Message
// Most of the functions are not actually implemented and NULL here.
static PyTypeObject message_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "libdns_python.Message",
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
    sizeof(s_Message),                  // tp_basicsize
    0,                                  // tp_itemsize
    (destructor)Message_destroy,        // tp_dealloc
    NULL,                               // tp_print
    NULL,                               // tp_getattr
    NULL,                               // tp_setattr
    NULL,                               // tp_reserved
    NULL,                               // tp_repr
    NULL,                               // tp_as_number
    NULL,                               // tp_as_sequence
    NULL,                               // tp_as_mapping
    NULL,                               // tp_hash 
    NULL,                               // tp_call
    Message_str,                        // tp_str
    NULL,                               // tp_getattro
    NULL,                               // tp_setattro
    NULL,                               // tp_as_buffer
    Py_TPFLAGS_DEFAULT,                 // tp_flags
Jelte Jansen's avatar
Jelte Jansen committed
1139
    "The Message class encapsulates a standard DNS message.",
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
    NULL,                               // tp_traverse
    NULL,                               // tp_clear
    NULL,                               // tp_richcompare
    0,                                  // tp_weaklistoffset
    NULL,                               // tp_iter
    NULL,                               // tp_iternext
    Message_methods,                    // tp_methods
    NULL,                               // tp_members
    NULL,                               // tp_getset
    NULL,                               // tp_base
    NULL,                               // tp_dict
    NULL,                               // tp_descr_get
    NULL,                               // tp_descr_set
    0,                                  // tp_dictoffset
    (initproc)Message_init,             // tp_init
    NULL,                               // tp_alloc
    PyType_GenericNew,                  // tp_new
    NULL,                               // tp_free
    NULL,                               // tp_is_gc
    NULL,                               // tp_bases
    NULL,                               // tp_mro
    NULL,                               // tp_cache
    NULL,                               // tp_subclasses
    NULL,                               // tp_weaklist
    NULL,                               // tp_del
    0                                   // tp_version_tag
1166
1167
1168
};

static int
1169
Message_init(s_Message* self, PyObject* args) {
1170
1171
1172
1173
1174
1175
1176
1177
    unsigned int i;
    // The constructor argument can be a string ("IN"), an integer (1),
    // or a sequence of numbers between 0 and 255 (wire code)
    
    if (PyArg_ParseTuple(args, "I", &i)) {
        PyErr_Clear();
        if (i == Message::PARSE) {
            self->message = new Message(Message::PARSE);
Jelte Jansen's avatar
Jelte Jansen committed
1178
            return (0);
1179
1180
        } else if (i == Message::RENDER) {
            self->message = new Message(Message::RENDER);
Jelte Jansen's avatar
Jelte Jansen committed
1181
            return (0);
1182
1183
        } else {
            PyErr_SetString(PyExc_TypeError, "Message mode must be Message.PARSE or Message.RENDER");
Jelte Jansen's avatar
Jelte Jansen committed
1184
            return (-1);
1185
1186
1187
1188
1189
        }
    }
    PyErr_Clear();
    PyErr_SetString(PyExc_TypeError,
                    "no valid type in constructor argument");
Jelte Jansen's avatar
Jelte Jansen committed
1190
    return (-1);
1191
1192
1193
}

static void
1194
Message_destroy(s_Message* self) {
1195
    delete self->message;
1196
1197
1198
1199
1200
    self->message = NULL;
    Py_TYPE(self)->tp_free(self);
}

static PyObject*
1201
Message_getHeaderFlag(s_Message* self, PyObject* args) {
1202
1203
    s_MessageFlag* messageflag;
    if (!PyArg_ParseTuple(args, "O!", &messageflag_type, &messageflag)) {
Jelte Jansen's avatar
Jelte Jansen committed
1204
        return (NULL);
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
    }
    
    if (self->message->getHeaderFlag(*messageflag->messageflag)) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}

static PyObject*
1215
Message_setHeaderFlag(s_Message* self, PyObject* args) {
1216
1217
    s_MessageFlag* messageflag;
    if (!PyArg_ParseTuple(args, "O!", &messageflag_type, &messageflag)) {
Jelte Jansen's avatar
Jelte Jansen committed
1218
        return (NULL);
1219
1220
    }

Jelte Jansen's avatar
Jelte Jansen committed
1221
1222
1223
1224
1225
1226
    try {
        self->message->setHeaderFlag(*messageflag->messageflag);
        Py_RETURN_NONE;
    } catch (isc::dns::InvalidMessageOperation imo) {
        PyErr_Clear();
        PyErr_SetString(po_InvalidMessageOperation, imo.what());
Jelte Jansen's avatar
Jelte Jansen committed
1227
        return (NULL);
Jelte Jansen's avatar
Jelte Jansen committed
1228
    }
1229
1230
1231
}

static PyObject*
1232
Message_clearHeaderFlag(s_Message* self, PyObject* args) {
1233
1234
    s_MessageFlag* messageflag;
    if (!PyArg_ParseTuple(args, "O!", &messageflag_type, &messageflag)) {
Jelte Jansen's avatar
Jelte Jansen committed
1235
        return (NULL);
1236
1237
    }

Jelte Jansen's avatar
Jelte Jansen committed
1238
1239
1240
1241
1242
1243
    try {
        self->message->clearHeaderFlag(*messageflag->messageflag);
        Py_RETURN_NONE;
    } catch (isc::dns::InvalidMessageOperation imo) {
        PyErr_Clear();
        PyErr_SetString(po_InvalidMessageOperation, imo.what());
Jelte Jansen's avatar
Jelte Jansen committed
1244
        return (NULL);
Jelte Jansen's avatar
Jelte Jansen committed
1245
    }
1246
1247
1248
1249
1250

    Py_RETURN_NONE;
}

static PyObject*
1251
Message_isDNSSECSupported(s_Message* self) {
1252
1253
1254
1255