miniupnpc.c 18 KB

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