File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpc / miniupnpcmodule.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:16:22 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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