PageRenderTime 40ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/ClassMaster2014/barahon/Cultivation_9_UnixSource/minorGems/network/upnp/miniupnpc/miniupnpc.c

https://gitlab.com/garheade/linux_camp
C | 857 lines | 712 code | 47 blank | 98 comment | 119 complexity | c35e644ab3de20fb5ca1243f20f9e7d1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /* $Id: miniupnpc.c,v 1.6 2010/04/20 13:38:32 jcr13 Exp $ */
  2. /* Project : miniupnp
  3. * Author : Thomas BERNARD
  4. * copyright (c) 2005-2009 Thomas Bernard
  5. * This software is subjet to the conditions detailed in the
  6. * provided LICENCE file. */
  7. #define __EXTENSIONS__ 1
  8. #if !defined(MACOSX) && !defined(__sun)
  9. #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
  10. #ifndef __cplusplus
  11. #define _XOPEN_SOURCE 600
  12. #endif
  13. #endif
  14. #ifndef __BSD_VISIBLE
  15. #define __BSD_VISIBLE 1
  16. #endif
  17. #endif
  18. // just define this everywhere... probably won't break anything else
  19. //#ifdef MACOSX
  20. #define _DARWIN_C_SOURCE
  21. //#endif
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #ifdef WIN32
  26. /* Win32 Specific includes and defines */
  27. #include <winsock2.h>
  28. #include <ws2tcpip.h>
  29. #include <io.h>
  30. #define snprintf _snprintf
  31. #if defined(_MSC_VER) && (_MSC_VER >= 1400)
  32. #define strncasecmp _memicmp
  33. #else
  34. #define strncasecmp memicmp
  35. #endif
  36. #define MAXHOSTNAMELEN 64
  37. #else
  38. /* Standard POSIX includes */
  39. #include <unistd.h>
  40. #include <sys/select.h>
  41. #include <sys/socket.h>
  42. #include <sys/types.h>
  43. #include <sys/param.h>
  44. #include <netinet/in.h>
  45. #include <arpa/inet.h>
  46. // Changed by Jason Rohrer
  47. // 2010-March-25
  48. // To compile on MacOS 10.2
  49. #ifndef BSD
  50. // poll not available on BSD
  51. #include <sys/poll.h>
  52. #endif
  53. #include <netdb.h>
  54. #include <strings.h>
  55. #include <errno.h>
  56. #define closesocket close
  57. #define MINIUPNPC_IGNORE_EINTR
  58. #endif
  59. #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
  60. #include <sys/time.h>
  61. #endif
  62. #include "miniupnpc.h"
  63. #include "minissdpc.h"
  64. #include "miniwget.h"
  65. #include "minisoap.h"
  66. #include "minixml.h"
  67. #include "upnpcommands.h"
  68. #ifdef WIN32
  69. #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
  70. #else
  71. #define PRINT_SOCKET_ERROR(x) perror(x)
  72. #endif
  73. // Changed by Jason Rohrer
  74. // 2010-March-25
  75. // To compile on MacOS 10.2
  76. // BSD does not define socklen_t
  77. #ifdef BSD
  78. #ifndef IPHONE
  79. #ifndef __OpenBSD__
  80. #ifndef _SOCKLEN_T // later versions of MacOS define it and mark it
  81. typedef int socklen_t;
  82. #endif
  83. #endif
  84. #endif
  85. #endif
  86. #define SOAPPREFIX "s"
  87. #define SERVICEPREFIX "u"
  88. #define SERVICEPREFIX2 'u'
  89. /* root description parsing */
  90. LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
  91. {
  92. struct xmlparser parser;
  93. /* xmlparser object */
  94. parser.xmlstart = buffer;
  95. parser.xmlsize = bufsize;
  96. parser.data = data;
  97. parser.starteltfunc = IGDstartelt;
  98. parser.endeltfunc = IGDendelt;
  99. parser.datafunc = IGDdata;
  100. parser.attfunc = 0;
  101. parsexml(&parser);
  102. #ifdef DEBUG
  103. printIGD(data);
  104. #endif
  105. }
  106. /* Content-length: nnn */
  107. static int getcontentlenfromline(const char * p, int n)
  108. {
  109. static const char contlenstr[] = "content-length";
  110. const char * p2 = contlenstr;
  111. int a = 0;
  112. while(*p2)
  113. {
  114. if(n==0)
  115. return -1;
  116. if(*p2 != *p && *p2 != (*p + 32))
  117. return -1;
  118. p++; p2++; n--;
  119. }
  120. if(n==0)
  121. return -1;
  122. if(*p != ':')
  123. return -1;
  124. p++; n--;
  125. while(*p == ' ')
  126. {
  127. if(n==0)
  128. return -1;
  129. p++; n--;
  130. }
  131. while(*p >= '0' && *p <= '9')
  132. {
  133. if(n==0)
  134. return -1;
  135. a = (a * 10) + (*p - '0');
  136. p++; n--;
  137. }
  138. return a;
  139. }
  140. static void
  141. getContentLengthAndHeaderLength(char * p, int n,
  142. int * contentlen, int * headerlen)
  143. {
  144. char * line;
  145. int linelen;
  146. int r;
  147. line = p;
  148. while(line < p + n)
  149. {
  150. linelen = 0;
  151. while(line[linelen] != '\r' && line[linelen] != '\r')
  152. {
  153. if(line+linelen >= p+n)
  154. return;
  155. linelen++;
  156. }
  157. r = getcontentlenfromline(line, linelen);
  158. if(r>0)
  159. *contentlen = r;
  160. line = line + linelen + 2;
  161. if(line[0] == '\r' && line[1] == '\n')
  162. {
  163. *headerlen = (line - p) + 2;
  164. return;
  165. }
  166. }
  167. }
  168. /* simpleUPnPcommand :
  169. * not so simple !
  170. * return values :
  171. * 0 - OK
  172. * -1 - error */
  173. int simpleUPnPcommand(int s, const char * url, const char * service,
  174. const char * action, struct UPNParg * args,
  175. char * buffer, int * bufsize)
  176. {
  177. struct sockaddr_in dest;
  178. char hostname[MAXHOSTNAMELEN+1];
  179. unsigned short port = 0;
  180. char * path;
  181. char soapact[128];
  182. char soapbody[2048];
  183. char * buf;
  184. int buffree;
  185. int n;
  186. int contentlen, headerlen; /* for the response */
  187. #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
  188. struct timeval timeout;
  189. #endif
  190. snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
  191. if(args==NULL)
  192. {
  193. /*soapbodylen = */snprintf(soapbody, sizeof(soapbody),
  194. "<?xml version=\"1.0\"?>\r\n"
  195. "<" SOAPPREFIX ":Envelope "
  196. "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  197. SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  198. "<" SOAPPREFIX ":Body>"
  199. "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
  200. "</" SERVICEPREFIX ":%s>"
  201. "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
  202. "\r\n", action, service, action);
  203. }
  204. else
  205. {
  206. char * p;
  207. const char * pe, * pv;
  208. int soapbodylen;
  209. soapbodylen = snprintf(soapbody, sizeof(soapbody),
  210. "<?xml version=\"1.0\"?>\r\n"
  211. "<" SOAPPREFIX ":Envelope "
  212. "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  213. SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
  214. "<" SOAPPREFIX ":Body>"
  215. "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
  216. action, service);
  217. p = soapbody + soapbodylen;
  218. while(args->elt)
  219. {
  220. /* check that we are never overflowing the string... */
  221. if(soapbody + sizeof(soapbody) <= p + 100)
  222. {
  223. /* we keep a margin of at least 100 bytes */
  224. *bufsize = 0;
  225. return -1;
  226. }
  227. *(p++) = '<';
  228. pe = args->elt;
  229. while(*pe)
  230. *(p++) = *(pe++);
  231. *(p++) = '>';
  232. if((pv = args->val))
  233. {
  234. while(*pv)
  235. *(p++) = *(pv++);
  236. }
  237. *(p++) = '<';
  238. *(p++) = '/';
  239. pe = args->elt;
  240. while(*pe)
  241. *(p++) = *(pe++);
  242. *(p++) = '>';
  243. args++;
  244. }
  245. *(p++) = '<';
  246. *(p++) = '/';
  247. *(p++) = SERVICEPREFIX2;
  248. *(p++) = ':';
  249. pe = action;
  250. while(*pe)
  251. *(p++) = *(pe++);
  252. strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
  253. soapbody + sizeof(soapbody) - p);
  254. }
  255. if(!parseURL(url, hostname, &port, &path)) return -1;
  256. if(s<0)
  257. {
  258. s = socket(PF_INET, SOCK_STREAM, 0);
  259. if(s<0)
  260. {
  261. PRINT_SOCKET_ERROR("socket");
  262. *bufsize = 0;
  263. return -1;
  264. }
  265. #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
  266. /* setting a 3 seconds timeout for the connect() call */
  267. timeout.tv_sec = 3;
  268. timeout.tv_usec = 0;
  269. if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
  270. {
  271. PRINT_SOCKET_ERROR("setsockopt");
  272. }
  273. timeout.tv_sec = 3;
  274. timeout.tv_usec = 0;
  275. if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
  276. {
  277. PRINT_SOCKET_ERROR("setsockopt");
  278. }
  279. #endif
  280. dest.sin_family = AF_INET;
  281. dest.sin_port = htons(port);
  282. dest.sin_addr.s_addr = inet_addr(hostname);
  283. n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr));
  284. #ifdef MINIUPNPC_IGNORE_EINTR
  285. while(n < 0 && errno == EINTR)
  286. {
  287. socklen_t len;
  288. fd_set wset;
  289. int err;
  290. FD_ZERO(&wset);
  291. FD_SET(s, &wset);
  292. if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
  293. continue;
  294. /*len = 0;*/
  295. /*n = getpeername(s, NULL, &len);*/
  296. len = sizeof(err);
  297. if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
  298. PRINT_SOCKET_ERROR("getsockopt");
  299. closesocket(s);
  300. return -1;
  301. }
  302. if(err != 0) {
  303. errno = err;
  304. n = -1;
  305. } else {
  306. n = 0;
  307. }
  308. }
  309. #endif
  310. if(n < 0)
  311. {
  312. PRINT_SOCKET_ERROR("connect");
  313. closesocket(s);
  314. *bufsize = 0;
  315. return -1;
  316. }
  317. }
  318. n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);
  319. if(n<=0) {
  320. #ifdef DEBUG
  321. printf("Error sending SOAP request\n");
  322. #endif
  323. closesocket(s);
  324. return -1;
  325. }
  326. contentlen = -1;
  327. headerlen = -1;
  328. buf = buffer;
  329. buffree = *bufsize;
  330. *bufsize = 0;
  331. while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {
  332. buffree -= n;
  333. buf += n;
  334. *bufsize += n;
  335. getContentLengthAndHeaderLength(buffer, *bufsize,
  336. &contentlen, &headerlen);
  337. #ifdef DEBUG
  338. printf("received n=%dbytes bufsize=%d ContLen=%d HeadLen=%d\n",
  339. n, *bufsize, contentlen, headerlen);
  340. #endif
  341. /* break if we received everything */
  342. if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)
  343. break;
  344. }
  345. closesocket(s);
  346. return 0;
  347. }
  348. /* parseMSEARCHReply()
  349. * the last 4 arguments are filled during the parsing :
  350. * - location/locationsize : "location:" field of the SSDP reply packet
  351. * - st/stsize : "st:" field of the SSDP reply packet.
  352. * The strings are NOT null terminated */
  353. static void
  354. parseMSEARCHReply(const char * reply, int size,
  355. const char * * location, int * locationsize,
  356. const char * * st, int * stsize)
  357. {
  358. int a, b, i;
  359. i = 0;
  360. a = i; /* start of the line */
  361. b = 0;
  362. while(i<size)
  363. {
  364. switch(reply[i])
  365. {
  366. case ':':
  367. if(b==0)
  368. {
  369. b = i; /* end of the "header" */
  370. /*for(j=a; j<b; j++)
  371. {
  372. putchar(reply[j]);
  373. }
  374. */
  375. }
  376. break;
  377. case '\x0a':
  378. case '\x0d':
  379. if(b!=0)
  380. {
  381. /*for(j=b+1; j<i; j++)
  382. {
  383. putchar(reply[j]);
  384. }
  385. putchar('\n');*/
  386. do { b++; } while(reply[b]==' ');
  387. if(0==strncasecmp(reply+a, "location", 8))
  388. {
  389. *location = reply+b;
  390. *locationsize = i-b;
  391. }
  392. else if(0==strncasecmp(reply+a, "st", 2))
  393. {
  394. *st = reply+b;
  395. *stsize = i-b;
  396. }
  397. b = 0;
  398. }
  399. a = i+1;
  400. break;
  401. default:
  402. break;
  403. }
  404. i++;
  405. }
  406. }
  407. /* port upnp discover : SSDP protocol */
  408. #define PORT 1900
  409. #define XSTR(s) STR(s)
  410. #define STR(s) #s
  411. #define UPNP_MCAST_ADDR "239.255.255.250"
  412. /* upnpDiscover() :
  413. * return a chained list of all devices found or NULL if
  414. * no devices was found.
  415. * It is up to the caller to free the chained list
  416. * delay is in millisecond (poll) */
  417. LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
  418. const char * minissdpdsock, int sameport)
  419. {
  420. struct UPNPDev * tmp;
  421. struct UPNPDev * devlist = 0;
  422. int opt = 1;
  423. static const char MSearchMsgFmt[] =
  424. "M-SEARCH * HTTP/1.1\r\n"
  425. "HOST: " UPNP_MCAST_ADDR ":" XSTR(PORT) "\r\n"
  426. "ST: %s\r\n"
  427. "MAN: \"ssdp:discover\"\r\n"
  428. "MX: %u\r\n"
  429. "\r\n";
  430. static const char * const deviceList[] = {
  431. "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
  432. "urn:schemas-upnp-org:service:WANIPConnection:1",
  433. "urn:schemas-upnp-org:service:WANPPPConnection:1",
  434. "upnp:rootdevice",
  435. 0
  436. };
  437. int deviceIndex = 0;
  438. char bufr[1536]; /* reception and emission buffer */
  439. int sudp;
  440. int n;
  441. struct sockaddr_in sockudp_r, sockudp_w;
  442. unsigned int mx;
  443. #ifndef WIN32
  444. /* first try to get infos from minissdpd ! */
  445. if(!minissdpdsock)
  446. minissdpdsock = "/var/run/minissdpd.sock";
  447. while(!devlist && deviceList[deviceIndex]) {
  448. devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
  449. minissdpdsock);
  450. /* We return what we have found if it was not only a rootdevice */
  451. if(devlist && !strstr(deviceList[deviceIndex], "rootdevice"))
  452. return devlist;
  453. deviceIndex++;
  454. }
  455. deviceIndex = 0;
  456. #endif
  457. /* fallback to direct discovery */
  458. #ifdef WIN32
  459. sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  460. #else
  461. sudp = socket(PF_INET, SOCK_DGRAM, 0);
  462. #endif
  463. if(sudp < 0)
  464. {
  465. PRINT_SOCKET_ERROR("socket");
  466. return NULL;
  467. }
  468. /* reception */
  469. memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
  470. sockudp_r.sin_family = AF_INET;
  471. if(sameport)
  472. sockudp_r.sin_port = htons(PORT);
  473. sockudp_r.sin_addr.s_addr = INADDR_ANY;
  474. /* emission */
  475. memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
  476. sockudp_w.sin_family = AF_INET;
  477. sockudp_w.sin_port = htons(PORT);
  478. sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
  479. #ifdef WIN32
  480. if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
  481. #else
  482. if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
  483. #endif
  484. {
  485. PRINT_SOCKET_ERROR("setsockopt");
  486. return NULL;
  487. }
  488. if(multicastif)
  489. {
  490. struct in_addr mc_if;
  491. mc_if.s_addr = inet_addr(multicastif);
  492. sockudp_r.sin_addr.s_addr = mc_if.s_addr;
  493. if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
  494. {
  495. PRINT_SOCKET_ERROR("setsockopt");
  496. }
  497. }
  498. /* Avant d'envoyer le paquet on bind pour recevoir la reponse */
  499. if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
  500. {
  501. PRINT_SOCKET_ERROR("bind");
  502. closesocket(sudp);
  503. return NULL;
  504. }
  505. /* Calculating maximum response time in seconds */
  506. mx = ((unsigned int)delay) / 1000u;
  507. /* receiving SSDP response packet */
  508. for(n = 0;;)
  509. {
  510. if(n == 0)
  511. {
  512. /* sending the SSDP M-SEARCH packet */
  513. n = snprintf(bufr, sizeof(bufr),
  514. MSearchMsgFmt, deviceList[deviceIndex++], mx);
  515. /*printf("Sending %s", bufr);*/
  516. n = sendto(sudp, bufr, n, 0,
  517. (struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
  518. if (n < 0) {
  519. PRINT_SOCKET_ERROR("sendto");
  520. closesocket(sudp);
  521. return devlist;
  522. }
  523. }
  524. /* Waiting for SSDP REPLY packet to M-SEARCH */
  525. n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
  526. if (n < 0) {
  527. /* error */
  528. closesocket(sudp);
  529. return devlist;
  530. } else if (n == 0) {
  531. /* no data or Time Out */
  532. if (devlist || (deviceList[deviceIndex] == 0)) {
  533. /* no more device type to look for... */
  534. closesocket(sudp);
  535. return devlist;
  536. }
  537. } else {
  538. const char * descURL=NULL;
  539. int urlsize=0;
  540. const char * st=NULL;
  541. int stsize=0;
  542. /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
  543. parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
  544. if(st&&descURL)
  545. {
  546. /*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
  547. stsize, st, urlsize, descURL); */
  548. tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
  549. tmp->pNext = devlist;
  550. tmp->descURL = tmp->buffer;
  551. tmp->st = tmp->buffer + 1 + urlsize;
  552. memcpy(tmp->buffer, descURL, urlsize);
  553. tmp->buffer[urlsize] = '\0';
  554. memcpy(tmp->buffer + urlsize + 1, st, stsize);
  555. tmp->buffer[urlsize+1+stsize] = '\0';
  556. devlist = tmp;
  557. }
  558. }
  559. }
  560. }
  561. /* freeUPNPDevlist() should be used to
  562. * free the chained list returned by upnpDiscover() */
  563. LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
  564. {
  565. struct UPNPDev * next;
  566. while(devlist)
  567. {
  568. next = devlist->pNext;
  569. free(devlist);
  570. devlist = next;
  571. }
  572. }
  573. static void
  574. url_cpy_or_cat(char * dst, const char * src, int n)
  575. {
  576. if( (src[0] == 'h')
  577. &&(src[1] == 't')
  578. &&(src[2] == 't')
  579. &&(src[3] == 'p')
  580. &&(src[4] == ':')
  581. &&(src[5] == '/')
  582. &&(src[6] == '/'))
  583. {
  584. strncpy(dst, src, n);
  585. }
  586. else
  587. {
  588. int l = strlen(dst);
  589. if(src[0] != '/')
  590. dst[l++] = '/';
  591. if(l<=n)
  592. strncpy(dst + l, src, n - l);
  593. }
  594. }
  595. /* Prepare the Urls for usage...
  596. */
  597. LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
  598. const char * descURL)
  599. {
  600. char * p;
  601. int n1, n2, n3;
  602. n1 = strlen(data->urlbase);
  603. if(n1==0)
  604. n1 = strlen(descURL);
  605. n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
  606. n2 = n1; n3 = n1;
  607. n1 += strlen(data->scpdurl);
  608. n2 += strlen(data->controlurl);
  609. n3 += strlen(data->controlurl_CIF);
  610. urls->ipcondescURL = (char *)malloc(n1);
  611. urls->controlURL = (char *)malloc(n2);
  612. urls->controlURL_CIF = (char *)malloc(n3);
  613. /* maintenant on chope la desc du WANIPConnection */
  614. if(data->urlbase[0] != '\0')
  615. strncpy(urls->ipcondescURL, data->urlbase, n1);
  616. else
  617. strncpy(urls->ipcondescURL, descURL, n1);
  618. p = strchr(urls->ipcondescURL+7, '/');
  619. if(p) p[0] = '\0';
  620. strncpy(urls->controlURL, urls->ipcondescURL, n2);
  621. strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
  622. url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
  623. url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
  624. url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
  625. #ifdef DEBUG
  626. printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
  627. strlen(urls->ipcondescURL), n1);
  628. printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
  629. strlen(urls->controlURL), n2);
  630. printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
  631. strlen(urls->controlURL_CIF), n3);
  632. #endif
  633. }
  634. LIBSPEC void
  635. FreeUPNPUrls(struct UPNPUrls * urls)
  636. {
  637. if(!urls)
  638. return;
  639. free(urls->controlURL);
  640. urls->controlURL = 0;
  641. free(urls->ipcondescURL);
  642. urls->ipcondescURL = 0;
  643. free(urls->controlURL_CIF);
  644. urls->controlURL_CIF = 0;
  645. }
  646. int ReceiveData(int socket, char * data, int length, int timeout)
  647. {
  648. int n;
  649. // No poll on BSD either...
  650. #if !defined(WIN32) && !defined(BSD)
  651. struct pollfd fds[1]; /* for the poll */
  652. #ifdef MINIUPNPC_IGNORE_EINTR
  653. do {
  654. #endif
  655. fds[0].fd = socket;
  656. fds[0].events = POLLIN;
  657. n = poll(fds, 1, timeout);
  658. #ifdef MINIUPNPC_IGNORE_EINTR
  659. } while(n < 0 && errno == EINTR);
  660. #endif
  661. if(n < 0)
  662. {
  663. PRINT_SOCKET_ERROR("poll");
  664. return -1;
  665. }
  666. else if(n == 0)
  667. {
  668. return 0;
  669. }
  670. #else
  671. fd_set socketSet;
  672. // where is this coming from? Jason Rohrer, 2010-March-25
  673. //TIMEVAL timeval;
  674. struct timeval timeV;
  675. FD_ZERO(&socketSet);
  676. FD_SET(socket, &socketSet);
  677. timeV.tv_sec = timeout / 1000;
  678. timeV.tv_usec = (timeout % 1000) * 1000;
  679. n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeV);
  680. if(n < 0)
  681. {
  682. PRINT_SOCKET_ERROR("select");
  683. return -1;
  684. }
  685. else if(n == 0)
  686. {
  687. return 0;
  688. }
  689. #endif
  690. n = recv(socket, data, length, 0);
  691. if(n<0)
  692. {
  693. PRINT_SOCKET_ERROR("recv");
  694. }
  695. return n;
  696. }
  697. int
  698. UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
  699. {
  700. char status[64];
  701. unsigned int uptime;
  702. status[0] = '\0';
  703. UPNP_GetStatusInfo(urls->controlURL, data->servicetype,
  704. status, &uptime, NULL);
  705. if(0 == strcmp("Connected", status))
  706. {
  707. return 1;
  708. }
  709. else
  710. return 0;
  711. }
  712. /* UPNP_GetValidIGD() :
  713. * return values :
  714. * 0 = NO IGD found
  715. * 1 = A valid connected IGD has been found
  716. * 2 = A valid IGD has been found but it reported as
  717. * not connected
  718. * 3 = an UPnP device has been found but was not recognized as an IGD
  719. *
  720. * In any non zero return case, the urls and data structures
  721. * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
  722. * free allocated memory.
  723. */
  724. LIBSPEC int
  725. UPNP_GetValidIGD(struct UPNPDev * devlist,
  726. struct UPNPUrls * urls,
  727. struct IGDdatas * data,
  728. char * lanaddr, int lanaddrlen)
  729. {
  730. char * descXML;
  731. int descXMLsize = 0;
  732. struct UPNPDev * dev;
  733. int ndev = 0;
  734. int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
  735. if(!devlist)
  736. {
  737. #ifdef DEBUG
  738. printf("Empty devlist\n");
  739. #endif
  740. return 0;
  741. }
  742. for(state = 1; state <= 3; state++)
  743. {
  744. for(dev = devlist; dev; dev = dev->pNext)
  745. {
  746. /* we should choose an internet gateway device.
  747. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
  748. descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
  749. lanaddr, lanaddrlen);
  750. if(descXML)
  751. {
  752. ndev++;
  753. memset(data, 0, sizeof(struct IGDdatas));
  754. memset(urls, 0, sizeof(struct UPNPUrls));
  755. parserootdesc(descXML, descXMLsize, data);
  756. free(descXML);
  757. descXML = NULL;
  758. if(0==strcmp(data->servicetype_CIF,
  759. "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
  760. || state >= 3 )
  761. {
  762. GetUPNPUrls(urls, data, dev->descURL);
  763. #ifdef DEBUG
  764. printf("UPNPIGD_IsConnected(%s) = %d\n",
  765. urls->controlURL,
  766. UPNPIGD_IsConnected(urls, data));
  767. #endif
  768. if((state >= 2) || UPNPIGD_IsConnected(urls, data))
  769. return state;
  770. FreeUPNPUrls(urls);
  771. }
  772. memset(data, 0, sizeof(struct IGDdatas));
  773. }
  774. #ifdef DEBUG
  775. else
  776. {
  777. printf("error getting XML description %s\n", dev->descURL);
  778. }
  779. #endif
  780. }
  781. }
  782. return 0;
  783. }
  784. /* UPNP_GetIGDFromUrl()
  785. * Used when skipping the discovery process.
  786. * return value :
  787. * 0 - Not ok
  788. * 1 - OK */
  789. int
  790. UPNP_GetIGDFromUrl(const char * rootdescurl,
  791. struct UPNPUrls * urls,
  792. struct IGDdatas * data,
  793. char * lanaddr, int lanaddrlen)
  794. {
  795. char * descXML;
  796. int descXMLsize = 0;
  797. descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
  798. lanaddr, lanaddrlen);
  799. if(descXML) {
  800. memset(data, 0, sizeof(struct IGDdatas));
  801. memset(urls, 0, sizeof(struct UPNPUrls));
  802. parserootdesc(descXML, descXMLsize, data);
  803. free(descXML);
  804. descXML = NULL;
  805. GetUPNPUrls(urls, data, rootdescurl);
  806. return 1;
  807. } else {
  808. return 0;
  809. }
  810. }