/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. /* 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[40]; /* 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. Py_BEGIN_ALLOW_THREADS
  70. self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
  71. 0/* multicast if*/,
  72. 0/*minissdpd socket*/,
  73. 0/*sameport flag*/,
  74. 0/*ip v6*/,
  75. 0/*error */);
  76. Py_END_ALLOW_THREADS
  77. /* Py_RETURN_NONE ??? */
  78. for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
  79. i++;
  80. res = Py_BuildValue("i", i);
  81. return res;
  82. }
  83. static PyObject *
  84. UPnP_selectigd(UPnPObject *self)
  85. {
  86. int r;
  87. Py_BEGIN_ALLOW_THREADS
  88. r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
  89. self->lanaddr, sizeof(self->lanaddr));
  90. Py_END_ALLOW_THREADS
  91. if(r)
  92. {
  93. return Py_BuildValue("s", self->urls.controlURL);
  94. }
  95. else
  96. {
  97. /* TODO: have our own exception type ! */
  98. PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
  99. return NULL;
  100. }
  101. }
  102. static PyObject *
  103. UPnP_totalbytesent(UPnPObject *self)
  104. {
  105. UNSIGNED_INTEGER i;
  106. Py_BEGIN_ALLOW_THREADS
  107. i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
  108. self->data.CIF.servicetype);
  109. Py_END_ALLOW_THREADS
  110. return Py_BuildValue("I", i);
  111. }
  112. static PyObject *
  113. UPnP_totalbytereceived(UPnPObject *self)
  114. {
  115. UNSIGNED_INTEGER i;
  116. Py_BEGIN_ALLOW_THREADS
  117. i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
  118. self->data.CIF.servicetype);
  119. Py_END_ALLOW_THREADS
  120. return Py_BuildValue("I", i);
  121. }
  122. static PyObject *
  123. UPnP_totalpacketsent(UPnPObject *self)
  124. {
  125. UNSIGNED_INTEGER i;
  126. Py_BEGIN_ALLOW_THREADS
  127. i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
  128. self->data.CIF.servicetype);
  129. Py_END_ALLOW_THREADS
  130. return Py_BuildValue("I", i);
  131. }
  132. static PyObject *
  133. UPnP_totalpacketreceived(UPnPObject *self)
  134. {
  135. UNSIGNED_INTEGER i;
  136. Py_BEGIN_ALLOW_THREADS
  137. i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
  138. self->data.CIF.servicetype);
  139. Py_END_ALLOW_THREADS
  140. return Py_BuildValue("I", i);
  141. }
  142. static PyObject *
  143. UPnP_statusinfo(UPnPObject *self)
  144. {
  145. char status[64];
  146. char lastconnerror[64];
  147. unsigned int uptime = 0;
  148. int r;
  149. status[0] = '\0';
  150. lastconnerror[0] = '\0';
  151. Py_BEGIN_ALLOW_THREADS
  152. r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
  153. status, &uptime, lastconnerror);
  154. Py_END_ALLOW_THREADS
  155. if(r==UPNPCOMMAND_SUCCESS) {
  156. return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
  157. } else {
  158. /* TODO: have our own exception type ! */
  159. PyErr_SetString(PyExc_Exception, strupnperror(r));
  160. return NULL;
  161. }
  162. }
  163. static PyObject *
  164. UPnP_connectiontype(UPnPObject *self)
  165. {
  166. char connectionType[64];
  167. int r;
  168. connectionType[0] = '\0';
  169. Py_BEGIN_ALLOW_THREADS
  170. r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
  171. self->data.first.servicetype,
  172. connectionType);
  173. Py_END_ALLOW_THREADS
  174. if(r==UPNPCOMMAND_SUCCESS) {
  175. return Py_BuildValue("s", connectionType);
  176. } else {
  177. /* TODO: have our own exception type ! */
  178. PyErr_SetString(PyExc_Exception, strupnperror(r));
  179. return NULL;
  180. }
  181. }
  182. static PyObject *
  183. UPnP_externalipaddress(UPnPObject *self)
  184. {
  185. char externalIPAddress[40];
  186. int r;
  187. externalIPAddress[0] = '\0';
  188. Py_BEGIN_ALLOW_THREADS
  189. r = UPNP_GetExternalIPAddress(self->urls.controlURL,
  190. self->data.first.servicetype,
  191. externalIPAddress);
  192. Py_END_ALLOW_THREADS
  193. if(r==UPNPCOMMAND_SUCCESS) {
  194. return Py_BuildValue("s", externalIPAddress);
  195. } else {
  196. /* TODO: have our own exception type ! */
  197. PyErr_SetString(PyExc_Exception, strupnperror(r));
  198. return NULL;
  199. }
  200. }
  201. /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
  202. * remoteHost)
  203. * protocol is 'UDP' or 'TCP' */
  204. static PyObject *
  205. UPnP_addportmapping(UPnPObject *self, PyObject *args)
  206. {
  207. char extPort[6];
  208. unsigned short ePort;
  209. char inPort[6];
  210. unsigned short iPort;
  211. const char * proto;
  212. const char * host;
  213. const char * desc;
  214. const char * remoteHost;
  215. const char * leaseDuration = "0";
  216. int r;
  217. if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
  218. &host, &iPort, &desc, &remoteHost))
  219. return NULL;
  220. Py_BEGIN_ALLOW_THREADS
  221. sprintf(extPort, "%hu", ePort);
  222. sprintf(inPort, "%hu", iPort);
  223. r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
  224. extPort, inPort, host, desc, proto,
  225. remoteHost, leaseDuration);
  226. Py_END_ALLOW_THREADS
  227. if(r==UPNPCOMMAND_SUCCESS)
  228. {
  229. Py_RETURN_TRUE;
  230. }
  231. else
  232. {
  233. // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
  234. // upnperrors.c
  235. //Py_RETURN_FALSE;
  236. /* TODO: have our own exception type ! */
  237. PyErr_SetString(PyExc_Exception, strupnperror(r));
  238. return NULL;
  239. }
  240. }
  241. /* DeletePortMapping(extPort, proto, removeHost='')
  242. * proto = 'UDP', 'TCP' */
  243. static PyObject *
  244. UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
  245. {
  246. char extPort[6];
  247. unsigned short ePort;
  248. const char * proto;
  249. const char * remoteHost = "";
  250. int r;
  251. if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
  252. return NULL;
  253. Py_BEGIN_ALLOW_THREADS
  254. sprintf(extPort, "%hu", ePort);
  255. r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
  256. extPort, proto, remoteHost);
  257. Py_END_ALLOW_THREADS
  258. if(r==UPNPCOMMAND_SUCCESS) {
  259. Py_RETURN_TRUE;
  260. } else {
  261. /* TODO: have our own exception type ! */
  262. PyErr_SetString(PyExc_Exception, strupnperror(r));
  263. return NULL;
  264. }
  265. }
  266. static PyObject *
  267. UPnP_getportmappingnumberofentries(UPnPObject *self)
  268. {
  269. unsigned int n = 0;
  270. int r;
  271. Py_BEGIN_ALLOW_THREADS
  272. r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
  273. self->data.first.servicetype,
  274. &n);
  275. Py_END_ALLOW_THREADS
  276. if(r==UPNPCOMMAND_SUCCESS) {
  277. return Py_BuildValue("I", n);
  278. } else {
  279. /* TODO: have our own exception type ! */
  280. PyErr_SetString(PyExc_Exception, strupnperror(r));
  281. return NULL;
  282. }
  283. }
  284. /* GetSpecificPortMapping(ePort, proto)
  285. * proto = 'UDP' or 'TCP' */
  286. static PyObject *
  287. UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
  288. {
  289. char extPort[6];
  290. unsigned short ePort;
  291. const char * proto;
  292. char intClient[40];
  293. char intPort[6];
  294. unsigned short iPort;
  295. char desc[80];
  296. char enabled[4];
  297. char leaseDuration[16];
  298. if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto))
  299. return NULL;
  300. extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
  301. desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
  302. Py_BEGIN_ALLOW_THREADS
  303. sprintf(extPort, "%hu", ePort);
  304. UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
  305. self->data.first.servicetype,
  306. extPort, proto,
  307. intClient, intPort,
  308. desc, enabled, leaseDuration);
  309. Py_END_ALLOW_THREADS
  310. if(intClient[0])
  311. {
  312. iPort = (unsigned short)atoi(intPort);
  313. return Py_BuildValue("(s,H,s,O,i)",
  314. intClient, iPort, desc,
  315. PyBool_FromLong(atoi(enabled)),
  316. atoi(leaseDuration));
  317. }
  318. else
  319. {
  320. Py_RETURN_NONE;
  321. }
  322. }
  323. /* GetGenericPortMapping(index) */
  324. static PyObject *
  325. UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
  326. {
  327. int i, r;
  328. char index[8];
  329. char intClient[40];
  330. char intPort[6];
  331. unsigned short iPort;
  332. char extPort[6];
  333. unsigned short ePort;
  334. char protocol[4];
  335. char desc[80];
  336. char enabled[6];
  337. char rHost[64];
  338. char duration[16]; /* lease duration */
  339. unsigned int dur;
  340. if(!PyArg_ParseTuple(args, "i", &i))
  341. return NULL;
  342. Py_BEGIN_ALLOW_THREADS
  343. snprintf(index, sizeof(index), "%d", i);
  344. rHost[0] = '\0'; enabled[0] = '\0';
  345. duration[0] = '\0'; desc[0] = '\0';
  346. extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
  347. r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
  348. self->data.first.servicetype,
  349. index,
  350. extPort, intClient, intPort,
  351. protocol, desc, enabled, rHost,
  352. duration);
  353. Py_END_ALLOW_THREADS
  354. if(r==UPNPCOMMAND_SUCCESS)
  355. {
  356. ePort = (unsigned short)atoi(extPort);
  357. iPort = (unsigned short)atoi(intPort);
  358. dur = (unsigned int)strtoul(duration, 0, 0);
  359. return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
  360. ePort, protocol, intClient, iPort,
  361. desc, enabled, rHost, dur);
  362. }
  363. else
  364. {
  365. Py_RETURN_NONE;
  366. }
  367. }
  368. /* miniupnpc.UPnP object Method Table */
  369. static PyMethodDef UPnP_methods[] = {
  370. {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
  371. "discover UPnP IGD devices on the network"
  372. },
  373. {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
  374. "select a valid UPnP IGD among discovered devices"
  375. },
  376. {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
  377. "return the total number of bytes sent by UPnP IGD"
  378. },
  379. {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
  380. "return the total number of bytes received by UPnP IGD"
  381. },
  382. {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
  383. "return the total number of packets sent by UPnP IGD"
  384. },
  385. {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
  386. "return the total number of packets received by UPnP IGD"
  387. },
  388. {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
  389. "return status and uptime"
  390. },
  391. {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
  392. "return IGD WAN connection type"
  393. },
  394. {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
  395. "return external IP address"
  396. },
  397. {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
  398. "add a port mapping"
  399. },
  400. {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
  401. "delete a port mapping"
  402. },
  403. {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
  404. "-- non standard --"
  405. },
  406. {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
  407. "get details about a specific port mapping entry"
  408. },
  409. {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
  410. "get all details about the port mapping at index"
  411. },
  412. {NULL} /* Sentinel */
  413. };
  414. static PyTypeObject UPnPType = {
  415. PyObject_HEAD_INIT(NULL)
  416. 0, /*ob_size*/
  417. "miniupnpc.UPnP", /*tp_name*/
  418. sizeof(UPnPObject), /*tp_basicsize*/
  419. 0, /*tp_itemsize*/
  420. (destructor)UPnPObject_dealloc,/*tp_dealloc*/
  421. 0, /*tp_print*/
  422. 0, /*tp_getattr*/
  423. 0, /*tp_setattr*/
  424. 0, /*tp_compare*/
  425. 0, /*tp_repr*/
  426. 0, /*tp_as_number*/
  427. 0, /*tp_as_sequence*/
  428. 0, /*tp_as_mapping*/
  429. 0, /*tp_hash */
  430. 0, /*tp_call*/
  431. 0, /*tp_str*/
  432. 0, /*tp_getattro*/
  433. 0, /*tp_setattro*/
  434. 0, /*tp_as_buffer*/
  435. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  436. "UPnP objects", /* tp_doc */
  437. 0, /* tp_traverse */
  438. 0, /* tp_clear */
  439. 0, /* tp_richcompare */
  440. 0, /* tp_weaklistoffset */
  441. 0, /* tp_iter */
  442. 0, /* tp_iternext */
  443. UPnP_methods, /* tp_methods */
  444. UPnP_members, /* tp_members */
  445. 0, /* tp_getset */
  446. 0, /* tp_base */
  447. 0, /* tp_dict */
  448. 0, /* tp_descr_get */
  449. 0, /* tp_descr_set */
  450. 0, /* tp_dictoffset */
  451. 0,/*(initproc)UPnP_init,*/ /* tp_init */
  452. 0, /* tp_alloc */
  453. #ifndef WIN32
  454. PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
  455. #else
  456. 0,
  457. #endif
  458. };
  459. /* module methods */
  460. static PyMethodDef miniupnpc_methods[] = {
  461. {NULL} /* Sentinel */
  462. };
  463. #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
  464. #define PyMODINIT_FUNC void
  465. #endif
  466. PyMODINIT_FUNC
  467. initminiupnpc(void)
  468. {
  469. PyObject* m;
  470. #ifdef WIN32
  471. UPnPType.tp_new = PyType_GenericNew;
  472. #endif
  473. if (PyType_Ready(&UPnPType) < 0)
  474. return;
  475. m = Py_InitModule3("miniupnpc", miniupnpc_methods,
  476. "miniupnpc module.");
  477. Py_INCREF(&UPnPType);
  478. PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
  479. }