miniupnpc.c 18 KB

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