VirtualIO.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. #include "main.h"
  2. #include "VirtualIO.h"
  3. #include "api__in_mp4.h"
  4. #include "api/service/waservicefactory.h"
  5. #include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
  6. #include "../nu/AutoChar.h"
  7. #include "../nu/ProgressTracker.h"
  8. #include <assert.h>
  9. #include <strsafe.h>
  10. #define HTTP_BUFFER_SIZE 65536
  11. // {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
  12. static const GUID internetConfigGroupGUID =
  13. {
  14. 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
  15. };
  16. static void SetUserAgent(api_httpreceiver *http)
  17. {
  18. char agent[256] = {0};
  19. StringCchPrintfA(agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString());
  20. http->addheader(agent);
  21. }
  22. static api_httpreceiver *SetupConnection(const char *url, uint64_t start_position, uint64_t end_position)
  23. {
  24. api_httpreceiver *http = 0;
  25. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  26. if (sf) http = (api_httpreceiver *)sf->getInterface();
  27. if (!http)
  28. return http;
  29. int use_proxy = 1;
  30. bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
  31. if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
  32. use_proxy = 0;
  33. const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
  34. http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
  35. if (start_position && start_position != (uint64_t)-1)
  36. {
  37. if (end_position == (uint64_t)-1)
  38. {
  39. char temp[128] = {0};
  40. StringCchPrintfA(temp, 128, "Range: bytes=%I64u-", start_position);
  41. http->addheader(temp);
  42. }
  43. else
  44. {
  45. char temp[128] = {0};
  46. StringCchPrintfA(temp, 128, "Range: bytes=%I64u-%I64u", start_position, end_position);
  47. http->addheader(temp);
  48. }
  49. }
  50. SetUserAgent(http);
  51. http->connect(url);
  52. return http;
  53. }
  54. static DWORD CALLBACK ProgressiveThread(LPVOID param);
  55. static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
  56. {
  57. LARGE_INTEGER li;
  58. li.QuadPart = distance;
  59. li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
  60. if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
  61. {
  62. li.QuadPart = -1;
  63. }
  64. return li.QuadPart;
  65. }
  66. int bufferCount;
  67. static void Buffering(int bufStatus, const wchar_t *displayString)
  68. {
  69. if (bufStatus < 0 || bufStatus > 100)
  70. return;
  71. char tempdata[75*2] = {0, };
  72. int csa = mod.SAGetMode();
  73. if (csa & 1)
  74. {
  75. for (int x = 0; x < bufStatus*75 / 100; x ++)
  76. tempdata[x] = x * 16 / 75;
  77. }
  78. else if (csa&2)
  79. {
  80. int offs = (csa & 1) ? 75 : 0;
  81. int x = 0;
  82. while (x < bufStatus*75 / 100)
  83. {
  84. tempdata[offs + x++] = -6 + x * 14 / 75;
  85. }
  86. while (x < 75)
  87. {
  88. tempdata[offs + x++] = 0;
  89. }
  90. }
  91. else if (csa == 4)
  92. {
  93. tempdata[0] = tempdata[1] = (bufStatus * 127 / 100);
  94. }
  95. if (csa) mod.SAAdd(tempdata, ++bufferCount, (csa == 3) ? 0x80000003 : csa);
  96. /*
  97. TODO
  98. wchar_t temp[64] = {0};
  99. StringCchPrintf(temp, 64, L"%s: %d%%",displayString, bufStatus);
  100. SetStatus(temp);
  101. */
  102. //SetVideoStatusText(temp); // TODO: find a way to set the old status back
  103. // videoOutput->notifyBufferState(static_cast<int>(bufStatus*2.55f));
  104. }
  105. class ProgressiveReader
  106. {
  107. public:
  108. ProgressiveReader(const char *url, HANDLE killswitch) : killswitch(killswitch)
  109. {
  110. thread_abort = CreateEvent(NULL, FALSE, FALSE, NULL);
  111. download_thread = 0;
  112. progressive_file_read = 0;
  113. progressive_file_write = 0;
  114. content_length=0;
  115. current_position=0;
  116. stream_disconnected=false;
  117. connected=false;
  118. end_of_file=false;
  119. wchar_t temppath[MAX_PATH-14] = {0}; // MAX_PATH-14 'cause MSDN said so
  120. GetTempPathW(MAX_PATH-14, temppath);
  121. GetTempFileNameW(temppath, L"wdl", 0, filename);
  122. this->url = _strdup(url);
  123. http = SetupConnection(url, 0, (uint64_t)-1);
  124. progressive_file_read = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
  125. progressive_file_write = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
  126. download_thread = CreateThread(0, 0, ProgressiveThread, this, 0, 0);
  127. while (!connected && !stream_disconnected && WaitForSingleObject(killswitch, 55) == WAIT_TIMEOUT)
  128. {
  129. // nop
  130. }
  131. Buffer();
  132. }
  133. ~ProgressiveReader()
  134. {
  135. if (download_thread)
  136. {
  137. SetEvent(thread_abort);
  138. WaitForSingleObject(download_thread, INFINITE);
  139. CloseHandle(download_thread);
  140. }
  141. if (thread_abort)
  142. {
  143. CloseHandle(thread_abort);
  144. }
  145. CloseHandle(progressive_file_read);
  146. CloseHandle(progressive_file_write);
  147. DeleteFile(filename);
  148. if (http)
  149. {
  150. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  151. if (sf) http = (api_httpreceiver *)sf->releaseInterface(http);
  152. http=0;
  153. }
  154. }
  155. void Buffer()
  156. {
  157. bufferCount=0;
  158. for (int i=0;i<101;i++)
  159. {
  160. Buffering(i, L"Buffering: ");
  161. WaitForSingleObject(killswitch, 55);
  162. }
  163. }
  164. void OnFinish()
  165. {
  166. stream_disconnected=true;
  167. }
  168. bool WaitForPosition(uint64_t position, uint64_t size)
  169. {
  170. do
  171. {
  172. bool valid = progress_tracker.Valid(position, position+size);
  173. if (valid)
  174. return true;
  175. else
  176. {
  177. if (position < current_position)
  178. {
  179. Reconnect(position, position+size);
  180. }
  181. else
  182. {
  183. Buffer();
  184. }
  185. }
  186. } while (WaitForSingleObject(killswitch, 0) == WAIT_TIMEOUT);
  187. return false;
  188. }
  189. size_t Read(void *buffer, size_t size)
  190. {
  191. if (WaitForPosition(current_position, (uint64_t)size) == false)
  192. return 0;
  193. DWORD bytes_read=0;
  194. ReadFile(progressive_file_read, buffer, size, &bytes_read, NULL);
  195. current_position += bytes_read;
  196. return bytes_read;
  197. }
  198. uint64_t GetFileLength()
  199. {
  200. return content_length;
  201. }
  202. void Reconnect(uint64_t position, uint64_t end)
  203. {
  204. SetEvent(thread_abort);
  205. WaitForSingleObject(download_thread, INFINITE);
  206. ResetEvent(thread_abort);
  207. uint64_t new_start, new_end;
  208. progress_tracker.Seek(position, end, &new_start, &new_end);
  209. CloseHandle(download_thread);
  210. stream_disconnected=false;
  211. connected=false;
  212. if (http)
  213. {
  214. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  215. if (sf) http = (api_httpreceiver *)sf->releaseInterface(http);
  216. http=0;
  217. }
  218. http = SetupConnection(url, new_start, new_end);
  219. Seek64(progressive_file_write, new_start, SEEK_SET);
  220. download_thread = CreateThread(0, 0, ProgressiveThread, this, 0, 0);
  221. while (!connected && !stream_disconnected && WaitForSingleObject(killswitch, 55) == WAIT_TIMEOUT)
  222. {
  223. // nop
  224. }
  225. Buffer();
  226. }
  227. int SetPosition(uint64_t position)
  228. {
  229. if (position == content_length)
  230. {
  231. end_of_file=true;
  232. }
  233. else
  234. {
  235. if (!progress_tracker.Valid(position, position))
  236. {
  237. Reconnect(position, (uint64_t)-1);
  238. }
  239. current_position = Seek64(progressive_file_read, position, SEEK_SET);
  240. end_of_file=false;
  241. }
  242. return 0;
  243. }
  244. int GetPosition(uint64_t *position)
  245. {
  246. if (end_of_file)
  247. *position = content_length;
  248. else
  249. *position = current_position;
  250. return 0;
  251. }
  252. int EndOfFile()
  253. {
  254. return !!stream_disconnected;
  255. }
  256. int Close()
  257. {
  258. SetEvent(thread_abort);
  259. while (!stream_disconnected && WaitForSingleObject(killswitch, 55) == WAIT_TIMEOUT)
  260. {
  261. // nop
  262. }
  263. return 0;
  264. }
  265. /* API used by download thread */
  266. void Write(const void *data, size_t data_len)
  267. {
  268. DWORD bytes_written = 0;
  269. WriteFile(progressive_file_write, data, data_len, &bytes_written, 0);
  270. progress_tracker.Write(data_len);
  271. }
  272. int Wait(int milliseconds)
  273. {
  274. HANDLE handles[] = {killswitch, thread_abort};
  275. int ret = WaitForMultipleObjects(2, handles, FALSE, milliseconds);
  276. if (ret == WAIT_OBJECT_0+1)
  277. return 1;
  278. else if (ret == WAIT_TIMEOUT)
  279. return 0;
  280. else
  281. return -1;
  282. }
  283. int DoRead(void *buffer, size_t bufferlen)
  284. {
  285. int ret = http->run();
  286. int bytes_received;
  287. do
  288. {
  289. ret = http->run();
  290. bytes_received= http->get_bytes(buffer, bufferlen);
  291. if (bytes_received)
  292. Write(buffer, bytes_received);
  293. } while (bytes_received);
  294. return ret;
  295. }
  296. int Connect()
  297. {
  298. do
  299. {
  300. int ret = http->run();
  301. if (ret == -1) // connection failed
  302. return ret;
  303. // ---- check our reply code ----
  304. int replycode = http->getreplycode();
  305. switch (replycode)
  306. {
  307. case 0:
  308. case 100:
  309. break;
  310. case 200:
  311. case 206:
  312. {
  313. const char *content_length_header = http->getheader("Content-Length");
  314. if (content_length_header)
  315. {
  316. uint64_t new_content_length = _strtoui64(content_length_header, 0, 10);
  317. //InterlockedExchange64((volatile LONGLONG *)&content_length, new_content_length);
  318. content_length = new_content_length; // TODO interlock on win32
  319. }
  320. connected=true;
  321. return 0;
  322. }
  323. default:
  324. return -1;
  325. }
  326. }
  327. while (Wait(55) == 0);
  328. return 0;
  329. }
  330. private:
  331. uint64_t current_position;
  332. volatile uint64_t content_length;
  333. bool end_of_file;
  334. bool stream_disconnected;
  335. bool connected;
  336. char *url;
  337. wchar_t filename[MAX_PATH];
  338. HANDLE progressive_file_read, progressive_file_write;
  339. ProgressTracker progress_tracker;
  340. HANDLE killswitch;
  341. HANDLE download_thread;
  342. api_httpreceiver *http;
  343. HANDLE thread_abort;
  344. };
  345. static DWORD CALLBACK ProgressiveThread(LPVOID param)
  346. {
  347. ProgressiveReader *reader = (ProgressiveReader *)param;
  348. if (reader->Connect() == 0)
  349. {
  350. int ret = 0;
  351. while (ret == 0)
  352. {
  353. ret=reader->Wait(10);
  354. if (ret >= 0)
  355. {
  356. char buffer[HTTP_BUFFER_SIZE] = {0};
  357. reader->DoRead(buffer, sizeof(buffer));
  358. }
  359. }
  360. }
  361. reader->OnFinish();
  362. return 0;
  363. }
  364. u_int64_t HTTPGetFileLength(void *user)
  365. {
  366. ProgressiveReader *reader = (ProgressiveReader *)user;
  367. return reader->GetFileLength();
  368. }
  369. int HTTPSetPosition(void *user, u_int64_t position)
  370. {
  371. ProgressiveReader *reader = (ProgressiveReader *)user;
  372. return reader->SetPosition(position);
  373. }
  374. int HTTPGetPosition(void *user, u_int64_t *position)
  375. {
  376. ProgressiveReader *reader = (ProgressiveReader *)user;
  377. return reader->GetPosition(position);
  378. }
  379. size_t HTTPRead(void *user, void *buffer, size_t size)
  380. {
  381. ProgressiveReader *reader = (ProgressiveReader *)user;
  382. return reader->Read(buffer, size);
  383. }
  384. size_t HTTPWrite(void *user, void *buffer, size_t size)
  385. {
  386. return 1;
  387. }
  388. int HTTPEndOfFile(void *user)
  389. {
  390. ProgressiveReader *reader = (ProgressiveReader *)user;
  391. return reader->EndOfFile();
  392. }
  393. int HTTPClose(void *user)
  394. {
  395. ProgressiveReader *reader = (ProgressiveReader *)user;
  396. return reader->Close();
  397. }
  398. Virtual_IO HTTPIO =
  399. {
  400. HTTPGetFileLength,
  401. HTTPSetPosition,
  402. HTTPGetPosition,
  403. HTTPRead,
  404. HTTPWrite,
  405. HTTPEndOfFile,
  406. HTTPClose,
  407. };
  408. void *CreateReader(const wchar_t *url, HANDLE killswitch)
  409. {
  410. if ( WAC_API_DOWNLOADMANAGER )
  411. {
  412. return new ProgressiveReader(AutoChar(url), killswitch);
  413. }
  414. else
  415. return 0;
  416. }
  417. void DestroyReader(void *user)
  418. {
  419. ProgressiveReader *reader = (ProgressiveReader *)user;
  420. delete reader;
  421. }
  422. void StopReader(void *user)
  423. {
  424. ProgressiveReader *reader = (ProgressiveReader *)user;
  425. reader->Close();
  426. }
  427. /* ----------------------------------- */
  428. struct Win32_State
  429. {
  430. Win32_State()
  431. {
  432. memset(buffer, 0, sizeof(buffer));
  433. handle=0;
  434. endOfFile=false;
  435. position.QuadPart = 0;
  436. event = CreateEvent(NULL, TRUE, TRUE, NULL);
  437. read_offset=0;
  438. io_active=false;
  439. }
  440. ~Win32_State()
  441. {
  442. if (handle && handle != INVALID_HANDLE_VALUE)
  443. CancelIo(handle);
  444. CloseHandle(event);
  445. }
  446. // void *userData;
  447. HANDLE handle;
  448. bool endOfFile;
  449. LARGE_INTEGER position;
  450. HANDLE event;
  451. OVERLAPPED overlapped;
  452. DWORD read_offset;
  453. bool io_active;
  454. char buffer[16384];
  455. };
  456. static __int64 FileSize64(HANDLE file)
  457. {
  458. LARGE_INTEGER position;
  459. position.QuadPart=0;
  460. position.LowPart = GetFileSize(file, (LPDWORD)&position.HighPart);
  461. if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
  462. return INVALID_FILE_SIZE;
  463. else
  464. return position.QuadPart;
  465. }
  466. u_int64_t UnicodeGetFileLength(void *user)
  467. {
  468. Win32_State *state = static_cast<Win32_State *>(user);
  469. assert(state->handle);
  470. return FileSize64(state->handle);
  471. }
  472. int UnicodeSetPosition(void *user, u_int64_t position)
  473. {
  474. Win32_State *state = static_cast<Win32_State *>(user);
  475. assert(state->handle);
  476. __int64 diff = position - state->position.QuadPart;
  477. if ((diff+state->read_offset) >= sizeof(state->buffer)
  478. || (diff+state->read_offset) < 0)
  479. {
  480. CancelIo(state->handle);
  481. state->io_active = 0;
  482. state->read_offset = 0;
  483. }
  484. else if (diff)
  485. state->read_offset += (DWORD)diff;
  486. state->position.QuadPart = position;
  487. state->endOfFile = false;
  488. return 0;
  489. }
  490. int UnicodeGetPosition(void *user, u_int64_t *position)
  491. {
  492. Win32_State *state = static_cast<Win32_State *>(user);
  493. assert(state->handle);
  494. *position = state->position.QuadPart;
  495. return 0;
  496. }
  497. static void DoRead(Win32_State *state)
  498. {
  499. WaitForSingleObject(state->event, INFINITE);
  500. state->overlapped.hEvent = state->event;
  501. state->overlapped.Offset = state->position.LowPart;
  502. state->overlapped.OffsetHigh = state->position.HighPart;
  503. state->read_offset = 0;
  504. ResetEvent(state->event);
  505. ReadFile(state->handle, state->buffer, sizeof(state->buffer), NULL, &state->overlapped);
  506. //int error = GetLastError();//ERROR_IO_PENDING = 997
  507. state->io_active=true;
  508. }
  509. size_t UnicodeRead(void *user, void *buffer, size_t size)
  510. {
  511. Win32_State *state = static_cast<Win32_State *>(user);
  512. assert(state->handle);
  513. size_t totalRead=0;
  514. HANDLE file = state->handle;
  515. if (!state->io_active)
  516. {
  517. DoRead(state);
  518. }
  519. if (state->read_offset == sizeof(state->buffer))
  520. {
  521. DoRead(state);
  522. }
  523. while (size > (sizeof(state->buffer) - state->read_offset))
  524. {
  525. DWORD bytesRead=0;
  526. BOOL res = GetOverlappedResult(file, &state->overlapped, &bytesRead, TRUE);
  527. if ((res && bytesRead != sizeof(state->buffer))
  528. || (!res && GetLastError() == ERROR_HANDLE_EOF))
  529. {
  530. state->endOfFile = true;
  531. }
  532. if (bytesRead > state->read_offset)
  533. {
  534. size_t bytesToCopy = bytesRead-state->read_offset;
  535. memcpy(buffer, state->buffer + state->read_offset, bytesToCopy);
  536. buffer=(uint8_t *)buffer + bytesToCopy;
  537. totalRead+=bytesToCopy;
  538. size-=bytesToCopy;
  539. if (state->endOfFile)
  540. return totalRead;
  541. state->position.QuadPart += bytesToCopy;
  542. DoRead(state);
  543. }
  544. else
  545. break;
  546. }
  547. while (1)
  548. {
  549. DWORD bytesRead=0;
  550. BOOL res = GetOverlappedResult(file, &state->overlapped, &bytesRead, FALSE);
  551. if ((res && bytesRead != sizeof(state->buffer))
  552. || (!res && GetLastError() == ERROR_HANDLE_EOF))
  553. {
  554. state->endOfFile = true;
  555. }
  556. if (bytesRead >= (size + state->read_offset))
  557. {
  558. memcpy(buffer, state->buffer + state->read_offset, size);
  559. state->read_offset += size;
  560. totalRead+=size;
  561. state->position.QuadPart += size;
  562. break;
  563. }
  564. if (state->endOfFile)
  565. break;
  566. WaitForSingleObject(state->event, 10); // wait 10 milliseconds or when buffer is done, whichever is faster
  567. }
  568. return totalRead;
  569. }
  570. size_t UnicodeWrite(void *user, void *buffer, size_t size)
  571. {
  572. Win32_State *state = static_cast<Win32_State *>(user);
  573. DWORD written = 0;
  574. assert(state->handle);
  575. WriteFile(state->handle, buffer, size, &written, NULL);
  576. return 0;
  577. }
  578. int UnicodeEndOfFile(void *user)
  579. {
  580. Win32_State *state = static_cast<Win32_State *>(user);
  581. return state->endOfFile;
  582. }
  583. int UnicodeClose(void *user)
  584. {
  585. Win32_State *state = static_cast<Win32_State *>(user);
  586. if (state->handle)
  587. CloseHandle(state->handle);
  588. state->handle=0;
  589. return 0;
  590. }
  591. Virtual_IO UnicodeIO =
  592. {
  593. UnicodeGetFileLength,
  594. UnicodeSetPosition,
  595. UnicodeGetPosition,
  596. UnicodeRead,
  597. UnicodeWrite,
  598. UnicodeEndOfFile,
  599. UnicodeClose,
  600. };
  601. void *CreateUnicodeReader(const wchar_t *filename)
  602. {
  603. HANDLE fileHandle = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  604. if (fileHandle == INVALID_HANDLE_VALUE)
  605. return 0;
  606. Win32_State *state = new Win32_State;
  607. if (!state)
  608. {
  609. CloseHandle(fileHandle);
  610. return 0;
  611. }
  612. state->endOfFile = false;
  613. state->handle = fileHandle;
  614. return state;
  615. }
  616. void DestroyUnicodeReader(void *reader)
  617. {
  618. if (reader) // need to check because of the cast
  619. delete (Win32_State *)reader;
  620. }