File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpc / miniupnpcmodule.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 00:36:10 2013 UTC (10 years, 10 months ago) by misho
Branches: miniupnpc, elwix, MAIN
CVS tags: v1_8p0, v1_8, HEAD
1.8

    1: /* $Id: miniupnpcmodule.c,v 1.1.1.2 2013/07/22 00:36:10 misho Exp $*/
    2: /* Project : miniupnp
    3:  * Author : Thomas BERNARD
    4:  * website : http://miniupnp.tuxfamily.org/
    5:  * copyright (c) 2007-2012 Thomas Bernard
    6:  * This software is subjet to the conditions detailed in the
    7:  * provided LICENCE file. */
    8: #include <Python.h>
    9: #define STATICLIB
   10: #include "structmember.h"
   11: #include "miniupnpc.h"
   12: #include "upnpcommands.h"
   13: #include "upnperrors.h"
   14: 
   15: /* for compatibility with Python < 2.4 */
   16: #ifndef Py_RETURN_NONE
   17: #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
   18: #endif
   19: 
   20: #ifndef Py_RETURN_TRUE
   21: #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
   22: #endif
   23: 
   24: #ifndef Py_RETURN_FALSE
   25: #define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
   26: #endif
   27: 
   28: /* for compatibility with Python < 3.0 */
   29: #ifndef PyVarObject_HEAD_INIT
   30: #define PyVarObject_HEAD_INIT(type, size) \
   31:     PyObject_HEAD_INIT(type) size,
   32: #endif
   33: 
   34: #ifndef Py_TYPE
   35: #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
   36: #endif
   37: 
   38: typedef struct {
   39:     PyObject_HEAD
   40:     /* Type-specific fields go here. */
   41: 	struct UPNPDev * devlist;
   42: 	struct UPNPUrls urls;
   43: 	struct IGDdatas data;
   44: 	unsigned int discoverdelay;	/* value passed to upnpDiscover() */
   45: 	char lanaddr[40];	/* our ip address on the LAN */
   46: 	char * multicastif;
   47: 	char * minissdpdsocket;
   48: } UPnPObject;
   49: 
   50: static PyMemberDef UPnP_members[] = {
   51: 	{"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
   52: 	 READONLY, "ip address on the LAN"
   53: 	},
   54: 	{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
   55: 	 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
   56: 	},
   57: 	/* T_STRING is allways readonly :( */
   58: 	{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
   59: 	 0, "IP of the network interface to be used for multicast operations"
   60: 	},
   61: 	{"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif),
   62: 	 0, "path of the MiniSSDPd unix socket"
   63: 	},
   64: 	{NULL}
   65: };
   66: 
   67: static void
   68: UPnPObject_dealloc(UPnPObject *self)
   69: {
   70: 	freeUPNPDevlist(self->devlist);
   71: 	FreeUPNPUrls(&self->urls);
   72: 	Py_TYPE(self)->tp_free((PyObject*)self);
   73: }
   74: 
   75: static PyObject *
   76: UPnP_discover(UPnPObject *self)
   77: {
   78: 	struct UPNPDev * dev;
   79: 	int i;
   80: 	PyObject *res = NULL;
   81: 	if(self->devlist)
   82: 	{
   83: 		freeUPNPDevlist(self->devlist);
   84: 		self->devlist = 0;
   85: 	}
   86: 	Py_BEGIN_ALLOW_THREADS
   87: 	self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
   88: 	                             0/* multicast if*/,
   89: 	                             0/*minissdpd socket*/,
   90: 								 0/*sameport flag*/,
   91: 	                             0/*ip v6*/,
   92: 	                             0/*error */);
   93: 	Py_END_ALLOW_THREADS
   94: 	/* Py_RETURN_NONE ??? */
   95: 	for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
   96: 		i++;
   97: 	res = Py_BuildValue("i", i);
   98: 	return res;
   99: }
  100: 
  101: static PyObject *
  102: UPnP_selectigd(UPnPObject *self)
  103: {
  104: 	int r;
  105: Py_BEGIN_ALLOW_THREADS
  106: 	r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
  107: 	                     self->lanaddr, sizeof(self->lanaddr));
  108: Py_END_ALLOW_THREADS
  109: 	if(r)
  110: 	{
  111: 		return Py_BuildValue("s", self->urls.controlURL);
  112: 	}
  113: 	else
  114: 	{
  115: 		/* TODO: have our own exception type ! */
  116: 		PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
  117: 		return NULL;
  118: 	}
  119: }
  120: 
  121: static PyObject *
  122: UPnP_totalbytesent(UPnPObject *self)
  123: {
  124: 	UNSIGNED_INTEGER i;
  125: Py_BEGIN_ALLOW_THREADS
  126: 	i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
  127: 	                           self->data.CIF.servicetype);
  128: Py_END_ALLOW_THREADS
  129: 	return Py_BuildValue("I", i);
  130: }
  131: 
  132: static PyObject *
  133: UPnP_totalbytereceived(UPnPObject *self)
  134: {
  135: 	UNSIGNED_INTEGER i;
  136: Py_BEGIN_ALLOW_THREADS
  137: 	i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
  138: 		                           self->data.CIF.servicetype);
  139: Py_END_ALLOW_THREADS
  140: 	return Py_BuildValue("I", i);
  141: }
  142: 
  143: static PyObject *
  144: UPnP_totalpacketsent(UPnPObject *self)
  145: {
  146: 	UNSIGNED_INTEGER i;
  147: Py_BEGIN_ALLOW_THREADS
  148: 	i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
  149: 		                         self->data.CIF.servicetype);
  150: Py_END_ALLOW_THREADS
  151: 	return Py_BuildValue("I", i);
  152: }
  153: 
  154: static PyObject *
  155: UPnP_totalpacketreceived(UPnPObject *self)
  156: {
  157: 	UNSIGNED_INTEGER i;
  158: Py_BEGIN_ALLOW_THREADS
  159: 	i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
  160: 		                          self->data.CIF.servicetype);
  161: Py_END_ALLOW_THREADS
  162: 	return Py_BuildValue("I", i);
  163: }
  164: 
  165: static PyObject *
  166: UPnP_statusinfo(UPnPObject *self)
  167: {
  168: 	char status[64];
  169: 	char lastconnerror[64];
  170: 	unsigned int uptime = 0;
  171: 	int r;
  172: 	status[0] = '\0';
  173: 	lastconnerror[0] = '\0';
  174: Py_BEGIN_ALLOW_THREADS
  175: 	r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
  176: 	                   status, &uptime, lastconnerror);
  177: Py_END_ALLOW_THREADS
  178: 	if(r==UPNPCOMMAND_SUCCESS) {
  179: 		return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
  180: 	} else {
  181: 		/* TODO: have our own exception type ! */
  182: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  183: 		return NULL;
  184: 	}
  185: }
  186: 
  187: static PyObject *
  188: UPnP_connectiontype(UPnPObject *self)
  189: {
  190: 	char connectionType[64];
  191: 	int r;
  192: 	connectionType[0] = '\0';
  193: Py_BEGIN_ALLOW_THREADS
  194: 	r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
  195: 	                               self->data.first.servicetype,
  196: 	                               connectionType);
  197: Py_END_ALLOW_THREADS
  198: 	if(r==UPNPCOMMAND_SUCCESS) {
  199: 		return Py_BuildValue("s", connectionType);
  200: 	} else {
  201: 		/* TODO: have our own exception type ! */
  202: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  203: 		return NULL;
  204: 	}
  205: }
  206: 
  207: static PyObject *
  208: UPnP_externalipaddress(UPnPObject *self)
  209: {
  210: 	char externalIPAddress[40];
  211: 	int r;
  212: 	externalIPAddress[0] = '\0';
  213: Py_BEGIN_ALLOW_THREADS
  214: 	r = UPNP_GetExternalIPAddress(self->urls.controlURL,
  215: 	                              self->data.first.servicetype,
  216: 	                              externalIPAddress);
  217: Py_END_ALLOW_THREADS
  218: 	if(r==UPNPCOMMAND_SUCCESS) {
  219: 		return Py_BuildValue("s", externalIPAddress);
  220: 	} else {
  221: 		/* TODO: have our own exception type ! */
  222: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  223: 		return NULL;
  224: 	}
  225: }
  226: 
  227: /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
  228:  *                remoteHost)
  229:  * protocol is 'UDP' or 'TCP' */
  230: static PyObject *
  231: UPnP_addportmapping(UPnPObject *self, PyObject *args)
  232: {
  233: 	char extPort[6];
  234: 	unsigned short ePort;
  235: 	char inPort[6];
  236: 	unsigned short iPort;
  237: 	const char * proto;
  238: 	const char * host;
  239: 	const char * desc;
  240: 	const char * remoteHost;
  241: 	const char * leaseDuration = "0";
  242: 	int r;
  243: 	if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
  244: 	                                     &host, &iPort, &desc, &remoteHost))
  245:         return NULL;
  246: Py_BEGIN_ALLOW_THREADS
  247: 	sprintf(extPort, "%hu", ePort);
  248: 	sprintf(inPort, "%hu", iPort);
  249: 	r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
  250: 	                        extPort, inPort, host, desc, proto,
  251: 	                        remoteHost, leaseDuration);
  252: Py_END_ALLOW_THREADS
  253: 	if(r==UPNPCOMMAND_SUCCESS)
  254: 	{
  255: 		Py_RETURN_TRUE;
  256: 	}
  257: 	else
  258: 	{
  259: 		// TODO: RAISE an Exception. See upnpcommands.h for errors codes.
  260: 		// upnperrors.c
  261: 		//Py_RETURN_FALSE;
  262: 		/* TODO: have our own exception type ! */
  263: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  264: 		return NULL;
  265: 	}
  266: }
  267: 
  268: /* DeletePortMapping(extPort, proto, removeHost='')
  269:  * proto = 'UDP', 'TCP' */
  270: static PyObject *
  271: UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
  272: {
  273: 	char extPort[6];
  274: 	unsigned short ePort;
  275: 	const char * proto;
  276: 	const char * remoteHost = "";
  277: 	int r;
  278: 	if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
  279: 		return NULL;
  280: Py_BEGIN_ALLOW_THREADS
  281: 	sprintf(extPort, "%hu", ePort);
  282: 	r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
  283: 	                           extPort, proto, remoteHost);
  284: Py_END_ALLOW_THREADS
  285: 	if(r==UPNPCOMMAND_SUCCESS) {
  286: 		Py_RETURN_TRUE;
  287: 	} else {
  288: 		/* TODO: have our own exception type ! */
  289: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  290: 		return NULL;
  291: 	}
  292: }
  293: 
  294: static PyObject *
  295: UPnP_getportmappingnumberofentries(UPnPObject *self)
  296: {
  297: 	unsigned int n = 0;
  298: 	int r;
  299: Py_BEGIN_ALLOW_THREADS
  300: 	r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
  301: 	                                   self->data.first.servicetype,
  302: 									   &n);
  303: Py_END_ALLOW_THREADS
  304: 	if(r==UPNPCOMMAND_SUCCESS) {
  305: 		return Py_BuildValue("I", n);
  306: 	} else {
  307: 		/* TODO: have our own exception type ! */
  308: 		PyErr_SetString(PyExc_Exception, strupnperror(r));
  309: 		return NULL;
  310: 	}
  311: }
  312: 
  313: /* GetSpecificPortMapping(ePort, proto)
  314:  * proto = 'UDP' or 'TCP' */
  315: static PyObject *
  316: UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
  317: {
  318: 	char extPort[6];
  319: 	unsigned short ePort;
  320: 	const char * proto;
  321: 	char intClient[40];
  322: 	char intPort[6];
  323: 	unsigned short iPort;
  324: 	char desc[80];
  325: 	char enabled[4];
  326: 	char leaseDuration[16];
  327: 	if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto))
  328: 		return NULL;
  329: 	extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
  330: 	desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
  331: Py_BEGIN_ALLOW_THREADS
  332: 	sprintf(extPort, "%hu", ePort);
  333: 	UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
  334: 	                                 self->data.first.servicetype,
  335: 									 extPort, proto,
  336: 									 intClient, intPort,
  337: 	                                 desc, enabled, leaseDuration);
  338: Py_END_ALLOW_THREADS
  339: 	if(intClient[0])
  340: 	{
  341: 		iPort = (unsigned short)atoi(intPort);
  342: 		return Py_BuildValue("(s,H,s,O,i)",
  343: 		                     intClient, iPort, desc,
  344: 		                     PyBool_FromLong(atoi(enabled)),
  345: 		                     atoi(leaseDuration));
  346: 	}
  347: 	else
  348: 	{
  349: 		Py_RETURN_NONE;
  350: 	}
  351: }
  352: 
  353: /* GetGenericPortMapping(index) */
  354: static PyObject *
  355: UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
  356: {
  357: 	int i, r;
  358: 	char index[8];
  359: 	char intClient[40];
  360: 	char intPort[6];
  361: 	unsigned short iPort;
  362: 	char extPort[6];
  363: 	unsigned short ePort;
  364: 	char protocol[4];
  365: 	char desc[80];
  366: 	char enabled[6];
  367: 	char rHost[64];
  368: 	char duration[16];	/* lease duration */
  369: 	unsigned int dur;
  370: 	if(!PyArg_ParseTuple(args, "i", &i))
  371: 		return NULL;
  372: Py_BEGIN_ALLOW_THREADS
  373: 	snprintf(index, sizeof(index), "%d", i);
  374: 	rHost[0] = '\0'; enabled[0] = '\0';
  375: 	duration[0] = '\0'; desc[0] = '\0';
  376: 	extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
  377: 	r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
  378: 	                                    self->data.first.servicetype,
  379: 										index,
  380: 										extPort, intClient, intPort,
  381: 										protocol, desc, enabled, rHost,
  382: 										duration);
  383: Py_END_ALLOW_THREADS
  384: 	if(r==UPNPCOMMAND_SUCCESS)
  385: 	{
  386: 		ePort = (unsigned short)atoi(extPort);
  387: 		iPort = (unsigned short)atoi(intPort);
  388: 		dur = (unsigned int)strtoul(duration, 0, 0);
  389: 		return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
  390: 		                     ePort, protocol, intClient, iPort,
  391: 		                     desc, enabled, rHost, dur);
  392: 	}
  393: 	else
  394: 	{
  395: 		Py_RETURN_NONE;
  396: 	}
  397: }
  398: 
  399: /* miniupnpc.UPnP object Method Table */
  400: static PyMethodDef UPnP_methods[] = {
  401:     {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
  402:      "discover UPnP IGD devices on the network"
  403:     },
  404: 	{"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
  405: 	 "select a valid UPnP IGD among discovered devices"
  406: 	},
  407: 	{"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
  408: 	 "return the total number of bytes sent by UPnP IGD"
  409: 	},
  410: 	{"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
  411: 	 "return the total number of bytes received by UPnP IGD"
  412: 	},
  413: 	{"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
  414: 	 "return the total number of packets sent by UPnP IGD"
  415: 	},
  416: 	{"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
  417: 	 "return the total number of packets received by UPnP IGD"
  418: 	},
  419: 	{"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
  420: 	 "return status and uptime"
  421: 	},
  422: 	{"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
  423: 	 "return IGD WAN connection type"
  424: 	},
  425: 	{"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
  426: 	 "return external IP address"
  427: 	},
  428: 	{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
  429: 	 "add a port mapping"
  430: 	},
  431: 	{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
  432: 	 "delete a port mapping"
  433: 	},
  434: 	{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
  435: 	 "-- non standard --"
  436: 	},
  437: 	{"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
  438: 	 "get details about a specific port mapping entry"
  439: 	},
  440: 	{"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
  441: 	 "get all details about the port mapping at index"
  442: 	},
  443:     {NULL}  /* Sentinel */
  444: };
  445: 
  446: static PyTypeObject UPnPType = {
  447:     PyVarObject_HEAD_INIT(NULL,
  448:     0)                         /*ob_size*/
  449:     "miniupnpc.UPnP",          /*tp_name*/
  450:     sizeof(UPnPObject),        /*tp_basicsize*/
  451:     0,                         /*tp_itemsize*/
  452:     (destructor)UPnPObject_dealloc,/*tp_dealloc*/
  453:     0,                         /*tp_print*/
  454:     0,                         /*tp_getattr*/
  455:     0,                         /*tp_setattr*/
  456:     0,                         /*tp_compare*/
  457:     0,                         /*tp_repr*/
  458:     0,                         /*tp_as_number*/
  459:     0,                         /*tp_as_sequence*/
  460:     0,                         /*tp_as_mapping*/
  461:     0,                         /*tp_hash */
  462:     0,                         /*tp_call*/
  463:     0,                         /*tp_str*/
  464:     0,                         /*tp_getattro*/
  465:     0,                         /*tp_setattro*/
  466:     0,                         /*tp_as_buffer*/
  467:     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
  468:     "UPnP objects",            /* tp_doc */
  469:     0,		                   /* tp_traverse */
  470:     0,		                   /* tp_clear */
  471:     0,		                   /* tp_richcompare */
  472:     0,		                   /* tp_weaklistoffset */
  473:     0,		                   /* tp_iter */
  474:     0,		                   /* tp_iternext */
  475:     UPnP_methods,              /* tp_methods */
  476:     UPnP_members,              /* tp_members */
  477:     0,                         /* tp_getset */
  478:     0,                         /* tp_base */
  479:     0,                         /* tp_dict */
  480:     0,                         /* tp_descr_get */
  481:     0,                         /* tp_descr_set */
  482:     0,                         /* tp_dictoffset */
  483:     0,/*(initproc)UPnP_init,*/      /* tp_init */
  484:     0,                         /* tp_alloc */
  485: #ifndef _WIN32
  486:     PyType_GenericNew,/*UPnP_new,*/      /* tp_new */
  487: #else
  488:     0,
  489: #endif
  490: };
  491: 
  492: /* module methods */
  493: static PyMethodDef miniupnpc_methods[] = {
  494:     {NULL}  /* Sentinel */
  495: };
  496: 
  497: #if PY_MAJOR_VERSION >= 3
  498: static struct PyModuleDef moduledef = {
  499:     PyModuleDef_HEAD_INIT,
  500:     "miniupnpc",     /* m_name */
  501:     "miniupnpc module.",  /* m_doc */
  502:     -1,                  /* m_size */
  503:     miniupnpc_methods,    /* m_methods */
  504:     NULL,                /* m_reload */
  505:     NULL,                /* m_traverse */
  506:     NULL,                /* m_clear */
  507:     NULL,                /* m_free */
  508: };
  509: #endif
  510: 
  511: #ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
  512: #define PyMODINIT_FUNC void
  513: #endif
  514: 
  515: PyMODINIT_FUNC
  516: #if PY_MAJOR_VERSION >= 3
  517: PyInit_miniupnpc(void)
  518: #else
  519: initminiupnpc(void)
  520: #endif
  521: {
  522:     PyObject* m;
  523: 
  524: #ifdef _WIN32
  525:     UPnPType.tp_new = PyType_GenericNew;
  526: #endif
  527:     if (PyType_Ready(&UPnPType) < 0)
  528:         return;
  529: 
  530: #if PY_MAJOR_VERSION >= 3
  531:     m = PyModule_Create(&moduledef);
  532: #else
  533:     m = Py_InitModule3("miniupnpc", miniupnpc_methods,
  534:                        "miniupnpc module.");
  535: #endif
  536: 
  537:     Py_INCREF(&UPnPType);
  538:     PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
  539:     
  540: #if PY_MAJOR_VERSION >= 3
  541:     return m;
  542: #endif
  543: }
  544: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>