diff --git a/0001-Use-print_function-also-for-Python2.patch b/0001-Use-print_function-also-for-Python2.patch new file mode 100644 index 0000000..dec1406 --- /dev/null +++ b/0001-Use-print_function-also-for-Python2.patch @@ -0,0 +1,127 @@ +From 2b3840deb32d58faa44cf4f02404b4fda51789ba Mon Sep 17 00:00:00 2001 +From: Tomas Hozza +Date: Tue, 14 Apr 2015 12:05:15 +0200 +Subject: [PATCH 1/4] Use print_function also for Python2 + +Signed-off-by: Tomas Hozza +--- + libunbound/python/examples/async-lookup.py | 1 + + libunbound/python/examples/dns-lookup.py | 1 + + libunbound/python/examples/dnssec-valid.py | 1 + + libunbound/python/examples/dnssec_test.py | 1 + + libunbound/python/examples/example8-1.py | 1 + + libunbound/python/examples/idn-lookup.py | 1 + + libunbound/python/examples/mx-lookup.py | 1 + + libunbound/python/examples/ns-lookup.py | 1 + + libunbound/python/examples/reverse-lookup.py | 1 + + 9 files changed, 9 insertions(+) + +diff --git a/libunbound/python/examples/async-lookup.py b/libunbound/python/examples/async-lookup.py +index cbb8ea0..81ba447 100644 +--- a/libunbound/python/examples/async-lookup.py ++++ b/libunbound/python/examples/async-lookup.py +@@ -32,6 +32,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + import time + +diff --git a/libunbound/python/examples/dns-lookup.py b/libunbound/python/examples/dns-lookup.py +index b3f4008..ec85673 100644 +--- a/libunbound/python/examples/dns-lookup.py ++++ b/libunbound/python/examples/dns-lookup.py +@@ -32,6 +32,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + + ctx = unbound.ub_ctx() +diff --git a/libunbound/python/examples/dnssec-valid.py b/libunbound/python/examples/dnssec-valid.py +index 5c3cad9..e613fd2 100644 +--- a/libunbound/python/examples/dnssec-valid.py ++++ b/libunbound/python/examples/dnssec-valid.py +@@ -32,6 +32,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import os + from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN + +diff --git a/libunbound/python/examples/dnssec_test.py b/libunbound/python/examples/dnssec_test.py +index 0d62b9f..a90ac0c 100644 +--- a/libunbound/python/examples/dnssec_test.py ++++ b/libunbound/python/examples/dnssec_test.py +@@ -1,4 +1,5 @@ + #!/usr/bin/env python ++from __future__ import print_function + from unbound import ub_ctx, RR_TYPE_A, RR_TYPE_RRSIG, RR_TYPE_NSEC, RR_TYPE_NSEC3 + import ldns + +diff --git a/libunbound/python/examples/example8-1.py b/libunbound/python/examples/example8-1.py +index ca868e5..ba093d9 100644 +--- a/libunbound/python/examples/example8-1.py ++++ b/libunbound/python/examples/example8-1.py +@@ -33,6 +33,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + + ctx = unbound.ub_ctx() +diff --git a/libunbound/python/examples/idn-lookup.py b/libunbound/python/examples/idn-lookup.py +index 2170637..8cc63e0 100644 +--- a/libunbound/python/examples/idn-lookup.py ++++ b/libunbound/python/examples/idn-lookup.py +@@ -33,6 +33,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + import locale + +diff --git a/libunbound/python/examples/mx-lookup.py b/libunbound/python/examples/mx-lookup.py +index f83f690..f3c4e5f 100644 +--- a/libunbound/python/examples/mx-lookup.py ++++ b/libunbound/python/examples/mx-lookup.py +@@ -33,6 +33,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + + ctx = unbound.ub_ctx() +diff --git a/libunbound/python/examples/ns-lookup.py b/libunbound/python/examples/ns-lookup.py +index bcd51de..5acf2a3 100644 +--- a/libunbound/python/examples/ns-lookup.py ++++ b/libunbound/python/examples/ns-lookup.py +@@ -33,6 +33,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + + ctx = unbound.ub_ctx() +diff --git a/libunbound/python/examples/reverse-lookup.py b/libunbound/python/examples/reverse-lookup.py +index 7e06844..da8ab1a 100644 +--- a/libunbound/python/examples/reverse-lookup.py ++++ b/libunbound/python/examples/reverse-lookup.py +@@ -32,6 +32,7 @@ + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ''' ++from __future__ import print_function + import unbound + + ctx = unbound.ub_ctx() +-- +2.1.0 + diff --git a/0002-libunbound-examples-produce-sorted-output.patch b/0002-libunbound-examples-produce-sorted-output.patch new file mode 100644 index 0000000..f85d9ae --- /dev/null +++ b/0002-libunbound-examples-produce-sorted-output.patch @@ -0,0 +1,183 @@ +From 17384c3ec2eb1d11dc430765890397679699fce1 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza +Date: Tue, 14 Apr 2015 12:05:50 +0200 +Subject: [PATCH 2/4] libunbound examples: produce sorted output + +Signed-off-by: Tomas Hozza +--- + libunbound/python/examples/async-lookup.py | 4 ++-- + libunbound/python/examples/dns-lookup.py | 2 +- + libunbound/python/examples/dnssec-valid.py | 2 +- + libunbound/python/examples/dnssec_test.py | 8 ++++---- + libunbound/python/examples/example8-1.py | 6 +++--- + libunbound/python/examples/idn-lookup.py | 6 +++--- + libunbound/python/examples/mx-lookup.py | 4 ++-- + libunbound/python/examples/ns-lookup.py | 2 +- + libunbound/python/examples/reverse-lookup.py | 2 +- + 9 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/libunbound/python/examples/async-lookup.py b/libunbound/python/examples/async-lookup.py +index 81ba447..936be32 100644 +--- a/libunbound/python/examples/async-lookup.py ++++ b/libunbound/python/examples/async-lookup.py +@@ -40,9 +40,9 @@ ctx = unbound.ub_ctx() + ctx.resolvconf("/etc/resolv.conf") + + def call_back(my_data,status,result): +- print("Call_back:", my_data) ++ print("Call_back:", sorted(my_data)) + if status == 0 and result.havedata: +- print("Result:", result.data.address_list) ++ print("Result:", sorted(result.data.address_list)) + my_data['done_flag'] = True + + +diff --git a/libunbound/python/examples/dns-lookup.py b/libunbound/python/examples/dns-lookup.py +index ec85673..a175dfb 100644 +--- a/libunbound/python/examples/dns-lookup.py ++++ b/libunbound/python/examples/dns-lookup.py +@@ -40,6 +40,6 @@ ctx.resolvconf("/etc/resolv.conf") + + status, result = ctx.resolve("www.nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: +- print("Result:", result.data.address_list) ++ print("Result:", sorted(result.data.address_list)) + elif status != 0: + print("Error:", unbound.ub_strerror(status)) +diff --git a/libunbound/python/examples/dnssec-valid.py b/libunbound/python/examples/dnssec-valid.py +index e613fd2..386f4c2 100644 +--- a/libunbound/python/examples/dnssec-valid.py ++++ b/libunbound/python/examples/dnssec-valid.py +@@ -49,7 +49,7 @@ if os.path.isfile("keys"): + status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN) + if status == 0 and result.havedata: + +- print("Result:", result.data.address_list) ++ print("Result:", sorted(result.data.address_list)) + + if result.secure: + print("Result is secure") +diff --git a/libunbound/python/examples/dnssec_test.py b/libunbound/python/examples/dnssec_test.py +index a90ac0c..430e51a 100644 +--- a/libunbound/python/examples/dnssec_test.py ++++ b/libunbound/python/examples/dnssec_test.py +@@ -13,16 +13,16 @@ def dnssecParse(domain, rrType=RR_TYPE_A): + raise RuntimeError("Error parsing DNS packet") + + rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_ANSWER) +- print("RRSIGs from answer:", rrsigs) ++ print("RRSIGs from answer:", sorted(rrsigs)) + + rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_AUTHORITY) +- print("RRSIGs from authority:", rrsigs) ++ print("RRSIGs from authority:", sorted(rrsigs)) + + nsecs = pkt.rr_list_by_type(RR_TYPE_NSEC, ldns.LDNS_SECTION_AUTHORITY) +- print("NSECs:", nsecs) ++ print("NSECs:", sorted(nsecs)) + + nsec3s = pkt.rr_list_by_type(RR_TYPE_NSEC3, ldns.LDNS_SECTION_AUTHORITY) +- print("NSEC3s:", nsec3s) ++ print("NSEC3s:", sorted(nsec3s)) + + print("---") + +diff --git a/libunbound/python/examples/example8-1.py b/libunbound/python/examples/example8-1.py +index ba093d9..723c406 100644 +--- a/libunbound/python/examples/example8-1.py ++++ b/libunbound/python/examples/example8-1.py +@@ -43,20 +43,20 @@ status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.mx_list: ++ for k in sorted(result.data.mx_list): + print(" priority:%d address:%s" % k) + + status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.address_list: ++ for k in sorted(result.data.address_list): + print(" address:%s" % k) + + status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.domain_list: ++ for k in sorted(result.data.domain_list): + print(" host: %s" % k) + +diff --git a/libunbound/python/examples/idn-lookup.py b/libunbound/python/examples/idn-lookup.py +index 8cc63e0..f283150 100644 +--- a/libunbound/python/examples/idn-lookup.py ++++ b/libunbound/python/examples/idn-lookup.py +@@ -46,18 +46,18 @@ status, result = ctx.resolve(u"www.háčkyčárky.cz", unbound.RR_TYPE_A, unboun + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.address_list: ++ for k in sorted(result.data.address_list): + print(" address:%s" % k) + + status, result = ctx.resolve(u"háčkyčárky.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.mx_list_idn: ++ for k in sorted(result.data.mx_list_idn): + print(" priority:%d address:%s" % k) + + status, result = ctx.resolve(unbound.reverse('217.31.204.66')+'.in-addr.arpa', unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result.data:", result.data) +- for k in result.data.domain_list_idn: ++ for k in sorted(result.data.domain_list_idn): + print(" dname:%s" % k) +diff --git a/libunbound/python/examples/mx-lookup.py b/libunbound/python/examples/mx-lookup.py +index f3c4e5f..e9394b3 100644 +--- a/libunbound/python/examples/mx-lookup.py ++++ b/libunbound/python/examples/mx-lookup.py +@@ -43,12 +43,12 @@ status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.mx_list: ++ for k in sorted(result.data.mx_list): + print(" priority:%d address:%s" % k) + + status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.address_list: ++ for k in sorted(result.data.address_list): + print(" address:%s" % k) +diff --git a/libunbound/python/examples/ns-lookup.py b/libunbound/python/examples/ns-lookup.py +index 5acf2a3..49f5672 100644 +--- a/libunbound/python/examples/ns-lookup.py ++++ b/libunbound/python/examples/ns-lookup.py +@@ -43,6 +43,6 @@ status, result = ctx.resolve("vutbr.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN + if status == 0 and result.havedata: + print("Result:") + print(" raw data:", result.data) +- for k in result.data.domain_list: ++ for k in sorted(result.data.domain_list): + print(" host: %s" % k) + +diff --git a/libunbound/python/examples/reverse-lookup.py b/libunbound/python/examples/reverse-lookup.py +index da8ab1a..c9a13fe 100644 +--- a/libunbound/python/examples/reverse-lookup.py ++++ b/libunbound/python/examples/reverse-lookup.py +@@ -40,5 +40,5 @@ ctx.resolvconf("/etc/resolv.conf") + + status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN) + if status == 0 and result.havedata: +- print("Result.data:", result.data, result.data.domain_list) ++ print("Result.data:", result.data, sorted(result.data.domain_list)) + +-- +2.1.0 + diff --git a/0003-libunbound-Python-libldns-is-not-used-anymore.patch b/0003-libunbound-Python-libldns-is-not-used-anymore.patch new file mode 100644 index 0000000..cac0d43 --- /dev/null +++ b/0003-libunbound-Python-libldns-is-not-used-anymore.patch @@ -0,0 +1,37 @@ +From a26697b196418201e1162f04317649d64aec89b5 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza +Date: Thu, 16 Apr 2015 11:29:21 +0200 +Subject: [PATCH 3/4] libunbound-Python: libldns is not used anymore + +Signed-off-by: Tomas Hozza +--- + libunbound/python/Makefile | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libunbound/python/Makefile b/libunbound/python/Makefile +index 86ba177..01b0577 100644 +--- a/libunbound/python/Makefile ++++ b/libunbound/python/Makefile +@@ -48,17 +48,14 @@ help: + #../../.libs/libunbound.so.0: ../../Makefile + #$(MAKE) -C ../.. + +-#../../ldns-src/lib/libldns.so: ../../ldns-src/Makefile +- #$(MAKE) -C ../../ldns-src +- + clean: + rm -rdf examples/unbound + rm -f _unbound.so libunbound_wrap.o + $(MAKE) -C ../.. clean + +-testenv: ../../.libs/libunbound.so.2 ../../ldns-src/lib/libldns.so ../../.libs/_unbound.so ++testenv: ../../.libs/libunbound.so.2 ../../.libs/_unbound.so + rm -rdf examples/unbound +- cd examples && mkdir unbound && ln -s ../../unbound.py unbound/__init__.py && ln -s ../../_unbound.so unbound/_unbound.so && ln -s ../../../../.libs/libunbound.so.2 unbound/libunbound.so.2 && ln -s ../../../../ldns-src/lib/libldns.so.1 unbound/libldns.so.1 && ls -la ++ cd examples && mkdir unbound && ln -s ../../unbound.py unbound/__init__.py && ln -s ../../_unbound.so unbound/_unbound.so && ln -s ../../../../.libs/libunbound.so.2 unbound/libunbound.so.2 && ls -la + cd examples && if test -f ../../../.libs/_unbound.so; then cp ../../../.libs/_unbound.so . ; fi + @echo "Run a script by typing ./script_name.py" + cd examples && LD_LIBRARY_PATH=unbound bash +-- +2.1.0 + diff --git a/0004-Resolve-Python-3-incompatibilities-in-libunbound-and.patch b/0004-Resolve-Python-3-incompatibilities-in-libunbound-and.patch new file mode 100644 index 0000000..ee7b777 --- /dev/null +++ b/0004-Resolve-Python-3-incompatibilities-in-libunbound-and.patch @@ -0,0 +1,356 @@ +From 5fe01bc3b8932b5dffa88578663727c3df694bc4 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza +Date: Tue, 14 Apr 2015 14:01:02 +0200 +Subject: [PATCH 4/4] Resolve Python 3 incompatibilities in libunbound and + pythonmod wrappers + +Signed-off-by: Tomas Hozza + +Fix issue with Python 3 mapping of FILE* using file_py3.i from ldns. +--- + Makefile.in | 3 +- + configure.ac | 2 + + libunbound/python/file_py3.i | 155 +++++++++++++++++++++++++++++++++++++++++ + libunbound/python/libunbound.i | 4 ++ + pythonmod/interface.i | 28 ++++---- + pythonmod/pythonmod.c | 8 ++- + 6 files changed, 184 insertions(+), 16 deletions(-) + create mode 100644 libunbound/python/file_py3.i + +diff --git a/Makefile.in b/Makefile.in +index 94b126d..a84b303 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -25,6 +25,7 @@ DNSTAP_SRC=@DNSTAP_SRC@ + DNSTAP_OBJ=@DNSTAP_OBJ@ + WITH_PYTHONMODULE=@WITH_PYTHONMODULE@ + WITH_PYUNBOUND=@WITH_PYUNBOUND@ ++PY_MAJOR_VERSION=@PY_MAJOR_VERSION@ + PYTHON_SITE_PKG=@PYTHON_SITE_PKG@ + PYTHONMOD_INSTALL=@PYTHONMOD_INSTALL@ + PYTHONMOD_UNINSTALL=@PYTHONMOD_UNINSTALL@ +@@ -393,7 +394,7 @@ libunbound_wrap.lo libunbound_wrap.o: libunbound/python/libunbound_wrap.c \ + unbound.h + libunbound/python/libunbound_wrap.c: $(srcdir)/libunbound/python/libunbound.i unbound.h + @-if test ! -d libunbound/python; then $(INSTALL) -d libunbound/python; fi +- $(SWIG) -python -o $@ $(CPPFLAGS) $(srcdir)/libunbound/python/libunbound.i ++ $(SWIG) -python -o $@ $(CPPFLAGS) -DPY_MAJOR_VERSION=$(PY_MAJOR_VERSION) $(srcdir)/libunbound/python/libunbound.i + + # Pyunbound python unbound wrapper + _unbound.la: libunbound_wrap.lo libunbound.la +diff --git a/configure.ac b/configure.ac +index 6028138..de809af 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -475,6 +475,8 @@ if test x_$ub_test_python != x_no; then + AC_ERROR([Python version >= 2.4.0 is required]) + fi + ++ PY_MAJOR_VERSION="`$PYTHON -c "import sys; print(sys.version_info.major)"`" ++ AC_SUBST(PY_MAJOR_VERSION) + # Have Python + AC_DEFINE(HAVE_PYTHON,1,[Define if you have Python libraries and header files.]) + LIBS="$PYTHON_LDFLAGS $LIBS" +diff --git a/libunbound/python/file_py3.i b/libunbound/python/file_py3.i +new file mode 100644 +index 0000000..5d8b5a2 +--- /dev/null ++++ b/libunbound/python/file_py3.i +@@ -0,0 +1,155 @@ ++/* ++ * file_py3.i: Typemaps for FILE* for Python 3 ++ * ++ * Copyright (c) 2011, Karel Slany (karel.slany AT nic.cz) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * * Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the organization nor the names of its ++ * contributors may be used to endorse or promote products derived from this ++ * software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++%{ ++#include ++#include ++%} ++ ++%types(FILE *); ++ ++//#define SWIG_FILE3_DEBUG ++ ++/* converts basic file descriptor flags onto a string */ ++%fragment("fdfl_to_str", "header") { ++const char * ++fdfl_to_str(int fdfl) { ++ ++ static const char * const file_mode[] = {"w+", "w", "r"}; ++ ++ if (fdfl & O_RDWR) { ++ return file_mode[0]; ++ } else if (fdfl & O_WRONLY) { ++ return file_mode[1]; ++ } else { ++ return file_mode[2]; ++ } ++} ++} ++ ++%fragment("is_obj_file", "header") { ++int ++is_obj_file(PyObject *obj) { ++ int fd, fdfl; ++ if (!PyLong_Check(obj) && /* is not an integer */ ++ PyObject_HasAttrString(obj, "fileno") && /* has fileno method */ ++ (PyObject_CallMethod(obj, "flush", NULL) != NULL) && /* flush() succeeded */ ++ ((fd = PyObject_AsFileDescriptor(obj)) != -1) && /* got file descriptor */ ++ ((fdfl = fcntl(fd, F_GETFL)) != -1) /* got descriptor flags */ ++ ) { ++ return 1; ++ } ++ else { ++ return 0; ++ } ++} ++} ++ ++%fragment("obj_to_file","header", fragment="fdfl_to_str,is_obj_file") { ++FILE * ++obj_to_file(PyObject *obj) { ++ int fd, fdfl; ++ FILE *fp; ++ if (is_obj_file(obj)) { ++ fd = PyObject_AsFileDescriptor(obj); ++ fdfl = fcntl(fd, F_GETFL); ++ fp = fdopen(dup(fd), fdfl_to_str(fdfl)); /* the FILE* must be flushed ++ and closed after being used */ ++#ifdef SWIG_FILE3_DEBUG ++ fprintf(stderr, "opening fd %d (fl %d \"%s\") as FILE %p\n", ++ fd, fdfl, fdfl_to_str(fdfl), (void *)fp); ++#endif ++ return fp; ++ } ++ return NULL; ++} ++} ++ ++/* returns -1 if error occurred */ ++/* caused magic SWIG Syntax errors when was commented out */ ++#if 0 ++%fragment("dispose_file", "header") { ++int ++dispose_file(FILE **fp) { ++#ifdef SWIG_FILE3_DEBUG ++ fprintf(stderr, "flushing FILE %p\n", (void *)fp); ++#endif ++ if (*fp == NULL) { ++ return 0; ++ } ++ if ((fflush(*fp) == 0) && /* flush file */ ++ (fclose(*fp) == 0)) { /* close file */ ++ *fp = NULL; ++ return 0; ++ } ++ return -1; ++} ++} ++#endif ++ ++%typemap(arginit, noblock = 1) FILE* { ++ $1 = NULL; ++} ++ ++/* ++ * added due to ub_ctx_debugout since since it is overloaded: ++ * takes void* and FILE*. In reality only FILE* but the wrapper ++ * and the function is declared in such way. ++ */ ++%typemap(typecheck, noblock = 1, fragment = "is_obj_file", precedence = SWIG_TYPECHECK_POINTER) FILE* { ++ $1 = is_obj_file($input); ++} ++ ++%typemap(check, noblock = 1) FILE* { ++ if ($1 == NULL) { ++ /* The generated wrapper function raises TypeError on mismatching types. */ ++ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " ++ "$argnum"" of type '" "$type""'"); ++ } ++} ++ ++%typemap(in, noblock = 1, fragment = "obj_to_file") FILE* { ++ $1 = obj_to_file($input); ++} ++ ++/* ++ * Commented out due the way how ub_ctx_debugout() uses the parameter. ++ * This typemap would cause the FILE* to be closed after return from ++ * the function. This caused Python interpreter to crash, since the ++ * function just stores the FILE* internally in ctx and use it for ++ * logging. So we'll leave the closing of the file on the OS. ++ */ ++/*%typemap(freearg, noblock = 1, fragment = "dispose_file") FILE* { ++ if (dispose_file(&$1) == -1) { ++ SWIG_exception_fail(SWIG_IOError, "closing file in method '" "$symname" "', argument " ++ "$argnum"" of type '" "$type""'"); ++ } ++}*/ +diff --git a/libunbound/python/libunbound.i b/libunbound/python/libunbound.i +index 1bef79f..3c0e45b 100644 +--- a/libunbound/python/libunbound.i ++++ b/libunbound/python/libunbound.i +@@ -60,7 +60,11 @@ + %} + + //%include "doc.i" ++#if PY_MAJOR_VERSION >= 3 ++%include "file_py3.i" // python 3 FILE * ++#else + %include "file.i" ++#endif + + %feature("docstring") strerror "Convert error value to a human readable string." + +diff --git a/pythonmod/interface.i b/pythonmod/interface.i +index cfaabb3..4b20c6e 100644 +--- a/pythonmod/interface.i ++++ b/pythonmod/interface.i +@@ -37,7 +37,7 @@ + %include "stdint.i" // uint_16_t can be known type now + + %inline %{ +- //converts [len][data][len][data][0] string to a List of labels (PyStrings) ++ //converts [len][data][len][data][0] string to a List of labels (PyBytes) + PyObject* GetNameAsLabelList(const char* name, int len) { + PyObject* list; + int cnt=0, i; +@@ -79,8 +79,8 @@ struct query_info { + %inline %{ + enum enum_rr_class { + RR_CLASS_IN = 1, +- RR_CLASS_CH = 3, +- RR_CLASS_HS = 4, ++ RR_CLASS_CH = 3, ++ RR_CLASS_HS = 4, + RR_CLASS_NONE = 254, + RR_CLASS_ANY = 255, + }; +@@ -164,7 +164,7 @@ struct query_info { + char buf[LDNS_MAX_DOMAINLEN+1]; + buf[0] = '\0'; + dname_str((uint8_t*)dname, buf); +- return PyString_FromString(buf); ++ return PyBytes_FromString(buf); + } + %} + +@@ -440,7 +440,7 @@ struct comm_reply { + reply_addr2str(reply, dest, 64); + if (dest[0] == 0) + return Py_None; +- return PyString_FromString(dest); ++ return PyBytes_FromString(dest); + } + + PyObject* _comm_reply_family_get(struct comm_reply* reply) { +@@ -448,9 +448,9 @@ struct comm_reply { + int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family; + + switch(af) { +- case AF_INET: return PyString_FromString("ip4"); +- case AF_INET6: return PyString_FromString("ip6"); +- case AF_UNIX: return PyString_FromString("unix"); ++ case AF_INET: return PyBytes_FromString("ip4"); ++ case AF_INET6: return PyBytes_FromString("ip6"); ++ case AF_UNIX: return PyBytes_FromString("unix"); + } + + return Py_None; +@@ -711,13 +711,13 @@ struct delegpt { + + %inline %{ + PyObject* _get_dp_dname(struct delegpt* dp) { +- return PyString_FromStringAndSize((char*)dp->name, dp->namelen); ++ return PyBytes_FromStringAndSize((char*)dp->name, dp->namelen); + } + PyObject* _get_dp_dname_components(struct delegpt* dp) { + return GetNameAsLabelList((char*)dp->name, dp->namelen); + } + PyObject* _get_dpns_dname(struct delegpt_ns* dpns) { +- return PyString_FromStringAndSize((char*)dpns->name, dpns->namelen); ++ return PyBytes_FromStringAndSize((char*)dpns->name, dpns->namelen); + } + PyObject* _get_dpns_dname_components(struct delegpt_ns* dpns) { + return GetNameAsLabelList((char*)dpns->name, dpns->namelen); +@@ -728,7 +728,7 @@ struct delegpt { + delegpt_addr_addr2str(target, dest, 64); + if (dest[0] == 0) + return Py_None; +- return PyString_FromString(dest); ++ return PyBytes_FromString(dest); + } + + %} +@@ -842,7 +842,7 @@ int checkList(PyObject *l) + for (i=0; i < PyList_Size(l); i++) + { + item = PyList_GetItem(l, i); +- if (!PyString_Check(item)) ++ if (!PyBytes_Check(item)) + return 0; + } + return 1; +@@ -864,12 +864,12 @@ int pushRRList(sldns_buffer* qb, PyObject *l, uint32_t default_ttl, int qsec, + + len = sldns_buffer_remaining(qb); + if(qsec) { +- if(sldns_str2wire_rr_question_buf(PyString_AsString(item), ++ if(sldns_str2wire_rr_question_buf(PyBytes_AsString(item), + sldns_buffer_current(qb), &len, NULL, NULL, 0, NULL, 0) + != 0) + return 0; + } else { +- if(sldns_str2wire_rr_buf(PyString_AsString(item), ++ if(sldns_str2wire_rr_buf(PyBytes_AsString(item), + sldns_buffer_current(qb), &len, NULL, default_ttl, + NULL, 0, NULL, 0) != 0) + return 0; +diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c +index 190d41a..48dbc01 100644 +--- a/pythonmod/pythonmod.c ++++ b/pythonmod/pythonmod.c +@@ -133,7 +133,13 @@ int pythonmod_init(struct module_env* env, int id) + /* Initialize Python libraries */ + if (!Py_IsInitialized()) + { +- Py_SetProgramName("unbound"); ++#if PY_MAJOR_VERSION >= 3 ++ wchar_t progname[8]; ++ mbstowcs(progname, "unbound", 8); ++#else ++ char *progname = "unbound"; ++#endif ++ Py_SetProgramName(progname); + Py_NoSiteFlag = 1; + Py_Initialize(); + PyEval_InitThreads(); +-- +2.1.0 +