[bind10-dev] Python 2 vs Python 3, was address dependency problems for beta/release

Francis Dupont fdupont at isc.org
Wed Nov 28 15:04:19 UTC 2012


> - Convert our C++ wrappers from Python 3 to Python 2

=> I did this for the AFTR/PCP (pcp/libpcp/libpcpmodule.c posted below)
It was not very hard, all critical structures and functions got new names
(BTW this avoids misuses, just a bit drastic). Can be funny with generated
interfaces...

IMHO just don't do this!

Regards

Francis Dupont <fdupont at isc.org>

PS: the file:

/*
 * Copyright (C) 2011-2012  Internet Systems Consortium, Inc. ("ISC")
 *
 * 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: 511b55cd096f070604b016408614f69d8b4a5ae8 $ */

/*
 * PCP (port-control-protocol) client library python module
 *
 * Francis_Dupont at isc.org, January 2011
 *
 * a la miniUPnP libnatpmp
 */

#include <Python.h>

#ifdef WIN32
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

#include "structmember.h"

#include "pcp.h"

/* for compatibility with Python < 2.4 */
#ifndef Py_RETURN_NONE
#define Py_RETURN_NONE	return Py_INCREF(Py_None), Py_None
#endif

#ifndef Py_RETURN_TRUE
#define Py_RETURN_TRUE	return Py_INCREF(Py_True), Py_True
#endif

#ifndef Py_RETURN_FALSE
#define Py_RETURN_FALSE	return Py_INCREF(Py_False), Py_False
#endif

typedef struct {
	PyObject_HEAD

	pcp_t pcp;
} PCPObject;

static void
PCPObject_dealloc(PCPObject *self)
{
	(void) pcp_close(&self->pcp);
#ifdef Py_TYPE
	Py_TYPE(self)->tp_free((PyObject *) self);
#else
	self->ob_type->tp_free((PyObject *) self);
#endif
}

/* pcp_init (called open) */

