PageRenderTime 166ms CodeModel.GetById 60ms app.highlight 55ms RepoModel.GetById 46ms app.codeStats 0ms

/thirdparty/libportfwd/third-party/miniupnpc-1.6/miniupnpcmodule.c

http://github.com/tomahawk-player/tomahawk
C | 507 lines | 448 code | 28 blank | 31 comment | 21 complexity | 2f005ce51341cb02933308a597845436 MD5 | raw file
  1/* $Id: miniupnpcmodule.c,v 1.18 2011/04/10 11:21:23 nanard 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
 28typedef 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
 40static 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
 57static void
 58UPnPObject_dealloc(UPnPObject *self)
 59{
 60	freeUPNPDevlist(self->devlist);
 61	FreeUPNPUrls(&self->urls);
 62	self->ob_type->tp_free((PyObject*)self);
 63}
 64
 65static PyObject *
 66UPnP_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
 91static PyObject *
 92UPnP_selectigd(UPnPObject *self)
 93{
 94	int r;
 95Py_BEGIN_ALLOW_THREADS
 96	r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
 97	                     self->lanaddr, sizeof(self->lanaddr));
 98Py_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
111static PyObject *
112UPnP_totalbytesent(UPnPObject *self)
113{
114	UNSIGNED_INTEGER i;
115Py_BEGIN_ALLOW_THREADS
116	i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
117	                           self->data.CIF.servicetype);
118Py_END_ALLOW_THREADS
119	return Py_BuildValue("I", i);
120}
121
122static PyObject *
123UPnP_totalbytereceived(UPnPObject *self)
124{
125	UNSIGNED_INTEGER i;
126Py_BEGIN_ALLOW_THREADS
127	i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
128		                           self->data.CIF.servicetype);
129Py_END_ALLOW_THREADS
130	return Py_BuildValue("I", i);
131}
132
133static PyObject *
134UPnP_totalpacketsent(UPnPObject *self)
135{
136	UNSIGNED_INTEGER i;
137Py_BEGIN_ALLOW_THREADS
138	i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
139		                         self->data.CIF.servicetype);
140Py_END_ALLOW_THREADS
141	return Py_BuildValue("I", i);
142}
143
144static PyObject *
145UPnP_totalpacketreceived(UPnPObject *self)
146{
147	UNSIGNED_INTEGER i;
148Py_BEGIN_ALLOW_THREADS
149	i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
150		                          self->data.CIF.servicetype);
151Py_END_ALLOW_THREADS
152	return Py_BuildValue("I", i);
153}
154
155static PyObject *
156UPnP_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';
164Py_BEGIN_ALLOW_THREADS
165	r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
166	                   status, &uptime, lastconnerror);
167Py_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
177static PyObject *
178UPnP_connectiontype(UPnPObject *self)
179{
180	char connectionType[64];
181	int r;
182	connectionType[0] = '\0';
183Py_BEGIN_ALLOW_THREADS
184	r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
185	                               self->data.first.servicetype,
186	                               connectionType);
187Py_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
197static PyObject *
198UPnP_externalipaddress(UPnPObject *self)
199{
200	char externalIPAddress[40];
201	int r;
202	externalIPAddress[0] = '\0';
203Py_BEGIN_ALLOW_THREADS
204	r = UPNP_GetExternalIPAddress(self->urls.controlURL,
205	                              self->data.first.servicetype,
206	                              externalIPAddress);
207Py_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' */
220static PyObject *
221UPnP_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;
236Py_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);
242Py_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' */
260static PyObject *
261UPnP_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;
270Py_BEGIN_ALLOW_THREADS
271	sprintf(extPort, "%hu", ePort);
272	r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
273	                           extPort, proto, remoteHost);
274Py_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
284static PyObject *
285UPnP_getportmappingnumberofentries(UPnPObject *self)
286{
287	unsigned int n = 0;
288	int r;
289Py_BEGIN_ALLOW_THREADS
290	r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
291	                                   self->data.first.servicetype,
292									   &n);
293Py_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' */
305static PyObject *
306UPnP_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';
321Py_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);
328Py_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) */
344static PyObject *
345UPnP_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;
362Py_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);
373Py_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 */
390static 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
436static 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 */
483static PyMethodDef miniupnpc_methods[] = {
484    {NULL}  /* Sentinel */
485};
486
487#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
488#define PyMODINIT_FUNC void
489#endif
490PyMODINIT_FUNC
491initminiupnpc(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