FileTorrent.cpp
上传用户:lds876
上传日期:2013-05-25
资源大小:567k
文件大小:12k
源码类别:

P2P编程

开发平台:

Visual C++

  1. // FileTorrent.cpp: implementation of the CFileTorrent class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "testbt.h"
  6. #include "FileTorrent.h"
  7. #include <direct.h>
  8. #include "bdecode.h"
  9. #include "BTFormat.h"
  10. #include "sha.h"
  11. #include "filebase.h"
  12. #ifdef _DEBUG
  13. #undef THIS_FILE
  14. static char THIS_FILE[]=__FILE__;
  15. #define new DEBUG_NEW
  16. #endif
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. CFileTorrent::CFileTorrent()
  21. {
  22. m_pResponse = 0;
  23. m_lSize = 0;
  24. m_bDirectory  = false;
  25. m_bOpened = false;
  26. m_bBad = false;
  27. m_hFileOpenDone = CreateEvent(0, true, true, 0);
  28. m_hCancel = CreateEvent(0, true, false, 0);
  29. m_hWnd = 0;
  30. m_lOpenIndex = 0;
  31. }
  32. CFileTorrent::~CFileTorrent()
  33. {
  34. Close();
  35. CloseHandle(m_hFileOpenDone);
  36. CloseHandle(m_hCancel);
  37. }
  38. memstream& CFileTorrent::GetMyId()
  39. {
  40. assert(m_memMyid.size() == 20);
  41. return m_memMyid;
  42. }
  43. string CFileTorrent::GetInfohashString()
  44. {
  45. assert(m_memInfohash.size() == 20);
  46. char infohash[20] = {0};
  47. memcpy(infohash, m_memInfohash, 20);
  48. string strRet;
  49. for (int i=0; i<20; i++)
  50. {
  51. char szText[20] = {0};
  52. if ((unsigned char) infohash[i] < 0x10)
  53. sprintf(szText, "0%x", (unsigned char) infohash[i]);
  54. else
  55. sprintf(szText, "%x", (unsigned char) infohash[i]);
  56. strRet += szText;
  57. }
  58. return strRet;
  59. }
  60. memstream& CFileTorrent::GetInfohash()
  61. {
  62. assert(m_memInfohash.size() == 20);
  63. return m_memInfohash;
  64. }
  65. CVal* CFileTorrent::GetInfo()
  66. {
  67. assert(m_pResponse);
  68. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  69. return pInfo;
  70. }
  71. CVal* CFileTorrent::GetResponse()
  72. {
  73. return m_pResponse;
  74. }
  75. string CFileTorrent::GetUrl()
  76. {
  77. assert(m_pResponse);
  78. return (*m_pResponse)[string("announce")]->pstrVal;
  79. }
  80. string CFileTorrent::GetComment()
  81. {
  82. assert(m_pResponse);
  83. string strComment;
  84. if (HasKey(m_pResponse->pmapVal, "comment"))
  85. strComment = (*m_pResponse)[string("comment")]->pstrVal;
  86. return strComment;
  87. }
  88. vector<CFileInfo>& CFileTorrent::GetFileInfo()
  89. {
  90. return m_vFiles;
  91. }
  92. vector<char*>& CFileTorrent::GetPieces()
  93. {
  94. return m_vPieces;
  95. }
  96. string CFileTorrent::GetTorrentFileName()
  97. {
  98. assert(!m_strTorrentFileName.empty());
  99. return m_strTorrentFileName;
  100. }
  101. string CFileTorrent::GetSaveName()
  102. {
  103. assert(!m_strSaveName.empty());
  104. return m_strSaveName;
  105. }
  106. BLONG CFileTorrent::GetFileLength()
  107. {
  108. return m_lSize;
  109. }
  110. void CFileTorrent::Close()
  111. {
  112. if (!IsEventSet(m_hFileOpenDone))
  113. {
  114. SetEvent(m_hCancel);
  115. WaitForSingleObject(m_hFileOpenDone, INFINITE);
  116. }
  117. m_bOpened = false;
  118. m_bBad = false;
  119. m_strBad = "";
  120. if (m_pResponse)
  121. delete m_pResponse;
  122. m_pResponse = 0;
  123. m_vPieces.clear();
  124. m_vFiles.clear();
  125. m_memMyid.clear();
  126. m_memInfohash.clear();
  127. m_strTorrentFileName = "";
  128. m_strSaveName = "";
  129. m_lSize = 0;
  130. }
  131. bool CFileTorrent::IsOpen()
  132. {
  133. if (!IsEventSet(m_hFileOpenDone))
  134. return false;
  135. return m_bOpened;
  136. }
  137. bool CFileTorrent::IsBad()
  138. {
  139. return m_bBad;
  140. }
  141. string CFileTorrent::GetBadMsg()
  142. {
  143. return m_strBad;
  144. }
  145. long CFileTorrent::GetOpenIndex()
  146. {
  147. return m_lOpenIndex;
  148. }
  149. bool CFileTorrent::OpenFileEx(string strFileName, string strSaveAs, HWND hWnd)
  150. {
  151. if (IsOpen() || !IsEventSet(m_hFileOpenDone))
  152. {
  153. assert(false);
  154. return false;
  155. }
  156. //
  157. // read data from *.torrent
  158. //
  159. if (strFileName.empty() || !hWnd)
  160. {
  161. assert(false);
  162. return false;
  163. }
  164. if (m_lOpenIndex ++ > 10000)
  165. m_lOpenIndex = 0;
  166. m_strTorrentFileName = strFileName;
  167. m_hWnd = hWnd;
  168. ResetEvent(m_hFileOpenDone);
  169. ResetEvent(m_hCancel);
  170. DWORD dwThreadId = 0;
  171. ::CreateThread(0, 0, OpenFileExProc, (void*)new CSize((long)this, m_lOpenIndex), 0, &dwThreadId);
  172. TRACE("rnopen file thread = (%x)", dwThreadId);
  173. return true;
  174. }
  175. DWORD WINAPI CFileTorrent::OpenFileExProc(void *pParam)
  176. {
  177. CSize* p = (CSize*) pParam;
  178. auto_ptr<CSize> a(p);
  179. CFileTorrent* pFileTorrent = (CFileTorrent*) p->cx;
  180. long lOpenIndex = p->cy;
  181. HWND hWnd = pFileTorrent->m_hWnd;
  182. pFileTorrent->ExtractFile(lOpenIndex);
  183. PostMessage(hWnd, WM_FILE_TORRENT_OPENED, lOpenIndex, 0);
  184. return 0;
  185. }
  186. void CFileTorrent::ExtractFile(long lOpenIndex)
  187. {
  188. ExtractFileData();
  189. assert(m_hWnd);
  190. if (m_bOpened) m_bBad = true;
  191. SetEvent(m_hFileOpenDone);
  192. }
  193. void CFileTorrent::ExtractFileData()
  194. {
  195. //
  196. // open file and read data
  197. //
  198. assert(!m_strTorrentFileName.empty());
  199. FILE* pfile = 0;
  200. pfile = fopen(m_strTorrentFileName.data(), "rb");
  201. if (!pfile) 
  202. {
  203. m_strBad = string("file (") + m_strTorrentFileName + ") can't find";
  204. return;
  205. }
  206. fseek(pfile, 0, SEEK_END);
  207. unsigned long lsize = ftell(pfile);
  208. char * pBuf = new char[lsize];
  209. auto_ptr<char> autoBuf(pBuf);
  210. fseek(pfile, 0, SEEK_SET);
  211. int iRet = fread(pBuf, 1, lsize, pfile);
  212. if (iRet != lsize)
  213. {
  214. fclose(pfile);
  215. m_strBad = string("read file ") + m_strTorrentFileName + " fail";
  216. return;
  217. }
  218. fclose(pfile);
  219. //
  220. // extract info from buffer.
  221. //
  222. CBdecode dec;
  223. m_pResponse = dec.bdecode(pBuf, lsize);
  224. if (!m_pResponse)
  225. {
  226. m_strBad = string("File(" + m_strTorrentFileName + ") -- bdecode error");
  227. return;
  228. }
  229. //
  230. // check info extracted.
  231. //
  232. try
  233. {
  234. CBTFormat btformat;
  235. btformat.CheckMessage(m_pResponse);
  236. }
  237. catch (string& e)
  238. {
  239. delete m_pResponse;
  240. m_pResponse = 0;
  241. e.data();
  242. m_strBad = string("File(" + m_strTorrentFileName + ") CheckMessage error");
  243. return;
  244. }
  245. //
  246. // Format data.
  247. //
  248. MakeMyid();
  249. MakeInfohash();
  250. MakePieces();
  251. m_bOpened = true;
  252. }
  253. bool CFileTorrent::OpenFile(string strFileName, string strSaveAs)
  254. {
  255. assert(!m_pResponse);
  256. // read data from *.torrent
  257. if (strFileName.empty())
  258. {
  259. assert(false);
  260. throw string("CFileTorrent::OpenFile() file name can't be empty");
  261. }
  262. m_strTorrentFileName = strFileName;
  263. ExtractFileData();
  264. return m_bOpened;
  265. }
  266. bool CFileTorrent::QueryDir()
  267. {
  268. assert(m_pResponse);
  269. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  270. if (HasKey(pInfo->pmapVal, "length"))
  271. {
  272. CVal* pLength = (*pInfo->pmapVal)["length"];
  273. BLONG lfilelen = pLength->lVal;
  274. m_strSaveName = (*pInfo->pmapVal)["name"]->pstrVal;
  275. m_lSize = lfilelen;
  276. m_bDirectory  = false;
  277. }
  278. else
  279. {
  280. CVal* pFiles = (*pInfo->pmapVal)["files"];
  281. BLONG lfilelen = 0;
  282. for (VALLIST::iterator iter = pFiles->plistVal->begin(); iter!= pFiles->plistVal->end(); iter++)
  283. {
  284. lfilelen += (*(*iter)->pmapVal)["length"]->lVal;
  285. }
  286. m_lSize = lfilelen;
  287. m_strSaveName = (*pInfo->pmapVal)["name"]->pstrVal;
  288. m_bDirectory  = true;
  289. }
  290. return true;
  291. }
  292. bool CFileTorrent::QuerySubFiles(vector<CFileInfo>& vFiles, bool& bDir, BLONG & lTotalSize)
  293. {
  294. if (!m_pResponse)
  295. {
  296. assert(m_pResponse);
  297. return false;
  298. }
  299. // Create the dir and vector files.
  300. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  301. if (HasKey(pInfo->pmapVal, "length"))
  302. {
  303. CVal* pLength = (*pInfo->pmapVal)["length"];
  304. BLONG lfilelen = pLength->lVal;
  305. string strFile = (*pInfo->pmapVal)["name"]->pstrVal;
  306. vFiles.push_back(CFileInfo(strFile, lfilelen));
  307. lTotalSize = lfilelen;
  308. }
  309. else
  310. {
  311. string strSaveName = (*pInfo->pmapVal)["name"]->pstrVal;
  312. CVal* pFiles = (*pInfo->pmapVal)["files"];
  313. for (VALLIST::iterator iter = pFiles->plistVal->begin(); 
  314. iter!= pFiles->plistVal->end(); iter++)
  315. {
  316. CVal* pLength = (*(*iter)->pmapVal)["length"];
  317. CVal* pPath = (*(*iter)->pmapVal)["path"];
  318. string strPath = strSaveName;
  319. for (int j=0; j<pPath->size(); j++)
  320. {
  321. if (strPath[strPath.size() - 1] != '\')
  322. strPath += "\";
  323. strPath += (*pPath)[j]->pstrVal;
  324. }
  325. vFiles.push_back(CFileInfo(strPath, pLength->lVal));
  326. lTotalSize += pLength->lVal;
  327. }
  328. } // end elseif
  329. return true;
  330. }
  331. bool CFileTorrent::CreateDir(string strSaveAs)
  332. {
  333. assert(m_pResponse);
  334. // Create the dir and vector files.
  335. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  336. if (HasKey(pInfo->pmapVal, "length"))
  337. {
  338. CVal* pLength = (*pInfo->pmapVal)["length"];
  339. BLONG lfilelen = pLength->lVal;
  340. string strFile = strSaveAs;
  341. if (strFile.empty())
  342. {
  343. assert(false);
  344. return false;
  345. }
  346. m_strSaveName = strFile;
  347. m_lSize = lfilelen;
  348. MakeDir(strFile);
  349. m_vFiles.push_back(CFileInfo(strFile, lfilelen));
  350. }
  351. else
  352. {
  353. CVal* pFiles = (*pInfo->pmapVal)["files"];
  354. BLONG lfilelen = 0;
  355. for (VALLIST::iterator iter = pFiles->plistVal->begin(); iter!= pFiles->plistVal->end(); iter++)
  356. {
  357. lfilelen += (*(*iter)->pmapVal)["length"]->lVal;
  358. }
  359. string strFile = formatDir(strSaveAs);
  360. if (strFile.empty())
  361. {
  362. assert(false);
  363. return false;
  364. }
  365. m_lSize = lfilelen;
  366. m_strSaveName = strFile;
  367. bool bRet = MakeDir(strFile, true);
  368. assert(bRet);
  369. for (iter = pFiles->plistVal->begin(); iter!= pFiles->plistVal->end(); iter++)
  370. {
  371. CVal* pLength = (*(*iter)->pmapVal)["length"];
  372. CVal* pPath = (*(*iter)->pmapVal)["path"];
  373. string strPath = strFile;
  374. for (int j=0; j<pPath->size(); j++)
  375. {
  376. if (strPath[strPath.size() - 1] != '\')
  377. strPath += "\";
  378. strPath += (*pPath)[j]->pstrVal;
  379. bRet = MakeDir(strPath);
  380. assert(bRet);
  381. }
  382. m_vFiles.push_back(CFileInfo(strPath, pLength->lVal));
  383. }
  384. } // end elseif
  385. return true;
  386. }
  387. string CFileTorrent::ChooseFile(string strDefaultName, unsigned long lsize, string strSaveas, bool bDir)
  388. {
  389. ASSERT(FALSE);
  390. if (bDir)
  391. {
  392. CString strDef, strFolder;
  393. if (!SelectFolder(strDef, strFolder))
  394. return "";
  395. string strSelected  = strFolder.GetBuffer(0);
  396. if (strSelected[strSelected.size() - 1] != '\')
  397. strSelected += '\';
  398. return strSelected + strDefaultName;
  399. }
  400. else
  401. {
  402. CFileDialog fileDialog(FALSE, 0, strDefaultName.data());
  403. int iRet = fileDialog.DoModal();
  404. if (iRet != IDOK)
  405. return "";
  406. return fileDialog.GetPathName(); // + fileDialog.GetFileName();
  407. // return string("d:\") + strDefaultName;
  408. }
  409. }
  410. bool CFileTorrent::MakeDir(string strFileName, bool bForceDir)
  411. {
  412. if (!bForceDir)
  413. {
  414. char path_buffer[_MAX_PATH];
  415. char drive[_MAX_DRIVE];
  416. char dir[_MAX_DIR];
  417. char fname[_MAX_FNAME];
  418. char ext[_MAX_EXT];
  419. _splitpath(strFileName.data(), drive, dir, fname, ext );
  420. _makepath( path_buffer, drive, dir, 0, 0);
  421. strFileName = path_buffer;
  422. }
  423. if (!_access(strFileName.data(), 0))
  424. return true;
  425. if (strFileName.empty())
  426. return false;
  427. // if (_mkdir(strFileName.data()))
  428. if (!MakeDirecotry(strFileName.data()))
  429. {
  430. long l= errno;
  431. throw string("makedir error : directory (") + strFileName + ")";
  432. }
  433. return true;
  434. }
  435. void CFileTorrent::MakeMyid()
  436. {
  437. string szMyId;
  438. char strBuf[100] = {0};
  439. long ltime;
  440. time(&ltime);
  441. sprintf(strBuf, "%d", ltime);
  442. szMyId = strBuf;  // szMyId = "1064570069.875";
  443. szMyId += " ";
  444. sprintf(strBuf, "%d", getpid());
  445. szMyId += strBuf; // szMyId += "1848";
  446. unsigned char sha1sum[20] = {0};
  447. CSHA sha;
  448. sha.start();
  449. sha.update((unsigned char*)szMyId.data(), szMyId.size());
  450. sha.finish(sha1sum);
  451. char myId[20] = {0};
  452. memset(myId, 0, 20);
  453. memcpy(myId+12, (char*)sha1sum + 12, 8);
  454. m_memMyid.clear();
  455. m_memMyid.write(myId, 20);
  456. // 'D(wxadx18xd1Omxccx07xa0xd7xfaxa6xcbpxfbtOr'
  457. // 'xfaxa6xcbpxfbtOr'
  458. // for (int z =0; z<20; z++)
  459. // TRACE("%x,", (unsigned char)pMyId[z]);
  460. }
  461. void CFileTorrent::MakeInfohash()
  462. {
  463. assert(m_pResponse);
  464. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  465. memstream strInfohash;
  466. CBdecode::bencode(pInfo, strInfohash);
  467. unsigned char sha1sum[20] = {0};
  468. CSHA sha;
  469. sha.start();
  470. sha.update((unsigned char*)(char*)strInfohash, strInfohash.size());
  471. sha.finish(sha1sum);
  472. // memcpy(pInfohash, (char*)sha1sum, 20);
  473. m_memInfohash.clear();
  474. m_memInfohash.write((char*)sha1sum, 20);
  475. }
  476. long CFileTorrent::getpid()
  477. {
  478. return GetCurrentProcessId();
  479. }
  480. void CFileTorrent::MakePieces()
  481. {
  482. assert(m_pResponse);
  483. CVal* pInfo = (*m_pResponse->pmapVal)["info"];
  484. char* pPieces = (*pInfo)[string("pieces")]->pstrVal;
  485. long lPiecesSize = (*pInfo)[string("pieces")]->lstrLen;
  486. long lNumPieces = lPiecesSize/20; 
  487. for (int i=0; i<lPiecesSize/20; i++)
  488. {
  489. m_vPieces.push_back(pPieces + i*20); 
  490. }
  491. }