static PyObject *
PCP_open(PyObject *self, PyObject *args, PyObject *kwds)
{
	PCPObject *pcp = (PCPObject *) self;
	char *server, *source = NULL;
	int family = AF_INET, port = 0, ret;
	struct sockaddr_in s4, l4;
	struct sockaddr_in6 s6, l6;
	static char *keywords[] = {"server", "family", "source", "port", 0};

	if (!PyArg_ParseTupleAndKeywords(args, kwds,
					 "s|izi", keywords,
					 &server, &family, &source, &port))
		return NULL;
	switch (family) {
	case AF_INET:
		memset(&s4, 0, sizeof(s4));
		s4.sin_family = AF_INET;
		if (inet_pton(AF_INET, server, &s4.sin_addr) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		s4.sin_port = htons((unsigned short) port);
		if (source != NULL) {
			memset(&l4, 0, sizeof(l4));
			l4.sin_family = AF_INET;
			if (inet_pton(AF_INET, source, &l4.sin_addr) <= 0)
				return Py_BuildValue("i", PCP_ERR_INVAL);
			ret = pcp_init((struct sockaddr *) &s4,
				       (struct sockaddr *) &l4,
				       &pcp->pcp);
		} else
			ret = pcp_init((struct sockaddr*) &s4,
				       NULL, &pcp->pcp);
		break;

	case AF_INET6:
		memset(&s6, 0, sizeof(s6));
		s6.sin6_family = AF_INET6;
		if (inet_pton(AF_INET6, server, &s6.sin6_addr) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		s6.sin6_port = htons((unsigned short) port);
		if (source != NULL) {
			memset(&l6, 0, sizeof(l6));
			l6.sin6_family = AF_INET6;
			if (inet_pton(AF_INET6, source, &l6.sin6_addr) <= 0)
				return Py_BuildValue("i", PCP_ERR_INVAL);
			ret = pcp_init((struct sockaddr *) &s6,
				       (struct sockaddr *) &l6,
				       &pcp->pcp);
		} else
			ret = pcp_init((struct sockaddr*) &s6,
				       NULL, &pcp->pcp);
		break;
	default:
		return Py_BuildValue("i", PCP_ERR_INVAL);
	}
	if (ret != PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* pcp_close */

static PyObject *
PCP_close(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	int ret;

	ret = pcp_close(&pcp->pcp);
	if (ret != PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* pcp_getsocket */

static PyObject *
PCP_getsocket(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	int sock, ret;

	ret = pcp_getsocket(&pcp->pcp, &sock);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", sock);
}

/* pcp_setrcsocket */

static PyObject *
PCP_setrcsocket(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	int sock, ret;

	if (!PyArg_ParseTuple(args, "i", &sock))
		return NULL;
	ret = pcp_setrcsocket(&pcp->pcp, sock);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* pcp_gettries */

static PyObject *
PCP_gettries(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	int trycnt, ret;

	ret = pcp_gettries(&pcp->pcp, &trycnt);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", trycnt);
}

/* pcp_gettimeout */

static PyObject *
PCP_gettimeout(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	struct timeval tv;
	double d;
	int relative, ret;

	if (!PyArg_ParseTuple(args, "i", &relative))
		return NULL;
	ret = pcp_gettimeout(&pcp->pcp, &tv, relative);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	d = (double) tv.tv_sec + (double) tv.tv_usec * .000001;
	return Py_BuildValue("d", d);
}

/* pcp_setreset */

static PyObject *
PCP_setreset(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	int reset, old, ret;

	if (!PyArg_ParseTuple(args, "i", &reset))
		return NULL;
	ret = pcp_setreset(&pcp->pcp, reset, &old);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", old);
}

/* pcp_setautofill */

static PyObject *
PCP_setautofill(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	int autofill, old, ret;

	if (!PyArg_ParseTuple(args, "i", &autofill))
		return NULL;
	ret = pcp_setautofill(&pcp->pcp, autofill, &old);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", old);
}

/* pcp_third_party */

static PyObject *
PCP_third_party(PyObject *self, PyObject *args)
{
	char *addr = NULL;
	int family = 0;
	uint8_t a[16];

	self = self;
	if (!PyArg_ParseTuple(args, "|is", &family, &addr))
		return NULL;
	if (addr == NULL)
		return Py_BuildValue("i", PCP_ERR_INVAL);
	switch (family) {
	case AF_INET:
		memcpy(a, pcp_mapped, 12);
		if (inet_pton(AF_INET, addr, a + 12) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		break;
	case AF_INET6:
		if (inet_pton(AF_INET6, addr, a) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		break;
	default:
		return Py_BuildValue("i", PCP_ERR_INVAL);
	}
#if PY_MAJOR_VERSION == 2
	return Py_BuildValue("is#", PCP_OPTION_THIRD_PARTY,
			     a, PCP_LEN_OPT3PTY);
#else
	return Py_BuildValue("iy#", PCP_OPTION_THIRD_PARTY,
			     a, PCP_LEN_OPT3PTY);
#endif
}

/* pcp_prefer_failure */

static PyObject *
PCP_prefer_failure(PyObject *self)
{
	self = self;
#if PY_MAJOR_VERSION == 2
	return Py_BuildValue("is#", PCP_OPTION_PREF_FAIL, (uint8_t *) "", 0);
#else
	return Py_BuildValue("iy#", PCP_OPTION_PREF_FAIL, (uint8_t *) "", 0);
#endif
}
			     
/* pcp_filter */

static PyObject *
PCP_filter(PyObject *self, PyObject *args)
{
	char *addr;
	int family, prefixlen, port;
	uint16_t n16;
	uint8_t val[20];

	self = self;
	if (!PyArg_ParseTuple(args, "iisi", &family, &prefixlen, &addr, &port))
		return NULL;
	val[PCP_OPTDFLT_RSVD] = 0;
	val[PCP_OPTDFLT_PLEN] = (uint8_t) prefixlen;
	n16 = htons((uint16_t) port);
	memcpy(val + PCP_OPTDFLT_PORT, &n16, 2);
	switch (family) {
	case AF_INET:
		val[PCP_OPTDFLT_PLEN] += 96;
		memcpy(val + PCP_OPTDFLT_PREF, pcp_mapped, 12);
		if (inet_pton(AF_INET, addr,
			      val + 12 + PCP_OPTDFLT_PREF) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		break;
	case AF_INET6:
		if (inet_pton(AF_INET6, addr,
			      val + PCP_OPTDFLT_PREF) <= 0)
			return Py_BuildValue("i", PCP_ERR_INVAL);
		break;
	default:
		return Py_BuildValue("i", PCP_ERR_INVAL);
	}
#if PY_MAJOR_VERSION == 2
	return Py_BuildValue("is#", PCP_OPTION_FILTER,
			     val, PCP_LEN_OPTFLT);
#else
	return Py_BuildValue("iy#", PCP_OPTION_FILTER,
			     val, PCP_LEN_OPTFLT);
#endif
}

/* parse request */

static int
parse_request(pcp_request_t *req, pcp_option_t ***options,
	      PyObject *args, PyObject *kwds)
{
	PyObject *poptions = NULL, *po, *v;
	static pcp_option_t o[PCP_VECOPT_SIZE], *t[PCP_VECOPT_SIZE];
	char *intaddr = NULL, *extaddr = NULL, *remotepeer = NULL;
	int opcode = PCP_OPCODE_MAP, protocol = 0;
	int lifetime = 0, intport = 0, extport = 0, peerport = 0, len, i;

	static char *keywords[] = {"opcode", "lifetime", "protocol",
				   "intaddr", "extaddr", "remotepeer",
				   "intport", "extport", "peerport",
				   "options", 0 };

	if (!PyArg_ParseTupleAndKeywords(args, kwds,
					 "|iiizzziiiO", keywords,
					 &opcode, &lifetime, &protocol,
					 &intaddr, &extaddr, &remotepeer,
					 &intport, &extport, &peerport,
					 &poptions))
		return PCP_ERR_APP0;
	memset(req, 0, sizeof(*req));
	memset(o, 0, sizeof(o));
	memset(t, 0, sizeof(t));
	req->opcode = opcode;
	req->protocol = protocol;
	req->lifetime = lifetime;
	if (intaddr != NULL) {
		if (strchr(intaddr, ':') == NULL) {
			if (inet_pton(AF_INET, intaddr, &req->intaddr4) <= 0)
				return PCP_ERR_INVAL;
			pcp_mapintaddr(req);
		} else if (inet_pton(AF_INET6, intaddr, req->intaddr6) <= 0)
			return PCP_ERR_INVAL;
	}
	req->intport = intport;
	if (extaddr != NULL) {
		if (strchr(extaddr, ':') == NULL) {
			if (inet_pton(AF_INET, extaddr, &req->extaddr4) <= 0)
				return PCP_ERR_INVAL;
			pcp_mapextaddr(req);
		} else if (inet_pton(AF_INET6, extaddr, req->extaddr6) <= 0)
			return PCP_ERR_INVAL;
	}
	req->extport = extport;
	if (opcode == PCP_OPCODE_PEER) {
		if (remotepeer != NULL) {
			if (strchr(remotepeer, ':') == NULL) {
				if (inet_pton(AF_INET,
					      remotepeer,
					      &req->remotepeer4) <= 0)
					return PCP_ERR_INVAL;
				pcp_mapremotepeer(req);
			} else if (inet_pton(AF_INET6,
					     remotepeer,
					     req->remotepeer6) <= 0)
				return PCP_ERR_INVAL;
		}
		req->peerport = peerport;
	}
	if (poptions == NULL)
		return PCP_OK;
	if (!PyList_Check(poptions)) {
		PyErr_SetString(PyExc_TypeError, "options is not a list");
		return PCP_ERR_APP0;
	}
	len = PyList_Size(poptions);
	if (len > PCP_MAX_OPTIONS) {
		PyErr_SetString(PyExc_ValueError, "too many options");
		return PCP_ERR_APP0;
	}
	for (i = 0; i < len; i++) {
		po = PyList_GetItem(poptions, i);
		if (po == NULL)
			return PCP_ERR_APP0;
		if (!PyTuple_Check(po) || (PyTuple_Size(po) != 2)) {
		err:
			PyErr_SetString(PyExc_ValueError,
					"bad tuple in options");
			return PCP_ERR_APP0;
		}
		v = PyTuple_GetItem(po, 0);
#if PY_MAJOR_VERSION == 2
		if ((v == NULL) || !PyInt_Check(v))
			goto err;
		o[i].code = (int) PyInt_AsLong(v);
#else
		if ((v == NULL) || !PyLong_Check(v))
			goto err;
		o[i].code = (int) PyLong_AsLong(v);
#endif
		v = PyTuple_GetItem(po, 1);
#if PY_MAJOR_VERSION == 2
		if ((v == NULL) || !PyString_Check(v))
			goto err;
		o[i].data = (uint8_t *) PyString_AsString(v);
		o[i].length = (uint16_t) PyString_Size(v);
#else
		if ((v == NULL) || !PyBytes_Check(v))
			goto err;
		o[i].data = (uint8_t *) PyBytes_AsString(v);
		o[i].length = (uint16_t) PyBytes_Size(v);
#endif
		t[i] = &o[i];
	}
	*options = t;
	return PCP_OK;
}

/* pcp_makerequest */

static PyObject *
PCP_makerequest(PyObject *self, PyObject *args, PyObject *kwds)
{
	PCPObject *pcp = (PCPObject *) self;
	pcp_request_t req;
	pcp_option_t **options = NULL;
	int ret;

	ret = parse_request(&req, &options, args, kwds);
	if (ret < PCP_OK) {
		if (ret == PCP_ERR_APP0)
			return NULL;
		return Py_BuildValue("i", ret);
	}
	ret = pcp_makerequest(&pcp->pcp, &req, options);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* pcp_sendrequest */

static PyObject *
PCP_sendrequest(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	int ret;

	ret = pcp_sendrequest(&pcp->pcp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* build response */

static PyObject *
build_response(pcp_response_t *resp)
{
	PyObject *options, *po;
	pcp_option_t *o;
	char intaddr[INET6_ADDRSTRLEN];
	char extaddr[INET6_ADDRSTRLEN];
	char remotepeer[INET6_ADDRSTRLEN];
	int i, announce = 0, peer = 0;

	switch (resp->assigned.opcode) {
	case PCP_OPCODE_ANNOUNCE | PCP_OPCODE_RESPONSE:
		announce = 1;
		break;
	case PCP_OPCODE_MAP | PCP_OPCODE_RESPONSE:
		if (pcp_unmapextaddr(&resp->assigned)) {
			if (inet_ntop(AF_INET, &resp->assigned.extaddr4,
				      extaddr, sizeof(extaddr)) == NULL)
				return NULL;
		} else if (inet_ntop(AF_INET6, resp->assigned.extaddr6,
				     extaddr, sizeof(extaddr)) == NULL)
			return NULL;
		break;
	case PCP_OPCODE_PEER | PCP_OPCODE_RESPONSE:
		if (pcp_unmapremotepeer(&resp->assigned)) {
			if (inet_ntop(AF_INET, &resp->assigned.remotepeer4,
				      remotepeer, sizeof(extaddr)) == NULL)
				return NULL;
		} else if (inet_ntop(AF_INET6, resp->assigned.remotepeer6,
				     remotepeer, sizeof(extaddr)) == NULL)
			return NULL;
		if (pcp_unmapextaddr(&resp->assigned)) {
			if (inet_ntop(AF_INET, &resp->assigned.extaddr4,
				      extaddr, sizeof(extaddr)) == NULL)
				return NULL;
		} else if (inet_ntop(AF_INET6, resp->assigned.extaddr6,
				     extaddr, sizeof(extaddr)) == NULL)
			return NULL;
		peer = 1;
		break;
	default:
		return NULL;
	}
	options = PyList_New(0);
	for (i = 0; i < resp->optcnt; i++) {
		o = &resp->options[i];
#if PY_MAJOR_VERSION == 2
		po = Py_BuildValue("is#", o->code,
				   o->data == NULL ? (uint8_t *) "" : o->data,
				   o->length);
#else
		po = Py_BuildValue("iy#", o->code,
				   o->data == NULL ? (uint8_t *) "" : o->data,
				   o->length);
#endif
		if (PyList_Append(options, po)) {
			Py_XDECREF(po);
			Py_XDECREF(options);
			return NULL;
		}
		Py_XDECREF(po);
	}
	if (announce)
		return Py_BuildValue(
			"{s:i,s:i,s:i,s:O}",
			"result", resp->result,
			"epoch", resp->epoch,
			"opcode", resp->assigned.opcode,
			"options", options);
	else if (!peer)
		return Py_BuildValue(
			"{s:i,s:i,s:i,s:i,s:s,s:s,s:i,s:i,s:i,s:O}",
			"result", resp->result,
			"epoch", resp->epoch,
			"opcode", resp->assigned.opcode,
			"protocol", resp->assigned.protocol,
			"intaddr", intaddr,
			"extaddr", extaddr,
			"lifetime", resp->assigned.lifetime,
			"intport", resp->assigned.intport,
			"extport", resp->assigned.extport,
			"options", options);
	else
		return Py_BuildValue(
			"{s:i,s:i,s:i,s:i,s:s,s:s,s:s,s:i,s:i,s:i,s:i,s:O}",
			"result", resp->result,
			"epoch", resp->epoch,
			"opcode", resp->assigned.opcode,
			"protocol", resp->assigned.protocol,
			"intaddr", intaddr,
			"extaddr", extaddr,
			"remotepeer", remotepeer,
			"lifetime", resp->assigned.lifetime,
			"intport", resp->assigned.intport,
			"extport", resp->assigned.extport,
			"peerport", resp->assigned.peerport,
			"options", options);
}

/* pcp_recvresponse */

static PyObject *
PCP_recvresponse(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	PyObject *tmp = NULL;
	pcp_response_t resp;
	int ret;

	memset(&resp, 0, sizeof(resp));
	ret = pcp_recvresponse(&pcp->pcp, &resp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	if (ret == PCP_OK)
		tmp = build_response(&resp);
	if (tmp == NULL)
		return Py_BuildValue("i{}", ret);
	else
		return Py_BuildValue("iN", ret, tmp);
}

/* pcp_getmapping */

static PyObject *
PCP_getmapping(PyObject *self, PyObject *args, PyObject *kwds)
{
	PCPObject *pcp = (PCPObject *) self;
	PyObject *tmp = NULL;
	pcp_request_t req;
	pcp_option_t **options = NULL;
	pcp_response_t resp;
	int ret;

	ret = parse_request(&req, &options, args, kwds);
	if (ret < PCP_OK) {
		if (ret == PCP_ERR_APP0)
			return NULL;
		return Py_BuildValue("i", ret);
	}
	memset(&resp, 0, sizeof(resp));
	ret = pcp_getmapping(&pcp->pcp, &req, options, &resp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	if (ret == PCP_OK)
		tmp = build_response(&resp);
	if (tmp == NULL)
		return Py_BuildValue("i{}", ret);
	else
		return Py_BuildValue("iN", ret, tmp);
}

/* pcp_renewmapping */

static PyObject *
PCP_renewmapping(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	PyObject *tmp = NULL;
	pcp_response_t resp;
	int ret;

	memset(&resp, 0, sizeof(resp));
	ret = pcp_renewmapping(&pcp->pcp, &resp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	if (ret == PCP_OK)
		tmp = build_response(&resp);
	if (tmp == NULL)
		return Py_BuildValue("i{}", ret);
	else
		return Py_BuildValue("iN", ret, tmp);
}

/* pcp_delmapping */

static PyObject *
PCP_delmapping(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	PyObject *tmp = NULL;
	pcp_response_t resp;
	int ret;

	memset(&resp, 0, sizeof(resp));
	ret = pcp_delmapping(&pcp->pcp, &resp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	if (ret == PCP_OK)
		tmp = build_response(&resp);
	if (tmp == NULL)
		return Py_BuildValue("i{}", ret);
	else
		return Py_BuildValue("iN", ret, tmp);
}

/* _pcp_fdinit */

static PyObject *
PCP_fdopen(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	int fd, ret;

	if (!PyArg_ParseTuple(args, "i", &fd))
		return NULL;
	ret = _pcp_fdinit(&pcp->pcp, fd);
	if (ret != PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* _pcp_setrequest */

static PyObject *
PCP_setrequest(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	uint8_t *req = NULL;
	int len, ret;

#if PY_MAJOR_VERSION == 2
	if (!PyArg_ParseTuple(args, "s#", &req, &len))
		return NULL;
#else
	if (!PyArg_ParseTuple(args, "y#", &req, &len))
		return NULL;
#endif
	ret = _pcp_setrequest(&pcp->pcp, req, (uint16_t) len);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* _pcp_getrequest */

static PyObject *
PCP_getrequest(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	uint8_t *req = NULL;
	uint16_t len;
	int ret;

	ret = _pcp_getrequest(&pcp->pcp, &req, &len);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
#if PY_MAJOR_VERSION == 2
	return Py_BuildValue("s#", req, (int) len);
#else
	return Py_BuildValue("y#", req, (int) len);
#endif
}

/* _pcp_setresponse */

static PyObject *
PCP_setresponse(PyObject *self, PyObject *args)
{
	PCPObject *pcp = (PCPObject *) self;
	uint8_t *resp = NULL;
	int len, ret;

#if PY_MAJOR_VERSION == 2
	if (!PyArg_ParseTuple(args, "s#", &resp, &len))
		return NULL;
#else
	if (!PyArg_ParseTuple(args, "y#", &resp, &len))
		return NULL;
#endif
	ret = _pcp_setresponse(&pcp->pcp, resp, (uint16_t) len);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	return Py_BuildValue("i", ret);
}

/* _pcp_getresponse */

static PyObject *
PCP_getresponse(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	uint8_t *resp = NULL;
	uint16_t len;
	int ret;

	ret = _pcp_getresponse(&pcp->pcp, &resp, &len);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
#if PY_MAJOR_VERSION == 2
	return Py_BuildValue("s#", resp, (int) len);
#else
	return Py_BuildValue("y#", resp, (int) len);
#endif
}

/* _pcp_submitresponse */

static PyObject *
PCP_submitresponse(PyObject *self)
{
	PCPObject *pcp = (PCPObject *) self;
	PyObject *tmp = NULL;
	pcp_response_t resp;
	int ret;

	memset(&resp, 0, sizeof(resp));
	ret = _pcp_submitresponse(&pcp->pcp, &resp);
	if (ret < PCP_OK) {
		PyErr_SetString(PyExc_Exception, pcp_strerror(ret));
		return NULL;
	}
	if (ret == PCP_OK)
		tmp = build_response(&resp);
	if (tmp == NULL)
		return Py_BuildValue("i{}", ret);
	else
		return Py_BuildValue("iN", ret, tmp);
}

static PyObject *
PCP_getoptinfo(PyObject *self, PyObject *args)
{
	uint8_t *odata;
	char buf[256];
	int code, len, isv4;
	size_t done;
	uint16_t n16;

	self = self;
#if PY_MAJOR_VERSION == 2
	if (!PyArg_ParseTuple(args, "is#", &code, &odata, &len))
		return NULL;
#else
	if (!PyArg_ParseTuple(args, "iy#", &code, &odata, &len))
		return NULL;
#endif
	memset(buf, 0, sizeof(buf));
	switch (code) {
	case PCP_OPTION_THIRD_PARTY:
		if (len == PCP_LEN_OPT0) {
			(void) snprintf(buf, sizeof(buf), "all");
			break;
		}
		if (len != PCP_LEN_OPT3PTY)
			Py_RETURN_NONE;
		if (memcmp(odata, pcp_mapped, 12) == 0)
			(void) inet_ntop(AF_INET, odata + 12,
					 buf, sizeof(buf));
		else
			(void) inet_ntop(AF_INET6, odata,
					 buf, sizeof(buf));
		break;


	case PCP_OPTION_PREF_FAIL:
		if (len != PCP_LEN_OPT0)
			Py_RETURN_NONE;
		break;
		
	case PCP_OPTION_FILTER:
		if (len != PCP_LEN_OPTFLT)
			Py_RETURN_NONE;
		if ((odata[1] >= 96) &&
		    (memcmp(odata + PCP_OPTDFLT_PREF, pcp_mapped, 12) == 0)) {
			isv4 = 1;
			(void) inet_ntop(AF_INET,
					 odata + 12 + PCP_OPTDFLT_PREF,
					 buf, sizeof(buf));
		} else {
			isv4 = 0;
			(void) inet_ntop(AF_INET6,
					 odata + PCP_OPTDFLT_PREF,
					 buf, sizeof(buf));
		}
		memcpy(&n16, odata + PCP_OPTDFLT_PORT, 2);
		n16 = ntohs(n16);
		done = strlen(buf);
		(void) snprintf(buf + done, sizeof(buf) - done, "/%d %hu",
				(int) isv4 ? odata[1] - 96 : odata[1], n16);
		break;
	default:
		Py_RETURN_NONE;
	}
	return Py_BuildValue("s", buf);
}

/* Method Table */

static PyMethodDef PCPObject_methods[] = {
	{ "open", (PyCFunction) PCP_open, METH_VARARGS | METH_KEYWORDS,
	  "open(server, [family:, source:, port:]) -> pcp_init" },
	{ "close", (PyCFunction) PCP_close, METH_NOARGS,
	  "close() -> pcp_close" },
	{ "getsocket", (PyCFunction) PCP_getsocket, METH_NOARGS,
	  "getsocket() -> pcp_getsocket (err<0 or socket)" },
	{ "setrcsocket", (PyCFunction) PCP_setrcsocket, METH_VARARGS,
	  "setrcsocket(sock) -> pcp_setrcsocket" },
	{ "gettries", (PyCFunction) PCP_gettries, METH_NOARGS,
	  "gettries() -> pcp_gettries (err<0 or socket)" },
	{ "gettimeout", (PyCFunction) PCP_gettimeout, METH_VARARGS,
	  "gettimeout(relative) -> pcp_gettimeout (tv_sec, tv_usec)" },
	{ "setreset", (PyCFunction) PCP_setreset, METH_VARARGS,
	  "setreset(reset) -> pcp_setreset (old)" },
	{ "setautofill", (PyCFunction) PCP_setautofill, METH_VARARGS,
	  "setautofill(autofill) -> pcp_setautofill (old)" },
	{ "third_party", (PyCFunction) PCP_third_party, METH_VARARGS,
	  "third_party(family, address) -> pcp_third_party" },
	{ "prefer_failure", (PyCFunction) PCP_prefer_failure, METH_NOARGS,
	  "prefer_failure() -> pcp_prefer_failure" },
	{ "filter", (PyCFunction) PCP_filter, METH_VARARGS,
	  "filter(family, address, port) -> pcp_filter" },
	{ "makerequest", (PyCFunction) PCP_makerequest,
	  METH_VARARGS | METH_KEYWORDS,
	  "makerequest([opcode:, protocol:, [int|ext]addr:, lifetime:, \n"
	  "[int|ext]port:, options]) -> pcp_makerequest" },
	{ "sendrequest", (PyCFunction) PCP_sendrequest, METH_NOARGS,
	  "sendrequest() -> pcp_sendrequest" },
	{ "recvresponse", (PyCFunction) PCP_recvresponse, METH_NOARGS,
	  "recvresponse() -> pcp_recvresponse {dict}" },
	{ "getmapping", (PyCFunction) PCP_getmapping,
	  METH_VARARGS | METH_KEYWORDS,
	  "getmapping([opcode:, protocol:, [int|ext]addr:, lifetime:, \n"
	  "[int|ext]port:, options]) -> pcp_getmapping {dict}" },
	{ "renewmapping", (PyCFunction) PCP_renewmapping, METH_NOARGS,
	  "renewmapping() -> pcp_renewmapping {dict}" },
	{ "delmapping", (PyCFunction) PCP_delmapping, METH_NOARGS,
	  "delmapping() -> pcp_delmapping {dict}" },
	{ "fdopen", (PyCFunction) PCP_fdopen, METH_VARARGS,
	  "fdopen(fd) -> _pcp_fdinit" },
	{ "setrequest", (PyCFunction) PCP_setrequest, METH_VARARGS,
	  "setrequest('req') -> _pcp_setrequest" },
	{ "getrequest", (PyCFunction) PCP_getrequest, METH_NOARGS,
	  "getrequest() -> _pcp_getrequest" },
	{ "setresponse", (PyCFunction) PCP_setresponse, METH_VARARGS,
	  "setresponse('req') -> _pcp_setresponse" },
	{ "getresponse", (PyCFunction) PCP_getresponse, METH_NOARGS,
	  "getresponse() -> _pcp_getresponse" },
	{ "submitresponse", (PyCFunction) PCP_submitresponse, METH_NOARGS,
	  "submitresponse() -> pcp_submitresponse {dict}" },
	{ "getoptinfo", (PyCFunction) PCP_getoptinfo, METH_VARARGS,
	  "getoptinfo() -> option info" },
	{ NULL, NULL, 0, NULL }
};

static PyTypeObject PCPType = {
#if PY_MAJOR_VERSION == 2
	PyObject_HEAD_INIT(NULL)
	0,				/* ob_size */
#else
	PyVarObject_HEAD_INIT(NULL, 0)
#endif
	"libpcp.PCP",			/* tp_name */
	sizeof(PCPObject),		/* tp_basicsize */
	0,				/* tp_itemsize */
	(destructor) PCPObject_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,		/* tp_flags */
	"PCP objects",			/* tp_doc */
	0,				/* tp_traverse */
	0,				/* tp_clear */
	0,				/* tp_richcompare */
	0,				/* tp_weaklistoffset */
	0,				/* tp_iter */
	0,				/* tp_iternext */
	PCPObject_methods,		/* tp_methods */
	0,				/* tp_members */
	0,				/* tp_getset */
	0,				/* tp_base */
	0,				/* tp_dict */
	0,				/* tp_descr_get */
	0,				/* tp_descr_set */
	0,				/* tp_dictoffset */
	0,				/* tp_init */
	0,				/* tp_alloc */
	0,				/* tp_new */
	0,				/* tp_free */
};

#if PY_MAJOR_VERSION == 2

/* module methods */
static PyMethodDef libpcp_methods[] = {
	{ NULL, NULL, 0, NULL }
};

#else

/* module definition */
static PyModuleDef libpcp_module = {
	PyModuleDef_HEAD_INIT,
	"libpcp",			/* m_name */
	"PCP client library",		/* m_doc */
	-1,				/* m_size */
	NULL,				/* m_methods */
	NULL,				/* m_reload */
	NULL,				/* m_traverse */
	NULL,				/* m_clear */
	NULL				/* m_free */
};
#endif

#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC	void
#endif

PyMODINIT_FUNC
#if PY_MAJOR_VERSION == 2
initlibpcp(void)
#else
PyInit_libpcp(void)
#endif
{
	PyObject *mod;

	PCPType.tp_new = PyType_GenericNew;

#if PY_MAJOR_VERSION == 2
	if (PyType_Ready(&PCPType) < 0)
		return;
#else
	if (PyType_Ready(&PCPType) < 0)
		return NULL;
#endif

#if PY_MAJOR_VERSION == 2
	mod = Py_InitModule3("libpcp",
			     libpcp_methods,
			     "PCP client library.");
	if (mod == NULL)
		return;
#else
	mod = PyModule_Create(&libpcp_module);
	if (mod == NULL)
		return NULL;
#endif

	Py_INCREF(&PCPType);
	PyModule_AddObject(mod, "PCP", (PyObject *) &PCPType);

	PyModule_AddIntConstant(mod, "PORT", PCP_PORT);
	PyModule_AddIntConstant(mod, "RC_PORT", PCP_RC_PORT);
	PyModule_AddIntConstant(mod, "OPCODE_ANNOUNCE", PCP_OPCODE_ANNOUNCE);
	PyModule_AddIntConstant(mod, "OPCODE_MAP", PCP_OPCODE_MAP);
	PyModule_AddIntConstant(mod, "OPCODE_PEER", PCP_OPCODE_PEER);
	PyModule_AddIntConstant(mod, "OPCODE_RESPONSE", PCP_OPCODE_RESPONSE);
	PyModule_AddIntConstant(mod, "OK", PCP_OK);
	PyModule_AddIntConstant(mod, "TRY_AGAIN", PCP_TRY_AGAIN);
	PyModule_AddIntConstant(mod, "ERR_INVAL", PCP_ERR_INVAL);
	PyModule_AddIntConstant(mod, "ERR_NOMEM", PCP_ERR_NOMEM);
	PyModule_AddIntConstant(mod, "ERR_SOCKET", PCP_ERR_SOCKET);
	PyModule_AddIntConstant(mod, "ERR_BIND", PCP_ERR_BIND);
	PyModule_AddIntConstant(mod, "ERR_CONNECT", PCP_ERR_CONNECT);
	PyModule_AddIntConstant(mod, "ERR_SEND", PCP_ERR_SEND);
	PyModule_AddIntConstant(mod, "ERR_RECV", PCP_ERR_RECV);
	PyModule_AddIntConstant(mod, "ERR_SYSCALL", PCP_ERR_SYSCALL);
	PyModule_AddIntConstant(mod, "ERR_NOREQUEST", PCP_ERR_NOREQUEST);
	PyModule_AddIntConstant(mod, "ERR_RECVBAD", PCP_ERR_RECVBAD);
	PyModule_AddIntConstant(mod, "ERR_TOOMANYOPTS", PCP_ERR_TOOMANYOPTS);
	PyModule_AddIntConstant(mod, "ERR_FAILURE", PCP_ERR_FAILURE);
	PyModule_AddIntConstant(mod, "ERR_APP0", PCP_ERR_APP0);
	PyModule_AddIntConstant(mod, "ERR_APP1", PCP_ERR_APP1);
	PyModule_AddIntConstant(mod, "ERR_APP2", PCP_ERR_APP2);
	PyModule_AddIntConstant(mod, "ERR_PROTOBASE", PCP_ERR_PROTOBASE);
	PyModule_AddIntConstant(mod, "ERR_UNSUPVERSION", PCP_ERR_UNSUPVERSION);
	PyModule_AddIntConstant(mod, "ERR_NOTAUTH", PCP_ERR_NOTAUTH);
	PyModule_AddIntConstant(mod, "ERR_BADREQUEST", PCP_ERR_BADREQUEST);
	PyModule_AddIntConstant(mod, "ERR_UNSUPOPCODE", PCP_ERR_UNSUPOPCODE);
	PyModule_AddIntConstant(mod, "ERR_UNSUPOPTION", PCP_ERR_UNSUPOPTION);
	PyModule_AddIntConstant(mod, "ERR_BADOPTION", PCP_ERR_BADOPTION);
	PyModule_AddIntConstant(mod, "ERR_NETFAILURE", PCP_ERR_NETFAILURE);
	PyModule_AddIntConstant(mod, "ERR_NORESOURCES", PCP_ERR_NORESOURCES);
	PyModule_AddIntConstant(mod, "ERR_UNSUPPROTO", PCP_ERR_UNSUPPROTO);
	PyModule_AddIntConstant(mod, "ERR_EXQUOTA", PCP_ERR_EXQUOTA);
	PyModule_AddIntConstant(mod, "ERR_CANTPROVIDE", PCP_ERR_CANTPROVIDE);
	PyModule_AddIntConstant(mod, "ERR_ADDRMISMATCH", PCP_ERR_ADDRMISMATCH);
	PyModule_AddIntConstant(mod, "ERR_TOOMANYPEER", PCP_ERR_TOOMANYPEER);
	PyModule_AddIntConstant(mod, "ERR_PROCERROR", PCP_ERR_PROCERROR);
	PyModule_AddIntConstant(mod, "OPTION_FILTER", PCP_OPTION_FILTER);
	PyModule_AddIntConstant(mod, "OPTION_PREF_FAIL", PCP_OPTION_PREF_FAIL);
	PyModule_AddIntConstant(mod, "OPTION_THIRD_PARTY",
				PCP_OPTION_THIRD_PARTY);
	PyModule_AddIntConstant(mod, "MAX_TRIES", PCP_MAX_TRIES);
	PyModule_AddIntConstant(mod, "MAX_TIMEOUT", PCP_MAX_TIMEOUT);

#if PY_MAJOR_VERSION > 2
	return mod;
#endif
}


More information about the bind10-dev mailing list