PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/BB10/upnp/NDK_project/public/miniwget.c

http://github.com/blackberry/WebWorks-Community-APIs
C | 579 lines | 493 code | 21 blank | 65 comment | 132 complexity | c104f3efc3aac142ce77c79801a509cf MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, LGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. /* $Id: miniwget.c,v 1.58 2012/08/11 05:52:49 nanard Exp $ */
  2. /* Project : miniupnp
  3. * Website : http://miniupnp.free.fr/
  4. * Author : Thomas Bernard
  5. * Copyright (c) 2005-2012 Thomas Bernard
  6. * This software is subject to the conditions detailed in the
  7. * LICENCE file provided in this distribution. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #if defined(__QNX__)
  13. #define MIN(x,y) (((x)<(y))?(x):(y))
  14. #endif
  15. #ifdef _WIN32
  16. #include <winsock2.h>
  17. #include <ws2tcpip.h>
  18. #include <io.h>
  19. #define MAXHOSTNAMELEN 64
  20. #define MIN(x,y) (((x)<(y))?(x):(y))
  21. #define snprintf _snprintf
  22. #define socklen_t int
  23. #ifndef strncasecmp
  24. #if defined(_MSC_VER) && (_MSC_VER >= 1400)
  25. #define strncasecmp _memicmp
  26. #else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  27. #define strncasecmp memicmp
  28. #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
  29. #endif /* #ifndef strncasecmp */
  30. #else /* #ifdef _WIN32 */
  31. #include <unistd.h>
  32. #include <sys/param.h>
  33. #if defined(__amigaos__) && !defined(__amigaos4__)
  34. #define socklen_t int
  35. #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
  36. #include <sys/select.h>
  37. #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
  38. #include <sys/socket.h>
  39. #include <netinet/in.h>
  40. #include <arpa/inet.h>
  41. #include <net/if.h>
  42. #include <netdb.h>
  43. #define closesocket close
  44. /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
  45. * during the connect() call */
  46. #define MINIUPNPC_IGNORE_EINTR
  47. #endif /* #else _WIN32 */
  48. #if defined(__sun) || defined(sun)
  49. #define MIN(x,y) (((x)<(y))?(x):(y))
  50. #endif
  51. #include "miniupnpcstrings.h"
  52. #include "miniwget.h"
  53. #include "connecthostport.h"
  54. #include "receivedata.h"
  55. /*
  56. * Read a HTTP response from a socket.
  57. * Process Content-Length and Transfer-encoding headers.
  58. * return a pointer to the content buffer, which length is saved
  59. * to the length parameter.
  60. */
  61. void *
  62. getHTTPResponse(int s, int * size)
  63. {
  64. char buf[2048];
  65. int n;
  66. int endofheaders = 0;
  67. int chunked = 0;
  68. int content_length = -1;
  69. unsigned int chunksize = 0;
  70. unsigned int bytestocopy = 0;
  71. /* buffers : */
  72. char * header_buf;
  73. unsigned int header_buf_len = 2048;
  74. unsigned int header_buf_used = 0;
  75. char * content_buf;
  76. unsigned int content_buf_len = 2048;
  77. unsigned int content_buf_used = 0;
  78. char chunksize_buf[32];
  79. unsigned int chunksize_buf_index;
  80. header_buf = malloc(header_buf_len);
  81. content_buf = malloc(content_buf_len);
  82. chunksize_buf[0] = '\0';
  83. chunksize_buf_index = 0;
  84. while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
  85. {
  86. if(endofheaders == 0)
  87. {
  88. int i;
  89. int linestart=0;
  90. int colon=0;
  91. int valuestart=0;
  92. if(header_buf_used + n > header_buf_len) {
  93. header_buf = realloc(header_buf, header_buf_used + n);
  94. header_buf_len = header_buf_used + n;
  95. }
  96. memcpy(header_buf + header_buf_used, buf, n);
  97. header_buf_used += n;
  98. /* search for CR LF CR LF (end of headers)
  99. * recognize also LF LF */
  100. i = 0;
  101. while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
  102. if(header_buf[i] == '\r') {
  103. i++;
  104. if(header_buf[i] == '\n') {
  105. i++;
  106. if(i < (int)header_buf_used && header_buf[i] == '\r') {
  107. i++;
  108. if(i < (int)header_buf_used && header_buf[i] == '\n') {
  109. endofheaders = i+1;
  110. }
  111. }
  112. }
  113. } else if(header_buf[i] == '\n') {
  114. i++;
  115. if(header_buf[i] == '\n') {
  116. endofheaders = i+1;
  117. }
  118. }
  119. i++;
  120. }
  121. if(endofheaders == 0)
  122. continue;
  123. /* parse header lines */
  124. for(i = 0; i < endofheaders - 1; i++) {
  125. if(colon <= linestart && header_buf[i]==':')
  126. {
  127. colon = i;
  128. while(i < (endofheaders-1)
  129. && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
  130. i++;
  131. valuestart = i + 1;
  132. }
  133. /* detecting end of line */
  134. else if(header_buf[i]=='\r' || header_buf[i]=='\n')
  135. {
  136. if(colon > linestart && valuestart > colon)
  137. {
  138. #ifdef DEBUG
  139. printf("header='%.*s', value='%.*s'\n",
  140. colon-linestart, header_buf+linestart,
  141. i-valuestart, header_buf+valuestart);
  142. #endif
  143. if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
  144. {
  145. content_length = atoi(header_buf+valuestart);
  146. #ifdef DEBUG
  147. printf("Content-Length: %d\n", content_length);
  148. #endif
  149. }
  150. else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
  151. && 0==strncasecmp(header_buf+valuestart, "chunked", 7))
  152. {
  153. #ifdef DEBUG
  154. printf("chunked transfer-encoding!\n");
  155. #endif
  156. chunked = 1;
  157. }
  158. }
  159. while(header_buf[i]=='\r' || header_buf[i] == '\n')
  160. i++;
  161. linestart = i;
  162. colon = linestart;
  163. valuestart = 0;
  164. }
  165. }
  166. /* copy the remaining of the received data back to buf */
  167. n = header_buf_used - endofheaders;
  168. memcpy(buf, header_buf + endofheaders, n);
  169. /* if(headers) */
  170. }
  171. if(endofheaders)
  172. {
  173. /* content */
  174. if(chunked)
  175. {
  176. int i = 0;
  177. while(i < n)
  178. {
  179. if(chunksize == 0)
  180. {
  181. /* reading chunk size */
  182. if(chunksize_buf_index == 0) {
  183. /* skipping any leading CR LF */
  184. if(i<n && buf[i] == '\r') i++;
  185. if(i<n && buf[i] == '\n') i++;
  186. }
  187. while(i<n && isxdigit(buf[i])
  188. && chunksize_buf_index < (sizeof(chunksize_buf)-1))
  189. {
  190. chunksize_buf[chunksize_buf_index++] = buf[i];
  191. chunksize_buf[chunksize_buf_index] = '\0';
  192. i++;
  193. }
  194. while(i<n && buf[i] != '\r' && buf[i] != '\n')
  195. i++; /* discarding chunk-extension */
  196. if(i<n && buf[i] == '\r') i++;
  197. if(i<n && buf[i] == '\n') {
  198. unsigned int j;
  199. for(j = 0; j < chunksize_buf_index; j++) {
  200. if(chunksize_buf[j] >= '0'
  201. && chunksize_buf[j] <= '9')
  202. chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
  203. else
  204. chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
  205. }
  206. chunksize_buf[0] = '\0';
  207. chunksize_buf_index = 0;
  208. i++;
  209. } else {
  210. /* not finished to get chunksize */
  211. continue;
  212. }
  213. #ifdef DEBUG
  214. printf("chunksize = %u (%x)\n", chunksize, chunksize);
  215. #endif
  216. if(chunksize == 0)
  217. {
  218. #ifdef DEBUG
  219. printf("end of HTTP content - %d %d\n", i, n);
  220. /*printf("'%.*s'\n", n-i, buf+i);*/
  221. #endif
  222. goto end_of_stream;
  223. }
  224. }
  225. bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
  226. if((content_buf_used + bytestocopy) > content_buf_len)
  227. {
  228. if(content_length >= (int)(content_buf_used + bytestocopy)) {
  229. content_buf_len = content_length;
  230. } else {
  231. content_buf_len = content_buf_used + bytestocopy;
  232. }
  233. content_buf = (char *)realloc((void *)content_buf,
  234. content_buf_len);
  235. }
  236. memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
  237. content_buf_used += bytestocopy;
  238. i += bytestocopy;
  239. chunksize -= bytestocopy;
  240. }
  241. }
  242. else
  243. {
  244. /* not chunked */
  245. if(content_length > 0
  246. && (int)(content_buf_used + n) > content_length) {
  247. /* skipping additional bytes */
  248. n = content_length - content_buf_used;
  249. }
  250. if(content_buf_used + n > content_buf_len)
  251. {
  252. if(content_length >= (int)(content_buf_used + n)) {
  253. content_buf_len = content_length;
  254. } else {
  255. content_buf_len = content_buf_used + n;
  256. }
  257. content_buf = (char *)realloc((void *)content_buf,
  258. content_buf_len);
  259. }
  260. memcpy(content_buf + content_buf_used, buf, n);
  261. content_buf_used += n;
  262. }
  263. }
  264. /* use the Content-Length header value if available */
  265. if(content_length > 0 && (int)content_buf_used >= content_length)
  266. {
  267. #ifdef DEBUG
  268. printf("End of HTTP content\n");
  269. #endif
  270. break;
  271. }
  272. }
  273. end_of_stream:
  274. free(header_buf); header_buf = NULL;
  275. *size = content_buf_used;
  276. if(content_buf_used == 0)
  277. {
  278. free(content_buf);
  279. content_buf = NULL;
  280. }
  281. return content_buf;
  282. }
  283. /* miniwget3() :
  284. * do all the work.
  285. * Return NULL if something failed. */
  286. static void *
  287. miniwget3(const char * host,
  288. unsigned short port, const char * path,
  289. int * size, char * addr_str, int addr_str_len,
  290. const char * httpversion, unsigned int scope_id)
  291. {
  292. char buf[2048];
  293. int s;
  294. int n;
  295. int len;
  296. int sent;
  297. void * content;
  298. *size = 0;
  299. s = connecthostport(host, port, scope_id);
  300. if(s < 0)
  301. return NULL;
  302. /* get address for caller ! */
  303. if(addr_str)
  304. {
  305. struct sockaddr_storage saddr;
  306. socklen_t saddrlen;
  307. saddrlen = sizeof(saddr);
  308. if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
  309. {
  310. perror("getsockname");
  311. }
  312. else
  313. {
  314. #if defined(__amigaos__) && !defined(__amigaos4__)
  315. /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
  316. * But his function make a string with the port : nn.nn.nn.nn:port */
  317. /* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
  318. NULL, addr_str, (DWORD *)&addr_str_len))
  319. {
  320. printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
  321. }*/
  322. /* the following code is only compatible with ip v4 addresses */
  323. strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
  324. #else
  325. #if 0
  326. if(saddr.sa_family == AF_INET6) {
  327. inet_ntop(AF_INET6,
  328. &(((struct sockaddr_in6 *)&saddr)->sin6_addr),
  329. addr_str, addr_str_len);
  330. } else {
  331. inet_ntop(AF_INET,
  332. &(((struct sockaddr_in *)&saddr)->sin_addr),
  333. addr_str, addr_str_len);
  334. }
  335. #endif
  336. /* getnameinfo return ip v6 address with the scope identifier
  337. * such as : 2a01:e35:8b2b:7330::%4281128194 */
  338. n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
  339. addr_str, addr_str_len,
  340. NULL, 0,
  341. NI_NUMERICHOST | NI_NUMERICSERV);
  342. if(n != 0) {
  343. #ifdef _WIN32
  344. fprintf(stderr, "getnameinfo() failed : %d\n", n);
  345. #else
  346. fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
  347. #endif
  348. }
  349. #endif
  350. }
  351. #ifdef DEBUG
  352. printf("address miniwget : %s\n", addr_str);
  353. #endif
  354. }
  355. len = snprintf(buf, sizeof(buf),
  356. "GET %s HTTP/%s\r\n"
  357. "Host: %s:%d\r\n"
  358. "Connection: Close\r\n"
  359. "User-Agent: SKY_skyplus\r\n"
  360. "\r\n",
  361. path, httpversion, host, port);
  362. // Replaced "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
  363. sent = 0;
  364. /* sending the HTTP request */
  365. while(sent < len)
  366. {
  367. n = send(s, buf+sent, len-sent, 0);
  368. if(n < 0)
  369. {
  370. perror("send");
  371. closesocket(s);
  372. return NULL;
  373. }
  374. else
  375. {
  376. sent += n;
  377. }
  378. }
  379. content = getHTTPResponse(s, size);
  380. closesocket(s);
  381. return content;
  382. }
  383. /* miniwget2() :
  384. * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
  385. static void *
  386. miniwget2(const char * host,
  387. unsigned short port, const char * path,
  388. int * size, char * addr_str, int addr_str_len,
  389. unsigned int scope_id)
  390. {
  391. char * respbuffer;
  392. #if 1
  393. respbuffer = miniwget3(host, port, path, size,
  394. addr_str, addr_str_len, "1.1", scope_id);
  395. #else
  396. respbuffer = miniwget3(host, port, path, size,
  397. addr_str, addr_str_len, "1.0", scope_id);
  398. if (*size == 0)
  399. {
  400. #ifdef DEBUG
  401. printf("Retrying with HTTP/1.1\n");
  402. #endif
  403. free(respbuffer);
  404. respbuffer = miniwget3(host, port, path, size,
  405. addr_str, addr_str_len, "1.1", scope_id);
  406. }
  407. #endif
  408. return respbuffer;
  409. }
  410. /* parseURL()
  411. * arguments :
  412. * url : source string not modified
  413. * hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
  414. * port : port (destination)
  415. * path : pointer to the path part of the URL
  416. *
  417. * Return values :
  418. * 0 - Failure
  419. * 1 - Success */
  420. int
  421. parseURL(const char * url,
  422. char * hostname, unsigned short * port,
  423. char * * path, unsigned int * scope_id)
  424. {
  425. char * p1, *p2, *p3;
  426. if(!url)
  427. return 0;
  428. p1 = strstr(url, "://");
  429. if(!p1)
  430. return 0;
  431. p1 += 3;
  432. if( (url[0]!='h') || (url[1]!='t')
  433. ||(url[2]!='t') || (url[3]!='p'))
  434. return 0;
  435. memset(hostname, 0, MAXHOSTNAMELEN + 1);
  436. if(*p1 == '[')
  437. {
  438. /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
  439. char * scope;
  440. scope = strchr(p1, '%');
  441. p2 = strchr(p1, ']');
  442. if(p2 && scope && scope < p2 && scope_id) {
  443. /* parse scope */
  444. #ifdef IF_NAMESIZE
  445. char tmp[IF_NAMESIZE];
  446. int l;
  447. scope++;
  448. /* "%25" is just '%' in URL encoding */
  449. if(scope[0] == '2' && scope[1] == '5')
  450. scope += 2; /* skip "25" */
  451. l = p2 - scope;
  452. if(l >= IF_NAMESIZE)
  453. l = IF_NAMESIZE - 1;
  454. memcpy(tmp, scope, l);
  455. tmp[l] = '\0';
  456. *scope_id = if_nametoindex(tmp);
  457. if(*scope_id == 0) {
  458. *scope_id = (unsigned int)strtoul(tmp, NULL, 10);
  459. }
  460. #else
  461. /* under windows, scope is numerical */
  462. char tmp[8];
  463. int l;
  464. scope++;
  465. /* "%25" is just '%' in URL encoding */
  466. if(scope[0] == '2' && scope[1] == '5')
  467. scope += 2; /* skip "25" */
  468. l = p2 - scope;
  469. if(l >= sizeof(tmp))
  470. l = sizeof(tmp) - 1;
  471. memcpy(tmp, scope, l);
  472. tmp[l] = '\0';
  473. *scope_id = (unsigned int)strtoul(tmp, NULL, 10);
  474. #endif
  475. }
  476. p3 = strchr(p1, '/');
  477. if(p2 && p3)
  478. {
  479. p2++;
  480. strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
  481. if(*p2 == ':')
  482. {
  483. *port = 0;
  484. p2++;
  485. while( (*p2 >= '0') && (*p2 <= '9'))
  486. {
  487. *port *= 10;
  488. *port += (unsigned short)(*p2 - '0');
  489. p2++;
  490. }
  491. }
  492. else
  493. {
  494. *port = 80;
  495. }
  496. *path = p3;
  497. return 1;
  498. }
  499. }
  500. p2 = strchr(p1, ':');
  501. p3 = strchr(p1, '/');
  502. if(!p3)
  503. return 0;
  504. if(!p2 || (p2>p3))
  505. {
  506. strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
  507. *port = 80;
  508. }
  509. else
  510. {
  511. strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
  512. *port = 0;
  513. p2++;
  514. while( (*p2 >= '0') && (*p2 <= '9'))
  515. {
  516. *port *= 10;
  517. *port += (unsigned short)(*p2 - '0');
  518. p2++;
  519. }
  520. }
  521. *path = p3;
  522. return 1;
  523. }
  524. void *
  525. miniwget(const char * url, int * size, unsigned int scope_id)
  526. {
  527. unsigned short port;
  528. char * path;
  529. /* protocol://host:port/chemin */
  530. char hostname[MAXHOSTNAMELEN+1];
  531. *size = 0;
  532. if(!parseURL(url, hostname, &port, &path, &scope_id))
  533. return NULL;
  534. #ifdef DEBUG
  535. printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
  536. hostname, port, path, scope_id);
  537. #endif
  538. return miniwget2(hostname, port, path, size, 0, 0, scope_id);
  539. }
  540. void *
  541. miniwget_getaddr(const char * url, int * size,
  542. char * addr, int addrlen, unsigned int scope_id)
  543. {
  544. unsigned short port;
  545. char * path;
  546. /* protocol://host:port/path */
  547. char hostname[MAXHOSTNAMELEN+1];
  548. *size = 0;
  549. if(addr)
  550. addr[0] = '\0';
  551. if(!parseURL(url, hostname, &port, &path, &scope_id))
  552. return NULL;
  553. #ifdef DEBUG
  554. printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
  555. hostname, port, path, scope_id);
  556. #endif
  557. return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
  558. }