| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 | /* $Id: miniupnpcmodule.c,v 1.31 2017/11/02 15:37:28 nanard Exp $*//* Project : miniupnp * Author : Thomas BERNARD * website : http://miniupnp.tuxfamily.org/ * copyright (c) 2007-2016 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */#include <Python.h>#define MINIUPNP_STATICLIB#include "structmember.h"#include "miniupnpc.h"#include "upnpcommands.h"#include "upnperrors.h"#ifdef _WIN32#include <winsock2.h>#endif/* 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/* for compatibility with Python < 3.0 */#ifndef PyVarObject_HEAD_INIT#define PyVarObject_HEAD_INIT(type, size) \    PyObject_HEAD_INIT(type) size,#endif#ifndef Py_TYPE#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)#endiftypedef struct {    PyObject_HEAD    /* Type-specific fields go here. */	struct UPNPDev * devlist;	struct UPNPUrls urls;	struct IGDdatas data;	unsigned int discoverdelay;	/* value passed to upnpDiscover() */	unsigned int localport;		/* value passed to upnpDiscover() */	char lanaddr[40];	/* our ip address on the LAN */	char * multicastif;	char * minissdpdsocket;} UPnPObject;static PyMemberDef UPnP_members[] = {	{"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),	 READONLY, "ip address on the LAN"	},	{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),	 0/*READWRITE*/, "value in ms used to wait for SSDP responses"	},	{"localport", T_UINT, offsetof(UPnPObject, localport),	 0/*READWRITE*/,	    "If localport is set to UPNP_LOCAL_PORT_SAME(1) "	    "SSDP packets will be sent from the source port "	    "1900 (same as destination port), if set to "	    "UPNP_LOCAL_PORT_ANY(0) system assign a source "	    "port, any other value will be attempted as the "	    "source port"	},	/* T_STRING is allways readonly :( */	{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),	 0, "IP of the network interface to be used for multicast operations"	},	{"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),	 0, "path of the MiniSSDPd unix socket"	},	{NULL}};static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds){	char* multicastif = NULL;	char* minissdpdsocket = NULL;	static char *kwlist[] = {		"multicastif", "minissdpdsocket", "discoverdelay",		"localport", NULL	};	if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,					&multicastif,					&minissdpdsocket,					&self->discoverdelay,					&self->localport))		return -1;	if(self->localport>1 &&	   (self->localport>65534||self->localport<1024)) {	    PyErr_SetString(PyExc_Exception, "Invalid localport value");	    return -1;	}	if(multicastif)		self->multicastif = strdup(multicastif);	if(minissdpdsocket)		self->minissdpdsocket = strdup(minissdpdsocket);	return 0;}static voidUPnPObject_dealloc(UPnPObject *self){	freeUPNPDevlist(self->devlist);	FreeUPNPUrls(&self->urls);	free(self->multicastif);	free(self->minissdpdsocket);	Py_TYPE(self)->tp_free((PyObject*)self);}static PyObject *UPnP_discover(UPnPObject *self){	struct UPNPDev * dev;	int i;	PyObject *res = NULL;	if(self->devlist)	{		freeUPNPDevlist(self->devlist);		self->devlist = 0;	}	Py_BEGIN_ALLOW_THREADS	self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,	                             self->multicastif,	                             self->minissdpdsocket,	                             (int)self->localport,	                             0/*ip v6*/,	                             2/* TTL */,	                             0/*error */);	Py_END_ALLOW_THREADS	/* Py_RETURN_NONE ??? */	for(dev = self->devlist, i = 0; dev; dev = dev->pNext)		i++;	res = Py_BuildValue("i", i);	return res;}static PyObject *UPnP_selectigd(UPnPObject *self){	int r;Py_BEGIN_ALLOW_THREADS	r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,	                     self->lanaddr, sizeof(self->lanaddr));Py_END_ALLOW_THREADS	if(r)	{		return Py_BuildValue("s", self->urls.controlURL);	}	else	{		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, "No UPnP device discovered");		return NULL;	}}static PyObject *UPnP_totalbytesent(UPnPObject *self){	UNSIGNED_INTEGER i;Py_BEGIN_ALLOW_THREADS	i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,	                           self->data.CIF.servicetype);Py_END_ALLOW_THREADS#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)	return Py_BuildValue("I", i);#else	return Py_BuildValue("i", (int)i);#endif}static PyObject *UPnP_totalbytereceived(UPnPObject *self){	UNSIGNED_INTEGER i;Py_BEGIN_ALLOW_THREADS	i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,		                           self->data.CIF.servicetype);Py_END_ALLOW_THREADS#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)	return Py_BuildValue("I", i);#else	return Py_BuildValue("i", (int)i);#endif}static PyObject *UPnP_totalpacketsent(UPnPObject *self){	UNSIGNED_INTEGER i;Py_BEGIN_ALLOW_THREADS	i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,		                         self->data.CIF.servicetype);Py_END_ALLOW_THREADS#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)	return Py_BuildValue("I", i);#else	return Py_BuildValue("i", (int)i);#endif}static PyObject *UPnP_totalpacketreceived(UPnPObject *self){	UNSIGNED_INTEGER i;Py_BEGIN_ALLOW_THREADS	i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,		                          self->data.CIF.servicetype);Py_END_ALLOW_THREADS#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)	return Py_BuildValue("I", i);#else	return Py_BuildValue("i", (int)i);#endif}static PyObject *UPnP_statusinfo(UPnPObject *self){	char status[64];	char lastconnerror[64];	unsigned int uptime = 0;	int r;	status[0] = '\0';	lastconnerror[0] = '\0';Py_BEGIN_ALLOW_THREADS	r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,	                   status, &uptime, lastconnerror);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)		return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);#else		return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);#endif	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}static PyObject *UPnP_connectiontype(UPnPObject *self){	char connectionType[64];	int r;	connectionType[0] = '\0';Py_BEGIN_ALLOW_THREADS	r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,	                               self->data.first.servicetype,	                               connectionType);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {		return Py_BuildValue("s", connectionType);	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}static PyObject *UPnP_externalipaddress(UPnPObject *self){	char externalIPAddress[40];	int r;	externalIPAddress[0] = '\0';Py_BEGIN_ALLOW_THREADS	r = UPNP_GetExternalIPAddress(self->urls.controlURL,	                              self->data.first.servicetype,	                              externalIPAddress);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {		return Py_BuildValue("s", externalIPAddress);	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, *                remoteHost) * protocol is 'UDP' or 'TCP' */static PyObject *UPnP_addportmapping(UPnPObject *self, PyObject *args){	char extPort[6];	unsigned short ePort;	char inPort[6];	unsigned short iPort;	const char * proto;	const char * host;	const char * desc;	const char * remoteHost;	const char * leaseDuration = "0";	int r;	if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto,	                                     &host, &iPort, &desc, &remoteHost))        return NULL;Py_BEGIN_ALLOW_THREADS	sprintf(extPort, "%hu", ePort);	sprintf(inPort, "%hu", iPort);	r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,	                        extPort, inPort, host, desc, proto,	                        remoteHost, leaseDuration);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS)	{		Py_RETURN_TRUE;	}	else	{		// TODO: RAISE an Exception. See upnpcommands.h for errors codes.		// upnperrors.c		//Py_RETURN_FALSE;		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc, *                   remoteHost) * protocol is 'UDP' or 'TCP' */static PyObject *UPnP_addanyportmapping(UPnPObject *self, PyObject *args){	char extPort[6];	unsigned short ePort;	char inPort[6];	unsigned short iPort;	char reservedPort[6];	const char * proto;	const char * host;	const char * desc;	const char * remoteHost;	const char * leaseDuration = "0";	int r;	if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost))        return NULL;Py_BEGIN_ALLOW_THREADS	sprintf(extPort, "%hu", ePort);	sprintf(inPort, "%hu", iPort);	r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,	                           extPort, inPort, host, desc, proto,	                           remoteHost, leaseDuration, reservedPort);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {		return Py_BuildValue("i", atoi(reservedPort));	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}/* DeletePortMapping(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */static PyObject *UPnP_deleteportmapping(UPnPObject *self, PyObject *args){	char extPort[6];	unsigned short ePort;	const char * proto;	const char * remoteHost = "";	int r;	if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))		return NULL;Py_BEGIN_ALLOW_THREADS	sprintf(extPort, "%hu", ePort);	r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,	                           extPort, proto, remoteHost);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {		Py_RETURN_TRUE;	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}/* DeletePortMappingRange(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */static PyObject *UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args){	char extPortStart[6];	unsigned short ePortStart;	char extPortEnd[6];	unsigned short ePortEnd;	const char * proto;	unsigned char manage;	char manageStr[1];	int r;	if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))		return NULL;Py_BEGIN_ALLOW_THREADS	sprintf(extPortStart, "%hu", ePortStart);	sprintf(extPortEnd, "%hu", ePortEnd);	sprintf(manageStr, "%hhu", manage);	r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,					extPortStart, extPortEnd, proto, manageStr);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {		Py_RETURN_TRUE;	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}static PyObject *UPnP_getportmappingnumberofentries(UPnPObject *self){	unsigned int n = 0;	int r;Py_BEGIN_ALLOW_THREADS	r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,	                                   self->data.first.servicetype,									   &n);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS) {#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)		return Py_BuildValue("I", n);#else		return Py_BuildValue("i", (int)n);#endif	} else {		/* TODO: have our own exception type ! */		PyErr_SetString(PyExc_Exception, strupnperror(r));		return NULL;	}}/* GetSpecificPortMapping(ePort, proto, remoteHost='') * proto = 'UDP' or 'TCP' */static PyObject *UPnP_getspecificportmapping(UPnPObject *self, PyObject *args){	char extPort[6];	unsigned short ePort;	const char * proto;	const char * remoteHost = "";	char intClient[40];	char intPort[6];	unsigned short iPort;	char desc[80];	char enabled[4];	char leaseDuration[16];	if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))		return NULL;	extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';	desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';Py_BEGIN_ALLOW_THREADS	sprintf(extPort, "%hu", ePort);	UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,	                                 self->data.first.servicetype,									 extPort, proto, remoteHost,									 intClient, intPort,	                                 desc, enabled, leaseDuration);Py_END_ALLOW_THREADS	if(intClient[0])	{		iPort = (unsigned short)atoi(intPort);		return Py_BuildValue("(s,H,s,O,i)",		                     intClient, iPort, desc,		                     PyBool_FromLong(atoi(enabled)),		                     atoi(leaseDuration));	}	else	{		Py_RETURN_NONE;	}}/* GetGenericPortMapping(index) */static PyObject *UPnP_getgenericportmapping(UPnPObject *self, PyObject *args){	int i, r;	char index[8];	char intClient[40];	char intPort[6];	unsigned short iPort;	char extPort[6];	unsigned short ePort;	char protocol[4];	char desc[80];	char enabled[6];	char rHost[64];	char duration[16];	/* lease duration */	unsigned int dur;	if(!PyArg_ParseTuple(args, "i", &i))		return NULL;Py_BEGIN_ALLOW_THREADS	snprintf(index, sizeof(index), "%d", i);	rHost[0] = '\0'; enabled[0] = '\0';	duration[0] = '\0'; desc[0] = '\0';	extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';	r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,	                                    self->data.first.servicetype,										index,										extPort, intClient, intPort,										protocol, desc, enabled, rHost,										duration);Py_END_ALLOW_THREADS	if(r==UPNPCOMMAND_SUCCESS)	{		ePort = (unsigned short)atoi(extPort);		iPort = (unsigned short)atoi(intPort);		dur = (unsigned int)strtoul(duration, 0, 0);#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)		return Py_BuildValue("(H,s,(s,H),s,s,s,I)",		                     ePort, protocol, intClient, iPort,		                     desc, enabled, rHost, dur);#else		return Py_BuildValue("(i,s,(s,i),s,s,s,i)",		                     (int)ePort, protocol, intClient, (int)iPort,		                     desc, enabled, rHost, (int)dur);#endif	}	else	{		Py_RETURN_NONE;	}}/* miniupnpc.UPnP object Method Table */static PyMethodDef UPnP_methods[] = {    {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,     "discover UPnP IGD devices on the network"    },	{"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,	 "select a valid UPnP IGD among discovered devices"	},	{"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,	 "return the total number of bytes sent by UPnP IGD"	},	{"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,	 "return the total number of bytes received by UPnP IGD"	},	{"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,	 "return the total number of packets sent by UPnP IGD"	},	{"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,	 "return the total number of packets received by UPnP IGD"	},	{"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,	 "return status and uptime"	},	{"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,	 "return IGD WAN connection type"	},	{"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,	 "return external IP address"	},	{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,	 "add a port mapping"	},	{"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,	 "add a port mapping, IGD to select alternative if necessary"	},	{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,	 "delete a port mapping"	},	{"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,	 "delete a range of port mappings"	},	{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,	 "-- non standard --"	},	{"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,	 "get details about a specific port mapping entry"	},	{"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,	 "get all details about the port mapping at index"	},    {NULL}  /* Sentinel */};static PyTypeObject UPnPType = {    PyVarObject_HEAD_INIT(NULL,    0)                         /*ob_size*/    "miniupnpc.UPnP",          /*tp_name*/    sizeof(UPnPObject),        /*tp_basicsize*/    0,                         /*tp_itemsize*/    (destructor)UPnPObject_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*/    "UPnP objects",            /* tp_doc */    0,		                   /* tp_traverse */    0,		                   /* tp_clear */    0,		                   /* tp_richcompare */    0,		                   /* tp_weaklistoffset */    0,		                   /* tp_iter */    0,		                   /* tp_iternext */    UPnP_methods,              /* tp_methods */    UPnP_members,              /* tp_members */    0,                         /* tp_getset */    0,                         /* tp_base */    0,                         /* tp_dict */    0,                         /* tp_descr_get */    0,                         /* tp_descr_set */    0,                         /* tp_dictoffset */    (initproc)UPnP_init,       /* tp_init */    0,                         /* tp_alloc */#ifndef _WIN32    PyType_GenericNew,/*UPnP_new,*/      /* tp_new */#else    0,#endif};/* module methods */static PyMethodDef miniupnpc_methods[] = {    {NULL}  /* Sentinel */};#if PY_MAJOR_VERSION >= 3static struct PyModuleDef moduledef = {    PyModuleDef_HEAD_INIT,    "miniupnpc",     /* m_name */    "miniupnpc module.",  /* m_doc */    -1,                  /* m_size */    miniupnpc_methods,    /* m_methods */    NULL,                /* m_reload */    NULL,                /* m_traverse */    NULL,                /* m_clear */    NULL,                /* m_free */};#endif#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */#define PyMODINIT_FUNC void#endifPyMODINIT_FUNC#if PY_MAJOR_VERSION >= 3PyInit_miniupnpc(void)#elseinitminiupnpc(void)#endif{    PyObject* m;#ifdef _WIN32    /* initialize Winsock. */    WSADATA wsaData;    int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);    UPnPType.tp_new = PyType_GenericNew;#endif    if (PyType_Ready(&UPnPType) < 0)#if PY_MAJOR_VERSION >= 3        return 0;#else        return;#endif#if PY_MAJOR_VERSION >= 3    m = PyModule_Create(&moduledef);#else    m = Py_InitModule3("miniupnpc", miniupnpc_methods,                       "miniupnpc module.");#endif    Py_INCREF(&UPnPType);    PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);#if PY_MAJOR_VERSION >= 3    return m;#endif}
 |