1 /* $Id: miniupnpcmodule.c,v 1.34 2019/05/20 19:07:16 nanard Exp $*/
2 /* vim: tabstop=4 shiftwidth=4 noexpandtab
3 * Project : miniupnp
4 * Author : Thomas BERNARD
5 * website : https://miniupnp.tuxfamily.org/
6 * copyright (c) 2007-2019 Thomas Bernard
7 * This software is subjet to the conditions detailed in the
8 * provided LICENCE file. */
9 #include <Python.h>
10 #define MINIUPNP_STATICLIB
11 #include "structmember.h"
12 #include "miniupnpc.h"
13 #include "upnpcommands.h"
14 #include "upnperrors.h"
15
16 #ifdef _WIN32
17 #include <winsock2.h>
18 #endif
19
20 /* for compatibility with Python < 2.4 */
21 #ifndef Py_RETURN_NONE
22 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
23 #endif
24
25 #ifndef Py_RETURN_TRUE
26 #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
27 #endif
28
29 #ifndef Py_RETURN_FALSE
30 #define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
31 #endif
32
33 /* for compatibility with Python < 3.0 */
34 #ifndef PyVarObject_HEAD_INIT
35 #define PyVarObject_HEAD_INIT(type, size) \
36 PyObject_HEAD_INIT(type) size,
37 #endif
38
39 #ifndef Py_TYPE
40 #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
41 #endif
42
43 typedef struct {
44 PyObject_HEAD
45 /* Type-specific fields go here. */
46 struct UPNPDev * devlist;
47 struct UPNPUrls urls;
48 struct IGDdatas data;
49 unsigned int discoverdelay; /* value passed to upnpDiscover() */
50 unsigned int localport; /* value passed to upnpDiscover() */
51 char lanaddr[40]; /* our ip address on the LAN */
52 char * multicastif;
53 char * minissdpdsocket;
54 } UPnPObject;
55
56 static PyMemberDef UPnP_members[] = {
57 {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
58 READONLY, "ip address on the LAN"
59 },
60 {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
61 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
62 },
63 {"localport", T_UINT, offsetof(UPnPObject, localport),
64 0/*READWRITE*/,
65 "If localport is set to UPNP_LOCAL_PORT_SAME(1) "
66 "SSDP packets will be sent from the source port "
67 "1900 (same as destination port), if set to "
68 "UPNP_LOCAL_PORT_ANY(0) system assign a source "
69 "port, any other value will be attempted as the "
70 "source port"
71 },
72 /* T_STRING is allways readonly :( */
73 {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
74 0, "IP of the network interface to be used for multicast operations"
75 },
76 {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
77 0, "path of the MiniSSDPd unix socket"
78 },
79 {NULL}
80 };
81
82
UPnP_init(UPnPObject * self,PyObject * args,PyObject * kwds)83 static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
84 {
85 char* multicastif = NULL;
86 char* minissdpdsocket = NULL;
87 static char *kwlist[] = {
88 "multicastif", "minissdpdsocket", "discoverdelay",
89 "localport", NULL
90 };
91
92 if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
93 &multicastif,
94 &minissdpdsocket,
95 &self->discoverdelay,
96 &self->localport))
97 return -1;
98
99 if(self->localport>1 &&
100 (self->localport>65534||self->localport<1024)) {
101 PyErr_SetString(PyExc_Exception, "Invalid localport value");
102 return -1;
103 }
104 if(multicastif)
105 self->multicastif = strdup(multicastif);
106 if(minissdpdsocket)
107 self->minissdpdsocket = strdup(minissdpdsocket);
108
109 return 0;
110 }
111
112 static void
UPnPObject_dealloc(UPnPObject * self)113 UPnPObject_dealloc(UPnPObject *self)
114 {
115 freeUPNPDevlist(self->devlist);
116 FreeUPNPUrls(&self->urls);
117 free(self->multicastif);
118 free(self->minissdpdsocket);
119 Py_TYPE(self)->tp_free((PyObject*)self);
120 }
121
122 static PyObject *
UPnP_discover(UPnPObject * self)123 UPnP_discover(UPnPObject *self)
124 {
125 struct UPNPDev * dev;
126 int i;
127 PyObject *res = NULL;
128 if(self->devlist)
129 {
130 freeUPNPDevlist(self->devlist);
131 self->devlist = 0;
132 }
133 Py_BEGIN_ALLOW_THREADS
134 self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
135 self->multicastif,
136 self->minissdpdsocket,
137 (int)self->localport,
138 0/*ip v6*/,
139 2/* TTL */,
140 0/*error */);
141 Py_END_ALLOW_THREADS
142 /* Py_RETURN_NONE ??? */
143 for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
144 i++;
145 res = Py_BuildValue("i", i);
146 return res;
147 }
148
149 static PyObject *
UPnP_selectigd(UPnPObject * self)150 UPnP_selectigd(UPnPObject *self)
151 {
152 int r;
153 Py_BEGIN_ALLOW_THREADS
154 r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
155 self->lanaddr, sizeof(self->lanaddr));
156 Py_END_ALLOW_THREADS
157 if(r)
158 {
159 return Py_BuildValue("s", self->urls.controlURL);
160 }
161 else
162 {
163 /* TODO: have our own exception type ! */
164 PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
165 return NULL;
166 }
167 }
168
169 static PyObject *
UPnP_totalbytesent(UPnPObject * self)170 UPnP_totalbytesent(UPnPObject *self)
171 {
172 UNSIGNED_INTEGER i;
173 Py_BEGIN_ALLOW_THREADS
174 i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
175 self->data.CIF.servicetype);
176 Py_END_ALLOW_THREADS
177 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
178 return Py_BuildValue("I", i);
179 #else
180 return Py_BuildValue("i", (int)i);
181 #endif
182 }
183
184 static PyObject *
UPnP_totalbytereceived(UPnPObject * self)185 UPnP_totalbytereceived(UPnPObject *self)
186 {
187 UNSIGNED_INTEGER i;
188 Py_BEGIN_ALLOW_THREADS
189 i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
190 self->data.CIF.servicetype);
191 Py_END_ALLOW_THREADS
192 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
193 return Py_BuildValue("I", i);
194 #else
195 return Py_BuildValue("i", (int)i);
196 #endif
197 }
198
199 static PyObject *
UPnP_totalpacketsent(UPnPObject * self)200 UPnP_totalpacketsent(UPnPObject *self)
201 {
202 UNSIGNED_INTEGER i;
203 Py_BEGIN_ALLOW_THREADS
204 i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
205 self->data.CIF.servicetype);
206 Py_END_ALLOW_THREADS
207 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
208 return Py_BuildValue("I", i);
209 #else
210 return Py_BuildValue("i", (int)i);
211 #endif
212 }
213
214 static PyObject *
UPnP_totalpacketreceived(UPnPObject * self)215 UPnP_totalpacketreceived(UPnPObject *self)
216 {
217 UNSIGNED_INTEGER i;
218 Py_BEGIN_ALLOW_THREADS
219 i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
220 self->data.CIF.servicetype);
221 Py_END_ALLOW_THREADS
222 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
223 return Py_BuildValue("I", i);
224 #else
225 return Py_BuildValue("i", (int)i);
226 #endif
227 }
228
229 static PyObject *
UPnP_statusinfo(UPnPObject * self)230 UPnP_statusinfo(UPnPObject *self)
231 {
232 char status[64];
233 char lastconnerror[64];
234 unsigned int uptime = 0;
235 int r;
236 status[0] = '\0';
237 lastconnerror[0] = '\0';
238 Py_BEGIN_ALLOW_THREADS
239 r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
240 status, &uptime, lastconnerror);
241 Py_END_ALLOW_THREADS
242 if(r==UPNPCOMMAND_SUCCESS) {
243 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
244 return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
245 #else
246 return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
247 #endif
248 } else {
249 /* TODO: have our own exception type ! */
250 PyErr_SetString(PyExc_Exception, strupnperror(r));
251 return NULL;
252 }
253 }
254
255 static PyObject *
UPnP_connectiontype(UPnPObject * self)256 UPnP_connectiontype(UPnPObject *self)
257 {
258 char connectionType[64];
259 int r;
260 connectionType[0] = '\0';
261 Py_BEGIN_ALLOW_THREADS
262 r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
263 self->data.first.servicetype,
264 connectionType);
265 Py_END_ALLOW_THREADS
266 if(r==UPNPCOMMAND_SUCCESS) {
267 return Py_BuildValue("s", connectionType);
268 } else {
269 /* TODO: have our own exception type ! */
270 PyErr_SetString(PyExc_Exception, strupnperror(r));
271 return NULL;
272 }
273 }
274
275 static PyObject *
UPnP_externalipaddress(UPnPObject * self)276 UPnP_externalipaddress(UPnPObject *self)
277 {
278 char externalIPAddress[40];
279 int r;
280 externalIPAddress[0] = '\0';
281 Py_BEGIN_ALLOW_THREADS
282 r = UPNP_GetExternalIPAddress(self->urls.controlURL,
283 self->data.first.servicetype,
284 externalIPAddress);
285 Py_END_ALLOW_THREADS
286 if(r==UPNPCOMMAND_SUCCESS) {
287 return Py_BuildValue("s", externalIPAddress);
288 } else {
289 /* TODO: have our own exception type ! */
290 PyErr_SetString(PyExc_Exception, strupnperror(r));
291 return NULL;
292 }
293 }
294
295 /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
296 * remoteHost, leaseDuration)
297 * protocol is 'UDP' or 'TCP' */
298 static PyObject *
UPnP_addportmapping(UPnPObject * self,PyObject * args)299 UPnP_addportmapping(UPnPObject *self, PyObject *args)
300 {
301 char extPort[6];
302 unsigned short ePort;
303 char inPort[6];
304 unsigned short iPort;
305 const char * proto;
306 const char * host;
307 const char * desc;
308 const char * remoteHost;
309 unsigned int intLeaseDuration = 0;
310 char strLeaseDuration[12];
311 int r;
312 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
313 if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto,
314 &host, &iPort, &desc, &remoteHost, &intLeaseDuration))
315 #else
316 if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto,
317 &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration))
318 #endif
319 return NULL;
320 Py_BEGIN_ALLOW_THREADS
321 sprintf(extPort, "%hu", ePort);
322 sprintf(inPort, "%hu", iPort);
323 sprintf(strLeaseDuration, "%u", intLeaseDuration);
324 r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
325 extPort, inPort, host, desc, proto,
326 remoteHost, strLeaseDuration);
327 Py_END_ALLOW_THREADS
328 if(r==UPNPCOMMAND_SUCCESS)
329 {
330 Py_RETURN_TRUE;
331 }
332 else
333 {
334 // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
335 // upnperrors.c
336 //Py_RETURN_FALSE;
337 /* TODO: have our own exception type ! */
338 PyErr_SetString(PyExc_Exception, strupnperror(r));
339 return NULL;
340 }
341 }
342
343 /* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
344 * remoteHost)
345 * protocol is 'UDP' or 'TCP' */
346 static PyObject *
UPnP_addanyportmapping(UPnPObject * self,PyObject * args)347 UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
348 {
349 char extPort[6];
350 unsigned short ePort;
351 char inPort[6];
352 unsigned short iPort;
353 char reservedPort[6];
354 const char * proto;
355 const char * host;
356 const char * desc;
357 const char * remoteHost;
358 const char * leaseDuration = "0";
359 int r;
360 if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
361 return NULL;
362 Py_BEGIN_ALLOW_THREADS
363 sprintf(extPort, "%hu", ePort);
364 sprintf(inPort, "%hu", iPort);
365 r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
366 extPort, inPort, host, desc, proto,
367 remoteHost, leaseDuration, reservedPort);
368 Py_END_ALLOW_THREADS
369 if(r==UPNPCOMMAND_SUCCESS) {
370 return Py_BuildValue("i", atoi(reservedPort));
371 } else {
372 /* TODO: have our own exception type ! */
373 PyErr_SetString(PyExc_Exception, strupnperror(r));
374 return NULL;
375 }
376 }
377
378
379 /* DeletePortMapping(extPort, proto, removeHost='')
380 * proto = 'UDP', 'TCP' */
381 static PyObject *
UPnP_deleteportmapping(UPnPObject * self,PyObject * args)382 UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
383 {
384 char extPort[6];
385 unsigned short ePort;
386 const char * proto;
387 const char * remoteHost = "";
388 int r;
389 if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
390 return NULL;
391 Py_BEGIN_ALLOW_THREADS
392 sprintf(extPort, "%hu", ePort);
393 r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
394 extPort, proto, remoteHost);
395 Py_END_ALLOW_THREADS
396 if(r==UPNPCOMMAND_SUCCESS) {
397 Py_RETURN_TRUE;
398 } else {
399 /* TODO: have our own exception type ! */
400 PyErr_SetString(PyExc_Exception, strupnperror(r));
401 return NULL;
402 }
403 }
404
405 /* DeletePortMappingRange(extPort, proto, removeHost='')
406 * proto = 'UDP', 'TCP' */
407 static PyObject *
UPnP_deleteportmappingrange(UPnPObject * self,PyObject * args)408 UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
409 {
410 char extPortStart[6];
411 unsigned short ePortStart;
412 char extPortEnd[6];
413 unsigned short ePortEnd;
414 const char * proto;
415 unsigned char manage;
416 char manageStr[6];
417 int r;
418 if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
419 return NULL;
420 Py_BEGIN_ALLOW_THREADS
421 sprintf(extPortStart, "%hu", ePortStart);
422 sprintf(extPortEnd, "%hu", ePortEnd);
423 sprintf(manageStr, "%hu", (unsigned short)manage);
424 r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
425 extPortStart, extPortEnd, proto, manageStr);
426 Py_END_ALLOW_THREADS
427 if(r==UPNPCOMMAND_SUCCESS) {
428 Py_RETURN_TRUE;
429 } else {
430 /* TODO: have our own exception type ! */
431 PyErr_SetString(PyExc_Exception, strupnperror(r));
432 return NULL;
433 }
434 }
435
436 static PyObject *
UPnP_getportmappingnumberofentries(UPnPObject * self)437 UPnP_getportmappingnumberofentries(UPnPObject *self)
438 {
439 unsigned int n = 0;
440 int r;
441 Py_BEGIN_ALLOW_THREADS
442 r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
443 self->data.first.servicetype,
444 &n);
445 Py_END_ALLOW_THREADS
446 if(r==UPNPCOMMAND_SUCCESS) {
447 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
448 return Py_BuildValue("I", n);
449 #else
450 return Py_BuildValue("i", (int)n);
451 #endif
452 } else {
453 /* TODO: have our own exception type ! */
454 PyErr_SetString(PyExc_Exception, strupnperror(r));
455 return NULL;
456 }
457 }
458
459 /* GetSpecificPortMapping(ePort, proto, remoteHost='')
460 * proto = 'UDP' or 'TCP' */
461 static PyObject *
UPnP_getspecificportmapping(UPnPObject * self,PyObject * args)462 UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
463 {
464 char extPort[6];
465 unsigned short ePort;
466 const char * proto;
467 const char * remoteHost = "";
468 char intClient[40];
469 char intPort[6];
470 unsigned short iPort;
471 char desc[80];
472 char enabled[4];
473 char leaseDuration[16];
474 if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
475 return NULL;
476 extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
477 desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
478 Py_BEGIN_ALLOW_THREADS
479 sprintf(extPort, "%hu", ePort);
480 UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
481 self->data.first.servicetype,
482 extPort, proto, remoteHost,
483 intClient, intPort,
484 desc, enabled, leaseDuration);
485 Py_END_ALLOW_THREADS
486 if(intClient[0])
487 {
488 iPort = (unsigned short)atoi(intPort);
489 return Py_BuildValue("(s,H,s,O,i)",
490 intClient, iPort, desc,
491 PyBool_FromLong(atoi(enabled)),
492 atoi(leaseDuration));
493 }
494 else
495 {
496 Py_RETURN_NONE;
497 }
498 }
499
500 /* GetGenericPortMapping(index) */
501 static PyObject *
UPnP_getgenericportmapping(UPnPObject * self,PyObject * args)502 UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
503 {
504 int i, r;
505 char index[8];
506 char intClient[40];
507 char intPort[6];
508 unsigned short iPort;
509 char extPort[6];
510 unsigned short ePort;
511 char protocol[4];
512 char desc[80];
513 char enabled[6];
514 char rHost[64];
515 char duration[16]; /* lease duration */
516 unsigned int dur;
517 if(!PyArg_ParseTuple(args, "i", &i))
518 return NULL;
519 Py_BEGIN_ALLOW_THREADS
520 snprintf(index, sizeof(index), "%d", i);
521 rHost[0] = '\0'; enabled[0] = '\0';
522 duration[0] = '\0'; desc[0] = '\0';
523 extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
524 r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
525 self->data.first.servicetype,
526 index,
527 extPort, intClient, intPort,
528 protocol, desc, enabled, rHost,
529 duration);
530 Py_END_ALLOW_THREADS
531 if(r==UPNPCOMMAND_SUCCESS)
532 {
533 ePort = (unsigned short)atoi(extPort);
534 iPort = (unsigned short)atoi(intPort);
535 dur = (unsigned int)strtoul(duration, 0, 0);
536 #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
537 return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
538 ePort, protocol, intClient, iPort,
539 desc, enabled, rHost, dur);
540 #else
541 return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
542 (int)ePort, protocol, intClient, (int)iPort,
543 desc, enabled, rHost, (int)dur);
544 #endif
545 }
546 else
547 {
548 Py_RETURN_NONE;
549 }
550 }
551
552 /* miniupnpc.UPnP object Method Table */
553 static PyMethodDef UPnP_methods[] = {
554 {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
555 "discover UPnP IGD devices on the network"
556 },
557 {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
558 "select a valid UPnP IGD among discovered devices"
559 },
560 {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
561 "return the total number of bytes sent by UPnP IGD"
562 },
563 {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
564 "return the total number of bytes received by UPnP IGD"
565 },
566 {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
567 "return the total number of packets sent by UPnP IGD"
568 },
569 {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
570 "return the total number of packets received by UPnP IGD"
571 },
572 {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
573 "return status and uptime"
574 },
575 {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
576 "return IGD WAN connection type"
577 },
578 {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
579 "return external IP address"
580 },
581 {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
582 "add a port mapping"
583 },
584 {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
585 "add a port mapping, IGD to select alternative if necessary"
586 },
587 {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
588 "delete a port mapping"
589 },
590 {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
591 "delete a range of port mappings"
592 },
593 {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
594 "-- non standard --"
595 },
596 {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
597 "get details about a specific port mapping entry"
598 },
599 {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
600 "get all details about the port mapping at index"
601 },
602 {NULL} /* Sentinel */
603 };
604
605 static PyTypeObject UPnPType = {
606 PyVarObject_HEAD_INIT(NULL,
607 0) /*ob_size*/
608 "miniupnpc.UPnP", /*tp_name*/
609 sizeof(UPnPObject), /*tp_basicsize*/
610 0, /*tp_itemsize*/
611 (destructor)UPnPObject_dealloc,/*tp_dealloc*/
612 0, /*tp_print*/
613 0, /*tp_getattr*/
614 0, /*tp_setattr*/
615 0, /*tp_compare*/
616 0, /*tp_repr*/
617 0, /*tp_as_number*/
618 0, /*tp_as_sequence*/
619 0, /*tp_as_mapping*/
620 0, /*tp_hash */
621 0, /*tp_call*/
622 0, /*tp_str*/
623 0, /*tp_getattro*/
624 0, /*tp_setattro*/
625 0, /*tp_as_buffer*/
626 Py_TPFLAGS_DEFAULT, /*tp_flags*/
627 "UPnP objects", /* tp_doc */
628 0, /* tp_traverse */
629 0, /* tp_clear */
630 0, /* tp_richcompare */
631 0, /* tp_weaklistoffset */
632 0, /* tp_iter */
633 0, /* tp_iternext */
634 UPnP_methods, /* tp_methods */
635 UPnP_members, /* tp_members */
636 0, /* tp_getset */
637 0, /* tp_base */
638 0, /* tp_dict */
639 0, /* tp_descr_get */
640 0, /* tp_descr_set */
641 0, /* tp_dictoffset */
642 (initproc)UPnP_init, /* tp_init */
643 0, /* tp_alloc */
644 #ifndef _WIN32
645 PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
646 #else
647 0,
648 #endif
649 };
650
651 /* module methods */
652 static PyMethodDef miniupnpc_methods[] = {
653 {NULL} /* Sentinel */
654 };
655
656 #if PY_MAJOR_VERSION >= 3
657 static struct PyModuleDef moduledef = {
658 PyModuleDef_HEAD_INIT,
659 "miniupnpc", /* m_name */
660 "miniupnpc module.", /* m_doc */
661 -1, /* m_size */
662 miniupnpc_methods, /* m_methods */
663 NULL, /* m_reload */
664 NULL, /* m_traverse */
665 NULL, /* m_clear */
666 NULL, /* m_free */
667 };
668 #endif
669
670 #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
671 #define PyMODINIT_FUNC void
672 #endif
673
674 PyMODINIT_FUNC
675 #if PY_MAJOR_VERSION >= 3
PyInit_miniupnpc(void)676 PyInit_miniupnpc(void)
677 #else
678 initminiupnpc(void)
679 #endif
680 {
681 PyObject* m;
682
683 #ifdef _WIN32
684 /* initialize Winsock. */
685 WSADATA wsaData;
686 int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
687 if (nResult != 0)
688 {
689 /* error code could be WSASYSNOTREADY WSASYSNOTREADY
690 * WSASYSNOTREADY WSASYSNOTREADY WSASYSNOTREADY */
691 #if PY_MAJOR_VERSION >= 3
692 return 0;
693 #else
694 return;
695 #endif
696 }
697
698 UPnPType.tp_new = PyType_GenericNew;
699 #endif
700 if (PyType_Ready(&UPnPType) < 0)
701 #if PY_MAJOR_VERSION >= 3
702 return 0;
703 #else
704 return;
705 #endif
706
707 #if PY_MAJOR_VERSION >= 3
708 m = PyModule_Create(&moduledef);
709 #else
710 m = Py_InitModule3("miniupnpc", miniupnpc_methods,
711 "miniupnpc module.");
712 #endif
713
714 Py_INCREF(&UPnPType);
715 PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
716
717 #if PY_MAJOR_VERSION >= 3
718 return m;
719 #endif
720 }
721
722