DataSocket.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /********************************************************************/
  2. /* */
  3. /* DataSocket.cpp */
  4. /* */
  5. /* Implementation of the Data Socket. */
  6. /* */
  7. /* Programmed by LYFZ van der Meer */
  8. /* http://www.LYFZvandermeer.nl */
  9. /* */
  10. /* Last updated: 29 july 2002 */
  11. /* */
  12. /********************************************************************/
  13. #include "stdafx.h"
  14. #include "resource.h"
  15. #include "DataSocket.h"
  16. #include "ConnectSocket.h"
  17. #include "ConnectThread.h"
  18. #include <afxpriv.h>
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define PACKET_SIZE 4096
  25. /********************************************************************/
  26. /* */
  27. /* Function name : CDataSocket::CDataSocket */
  28. /* Description : Constructor */
  29. /* */
  30. /********************************************************************/
  31. CDataSocket::CDataSocket(CConnectSocket *pSocket, int nTransferType)
  32. {
  33. m_nTransferType = nTransferType;
  34. m_pConnectSocket = pSocket;
  35. m_nStatus = XFERMODE_IDLE;
  36. m_strData = "";
  37. m_File.m_hFile = NULL;
  38. m_bConnected = FALSE;
  39. m_dwRestartOffset = 0;
  40. m_bInitialized = FALSE;
  41. }
  42. /********************************************************************/
  43. /* */
  44. /* Function name : CDataSocket::~CDataSocket */
  45. /* Description : Destructor */
  46. /* */
  47. /********************************************************************/
  48. CDataSocket::~CDataSocket()
  49. {
  50. m_bConnected = FALSE;
  51. TRACE0("CDataSocket destroyed.\n");
  52. }
  53. #if 0
  54. BEGIN_MESSAGE_MAP(CDataSocket, CAsyncSocket)
  55. //{{AFX_MSG_MAP(CDataSocket)
  56. //}}AFX_MSG_MAP
  57. END_MESSAGE_MAP()
  58. #endif // 0
  59. /********************************************************************/
  60. /* */
  61. /* Function name : CDataSocket::OnSend */
  62. /* Description : Called by the framework to notify socket that */
  63. /* it can send data by calling the Send method. */
  64. /* */
  65. /********************************************************************/
  66. void CDataSocket::OnSend(int nErrorCode)
  67. {
  68. CAsyncSocket::OnSend(nErrorCode);
  69. switch(m_nStatus)
  70. {
  71. case XFERMODE_LIST:
  72. {
  73. while (m_nTotalBytesTransfered < m_nTotalBytesSend)
  74. {
  75. DWORD dwRead;
  76. int dwBytes;
  77. CString strData;
  78. dwRead = m_strData.GetLength();
  79. if (dwRead <= PACKET_SIZE)
  80. {
  81. strData = m_strData;
  82. }
  83. else
  84. {
  85. strData = m_strData.Left(PACKET_SIZE);
  86. dwRead = strData.GetLength();
  87. }
  88. if ((dwBytes = Send(strData, dwRead)) == SOCKET_ERROR)
  89. {
  90. if (GetLastError() == WSAEWOULDBLOCK)
  91. {
  92. Sleep(0);
  93. break;
  94. }
  95. else
  96. {
  97. TCHAR szError[256];
  98. wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
  99. // close the data connection.
  100. Close();
  101. m_nTotalBytesSend = 0;
  102. m_nTotalBytesTransfered = 0;
  103. // change status
  104. m_nStatus = XFERMODE_IDLE;
  105. m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
  106. // destroy this socket
  107. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  108. }
  109. }
  110. else
  111. {
  112. m_nTotalBytesTransfered += dwBytes;
  113. m_strData = m_strData.Mid(dwBytes);
  114. ((CConnectThread *)AfxGetThread())->IncSentBytes(dwBytes);
  115. }
  116. }
  117. if (m_nTotalBytesTransfered == m_nTotalBytesSend)
  118. {
  119. // close the data connection.
  120. Close();
  121. m_nTotalBytesSend = 0;
  122. m_nTotalBytesTransfered = 0;
  123. // change status
  124. m_nStatus = XFERMODE_IDLE;
  125. // tell the client the transfer is complete.
  126. m_pConnectSocket->SendResponse("226 Transfer complete");
  127. // destroy this socket
  128. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  129. }
  130. break;
  131. }
  132. case XFERMODE_SEND:
  133. {
  134. while (m_nTotalBytesTransfered < m_nTotalBytesSend)
  135. {
  136. // allocate space to store data
  137. byte data[PACKET_SIZE];
  138. m_File.Seek(m_nTotalBytesTransfered, CFile::begin);
  139. DWORD dwRead = m_File.Read(data, PACKET_SIZE);
  140. int dwBytes;
  141. if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
  142. {
  143. if (GetLastError() == WSAEWOULDBLOCK)
  144. {
  145. Sleep(0);
  146. break;
  147. }
  148. else
  149. {
  150. TCHAR szError[256];
  151. wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
  152. // close file.
  153. m_File.Close();
  154. m_File.m_hFile = NULL;
  155. // close the data connection.
  156. Close();
  157. m_nTotalBytesSend = 0;
  158. m_nTotalBytesTransfered = 0;
  159. // change status
  160. m_nStatus = XFERMODE_IDLE;
  161. m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
  162. // destroy this socket
  163. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  164. // download failed
  165. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_DOWNLOADFAILED);
  166. }
  167. }
  168. else
  169. {
  170. m_nTotalBytesTransfered += dwBytes;
  171. ((CConnectThread *)AfxGetThread())->IncSentBytes(dwBytes);
  172. }
  173. }
  174. if (m_nTotalBytesTransfered == m_nTotalBytesSend)
  175. {
  176. // close file.
  177. m_File.Close();
  178. m_File.m_hFile = NULL;
  179. // close the data connection.
  180. Close();
  181. m_nTotalBytesSend = 0;
  182. m_nTotalBytesTransfered = 0;
  183. // change status
  184. m_nStatus = XFERMODE_IDLE;
  185. // tell the client the transfer is complete.
  186. m_pConnectSocket->SendResponse("226 Transfer complete");
  187. // destroy this socket
  188. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  189. // download successfull
  190. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_DOWNLOADSUCCEEDED);
  191. }
  192. break;
  193. }
  194. // default:
  195. // break;
  196. }
  197. }
  198. /********************************************************************/
  199. /* */
  200. /* Function name : CDataSocket::OnConnect */
  201. /* Description : Called by the framework to notify connecting */
  202. /* socket that its connection attempt is completed */
  203. /* */
  204. /********************************************************************/
  205. void CDataSocket::OnConnect(int nErrorCode)
  206. {
  207. if (nErrorCode)
  208. {
  209. m_nStatus = XFERMODE_ERROR;
  210. m_pConnectSocket->SendResponse("425 Can't open data connection.");
  211. // destroy this socket
  212. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  213. }
  214. else
  215. {
  216. switch (m_nTransferType)
  217. {
  218. case 0: // List Directory
  219. m_nStatus = XFERMODE_LIST;
  220. m_bConnected = TRUE;
  221. OnSend(0);
  222. break;
  223. case 1: // Send File
  224. if (PrepareSendFile(m_strData))
  225. {
  226. m_nStatus = XFERMODE_SEND;
  227. m_bConnected = TRUE;
  228. }
  229. else
  230. {
  231. Close();
  232. }
  233. break;
  234. case 2: // Receive File
  235. if (PrepareReceiveFile(m_strData))
  236. {
  237. m_nStatus = XFERMODE_RECEIVE;
  238. m_bConnected = TRUE;
  239. }
  240. else
  241. {
  242. Close();
  243. m_pConnectSocket->SendResponse("450 can't access file.");
  244. // destroy this socket
  245. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  246. // upload failed
  247. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
  248. }
  249. break;
  250. }
  251. }
  252. CAsyncSocket::OnConnect(nErrorCode);
  253. }
  254. /********************************************************************/
  255. /* */
  256. /* Function name : CDataSocket::OnClose */
  257. /* Description : Called by the framework to notify this socket */
  258. /* that the connected socket is closed. */
  259. /* */
  260. /********************************************************************/
  261. void CDataSocket::OnClose(int nErrorCode)
  262. {
  263. TRACE0("CDataSocket() OnClose()\n");
  264. if (m_pConnectSocket)
  265. {
  266. // shutdown sends
  267. ShutDown(1);
  268. if (m_nStatus == XFERMODE_RECEIVE)
  269. {
  270. while(Receive() != 0)
  271. {
  272. // receive remaining data
  273. }
  274. }
  275. else
  276. {
  277. m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
  278. // destroy this socket
  279. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  280. // upload failed
  281. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
  282. }
  283. }
  284. m_nStatus = XFERMODE_IDLE;
  285. m_bConnected = FALSE;
  286. CAsyncSocket::OnClose(nErrorCode);
  287. }
  288. /********************************************************************/
  289. /* */
  290. /* Function name : CDataSocket::OnAccept */
  291. /* Description : Notify this listening socket that it can accept */
  292. /* pending connection requests. */
  293. /* */
  294. /********************************************************************/
  295. void CDataSocket::OnAccept(int nErrorCode)
  296. {
  297. // Accept the connection using a temp CSocket object.
  298. CAsyncSocket tmpSocket;
  299. Accept(tmpSocket);
  300. SOCKET socket = tmpSocket.Detach();
  301. Close();
  302. Attach(socket);
  303. m_bConnected = TRUE;
  304. if (!m_bInitialized)
  305. SetTransferType(m_nTransferType);
  306. CAsyncSocket::OnAccept(nErrorCode);
  307. }
  308. /********************************************************************/
  309. /* */
  310. /* Function name : CDataSocket::GetStatus */
  311. /* Description : Get socket status. */
  312. /* */
  313. /********************************************************************/
  314. int CDataSocket::GetStatus()
  315. {
  316. return m_nStatus;
  317. }
  318. /********************************************************************/
  319. /* */
  320. /* Function name : CDataSocket::PrepareSendFile */
  321. /* Description : Prepare socket to send a file. */
  322. /* */
  323. /********************************************************************/
  324. BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
  325. {
  326. // close file if it's already open
  327. if (m_File.m_hFile != NULL)
  328. {
  329. m_File.Close();
  330. }
  331. // open source file
  332. if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
  333. {
  334. return FALSE;
  335. }
  336. m_nTotalBytesSend = m_File.GetLength();
  337. if (m_dwRestartOffset < m_nTotalBytesSend)
  338. m_nTotalBytesTransfered = m_dwRestartOffset;
  339. else
  340. m_nTotalBytesTransfered = 0;
  341. return TRUE;
  342. }
  343. /********************************************************************/
  344. /* */
  345. /* Function name : CDataSocket::PrepareReceiveFile */
  346. /* Description : Prepare socket to receive a file. */
  347. /* */
  348. /********************************************************************/
  349. BOOL CDataSocket::PrepareReceiveFile(LPCTSTR lpszFilename)
  350. {
  351. // close file if it's already open
  352. if (m_File.m_hFile != NULL)
  353. {
  354. m_File.Close();
  355. }
  356. // open destination file
  357. if (!m_File.Open(lpszFilename, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate | CFile::shareDenyWrite))
  358. {
  359. return FALSE;
  360. }
  361. m_nTotalBytesReceive = 0;
  362. m_nTotalBytesTransfered = 0;
  363. if (m_dwRestartOffset)
  364. {
  365. m_File.SetLength(m_dwRestartOffset);
  366. m_File.SeekToEnd();
  367. }
  368. return TRUE;
  369. }
  370. /********************************************************************/
  371. /* */
  372. /* Function name : CDataSocket::OnReceive */
  373. /* Description : Called by the framework to notify this socket */
  374. /* that there is data in the buffer that can be */
  375. /* retrieved by calling the Receive member function.*/
  376. /* */
  377. /********************************************************************/
  378. void CDataSocket::OnReceive(int nErrorCode)
  379. {
  380. CAsyncSocket::OnReceive(nErrorCode);
  381. Receive();
  382. }
  383. /********************************************************************/
  384. /* */
  385. /* Function name : CDataSocket::Receive */
  386. /* Description : Receive data from a socket */
  387. /* */
  388. /********************************************************************/
  389. int CDataSocket::Receive()
  390. {
  391. int nRead = 0;
  392. if (m_nStatus == XFERMODE_RECEIVE)
  393. {
  394. if (m_File.m_hFile == NULL)
  395. return 0;
  396. byte data[PACKET_SIZE];
  397. nRead = CAsyncSocket::Receive(data, PACKET_SIZE);
  398. switch(nRead)
  399. {
  400. case 0:
  401. {
  402. m_File.Close();
  403. m_File.m_hFile = NULL;
  404. Close();
  405. // tell the client the transfer is complete.
  406. m_pConnectSocket->SendResponse("226 Transfer complete");
  407. // destroy this socket
  408. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  409. // upload succesfull
  410. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADSUCCEEDED);
  411. break;
  412. }
  413. case SOCKET_ERROR:
  414. {
  415. if (GetLastError() != WSAEWOULDBLOCK)
  416. {
  417. m_File.Close();
  418. m_File.m_hFile = NULL;
  419. Close();
  420. m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
  421. // destroy this socket
  422. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  423. // upload failed
  424. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
  425. }
  426. break;
  427. }
  428. default:
  429. {
  430. ((CConnectThread *)AfxGetThread())->IncReceivedBytes(nRead);
  431. TRY
  432. {
  433. m_File.Write(data, nRead);
  434. }
  435. CATCH_ALL(e)
  436. {
  437. m_File.Close();
  438. m_File.m_hFile = NULL;
  439. Close();
  440. m_pConnectSocket->SendResponse("450 Can't access file.");
  441. // destroy this socket
  442. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  443. // upload failed
  444. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
  445. return 0;
  446. }
  447. END_CATCH_ALL;
  448. break;
  449. }
  450. }
  451. }
  452. return nRead;
  453. }
  454. /********************************************************************/
  455. /* */
  456. /* Function name : CDataSocket::SetData */
  457. /* Description : Set data that is initially send to client. */
  458. /* */
  459. /********************************************************************/
  460. void CDataSocket::SetData(LPCTSTR lpszData)
  461. {
  462. m_strData = lpszData;
  463. m_nTotalBytesSend = m_strData.GetLength();
  464. m_nTotalBytesTransfered = 0;
  465. }
  466. /********************************************************************/
  467. /* */
  468. /* Function name : CDataSocket::SetTransferType */
  469. /* Description : Set transfer type: */
  470. /* 0 = LIST DIR, 1 = SEND FILE, 2 = RECEIVE FILE */
  471. /* */
  472. /********************************************************************/
  473. void CDataSocket::SetTransferType(int nType, BOOL bWaitForAccept)
  474. {
  475. m_nTransferType = nType;
  476. if (bWaitForAccept && !m_bConnected)
  477. {
  478. m_bInitialized = FALSE;
  479. return;
  480. }
  481. if (m_bConnected && m_nTransferType != -1)
  482. m_pConnectSocket->SendResponse("150 Connection accepted");
  483. m_bInitialized = TRUE;
  484. switch(m_nTransferType)
  485. {
  486. case 0: // List Directory
  487. m_nStatus = XFERMODE_LIST;
  488. OnSend(0);
  489. break;
  490. case 1: // Send File
  491. if (PrepareSendFile(m_strData))
  492. {
  493. m_nStatus = XFERMODE_SEND;
  494. m_bConnected = TRUE;
  495. OnSend(0);
  496. }
  497. else
  498. {
  499. Close();
  500. }
  501. break;
  502. case 2: // Receive File
  503. if (PrepareReceiveFile(m_strData))
  504. {
  505. m_nStatus = XFERMODE_RECEIVE;
  506. m_bConnected = TRUE;
  507. OnSend(0);
  508. }
  509. else
  510. {
  511. Close();
  512. m_pConnectSocket->SendResponse("450 Can't access file.");
  513. // destroy this socket
  514. AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
  515. // upload failed
  516. ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
  517. }
  518. break;
  519. default:
  520. m_bInitialized = FALSE;
  521. break;
  522. }
  523. }
  524. /********************************************************************/
  525. /* */
  526. /* Function name : CDataSocket::SetRestartOffset */
  527. /* Description : Set offset of where to restart file transfer. */
  528. /* */
  529. /********************************************************************/
  530. void CDataSocket::SetRestartOffset(DWORD dwOffset)
  531. {
  532. m_dwRestartOffset = dwOffset;
  533. }