hashswf.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * Copyright (C) 2009-2010 Howard Chu
  3. *
  4. * This file is part of librtmp.
  5. *
  6. * librtmp is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as
  8. * published by the Free Software Foundation; either version 2.1,
  9. * or (at your option) any later version.
  10. *
  11. * librtmp is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with librtmp see the file COPYING. If not, write to
  18. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. * http://www.gnu.org/copyleft/lgpl.html
  21. */
  22. #ifdef USE_HASHSWF
  23. #include "rtmp_sys.h"
  24. #include "log.h"
  25. #include "http.h"
  26. #ifdef CRYPTO
  27. #ifdef __APPLE__
  28. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  29. #endif
  30. #if defined(USE_MBEDTLS)
  31. #include <mbedtls/md.h>
  32. #ifndef SHA256_DIGEST_LENGTH
  33. #define SHA256_DIGEST_LENGTH 32
  34. #endif
  35. typedef mbedtls_md_context_t *HMAC_CTX;
  36. #define HMAC_setup(ctx, key, len) ctx = malloc(sizeof(mbedtls_md_context_t)); mbedtls_md_init(ctx); \
  37. mbedtls_md_setup(ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); \
  38. mbedtls_md_hmac_starts(ctx, (const unsigned char *)key, len)
  39. #define HMAC_crunch(ctx, buf, len) mbedtls_md_hmac_update(ctx, buf, len)
  40. #define HMAC_finish(ctx, dig) mbedtls_md_hmac_finish(ctx, dig)
  41. #define HMAC_close(ctx) free(ctx); mbedtls_md_free(ctx); ctx = NULL
  42. #elif defined(USE_POLARSSL)
  43. #include <polarssl/sha2.h>
  44. #ifndef SHA256_DIGEST_LENGTH
  45. #define SHA256_DIGEST_LENGTH 32
  46. #endif
  47. #define HMAC_CTX sha2_context
  48. #define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0)
  49. #define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len)
  50. #define HMAC_finish(ctx, dig) sha2_hmac_finish(&ctx, dig)
  51. #define HMAC_close(ctx)
  52. #elif defined(USE_GNUTLS)
  53. #include <nettle/hmac.h>
  54. #ifndef SHA256_DIGEST_LENGTH
  55. #define SHA256_DIGEST_LENGTH 32
  56. #endif
  57. #undef HMAC_CTX
  58. #define HMAC_CTX struct hmac_sha256_ctx
  59. #define HMAC_setup(ctx, key, len) hmac_sha256_set_key(&ctx, len, key)
  60. #define HMAC_crunch(ctx, buf, len) hmac_sha256_update(&ctx, len, buf)
  61. #define HMAC_finish(ctx, dig) hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, dig)
  62. #define HMAC_close(ctx)
  63. #else /* USE_OPENSSL */
  64. #include <openssl/ssl.h>
  65. #include <openssl/sha.h>
  66. #include <openssl/hmac.h>
  67. #include <openssl/rc4.h>
  68. #define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, (unsigned char *)key, len, EVP_sha256(), 0)
  69. #define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, (unsigned char *)buf, len)
  70. #define HMAC_finish(ctx, dig, len) HMAC_Final(&ctx, (unsigned char *)dig, &len);
  71. #define HMAC_close(ctx) HMAC_CTX_cleanup(&ctx)
  72. #endif
  73. #include <zlib.h>
  74. #endif /* CRYPTO */
  75. #define AGENT "Mozilla/5.0"
  76. HTTPResult
  77. HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
  78. {
  79. char *host, *path;
  80. char *p1, *p2;
  81. char hbuf[256];
  82. int port = 80;
  83. #ifdef CRYPTO
  84. int ssl = 0;
  85. #endif
  86. int hlen, flen = 0;
  87. int rc, i;
  88. int len_known;
  89. HTTPResult ret = HTTPRES_OK;
  90. struct sockaddr_in sa;
  91. RTMPSockBuf sb = {0};
  92. http->status = -1;
  93. memset(&sa, 0, sizeof(struct sockaddr_in));
  94. sa.sin_family = AF_INET;
  95. /* we only handle http here */
  96. if (strncasecmp(url, "http", 4))
  97. return HTTPRES_BAD_REQUEST;
  98. if (url[4] == 's')
  99. {
  100. #ifdef CRYPTO
  101. ssl = 1;
  102. port = 443;
  103. if (!RTMP_TLS_ctx)
  104. RTMP_TLS_Init();
  105. #else
  106. return HTTPRES_BAD_REQUEST;
  107. #endif
  108. }
  109. p1 = strchr(url + 4, ':');
  110. if (!p1 || strncmp(p1, "://", 3))
  111. return HTTPRES_BAD_REQUEST;
  112. host = p1 + 3;
  113. path = strchr(host, '/');
  114. hlen = path - host;
  115. strncpy(hbuf, host, hlen);
  116. hbuf[hlen] = '\0';
  117. host = hbuf;
  118. p1 = strrchr(host, ':');
  119. if (p1)
  120. {
  121. *p1++ = '\0';
  122. port = atoi(p1);
  123. }
  124. sa.sin_addr.s_addr = inet_addr(host);
  125. if (sa.sin_addr.s_addr == INADDR_NONE)
  126. {
  127. struct hostent *hp = gethostbyname(host);
  128. if (!hp || !hp->h_addr)
  129. return HTTPRES_LOST_CONNECTION;
  130. sa.sin_addr = *(struct in_addr *)hp->h_addr;
  131. }
  132. sa.sin_port = htons(port);
  133. sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  134. if (sb.sb_socket == INVALID_SOCKET)
  135. return HTTPRES_LOST_CONNECTION;
  136. i =
  137. snprintf(sb.sb_buf, RTMP_BUFFER_CACHE_SIZE,
  138. "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferer: %.*s\r\n",
  139. path, AGENT, host, (int)(path - url + 1), url);
  140. if (http->date[0])
  141. i += snprintf(sb.sb_buf + i, RTMP_BUFFER_CACHE_SIZE, "If-Modified-Since: %s\r\n", http->date);
  142. i += snprintf(sb.sb_buf + i, RTMP_BUFFER_CACHE_SIZE, "\r\n");
  143. if (connect
  144. (sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0)
  145. {
  146. ret = HTTPRES_LOST_CONNECTION;
  147. goto leave;
  148. }
  149. #ifdef CRYPTO
  150. if (ssl)
  151. {
  152. #ifdef NO_SSL
  153. RTMP_Log(RTMP_LOGERROR, "%s, No SSL/TLS support", __FUNCTION__);
  154. ret = HTTPRES_BAD_REQUEST;
  155. goto leave;
  156. #else
  157. TLS_client(RTMP_TLS_ctx, sb.sb_ssl);
  158. #if defined(USE_MBEDTLS)
  159. mbedtls_net_context *server_fd = &RTMP_TLS_ctx->net;
  160. server_fd->fd = sb.sb_socket;
  161. TLS_setfd(sb.sb_ssl, server_fd);
  162. #else
  163. TLS_setfd(sb.sb_ssl, sb.sb_socket);
  164. #endif
  165. int connect_return = TLS_connect(sb.sb_ssl);
  166. if (connect_return < 0)
  167. {
  168. RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
  169. ret = HTTPRES_LOST_CONNECTION;
  170. goto leave;
  171. }
  172. #endif
  173. }
  174. #endif
  175. RTMPSockBuf_Send(&sb, sb.sb_buf, i);
  176. /* set timeout */
  177. #define HTTP_TIMEOUT 5
  178. {
  179. SET_RCVTIMEO(tv, HTTP_TIMEOUT);
  180. if (setsockopt
  181. (sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
  182. {
  183. RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
  184. __FUNCTION__, HTTP_TIMEOUT);
  185. }
  186. }
  187. sb.sb_size = 0;
  188. sb.sb_timedout = FALSE;
  189. if (RTMPSockBuf_Fill(&sb) < 1)
  190. {
  191. ret = HTTPRES_LOST_CONNECTION;
  192. goto leave;
  193. }
  194. if (strncmp(sb.sb_buf, "HTTP/1", 6))
  195. {
  196. ret = HTTPRES_BAD_REQUEST;
  197. goto leave;
  198. }
  199. p1 = strchr(sb.sb_buf, ' ');
  200. rc = atoi(p1 + 1);
  201. http->status = rc;
  202. if (rc >= 300)
  203. {
  204. if (rc == 304)
  205. {
  206. ret = HTTPRES_OK_NOT_MODIFIED;
  207. goto leave;
  208. }
  209. else if (rc == 404)
  210. ret = HTTPRES_NOT_FOUND;
  211. else if (rc >= 500)
  212. ret = HTTPRES_SERVER_ERROR;
  213. else if (rc >= 400)
  214. ret = HTTPRES_BAD_REQUEST;
  215. else
  216. ret = HTTPRES_REDIRECTED;
  217. }
  218. p1 = memchr(sb.sb_buf, '\n', sb.sb_size);
  219. if (!p1)
  220. {
  221. ret = HTTPRES_BAD_REQUEST;
  222. goto leave;
  223. }
  224. sb.sb_start = p1 + 1;
  225. sb.sb_size -= sb.sb_start - sb.sb_buf;
  226. while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size)))
  227. {
  228. if (*sb.sb_start == '\r')
  229. {
  230. sb.sb_start += 2;
  231. sb.sb_size -= 2;
  232. break;
  233. }
  234. else if (!strncasecmp
  235. (sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1))
  236. {
  237. flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1);
  238. }
  239. else if (!strncasecmp
  240. (sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1))
  241. {
  242. *p2 = '\0';
  243. strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1);
  244. }
  245. p2 += 2;
  246. sb.sb_size -= p2 - sb.sb_start;
  247. sb.sb_start = p2;
  248. if (sb.sb_size < 1)
  249. {
  250. if (RTMPSockBuf_Fill(&sb) < 1)
  251. {
  252. ret = HTTPRES_LOST_CONNECTION;
  253. goto leave;
  254. }
  255. }
  256. }
  257. len_known = flen > 0;
  258. while ((!len_known || flen > 0) &&
  259. (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
  260. {
  261. cb(sb.sb_start, 1, sb.sb_size, http->data);
  262. if (len_known)
  263. flen -= sb.sb_size;
  264. http->size += sb.sb_size;
  265. sb.sb_size = 0;
  266. }
  267. if (flen > 0)
  268. ret = HTTPRES_LOST_CONNECTION;
  269. leave:
  270. RTMPSockBuf_Close(&sb);
  271. return ret;
  272. }
  273. #ifdef CRYPTO
  274. #define CHUNK 16384
  275. struct info
  276. {
  277. z_stream *zs;
  278. HMAC_CTX ctx;
  279. int first;
  280. int zlib;
  281. int size;
  282. };
  283. static size_t
  284. swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
  285. {
  286. struct info *i = stream;
  287. char *p = ptr;
  288. size_t len = size * nmemb;
  289. if (i->first)
  290. {
  291. i->first = 0;
  292. /* compressed? */
  293. if (!strncmp(p, "CWS", 3))
  294. {
  295. *p = 'F';
  296. i->zlib = 1;
  297. }
  298. HMAC_crunch(i->ctx, (unsigned char *)p, 8);
  299. p += 8;
  300. len -= 8;
  301. i->size = 8;
  302. }
  303. if (i->zlib)
  304. {
  305. unsigned char out[CHUNK];
  306. i->zs->next_in = (unsigned char *)p;
  307. i->zs->avail_in = (uInt)len;
  308. do
  309. {
  310. i->zs->avail_out = CHUNK;
  311. i->zs->next_out = out;
  312. inflate(i->zs, Z_NO_FLUSH);
  313. len = CHUNK - i->zs->avail_out;
  314. i->size += (int)len;
  315. HMAC_crunch(i->ctx, out, len);
  316. }
  317. while (i->zs->avail_out == 0);
  318. }
  319. else
  320. {
  321. i->size += (int)len;
  322. HMAC_crunch(i->ctx, (unsigned char *)p, len);
  323. }
  324. return size * nmemb;
  325. }
  326. static int tzoff;
  327. static int tzchecked;
  328. #define JAN02_1980 318340800
  329. static const char *monthtab[12] = { "Jan", "Feb", "Mar",
  330. "Apr", "May", "Jun",
  331. "Jul", "Aug", "Sep",
  332. "Oct", "Nov", "Dec"
  333. };
  334. static const char *days[] =
  335. { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  336. /* Parse an HTTP datestamp into Unix time */
  337. static time_t
  338. make_unix_time(char *s)
  339. {
  340. struct tm time;
  341. int i, ysub = 1900, fmt = 0;
  342. char *month;
  343. char *n;
  344. time_t res;
  345. if (s[3] != ' ')
  346. {
  347. fmt = 1;
  348. if (s[3] != ',')
  349. ysub = 0;
  350. }
  351. for (n = s; *n; ++n)
  352. if (*n == '-' || *n == ':')
  353. *n = ' ';
  354. time.tm_mon = 0;
  355. n = strchr(s, ' ');
  356. if (fmt)
  357. {
  358. /* Day, DD-MMM-YYYY HH:MM:SS GMT */
  359. time.tm_mday = strtol(n + 1, &n, 0);
  360. month = n + 1;
  361. n = strchr(month, ' ');
  362. time.tm_year = strtol(n + 1, &n, 0);
  363. time.tm_hour = strtol(n + 1, &n, 0);
  364. time.tm_min = strtol(n + 1, &n, 0);
  365. time.tm_sec = strtol(n + 1, NULL, 0);
  366. }
  367. else
  368. {
  369. /* Unix ctime() format. Does not conform to HTTP spec. */
  370. /* Day MMM DD HH:MM:SS YYYY */
  371. month = n + 1;
  372. n = strchr(month, ' ');
  373. while (isspace(*n))
  374. n++;
  375. time.tm_mday = strtol(n, &n, 0);
  376. time.tm_hour = strtol(n + 1, &n, 0);
  377. time.tm_min = strtol(n + 1, &n, 0);
  378. time.tm_sec = strtol(n + 1, &n, 0);
  379. time.tm_year = strtol(n + 1, NULL, 0);
  380. }
  381. if (time.tm_year > 100)
  382. time.tm_year -= ysub;
  383. for (i = 0; i < 12; i++)
  384. if (!strncasecmp(month, monthtab[i], 3))
  385. {
  386. time.tm_mon = i;
  387. break;
  388. }
  389. time.tm_isdst = 0; /* daylight saving is never in effect in GMT */
  390. /* this is normally the value of extern int timezone, but some
  391. * braindead C libraries don't provide it.
  392. */
  393. if (!tzchecked)
  394. {
  395. struct tm *tc;
  396. time_t then = JAN02_1980;
  397. tc = localtime(&then);
  398. tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec;
  399. tzchecked = 1;
  400. }
  401. res = mktime(&time);
  402. /* Unfortunately, mktime() assumes the input is in local time,
  403. * not GMT, so we have to correct it here.
  404. */
  405. if (res != -1)
  406. res += tzoff;
  407. return res;
  408. }
  409. /* Convert a Unix time to a network time string
  410. * Weekday, DD-MMM-YYYY HH:MM:SS GMT
  411. */
  412. static void
  413. strtime(time_t * t, char *s, size_t size)
  414. {
  415. struct tm *tm;
  416. tm = gmtime((time_t *) t);
  417. snprintf(s, size, "%s, %02d %s %d %02d:%02d:%02d GMT",
  418. days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon],
  419. tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
  420. }
  421. #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
  422. int
  423. RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
  424. int age)
  425. {
  426. FILE *f = NULL;
  427. char *path, date[64], cctim[64];
  428. long pos = 0;
  429. time_t ctim = -1, cnow;
  430. int i, got = 0, ret = 0;
  431. unsigned int hlen;
  432. struct info in = { 0 };
  433. struct HTTP_ctx http = { 0 };
  434. HTTPResult httpres;
  435. z_stream zs = { 0 };
  436. AVal home, hpre;
  437. date[0] = '\0';
  438. #ifdef _WIN32
  439. #ifdef XBMC4XBOX
  440. hpre.av_val = "Q:";
  441. hpre.av_len = 2;
  442. home.av_val = "\\UserData";
  443. #else
  444. hpre.av_val = getenv("HOMEDRIVE");
  445. hpre.av_len = (int)strlen(hpre.av_val);
  446. home.av_val = getenv("HOMEPATH");
  447. #endif
  448. #define DIRSEP "\\"
  449. #else /* !_WIN32 */
  450. hpre.av_val = "";
  451. hpre.av_len = 0;
  452. home.av_val = getenv("HOME");
  453. #define DIRSEP "/"
  454. #endif
  455. if (!home.av_val)
  456. home.av_val = ".";
  457. home.av_len = (int)strlen(home.av_val);
  458. /* SWF hash info is cached in a fixed-format file.
  459. * url: <url of SWF file>
  460. * ctim: HTTP datestamp of when we last checked it.
  461. * date: HTTP datestamp of the SWF's last modification.
  462. * size: SWF size in hex
  463. * hash: SWF hash in hex
  464. *
  465. * These fields must be present in this order. All fields
  466. * besides URL are fixed size.
  467. */
  468. size_t path_size = hpre.av_len + home.av_len + sizeof(DIRSEP ".swfinfo");
  469. path = malloc(path_size);
  470. snprintf(path, path_size, "%s%s" DIRSEP ".swfinfo", hpre.av_val, home.av_val);
  471. f = fopen(path, "r+");
  472. while (f)
  473. {
  474. char buf[4096], *file, *p;
  475. file = strchr(url, '/');
  476. if (!file)
  477. break;
  478. file += 2;
  479. file = strchr(file, '/');
  480. if (!file)
  481. break;
  482. file++;
  483. hlen = file - url;
  484. p = strrchr(file, '/');
  485. if (p)
  486. file = p;
  487. else
  488. file--;
  489. while (fgets(buf, sizeof(buf), f))
  490. {
  491. char *r1;
  492. got = 0;
  493. if (strncmp(buf, "url: ", 5))
  494. continue;
  495. if (strncmp(buf + 5, url, hlen))
  496. continue;
  497. r1 = strrchr(buf, '/');
  498. i = (int)strlen(r1);
  499. r1[--i] = '\0';
  500. if (strncmp(r1, file, i))
  501. continue;
  502. pos = ftell(f);
  503. while (got < 4 && fgets(buf, sizeof(buf), f))
  504. {
  505. if (!strncmp(buf, "size: ", 6))
  506. {
  507. *size = strtol(buf + 6, NULL, 16);
  508. got++;
  509. }
  510. else if (!strncmp(buf, "hash: ", 6))
  511. {
  512. unsigned char *ptr = hash, *in = (unsigned char *)buf + 6;
  513. int l = (int)strlen((char *)in) - 1;
  514. for (i = 0; i < l; i += 2)
  515. *ptr++ = (HEX2BIN(in[i]) << 4) | HEX2BIN(in[i + 1]);
  516. got++;
  517. }
  518. else if (!strncmp(buf, "date: ", 6))
  519. {
  520. buf[strlen(buf) - 1] = '\0';
  521. strncpy(date, buf + 6, sizeof(date));
  522. got++;
  523. }
  524. else if (!strncmp(buf, "ctim: ", 6))
  525. {
  526. buf[strlen(buf) - 1] = '\0';
  527. ctim = make_unix_time(buf + 6);
  528. got++;
  529. }
  530. else if (!strncmp(buf, "url: ", 5))
  531. break;
  532. }
  533. break;
  534. }
  535. break;
  536. }
  537. cnow = time(NULL);
  538. /* If we got a cache time, see if it's young enough to use directly */
  539. if (age && ctim > 0)
  540. {
  541. ctim = cnow - ctim;
  542. ctim /= 3600 * 24; /* seconds to days */
  543. if (ctim < age) /* ok, it's new enough */
  544. goto out;
  545. }
  546. in.first = 1;
  547. HMAC_setup(in.ctx, "Genuine Adobe Flash Player 001", 30);
  548. inflateInit(&zs);
  549. in.zs = &zs;
  550. http.date = date;
  551. http.data = &in;
  552. httpres = HTTP_get(&http, url, swfcrunch);
  553. inflateEnd(&zs);
  554. if (httpres != HTTPRES_OK && httpres != HTTPRES_OK_NOT_MODIFIED)
  555. {
  556. ret = -1;
  557. if (httpres == HTTPRES_LOST_CONNECTION)
  558. RTMP_Log(RTMP_LOGERROR, "%s: connection lost while downloading swfurl %s",
  559. __FUNCTION__, url);
  560. else if (httpres == HTTPRES_NOT_FOUND)
  561. RTMP_Log(RTMP_LOGERROR, "%s: swfurl %s not found", __FUNCTION__, url);
  562. else
  563. RTMP_Log(RTMP_LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)",
  564. __FUNCTION__, url, http.status);
  565. }
  566. else
  567. {
  568. if (got && pos)
  569. fseek(f, pos, SEEK_SET);
  570. else
  571. {
  572. char *q;
  573. if (!f)
  574. f = fopen(path, "w");
  575. if (!f)
  576. {
  577. int err = errno;
  578. RTMP_Log(RTMP_LOGERROR,
  579. "%s: couldn't open %s for writing, errno %d (%s)",
  580. __FUNCTION__, path, err, strerror(err));
  581. ret = -1;
  582. goto out;
  583. }
  584. fseek(f, 0, SEEK_END);
  585. q = strchr(url, '?');
  586. if (q)
  587. i = q - url;
  588. else
  589. i = (int)strlen(url);
  590. fprintf(f, "url: %.*s\n", i, url);
  591. }
  592. strtime(&cnow, cctim, sizeof(cctim));
  593. fprintf(f, "ctim: %s\n", cctim);
  594. if (!in.first)
  595. {
  596. #if defined(USE_MBEDTLS) || defined(USE_POLARSSL) || defined(USE_GNUTLS)
  597. HMAC_finish(in.ctx, hash);
  598. #else
  599. HMAC_finish(in.ctx, hash, hlen);
  600. #endif
  601. *size = in.size;
  602. fprintf(f, "date: %s\n", date);
  603. fprintf(f, "size: %08x\n", in.size);
  604. fprintf(f, "hash: ");
  605. for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
  606. fprintf(f, "%02x", hash[i]);
  607. fprintf(f, "\n");
  608. }
  609. }
  610. HMAC_close(in.ctx);
  611. out:
  612. free(path);
  613. if (f)
  614. fclose(f);
  615. return ret;
  616. }
  617. #else
  618. int
  619. RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
  620. int age)
  621. {
  622. (void)url;
  623. (void)size;
  624. (void)hash;
  625. (void)age;
  626. return -1;
  627. }
  628. #endif
  629. #endif