Annotation of embedaddon/miniupnpc/miniupnpcmodule.c, revision 1.1.1.1
1.1 misho 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:
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>