diff --git a/examples/async-uv-get-ip.py b/examples/async-uv-get-ip.py new file mode 100755 index 0000000..bd005fc --- /dev/null +++ b/examples/async-uv-get-ip.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# + +""" +get-ip.py: resolve given DNS names into IP addresses. The -s switch +constains answers to only ones secured by DNSSEC. The -4 switch only +returns IPv4 addresses, the -6 switch only IPv6 addresses. + +An example run: +$ python async-get-ip.py www.panix.com www.isoc.org www.verisignlabs.com + +submitted query for www.panix.com +submitted query for www.isoc.org +submitted query for www.verisignlabs.com +www.panix.com: IPv4 166.84.62.125 +www.panix.com: IPv4 166.84.62.253 +www.verisignlabs.com: IPv4 72.13.58.64 +www.verisignlabs.com: IPv6 2620:74:13:4400::201 +www.isoc.org: IPv4 212.110.167.157 +www.isoc.org: IPv6 2001:41c8:20::19 + +""" + +import getdns, sys, getopt + +desired_addr_type = None + +def cbk(type, result, userarg, tid): + if type == getdns.CALLBACK_COMPLETE: + status = result.status + if status == getdns.RESPSTATUS_GOOD: + for addr in result.just_address_answers: + addr_type = addr['address_type'] + addr_data = addr['address_data'] + if (desired_addr_type == None) or (addr_type == desired_addr_type): + print("{0}: {1} {2}".format(userarg, addr_type, addr_data)) + elif status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: + print("{0}: No DNSSEC secured responses found".format(hostname)) + else: + print("{0}: getdns.address() returned error: {1}".format(hostname, status)) + elif type == getdns.CALLBACK_CANCEL: + print('Callback cancelled') + elif type == getdns.CALLBACK_TIMEOUT: + print('Query timed out') + else: + print('Unknown error') + + +def usage(): + print("""\ +Usage: get-ip.py [-s] [-4|-6] ... + + -s: only return DNSSEC secured answers + -4: only return IPv4 address answers + -6: only return IPv6 address answers + +-4 and -6 are mutually exclusive. If both are specified, IPv6 wins. +""") + sys.exit(1) + +try: + (options, args) = getopt.getopt(sys.argv[1:], 's46') +except getopt.GetoptError: + usage() +else: + if not args: + usage() + +extensions = { "return_both_v4_and_v6" : getdns.EXTENSION_TRUE } + +for (opt, optval) in options: + if opt == "-s": + extensions["dnssec_return_only_secure"] = getdns.EXTENSION_TRUE + elif opt == "-4": + desired_addr_type = "IPv4" + elif opt == "-6": + desired_addr_type = "IPv6" + +ctx = getdns.UVContext() +tids = [] +for hostname in args: + try: + tids.append(ctx.address(name=hostname, extensions=extensions, callback='cbk', userarg=hostname)) + print ('submitted query for {0}'.format(hostname)) + except getdns.error as e: + print(str(e)) + break +ctx.run() diff --git a/examples/samples.txt b/examples/samples.txt new file mode 100644 index 0000000..1db4412 --- /dev/null +++ b/examples/samples.txt @@ -0,0 +1,500 @@ +000webhost.com +20minutos.es +4shared.com +abc.es +abc.net.au +abcnews.go.com +aboutads.info +about.com +abril.com.br +academia.edu +accounts.google.com +addthis.com +addtoany.com +adobe.com +adssettings.google.com +afternic.com +akamaihd.net +alibaba.com +aliexpress.com +allaboutcookies.org +amazon.ca +amazon.co.jp +amazon.com +amazon.co.uk +amazon.de +amazon.es +amazon.fr +amazon.in +amzn.to +android.com +answers.com +answers.yahoo.com +aol.com +apache.org +ap.org +apple.com +archive.org +archives.gov +arxiv.org +asus.com +bandcamp.com +bbc.com +bbc.co.uk +berkeley.edu +biblegateway.com +biglobe.ne.jp +billboard.com +bing.com +bit.ly +bitly.com +blackberry.com +bloglovin.com +bloomberg.com +booking.com +books.google.com +boston.com +box.com +bp1.blogger.com +bp2.blogger.com +bp.blogspot.com +brandbucket.com +britannica.com +bt.com +businessinsider.com +businessinsider.com.au +buydomains.com +buzzfeed.com +calameo.com +cambridge.org +canva.com +cbc.ca +cbslocal.com +cbsnews.com +cdc.gov +change.org +channel4.com +chicagotribune.com +chinadaily.com.cn +chron.com +cia.gov +cloudflare.com +cmu.edu +cnbc.com +cnet.com +cnn.com +code.google.com +columbia.edu +consumerreports.org +cornell.edu +corriere.it +cpanel.com +cpanel.net +creativecommons.org +csmonitor.com +dailymail.co.uk +dailymotion.com +dan.com +daum.net +debian.org +deezer.com +dell.com +depositfiles.com +detik.com +developers.google.com +de.wikipedia.org +dictionary.com +digg.com +digitaltrends.com +discovery.com +disney.com +disney.go.com +disqus.com +docs.google.com +doubleclick.net +draft.blogger.com +dreniq.com +drive.google.com +dropbox.com +dw.com +ea.com +ebay.com +economist.com +ed.gov +ehow.com +elmundo.es +elpais.com +elsevier.com +e-monsite.com +enable-javascript.com +engadget.com +en.wikipedia.org +eonline.com +epa.gov +e-recht24.de +espn.com +espn.go.com +es.wikipedia.org +etsy.com +europa.eu +eventbrite.com +evernote.com +example.com +express.co.uk +facebook.com +fandom.com +fastcompany.com +fb.com +fb.me +fda.gov +feedburner.com +feedproxy.google.com +fifa.com +files.wordpress.com +finance.yahoo.com +forbes.com +forms.gle +fortune.com +foursquare.com +foxnews.com +fr.wikipedia.org +ftc.gov +ft.com +get.google.com +ggpht.com +giphy.com +github.com +gizmodo.com +globo.com +gmail.com +gnu.org +godaddy.com +gofundme.com +goodreads.com +goo.gl +googleblog.com +google.ca +google.co.id +google.co.in +google.co.jp +google.com.au +google.com.br +google.com.tw +google.co.uk +google.de +google.es +google.fr +google.it +google.nl +google.pl +google.ru +googleusercontent.com +goo.ne.jp +gravatar.com +greenpeace.org +groups.google.com +gstatic.com +guardian.co.uk +harvard.edu +hatena.ne.jp +hm.com +hollywoodreporter.com +house.gov +hp.com +huawei.com +huffingtonpost.com +huffpost.com +hugedomains.com +ibm.com +icann.org +id.wikipedia.org +ietf.org +ig.com.br +ign.com +ikea.com +imageshack.com +imageshack.us +imdb.com +inc.com +independent.co.uk +indiatimes.com +instagram.com +instructables.com +intel.com +ipv4.google.com +iso.org +issuu.com +istockphoto.com +it.wikipedia.org +iubenda.com +ja.wikipedia.org +jimdofree.com +khanacademy.org +kickstarter.com +last.fm +latimes.com +lefigaro.fr +lemonde.fr +lifehacker.com +line.me +linkedin.com +list-manage.com +live.com +liveinternet.ru +loc.gov +lonelyplanet.com +mail.google.com +mail.ru +mail.yahoo.com +maps.google.com +marketingplatform.google.com +marketwatch.com +marriott.com +mashable.com +mayoclinic.org +mediafire.com +medium.com +mega.nz +megaupload.com +merriam-webster.com +metro.co.uk +microsoft.com +mirror.co.uk +mit.edu +mixcloud.com +m.me +mozilla.com +mozilla.org +msn.com +m.wikipedia.org +myaccount.google.com +myspace.com +mysql.com +my.yahoo.com +namecheap.com +narod.ru +nasa.gov +nationalgeographic.com +nature.com +naver.com +naver.jp +nba.com +nbcnews.com +netflix.com +netvibes.com +networkadvertising.org +news.com.au +news.google.com +newsweek.com +news.yahoo.com +newyorker.com +nginx.com +nginx.org +nicovideo.jp +nih.gov +nikkei.com +noaa.gov +nokia.com +npr.org +nvidia.com +nydailynews.com +nypost.com +nytimes.com +office.com +ok.ru +opera.com +oracle.com +orange.fr +oreilly.com +oup.com +over-blog-kiwi.com +ovh.com +ovh.co.uk +ovh.net +ox.ac.uk +parallels.com +paypal.com +pbs.org +pcmag.com +pexels.com +photobucket.com +photos.google.com +php.net +picasa.google.com +picasaweb.google.com +pinterest.com +pinterest.co.uk +pixabay.com +play.google.com +playstation.com +plesk.com +plos.org +plus.google.com +pl.wikipedia.org +policies.google.com +politico.com +prestashop.com +princeton.edu +privacyshield.gov +prnewswire.com +psu.edu +psychologytoday.com +pt.wikipedia.org +public-api.wordpress.com +qq.com +quora.com +rakuten.co.jp +rapidshare.com +rediff.com +repubblica.it +researchgate.net +reuters.com +reverbnation.com +ria.ru +rollingstone.com +rottentomatoes.com +rt.com +ru.wikipedia.org +samsung.com +sapo.pt +sciencedaily.com +sciencedirect.com +sciencemag.org +scientificamerican.com +scoop.it +scribd.com +search.google.com +search.yahoo.com +secureserver.net +sedo.com +sendspace.com +sfgate.com +shopify.com +shop-pro.jp +shutterstock.com +si.edu +sina.com.cn +sites.google.com +sky.com +skype.com +slate.com +slideshare.net +smh.com.au +softpedia.com +so-net.ne.jp +soratemplates.com +soundcloud.com +spiegel.de +sports.yahoo.com +spotify.com +springer.com +sputniknews.com +ssl-images-amazon.com +stackoverflow.com +standard.co.uk +stanford.edu +state.gov +statista.com +steampowered.com +storage.googleapis.com +stuff.co.nz +support.google.com +surveymonkey.com +tabelog.com +target.com +t.co +teamviewer.com +techcrunch.com +techradar.com +ted.com +telegram.me +telegraph.co.uk +terra.com.br +theatlantic.com +thedailybeast.com +thefreedictionary.com +theglobeandmail.com +theguardian.com +themeforest.net +thestar.com +thesun.co.uk +thetimes.co.uk +theverge.com +thoughtco.com +time.com +timeout.com +tinyurl.com +t.me +tools.google.com +translate.google.com +tripadvisor.com +trustpilot.com +twitch.tv +twitter.com +ubuntu.com +ucoz.ru +umich.edu +unesco.org +un.org +uol.com.br +urbandictionary.com +usatoday.com +usgs.gov +usnews.com +utexas.edu +variety.com +vchecks.me +venturebeat.com +viagens.com.br +vice.com +video.google.com +vimeo.com +vk.com +vox.com +w3.org +walmart.com +wa.me +washington.edu +washingtonpost.com +weather.com +webmd.com +weibo.com +welt.de +whatsapp.com +whitehouse.gov +who.int +wikia.com +wikihow.com +wikimedia.org +wiktionary.org +wiley.com +windowsphone.com +wired.com +wordpress.org +worldbank.org +wp.com +wsj.com +www.blogger.com +www.google.com +www.gov.uk +www.livejournal.com +www.over-blog.com +www.weebly.com +www.wikipedia.org +www.wix.com +www.yahoo.com +xbox.com +xing.com +xinhuanet.com +yadi.sk +yahoo.co.jp +yale.edu +yandex.ru +yelp.com +youronlinechoices.com +youtu.be +youtube.com +ytimg.com +zeit.de +zendesk.com +ziddu.com diff --git a/getdns.c b/getdns.c index 0978cf0..92994a2 100644 --- a/getdns.c +++ b/getdns.c @@ -45,6 +45,9 @@ #include #include #include "pygetdns.h" +#ifdef WITH_UV +extern PyTypeObject getdns_UVContextType; +#endif PyObject *getdns_error; @@ -268,7 +271,12 @@ PyTypeObject getdns_ContextType = { context_getattro, /*tp_getattro*/ context_setattro, /*tp_setattro*/ 0, /*tp_as_buffer*/ +#ifdef WITH_UV + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, /*tp_flags*/ +#else Py_TPFLAGS_DEFAULT, /*tp_flags*/ +#endif "Context object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -503,6 +511,18 @@ PyInit_getdns(void) } Py_INCREF(&getdns_ContextType); PyModule_AddObject(g, "Context", (PyObject *)&getdns_ContextType); +#ifdef WITH_UV + Py_INCREF(&getdns_UVContextType); + if (PyModule_AddObject(g, "UVContext", (PyObject *)&getdns_UVContextType) < 0) { + Py_DECREF(g); + Py_DECREF((PyObject *)&getdns_UVContextType); + return NULL; + } + if (PyType_Ready(&getdns_UVContextType) < 0) { + PyErr_SetString(PyExc_ImportError, "Unable to initialize getdns.UVContext"); + return NULL; + } +#endif PyModule_AddStringConstant(g, "getdns_version", getdns_get_version()); PyModule_AddStringConstant(g, "__version__", PYGETDNS_VERSION); add_getdns_constants(g); @@ -533,6 +553,18 @@ initgetdns(void) return; Py_INCREF(&getdns_ContextType); PyModule_AddObject(g, "Context", (PyObject *)&getdns_ContextType); +#ifdef WITH_UV + Py_INCREF(&getdns_UVContextType); + if (PyModule_AddObject(g, "UVContext", (PyObject *)&getdns_UVContextType) < 0) { + Py_DECREF(g); + Py_DECREF((PyObject *)&getdns_UVContextType); + return NULL; + } + if (PyType_Ready(&getdns_UVContextType) < 0) { + PyErr_SetString(PyExc_ImportError, "Unable to initialize getdns.UVContext"); + return NULL; + } +#endif PyModule_AddStringConstant(g, "__version__", PYGETDNS_VERSION); PyModule_AddStringConstant(g, "getdns_version", getdns_get_version()); add_getdns_constants(g); diff --git a/getdns_ext_uv.c b/getdns_ext_uv.c new file mode 100644 index 0000000..824389a --- /dev/null +++ b/getdns_ext_uv.c @@ -0,0 +1,97 @@ + +#include "pygetdns_ext_libuv.h" +#include + +extern PyTypeObject getdns_ContextType; + +PyTypeObject getdns_UVContextType = { +#if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, +#endif + "getdns.UVContext", + sizeof(getdns_UVContextObject), + 0, /*tp_itemsize*/ + (destructor)uvcontext_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "UV Context object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + UVContext_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &getdns_ContextType, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)uvcontext_init, /* tp_init */ +}; + +static PyMethodDef UVContext_methods[] = { + /* + { "run", (PyCFunction)uvcontext_run, METH_VARARGS|METH_KEYWORDS, + "run unprocessed events with uvloop" }, + */ + { NULL } +}; + +int +uvcontext_init(getdns_UVContextObject *self, PyObject *args, PyObject *keywds) +{ + + getdns_return_t r; + + if (getdns_ContextType.tp_init((PyObject *)self, args, keywds) < 0) { + return -1; + } + + if (uv_loop_init(&(self->loop))) { + return -1; + } + + if ((r = getdns_extension_set_libuv_loop((self->context).context, &(self->loop)))) + fprintf( stderr, "Unable to set the event loop: %s\n" + , getdns_get_errorstr_by_id(r)); + + return 0; + +} + +PyObject * +uvcontext_run(getdns_UVContextObject *self, PyObject *args, PyObject *keywds) +{ + uv_run(&(self->loop), UV_RUN_DEFAULT); + Py_RETURN_NONE; +} + +void +uvcontext_dealloc(getdns_UVContextObject *self) +{ + uv_stop(&(self->loop)); + uv_loop_close(&(self->loop)); + getdns_ContextType.tp_dealloc((PyObject *)self); +} + + diff --git a/pygetdns.h b/pygetdns.h index 7075718..d39e049 100644 --- a/pygetdns.h +++ b/pygetdns.h @@ -32,7 +32,7 @@ #ifndef PYGETDNS_H #define PYGETDNS_H -#define PYGETDNS_VERSION "v1.0.0b" +#define PYGETDNS_VERSION "v1.6.0" #define GETDNS_DOCSTRING "getdns bindings for Python (see http://www.getdnsapi.net)" #define GETDNS_STR_IPV4 "IPv4" diff --git a/pygetdns_ext_libuv.h b/pygetdns_ext_libuv.h new file mode 100644 index 0000000..ac37aa5 --- /dev/null +++ b/pygetdns_ext_libuv.h @@ -0,0 +1,23 @@ +/* + * defines for pygetdns UVContext subtype + */ +#ifndef PYGETDNS_EX_UV_H +#define PYGETDNS_EX_UV_H + +#include +#include +#include +#include +#include +#include "pygetdns.h" +typedef struct { + getdns_ContextObject context; + uv_loop_t loop; +} getdns_UVContextObject; + +static int uvcontext_init(getdns_UVContextObject *self, PyObject *args, PyObject *keywds); +static void uvcontext_dealloc(getdns_UVContextObject *self); +static PyObject *uvcontext_run(getdns_UVContextObject *self, PyObject *args, PyObject *keywds); +static PyMethodDef UVContext_methods[]; + +#endif /* PYGETDNS_EX_UV_H */ diff --git a/setup.py b/setup.py index 8069902..eee3e8b 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,11 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# XXX +# https://thomasnyberg.com/what_are_extension_modules.html +# Py_BEGIN_ALLOW_THREADS +# setuptools +# XXX from distutils.core import setup, Extension from distutils.fancy_getopt import fancy_getopt @@ -35,7 +40,10 @@ CFLAGS = [ '-g' ] lib_dir = "" - +libraries = [ 'getdns' ] +define_macros = [] +sources = [ 'getdns.c', 'pygetdns_util.c', 'context.c', + 'context_util.c', 'result.c' ] if '--with-getdns' in sys.argv: getdns_root = sys.argv[sys.argv.index('--with-getdns')+1] @@ -45,6 +53,12 @@ sys.argv.remove('--with-getdns') sys.argv.remove(getdns_root) +if '--with-ext-uv' in sys.argv: + sys.argv.remove('--with-ext-uv') + define_macros.append(('WITH_UV', None)) + libraries.extend(['getdns_ext_uv', 'uv']) + sources.append('getdns_ext_uv.c') + library_dirs = [ '/usr/local/lib' ] if lib_dir: library_dirs.append(lib_dir) @@ -57,10 +71,10 @@ getdns_module = Extension('getdns', include_dirs = [ '/usr/local/include', ], - libraries = [ 'getdns' ], + libraries = libraries, + define_macros = define_macros, library_dirs = library_dirs, - sources = [ 'getdns.c', 'pygetdns_util.c', 'context.c', - 'context_util.c', 'result.c' ], + sources = sources, extra_compile_args = CFLAGS, runtime_library_dirs = library_dirs, )