Annotation of embedaddon/miniupnpc/miniupnpcmodule.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* $Id: miniupnpcmodule.c,v 1.21 2012/08/29 07:51:30 nanard Exp $*/
1.1 misho 2: /* Project : miniupnp
3: * Author : Thomas BERNARD
4: * website : http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho 5: * copyright (c) 2007-2012 Thomas Bernard
1.1 misho 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:
1.1.1.2 ! misho 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:
1.1 misho 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);
1.1.1.2 ! misho 72: Py_TYPE(self)->tp_free((PyObject*)self);
1.1 misho 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;
1.1.1.2 ! misho 85: }
1.1 misho 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,
1.1.1.2 ! misho 228: * remoteHost)
1.1 misho 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:
1.1.1.2 ! misho 313: /* GetSpecificPortMapping(ePort, proto)
1.1 misho 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 = {
1.1.1.2 ! misho 447: PyVarObject_HEAD_INIT(NULL,
! 448: 0) /*ob_size*/
1.1 misho 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 */
1.1.1.2 ! misho 485: #ifndef _WIN32
1.1 misho 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:
1.1.1.2 ! misho 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:
1.1 misho 511: #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
512: #define PyMODINIT_FUNC void
513: #endif
1.1.1.2 ! misho 514:
1.1 misho 515: PyMODINIT_FUNC
1.1.1.2 ! misho 516: #if PY_MAJOR_VERSION >= 3
! 517: PyInit_miniupnpc(void)
! 518: #else
! 519: initminiupnpc(void)
! 520: #endif
1.1 misho 521: {
522: PyObject* m;
523:
1.1.1.2 ! misho 524: #ifdef _WIN32
1.1 misho 525: UPnPType.tp_new = PyType_GenericNew;
526: #endif
527: if (PyType_Ready(&UPnPType) < 0)
528: return;
529:
1.1.1.2 ! misho 530: #if PY_MAJOR_VERSION >= 3
! 531: m = PyModule_Create(&moduledef);
! 532: #else
1.1 misho 533: m = Py_InitModule3("miniupnpc", miniupnpc_methods,
534: "miniupnpc module.");
1.1.1.2 ! misho 535: #endif
1.1 misho 536:
537: Py_INCREF(&UPnPType);
538: PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
1.1.1.2 ! misho 539:
! 540: #if PY_MAJOR_VERSION >= 3
! 541: return m;
! 542: #endif
1.1 misho 543: }
544:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>