http.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. #include "api__in_vorbis.h"
  2. #include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
  3. #include "rf.h"
  4. #include "main.h"
  5. #include "../Winamp/wa_ipc.h"
  6. #include <api/service/waservicefactory.h>
  7. #include "../nu/AutoWide.h"
  8. #include "../nu/AutoChar.h"
  9. extern CfgInt cfg_fix0r,cfg_httpseek2,cfg_proxy_mode,cfg_prebuf1,cfg_prebuf2,cfg_fsave,cfg_http_bsize;
  10. #define CANSEEK
  11. WORD *wdup(const char * src);//info.c
  12. #define zeromem(x) memset(&x,0,sizeof(x))
  13. class StreamSave
  14. {
  15. private:
  16. ogg_sync_state oy_src;
  17. ogg_stream_state os_src;
  18. ogg_stream_state os_dst;
  19. ogg_page og_src;
  20. ogg_page og_dst;
  21. ogg_packet op;
  22. StringW tmp_fn;
  23. BOOL is_temp;
  24. BOOL got_streams,got_delta,use_fix0r;
  25. ogg_int64_t pcm_delta;
  26. int packets,serial;
  27. HANDLE hFile;
  28. public:
  29. StreamSave()
  30. {
  31. zeromem(oy_src);
  32. zeromem(os_src);
  33. zeromem(os_dst);
  34. zeromem(og_src);
  35. zeromem(og_dst);
  36. zeromem(op);
  37. got_streams=0;
  38. got_delta=0;
  39. pcm_delta=0;
  40. hFile=0;
  41. packets=0;
  42. serial=0;
  43. is_temp=1;
  44. tmp_fn=cfg_dumpdir;
  45. if (tmp_fn[tmp_fn.Length()-1]!='\\') tmp_fn.AddChar('\\');
  46. tmp_fn+=StringPrintfW(L"oggtemp%u.foo",GetTickCount64()&0xFFFF);
  47. hFile=CreateFileW(tmp_fn,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_HIDDEN,0);
  48. if (hFile==INVALID_HANDLE_VALUE) hFile=0;
  49. else
  50. {
  51. ogg_sync_init(&oy_src);
  52. use_fix0r=cfg_fix0r;
  53. }
  54. };
  55. void Write(void * ptr,UINT siz)
  56. {
  57. if (!hFile) return;
  58. void * b=ogg_sync_buffer(&oy_src,siz);
  59. memcpy(b,ptr,siz);
  60. ogg_sync_wrote(&oy_src,siz);
  61. while(ogg_sync_pageout(&oy_src,&og_src)>0)
  62. {
  63. if (!got_streams)
  64. {
  65. serial=ogg_page_serialno(&og_src);
  66. ogg_stream_init(&os_src,serial);
  67. ogg_stream_init(&os_dst,serial);
  68. got_streams=1;
  69. packets=0;
  70. got_delta=0;
  71. }
  72. else if (serial!=ogg_page_serialno(&og_src))
  73. {
  74. if (got_streams)
  75. {
  76. /*while(ogg_stream_flush(&os_dst,&og_dst))
  77. {
  78. write_page(dst,&og_dst,&wb);
  79. }*/
  80. ogg_stream_clear(&os_src);
  81. ogg_stream_clear(&os_dst);
  82. }
  83. serial=ogg_page_serialno(&og_src);
  84. ogg_stream_init(&os_src,serial);
  85. ogg_stream_init(&os_dst,serial);
  86. packets=0;
  87. got_delta=0;
  88. }
  89. ogg_stream_pagein(&os_src,&og_src);
  90. while(ogg_stream_packetout(&os_src,&op)>0)
  91. {
  92. if (use_fix0r && !got_delta && packets>2 && op.granulepos>=0) //hack to fix saved streams
  93. {
  94. got_delta=1;
  95. if (op.granulepos>4096*(packets-2)) pcm_delta=op.granulepos;
  96. }
  97. if (got_delta)
  98. {
  99. if (op.granulepos>=pcm_delta) op.granulepos-=pcm_delta;
  100. else if (op.granulepos>0) op.granulepos=0;
  101. }
  102. ogg_stream_packetin(&os_dst,&op);
  103. packets++;
  104. }
  105. while((packets==3 ? ogg_stream_flush(&os_dst,&og_dst) : ogg_stream_pageout(&os_dst,&og_dst))>0)
  106. {
  107. DWORD bw = 0;
  108. WriteFile(hFile,og_dst.header,og_dst.header_len,&bw,0);
  109. bw = 0; WriteFile(hFile,og_dst.body,og_dst.body_len,&bw,0);
  110. }
  111. }
  112. }
  113. void FixName(VorbisFile * vf,const char * streamname)
  114. {
  115. if (!hFile) return;
  116. CloseHandle(hFile);
  117. StringW fn(cfg_dumpdir);
  118. if (fn[fn.Length()-1]!='\\') fn.AddChar('\\');
  119. UINT n=fn.Length();
  120. fn+=(wchar_t *)AutoWide(vf->get_meta("TITLE", 0), CP_UTF8);
  121. UINT m=fn.Length();
  122. while(n<m)
  123. {
  124. char * b="/\\:*?\"<>|";
  125. while(b && *b)
  126. {
  127. if (fn[n]==*b) {fn.SetChar(n,'_');break;}
  128. b++;
  129. }
  130. n++;
  131. };
  132. fn.AddStringA(".ogg");
  133. if (!MoveFileW(tmp_fn,fn))
  134. {
  135. DeleteFileW(fn);
  136. MoveFileW(tmp_fn,fn);
  137. }
  138. SetFileAttributesW(fn,FILE_ATTRIBUTE_NORMAL);
  139. hFile=CreateFileW(fn,GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
  140. if (hFile==INVALID_HANDLE_VALUE) {hFile=0;}
  141. else SetFilePointer(hFile,0,0,FILE_END);
  142. is_temp=0;
  143. }
  144. ~StreamSave()
  145. {
  146. if (hFile)
  147. {
  148. /*if (got_streams)
  149. {
  150. while(ogg_stream_flush(&os_dst,&og_dst))
  151. {
  152. write_page(dst,&og_dst,&wb);
  153. }
  154. }*/
  155. ogg_stream_clear(&os_src);
  156. ogg_stream_clear(&os_dst);
  157. SetFilePointer(hFile,0,0,FILE_CURRENT);
  158. CloseHandle(hFile);
  159. if (is_temp) DeleteFileW(tmp_fn);
  160. }
  161. ogg_sync_clear(&oy_src);
  162. }
  163. };
  164. static const char * do_proxy(const char * url)
  165. {
  166. switch(cfg_proxy_mode)
  167. {
  168. default:
  169. return 0;
  170. case 1:
  171. {
  172. const char * p=strstr(url,"://");
  173. if (!p) p=url;
  174. while(p && *p && *p!=':' && *p!='/') p++;
  175. if (p && *p==':')
  176. {
  177. if (atoi(p+1)!=80) return 0;
  178. }
  179. }
  180. case 2:
  181. {
  182. char *x = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_PROXY_STRING);
  183. if (x == (char *)1 || !x || !*x)
  184. return 0;
  185. return x;
  186. }
  187. }
  188. }
  189. class VorbisFile_HTTP : public VorbisFile
  190. {
  191. protected:
  192. api_httpreceiver *get;
  193. UINT bsize;
  194. uint64_t len;
  195. UINT pos;
  196. UINT seekpos;
  197. BOOL can_seek;
  198. StreamSave * saver;
  199. virtual void Idle();
  200. virtual int f_seek(__int64 offset,int whence);
  201. virtual size_t f_read(UINT siz,void * ptr);
  202. virtual UINT f_tell();
  203. virtual UINT FileSize() {return len;}
  204. bool is_live;
  205. public:
  206. virtual int GetType() {return TYPE_HTTP;}
  207. virtual bool IsLive() {return is_live;}
  208. bool http_init();
  209. void do_prebuf() {VorbisFile::do_prebuf();fillbuf(bsize * cfg_prebuf1 / 100,0);}
  210. VorbisFile_HTTP(UINT s, const wchar_t *u,bool is_info, bool hasauth) : VorbisFile(u,is_info), usedauth(hasauth)
  211. {
  212. get=0;
  213. can_seek=0;
  214. len=pos=seekpos=0;
  215. bsize=s;
  216. saver=0;
  217. m_needs_auth=0;
  218. lpinfo[0]=0;
  219. force_lpinfo[0]=0;
  220. is_live = false;
  221. memset(dlg_realm, 0, sizeof(dlg_realm));
  222. }
  223. ~VorbisFile_HTTP()
  224. {
  225. if (get)
  226. {
  227. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  228. if (sf)
  229. sf->releaseInterface(get);
  230. get=0;
  231. }
  232. if (saver) delete saver;
  233. }
  234. void fillbuf(UINT max,bool shutup);
  235. size_t _http_read(char* ptr,size_t total);
  236. int reconnect(UINT ofs);
  237. virtual void post_init()
  238. {
  239. if (saver) saver->FixName(this,get->getheader("ice-name"));
  240. }
  241. static BOOL CALLBACK httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
  242. int m_needs_auth;
  243. char dlg_realm[256];
  244. char lpinfo[256];
  245. char force_lpinfo[256];
  246. bool usedauth;
  247. };
  248. int VorbisFile_HTTP::reconnect(UINT ofs)
  249. {
  250. // get.reset_headers();
  251. get->addheader("User-Agent: WinampOGG/5.24(MPEG stream compatible)");
  252. get->addheader("Accept:*/*");
  253. if (ofs>0) get->addheader(StringPrintf("Range: bytes=%u-",ofs));
  254. get->connect(AutoChar(url));
  255. Status(WASABI_API_LNGSTRINGW(IDS_CONNECTING));
  256. int st=get->run();
  257. if (st<0)
  258. {
  259. return 1;
  260. }
  261. return 0;
  262. }
  263. void VorbisFile_HTTP::fillbuf(UINT max,bool shutup)
  264. {
  265. if (len>0 && pos+max>len) max=len-pos;
  266. while(!Aborting() && !abort_prebuf) //stop prebuffering if we wanna seek
  267. {
  268. if (!shutup)
  269. {
  270. Status(StringPrintfW(WASABI_API_LNGSTRINGW(IDS_PREBUFFERING), get->bytes_available()*100/bsize));
  271. }
  272. if (get->run()) break;
  273. if (Aborting() || abort_prebuf || get->bytes_available()>=(int)max) break;
  274. Sleep(2);
  275. }
  276. if (!shutup)
  277. {
  278. Status(0);
  279. }
  280. }
  281. size_t VorbisFile_HTTP::_http_read(char* ptr,size_t total)
  282. {
  283. #ifdef CANSEEK
  284. if (seekpos!=-1)
  285. {
  286. UINT sp=seekpos;
  287. seekpos=-1;
  288. if (sp!=pos)
  289. {
  290. if (sp>pos && sp<=pos+get->bytes_available())
  291. {
  292. get->get_bytes(0,sp-pos);
  293. }
  294. else
  295. {
  296. if (reconnect(sp))
  297. {
  298. return 0;//oh well...
  299. }
  300. }
  301. pos=sp;
  302. }
  303. }
  304. #endif
  305. UINT wr=0;
  306. while(!Aborting() && wr<total)
  307. {
  308. int st=get->run();
  309. int d=get->get_bytes(ptr,(int)total-wr);
  310. if (st && !d) break;
  311. wr+=d;
  312. ptr+=d;
  313. pos+=d;
  314. if ((len>0 && pos>=len) || wr>=total || Aborting()) break;
  315. if (use_prebuf) fillbuf(bsize * cfg_prebuf2 / 100,0);
  316. else Sleep(1);
  317. }
  318. return wr;
  319. }
  320. void VorbisFile_HTTP::Idle()
  321. {
  322. get->run();
  323. Sleep(1);
  324. get->run();
  325. Sleep(1);
  326. }
  327. size_t VorbisFile_HTTP::f_read(UINT siz,void* ptr)
  328. {
  329. if (Aborting()) return 0;//fixme
  330. int i=(int)_http_read((char*)ptr,siz);
  331. if (i>0 && saver) saver->Write(ptr,i);
  332. return i;
  333. }
  334. int VorbisFile_HTTP::f_seek(ogg_int64_t offset,int whence)
  335. {
  336. #ifdef CANSEEK
  337. if (can_seek)
  338. {
  339. switch(whence)
  340. {
  341. case FILE_BEGIN:
  342. seekpos=(int)offset;
  343. break;
  344. case FILE_END:
  345. seekpos=len+(int)offset;
  346. break;
  347. case FILE_CURRENT:
  348. seekpos=pos+(int)offset;
  349. break;
  350. }
  351. if (seekpos>len) seekpos=len;
  352. return 0;
  353. }
  354. else
  355. #endif
  356. return -1;
  357. }
  358. UINT VorbisFile_HTTP::f_tell()
  359. {
  360. #ifdef CANSEEK
  361. if (can_seek)
  362. {
  363. if (seekpos!=-1) return seekpos;
  364. else return pos;
  365. }
  366. else
  367. #endif
  368. return -1;
  369. }
  370. HWND GetDialogBoxParent()
  371. {
  372. HWND parent = (HWND)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
  373. if (!parent || parent == (HWND)1)
  374. return mod.hMainWindow;
  375. return parent;
  376. }
  377. bool VorbisFile_HTTP::http_init()
  378. {
  379. if (mod.service)
  380. {
  381. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  382. if (sf) get = (api_httpreceiver *)sf->getInterface();
  383. }
  384. if (!get) return false;
  385. get->open(API_DNS_AUTODNS, bsize, do_proxy(AutoChar(url)));
  386. if (reconnect(0))
  387. {
  388. return 0;
  389. }
  390. #ifdef CANSEEK
  391. // if (cfg_httpseek)
  392. {
  393. //need to get http headers first
  394. while(!memcmp(get->getallheaders(),"\0\0",2))
  395. {
  396. if (get->run()<0 || Aborting())
  397. {
  398. int reply = get->getreplycode();
  399. if ( reply == 401 )
  400. {
  401. api_connection *mcon=get->GetConnection();
  402. if ( mcon && mcon->GetReceiveBytesAvailable())
  403. {
  404. char p[1024]="";
  405. while ( mcon->GetReceiveBytesAvailable() )
  406. {
  407. char b[2048]="";
  408. mcon->ReceiveLine(b,2048);
  409. if ( *b )
  410. {
  411. char *t= strstr(b,"WWW-Authenticate:");
  412. if ( t && *t )
  413. {
  414. char *y = strstr(t,"\"");
  415. if ( y && *y )
  416. {
  417. y++;
  418. if ( *y )
  419. {
  420. char *u = strstr(y,"\"");
  421. if ( u && *u )
  422. {
  423. *u = 0;
  424. wsprintfA(p,"%s",y);
  425. }
  426. }
  427. }
  428. }
  429. }
  430. }
  431. if ( *p ) // found our realm
  432. {
  433. if (!force_lpinfo[0]) GetPrivateProfileStringA("HTTP-AUTH",p,"",force_lpinfo,sizeof(force_lpinfo),INI_FILE);
  434. if (!force_lpinfo[0] || lpinfo[0] || usedauth )
  435. {
  436. lstrcpynA(dlg_realm,p,sizeof(dlg_realm));
  437. if (!WASABI_API_DIALOGBOXPARAM(IDD_HTTPAUTH, GetDialogBoxParent(), httpDlgProc, (LPARAM)this))
  438. {
  439. force_lpinfo[0]=0;
  440. }
  441. else
  442. {
  443. WritePrivateProfileStringA("HTTP-AUTH",p,force_lpinfo,INI_FILE);
  444. }
  445. }
  446. Status(WASABI_API_LNGSTRINGW(IDS_AUTH_REQUIRED));
  447. m_needs_auth=1;
  448. }
  449. }
  450. }
  451. return 0;
  452. }
  453. //hg->get.wait(10);
  454. Sleep(1);
  455. }
  456. len=get->content_length();
  457. const char* poo=get->getheader("icy-name");
  458. if (poo) stream_title=poo;
  459. if (cfg_httpseek2 && len) can_seek=1;
  460. is_live=(len<=0);
  461. }
  462. #endif
  463. //if (hg->len==0 || hg->len==-1) hg->can_seek=0;
  464. seekpos=-1;
  465. if (cfg_fsave && !can_seek)
  466. {
  467. saver=new StreamSave;
  468. }
  469. return 1;
  470. }
  471. VorbisFile * VorbisFile::Create_HTTP(const char * url,bool is_info)
  472. {
  473. VorbisFile_HTTP * r=new VorbisFile_HTTP(cfg_http_bsize,AutoWide(url),is_info, false);
  474. if (r)
  475. {
  476. if (!r->http_init())
  477. {
  478. int trys=0;
  479. while ( r && r->m_needs_auth && trys++ < 2)
  480. {
  481. const char *p=strstr(url,"://");
  482. if (p && *p)
  483. {
  484. p += 3;
  485. if (p && *p)
  486. {
  487. char lurl[4096] = {0};
  488. wsprintfA(lurl, "http://%s@%s", r->force_lpinfo, p);
  489. delete r;
  490. r = new VorbisFile_HTTP(cfg_http_bsize,AutoWide(lurl),is_info, true);
  491. if (r && r->http_init())
  492. {
  493. return r;
  494. }
  495. }
  496. }
  497. }
  498. delete r;
  499. r=0;
  500. }
  501. }
  502. return r;
  503. }
  504. BOOL CALLBACK VorbisFile_HTTP::httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  505. {
  506. VorbisFile_HTTP *_this;
  507. switch (uMsg)
  508. {
  509. case WM_INITDIALOG:
  510. #ifdef WIN64
  511. SetWindowLong(hwndDlg, GWLP_USERDATA, (LONG)lParam);
  512. _this = (VorbisFile_HTTP*)(GetWindowLong(hwndDlg, GWLP_USERDATA));
  513. #else
  514. SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)lParam);
  515. _this = (VorbisFile_HTTP*)GetWindowLong(hwndDlg, GWL_USERDATA);
  516. #endif
  517. if (_this->force_lpinfo[0])
  518. SetDlgItemTextA(hwndDlg,IDC_EDITAUTH,_this->force_lpinfo);
  519. else SetDlgItemTextA(hwndDlg,IDC_EDITAUTH,_this->lpinfo);
  520. SetDlgItemTextA(hwndDlg,IDC_REALM,_this->dlg_realm);
  521. return 1;
  522. case WM_COMMAND:
  523. #ifdef WIN64
  524. _this = (VorbisFile_HTTP*)GetWindowLong(hwndDlg, GWLP_USERDATA);
  525. #else
  526. _this = (VorbisFile_HTTP*)GetWindowLong(hwndDlg, GWL_USERDATA);
  527. #endif
  528. if (LOWORD(wParam) == IDOKAUTH)
  529. {
  530. char *p;
  531. GetDlgItemTextA(hwndDlg,IDC_EDITAUTH,_this->force_lpinfo,sizeof(_this->force_lpinfo));
  532. p = strstr(_this->force_lpinfo,"\r");
  533. if ( p && *p ) *p=0;
  534. p = strstr(_this->force_lpinfo,"\n");
  535. if ( p && *p ) *p=0;
  536. EndDialog(hwndDlg,1);
  537. }
  538. else if (LOWORD(wParam) == IDCANCELAUTH)
  539. {
  540. EndDialog(hwndDlg,0);
  541. }
  542. break;
  543. }
  544. return 0;
  545. }