miniupnpcmodule.c 13 KB

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