miniupnpc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. #define _CRT_SECURE_NO_WARNINGS
  2. /* $Id: miniupnpc.c,v 1.141 2015/10/26 17:05:07 nanard Exp $ */
  3. /* vim: tabstop=4 shiftwidth=4 noexpandtab */
  4. /* Project : miniupnp
  5. * Web : http://miniupnp.free.fr/
  6. * Author : Thomas BERNARD
  7. * copyright (c) 2005-2015 Thomas Bernard
  8. * This software is subjet to the conditions detailed in the
  9. * provided LICENSE file. */
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #ifdef _WIN32
  14. /* Win32 Specific includes and defines */
  15. #include <winsock2.h>
  16. #include <ws2tcpip.h>
  17. #include <io.h>
  18. #include <iphlpapi.h>
  19. #define snprintf _snprintf
  20. #define strdup _strdup
  21. #ifndef strncasecmp
  22. #if defined(_MSC_VER) && (_MSC_VER >= 1400)
  23. #define strncasecmp _memicmp
  24. #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  25. #define strncasecmp memicmp
  26. #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  27. #endif /* #ifndef strncasecmp */
  28. #define MAXHOSTNAMELEN 64
  29. #else /* #ifdef _WIN32 */
  30. /* Standard POSIX includes */
  31. #include <unistd.h>
  32. #if defined(__amigaos__) && !defined(__amigaos4__)
  33. /* Amiga OS 3 specific stuff */
  34. #define socklen_t int
  35. #else
  36. #include <sys/select.h>
  37. #endif
  38. #include <sys/socket.h>
  39. #include <sys/types.h>
  40. #include <sys/param.h>
  41. #include <netinet/in.h>
  42. #include <arpa/inet.h>
  43. #include <netdb.h>
  44. #include <net/if.h>
  45. #if !defined(__amigaos__) && !defined(__amigaos4__)
  46. #include <poll.h>
  47. #endif
  48. #include <strings.h>
  49. #include <errno.h>
  50. #define closesocket close
  51. #endif /* #else _WIN32 */
  52. #ifdef __GNU__
  53. #define MAXHOSTNAMELEN 64
  54. #endif
  55. #include "miniupnpc.h"
  56. #include "minissdpc.h"
  57. #include "miniwget.h"
  58. #include "minisoap.h"
  59. #include "minixml.h"
  60. #include "upnpcommands.h"
  61. #include "connecthostport.h"
  62. /* compare the begining of a string with a constant string */
  63. #define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
  64. #ifndef MAXHOSTNAMELEN
  65. #define MAXHOSTNAMELEN 64
  66. #endif
  67. #define SOAPPREFIX "s"
  68. #define SERVICEPREFIX "u"
  69. #define SERVICEPREFIX2 'u'
  70. /* root description parsing */
  71. MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
  72. {
  73. struct xmlparser parser;
  74. /* xmlparser object */
  75. parser.xmlstart = buffer;
  76. parser.xmlsize = bufsize;
  77. parser.data = data;
  78. parser.starteltfunc = IGDstartelt;
  79. parser.endeltfunc = IGDendelt;
  80. parser.datafunc = IGDdata;
  81. parser.attfunc = 0;
  82. parsexml(&parser);
  83. #ifdef DEBUG
  84. printIGD(data);
  85. #endif
  86. }
  87. /* simpleUPnPcommand2 :
  88. * not so simple !
  89. * return values :
  90. * pointer - OK
  91. * NULL - error */
  92. char * simpleUPnPcommand2(int s, const char * url, const char * service,
  93. const char * action, struct UPNParg * args,
  94. int * bufsize, const char * httpversion)
  95. {
  96. char hostname[MAXHOSTNAMELEN+1];
  97. unsigned short port = 0;
  98. char * path;
  99. char soapact[128];
  100. char soapbody[2048];
  101. int soapbodylen;
  102. char * buf;
  103. int n;
  104. *bufsize = 0;
  105. snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
  106. if(args==NULL)
  107. {
  108. soapbodylen = snprintf(soapbody, sizeof(soapbody),
  109. "<?xml version=\"1.0\"?>\r\n"
  110. "<" SOAPPREFIX ":Envelope "
  111. "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  112. SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  113. "<" SOAPPREFIX ":Body>"
  114. "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
  115. "</" SERVICEPREFIX ":%s>"
  116. "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
  117. "\r\n", action, service, action);
  118. if ((unsigned int)soapbodylen >= sizeof(soapbody))
  119. return NULL;
  120. }
  121. else
  122. {
  123. char * p;
  124. const char * pe, * pv;
  125. const char * const pend = soapbody + sizeof(soapbody);
  126. soapbodylen = snprintf(soapbody, sizeof(soapbody),
  127. "<?xml version=\"1.0\"?>\r\n"
  128. "<" SOAPPREFIX ":Envelope "
  129. "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  130. SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  131. "<" SOAPPREFIX ":Body>"
  132. "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
  133. action, service);
  134. if ((unsigned int)soapbodylen >= sizeof(soapbody))
  135. return NULL;
  136. p = soapbody + soapbodylen;
  137. while(args->elt)
  138. {
  139. if(p >= pend) /* check for space to write next byte */
  140. return NULL;
  141. *(p++) = '<';
  142. pe = args->elt;
  143. while(p < pend && *pe)
  144. *(p++) = *(pe++);
  145. if(p >= pend) /* check for space to write next byte */
  146. return NULL;
  147. *(p++) = '>';
  148. if((pv = args->val))
  149. {
  150. while(p < pend && *pv)
  151. *(p++) = *(pv++);
  152. }
  153. if((p+2) > pend) /* check for space to write next 2 bytes */
  154. return NULL;
  155. *(p++) = '<';
  156. *(p++) = '/';
  157. pe = args->elt;
  158. while(p < pend && *pe)
  159. *(p++) = *(pe++);
  160. if(p >= pend) /* check for space to write next byte */
  161. return NULL;
  162. *(p++) = '>';
  163. args++;
  164. }
  165. if((p+4) > pend) /* check for space to write next 4 bytes */
  166. return NULL;
  167. *(p++) = '<';
  168. *(p++) = '/';
  169. *(p++) = SERVICEPREFIX2;
  170. *(p++) = ':';
  171. pe = action;
  172. while(p < pend && *pe)
  173. *(p++) = *(pe++);
  174. strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
  175. pend - p);
  176. if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
  177. return NULL;
  178. }
  179. if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
  180. if(s < 0) {
  181. s = connecthostport(hostname, port, 0);
  182. if(s < 0) {
  183. /* failed to connect */
  184. return NULL;
  185. }
  186. }
  187. n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion);
  188. if(n<=0) {
  189. #ifdef DEBUG
  190. printf("Error sending SOAP request\n");
  191. #endif
  192. closesocket(s);
  193. return NULL;
  194. }
  195. buf = getHTTPResponse(s, bufsize);
  196. #ifdef DEBUG
  197. if(*bufsize > 0 && buf)
  198. {
  199. printf("SOAP Response :\n%.*s\n", *bufsize, buf);
  200. }
  201. #endif
  202. closesocket(s);
  203. return buf;
  204. }
  205. /* simpleUPnPcommand :
  206. * not so simple !
  207. * return values :
  208. * pointer - OK
  209. * NULL - error */
  210. char * simpleUPnPcommand(int s, const char * url, const char * service,
  211. const char * action, struct UPNParg * args,
  212. int * bufsize)
  213. {
  214. char * buf;
  215. #if 1
  216. buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
  217. #else
  218. buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0");
  219. if (!buf || *bufsize == 0)
  220. {
  221. #if DEBUG
  222. printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
  223. #endif
  224. buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
  225. }
  226. #endif
  227. return buf;
  228. }
  229. /* upnpDiscoverDevices() :
  230. * return a chained list of all devices found or NULL if
  231. * no devices was found.
  232. * It is up to the caller to free the chained list
  233. * delay is in millisecond (poll).
  234. * UDA v1.1 says :
  235. * The TTL for the IP packet SHOULD default to 2 and
  236. * SHOULD be configurable. */
  237. MINIUPNP_LIBSPEC struct UPNPDev *
  238. upnpDiscoverDevices(const char * const deviceTypes[],
  239. int delay, const char * multicastif,
  240. const char * minissdpdsock, int localport,
  241. int ipv6, unsigned char ttl,
  242. int * error,
  243. int searchalltypes)
  244. {
  245. struct UPNPDev * tmp;
  246. struct UPNPDev * devlist = 0;
  247. #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
  248. int deviceIndex;
  249. #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
  250. if(error)
  251. *error = UPNPDISCOVER_UNKNOWN_ERROR;
  252. #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
  253. /* first try to get infos from minissdpd ! */
  254. if(!minissdpdsock)
  255. minissdpdsock = "/var/run/minissdpd.sock";
  256. for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
  257. struct UPNPDev * minissdpd_devlist;
  258. int only_rootdevice = 1;
  259. minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
  260. minissdpdsock, 0);
  261. if(minissdpd_devlist) {
  262. #ifdef DEBUG
  263. printf("returned by MiniSSDPD: %s\t%s\n",
  264. minissdpd_devlist->st, minissdpd_devlist->descURL);
  265. #endif /* DEBUG */
  266. if(!strstr(minissdpd_devlist->st, "rootdevice"))
  267. only_rootdevice = 0;
  268. for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
  269. #ifdef DEBUG
  270. printf("returned by MiniSSDPD: %s\t%s\n",
  271. tmp->pNext->st, tmp->pNext->descURL);
  272. #endif /* DEBUG */
  273. if(!strstr(tmp->st, "rootdevice"))
  274. only_rootdevice = 0;
  275. }
  276. tmp->pNext = devlist;
  277. devlist = minissdpd_devlist;
  278. if(!searchalltypes && !only_rootdevice)
  279. break;
  280. }
  281. }
  282. for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
  283. /* We return what we have found if it was not only a rootdevice */
  284. if(!strstr(tmp->st, "rootdevice")) {
  285. if(error)
  286. *error = UPNPDISCOVER_SUCCESS;
  287. return devlist;
  288. }
  289. }
  290. #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
  291. /* direct discovery if minissdpd responses are not sufficient */
  292. {
  293. struct UPNPDev * discovered_devlist;
  294. discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
  295. ipv6, ttl, error, searchalltypes);
  296. if(devlist == NULL)
  297. devlist = discovered_devlist;
  298. else {
  299. for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
  300. tmp->pNext = discovered_devlist;
  301. }
  302. }
  303. return devlist;
  304. }
  305. /* upnpDiscover() Discover IGD device */
  306. MINIUPNP_LIBSPEC struct UPNPDev *
  307. upnpDiscover(int delay, const char * multicastif,
  308. const char * minissdpdsock, int localport,
  309. int ipv6, unsigned char ttl,
  310. int * error)
  311. {
  312. static const char * const deviceList[] = {
  313. #if 0
  314. "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
  315. "urn:schemas-upnp-org:service:WANIPConnection:2",
  316. #endif
  317. "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
  318. "urn:schemas-upnp-org:service:WANIPConnection:1",
  319. "urn:schemas-upnp-org:service:WANPPPConnection:1",
  320. "upnp:rootdevice",
  321. /*"ssdp:all",*/
  322. 0
  323. };
  324. return upnpDiscoverDevices(deviceList,
  325. delay, multicastif, minissdpdsock, localport,
  326. ipv6, ttl, error, 0);
  327. }
  328. /* upnpDiscoverAll() Discover all UPnP devices */
  329. MINIUPNP_LIBSPEC struct UPNPDev *
  330. upnpDiscoverAll(int delay, const char * multicastif,
  331. const char * minissdpdsock, int localport,
  332. int ipv6, unsigned char ttl,
  333. int * error)
  334. {
  335. static const char * const deviceList[] = {
  336. /*"upnp:rootdevice",*/
  337. "ssdp:all",
  338. 0
  339. };
  340. return upnpDiscoverDevices(deviceList,
  341. delay, multicastif, minissdpdsock, localport,
  342. ipv6, ttl, error, 0);
  343. }
  344. /* upnpDiscoverDevice() Discover a specific device */
  345. MINIUPNP_LIBSPEC struct UPNPDev *
  346. upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
  347. const char * minissdpdsock, int localport,
  348. int ipv6, unsigned char ttl,
  349. int * error)
  350. {
  351. const char * const deviceList[] = {
  352. device,
  353. 0
  354. };
  355. return upnpDiscoverDevices(deviceList,
  356. delay, multicastif, minissdpdsock, localport,
  357. ipv6, ttl, error, 0);
  358. }
  359. static char *
  360. build_absolute_url(const char * baseurl, const char * descURL,
  361. const char * url, unsigned int scope_id)
  362. {
  363. int l, n;
  364. char * s;
  365. const char * base;
  366. char * p;
  367. #if defined(IF_NAMESIZE) && !defined(_WIN32)
  368. char ifname[IF_NAMESIZE];
  369. #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  370. char scope_str[8];
  371. #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  372. if( (url[0] == 'h')
  373. &&(url[1] == 't')
  374. &&(url[2] == 't')
  375. &&(url[3] == 'p')
  376. &&(url[4] == ':')
  377. &&(url[5] == '/')
  378. &&(url[6] == '/'))
  379. return strdup(url);
  380. base = (baseurl[0] == '\0') ? descURL : baseurl;
  381. n = strlen(base);
  382. if(n > 7) {
  383. p = strchr(base + 7, '/');
  384. if(p)
  385. n = p - base;
  386. }
  387. l = n + strlen(url) + 1;
  388. if(url[0] != '/')
  389. l++;
  390. if(scope_id != 0) {
  391. #if defined(IF_NAMESIZE) && !defined(_WIN32)
  392. if(if_indextoname(scope_id, ifname)) {
  393. l += 3 + strlen(ifname); /* 3 == strlen(%25) */
  394. }
  395. #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  396. /* under windows, scope is numerical */
  397. l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
  398. #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  399. }
  400. s = malloc(l);
  401. if(s == NULL) return NULL;
  402. memcpy(s, base, n);
  403. if(scope_id != 0) {
  404. s[n] = '\0';
  405. if(0 == memcmp(s, "http://[fe80:", 13)) {
  406. /* this is a linklocal IPv6 address */
  407. p = strchr(s, ']');
  408. if(p) {
  409. /* insert %25<scope> into URL */
  410. #if defined(IF_NAMESIZE) && !defined(_WIN32)
  411. memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
  412. memcpy(p, "%25", 3);
  413. memcpy(p + 3, ifname, strlen(ifname));
  414. n += 3 + strlen(ifname);
  415. #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  416. memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
  417. memcpy(p, "%25", 3);
  418. memcpy(p + 3, scope_str, strlen(scope_str));
  419. n += 3 + strlen(scope_str);
  420. #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
  421. }
  422. }
  423. }
  424. if(url[0] != '/')
  425. s[n++] = '/';
  426. memcpy(s + n, url, l - n);
  427. return s;
  428. }
  429. /* Prepare the Urls for usage...
  430. */
  431. MINIUPNP_LIBSPEC void
  432. GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
  433. const char * descURL, unsigned int scope_id)
  434. {
  435. /* strdup descURL */
  436. urls->rootdescURL = strdup(descURL);
  437. /* get description of WANIPConnection */
  438. urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
  439. data->first.scpdurl, scope_id);
  440. urls->controlURL = build_absolute_url(data->urlbase, descURL,
  441. data->first.controlurl, scope_id);
  442. urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
  443. data->CIF.controlurl, scope_id);
  444. urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
  445. data->IPv6FC.controlurl, scope_id);
  446. #ifdef DEBUG
  447. printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
  448. printf("urls->controlURL='%s'\n", urls->controlURL);
  449. printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
  450. printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
  451. #endif
  452. }
  453. MINIUPNP_LIBSPEC void
  454. FreeUPNPUrls(struct UPNPUrls * urls)
  455. {
  456. if(!urls)
  457. return;
  458. free(urls->controlURL);
  459. urls->controlURL = 0;
  460. free(urls->ipcondescURL);
  461. urls->ipcondescURL = 0;
  462. free(urls->controlURL_CIF);
  463. urls->controlURL_CIF = 0;
  464. free(urls->controlURL_6FC);
  465. urls->controlURL_6FC = 0;
  466. free(urls->rootdescURL);
  467. urls->rootdescURL = 0;
  468. }
  469. int
  470. UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
  471. {
  472. char status[64];
  473. unsigned int uptime;
  474. status[0] = '\0';
  475. UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
  476. status, &uptime, NULL);
  477. if(0 == strcmp("Connected", status))
  478. return 1;
  479. else if(0 == strcmp("Up", status)) /* Also accept "Up" */
  480. return 1;
  481. else
  482. return 0;
  483. }
  484. /* UPNP_GetValidIGD() :
  485. * return values :
  486. * -1 = Internal error
  487. * 0 = NO IGD found
  488. * 1 = A valid connected IGD has been found
  489. * 2 = A valid IGD has been found but it reported as
  490. * not connected
  491. * 3 = an UPnP device has been found but was not recognized as an IGD
  492. *
  493. * In any positive non zero return case, the urls and data structures
  494. * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
  495. * free allocated memory.
  496. */
  497. MINIUPNP_LIBSPEC int
  498. UPNP_GetValidIGD(struct UPNPDev * devlist,
  499. struct UPNPUrls * urls,
  500. struct IGDdatas * data,
  501. char * lanaddr, int lanaddrlen)
  502. {
  503. struct xml_desc {
  504. char * xml;
  505. int size;
  506. int is_igd;
  507. } * desc = NULL;
  508. struct UPNPDev * dev;
  509. int ndev = 0;
  510. int i;
  511. int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
  512. int n_igd = 0;
  513. char extIpAddr[16];
  514. if(!devlist)
  515. {
  516. #ifdef DEBUG
  517. printf("Empty devlist\n");
  518. #endif
  519. return 0;
  520. }
  521. /* counting total number of devices in the list */
  522. for(dev = devlist; dev; dev = dev->pNext)
  523. ndev++;
  524. if(ndev > 0)
  525. {
  526. desc = calloc(ndev, sizeof(struct xml_desc));
  527. if(!desc)
  528. return -1; /* memory allocation error */
  529. }
  530. /* Step 1 : downloading descriptions and testing type */
  531. for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
  532. {
  533. /* we should choose an internet gateway device.
  534. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
  535. desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
  536. lanaddr, lanaddrlen,
  537. dev->scope_id);
  538. #ifdef DEBUG
  539. if(!desc[i].xml)
  540. {
  541. printf("error getting XML description %s\n", dev->descURL);
  542. }
  543. #endif
  544. if(desc[i].xml)
  545. {
  546. memset(data, 0, sizeof(struct IGDdatas));
  547. memset(urls, 0, sizeof(struct UPNPUrls));
  548. parserootdesc(desc[i].xml, desc[i].size, data);
  549. if(COMPARE(data->CIF.servicetype,
  550. "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
  551. {
  552. desc[i].is_igd = 1;
  553. n_igd++;
  554. }
  555. }
  556. }
  557. /* iterate the list to find a device depending on state */
  558. for(state = 1; state <= 3; state++)
  559. {
  560. for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
  561. {
  562. if(desc[i].xml)
  563. {
  564. memset(data, 0, sizeof(struct IGDdatas));
  565. memset(urls, 0, sizeof(struct UPNPUrls));
  566. parserootdesc(desc[i].xml, desc[i].size, data);
  567. if(desc[i].is_igd || state >= 3 )
  568. {
  569. GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
  570. /* in state 2 and 3 we dont test if device is connected ! */
  571. if(state >= 2)
  572. goto free_and_return;
  573. #ifdef DEBUG
  574. printf("UPNPIGD_IsConnected(%s) = %d\n",
  575. urls->controlURL,
  576. UPNPIGD_IsConnected(urls, data));
  577. #endif
  578. /* checks that status is connected AND there is a external IP address assigned */
  579. if(UPNPIGD_IsConnected(urls, data)
  580. && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
  581. goto free_and_return;
  582. FreeUPNPUrls(urls);
  583. if(data->second.servicetype[0] != '\0') {
  584. #ifdef DEBUG
  585. printf("We tried %s, now we try %s !\n",
  586. data->first.servicetype, data->second.servicetype);
  587. #endif
  588. /* swaping WANPPPConnection and WANIPConnection ! */
  589. memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
  590. memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
  591. memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
  592. GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
  593. #ifdef DEBUG
  594. printf("UPNPIGD_IsConnected(%s) = %d\n",
  595. urls->controlURL,
  596. UPNPIGD_IsConnected(urls, data));
  597. #endif
  598. if(UPNPIGD_IsConnected(urls, data)
  599. && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
  600. goto free_and_return;
  601. FreeUPNPUrls(urls);
  602. }
  603. }
  604. memset(data, 0, sizeof(struct IGDdatas));
  605. }
  606. }
  607. }
  608. state = 0;
  609. free_and_return:
  610. if(desc) {
  611. for(i = 0; i < ndev; i++) {
  612. if(desc[i].xml) {
  613. free(desc[i].xml);
  614. }
  615. }
  616. free(desc);
  617. }
  618. return state;
  619. }
  620. /* UPNP_GetIGDFromUrl()
  621. * Used when skipping the discovery process.
  622. * return value :
  623. * 0 - Not ok
  624. * 1 - OK */
  625. int
  626. UPNP_GetIGDFromUrl(const char * rootdescurl,
  627. struct UPNPUrls * urls,
  628. struct IGDdatas * data,
  629. char * lanaddr, int lanaddrlen)
  630. {
  631. char * descXML;
  632. int descXMLsize = 0;
  633. descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
  634. lanaddr, lanaddrlen, 0);
  635. if(descXML) {
  636. memset(data, 0, sizeof(struct IGDdatas));
  637. memset(urls, 0, sizeof(struct UPNPUrls));
  638. parserootdesc(descXML, descXMLsize, data);
  639. free(descXML);
  640. descXML = NULL;
  641. GetUPNPUrls(urls, data, rootdescurl, 0);
  642. return 1;
  643. } else {
  644. return 0;
  645. }
  646. }