123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- /********************************************************************/
- /* */
- /* DataSocket.cpp */
- /* */
- /* Implementation of the Data Socket. */
- /* */
- /* Programmed by LYFZ van der Meer */
- /* http://www.LYFZvandermeer.nl */
- /* */
- /* Last updated: 29 july 2002 */
- /* */
- /********************************************************************/
- #include "stdafx.h"
- #include "resource.h"
- #include "DataSocket.h"
- #include "ConnectSocket.h"
- #include "ConnectThread.h"
- #include <afxpriv.h>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define PACKET_SIZE 4096
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::CDataSocket */
- /* Description : Constructor */
- /* */
- /********************************************************************/
- CDataSocket::CDataSocket(CConnectSocket *pSocket, int nTransferType)
- {
- m_nTransferType = nTransferType;
- m_pConnectSocket = pSocket;
- m_nStatus = XFERMODE_IDLE;
- m_strData = "";
- m_File.m_hFile = NULL;
- m_bConnected = FALSE;
- m_dwRestartOffset = 0;
- m_bInitialized = FALSE;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::~CDataSocket */
- /* Description : Destructor */
- /* */
- /********************************************************************/
- CDataSocket::~CDataSocket()
- {
- m_bConnected = FALSE;
- TRACE0("CDataSocket destroyed.\n");
- }
- #if 0
- BEGIN_MESSAGE_MAP(CDataSocket, CAsyncSocket)
- //{{AFX_MSG_MAP(CDataSocket)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- #endif // 0
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::OnSend */
- /* Description : Called by the framework to notify socket that */
- /* it can send data by calling the Send method. */
- /* */
- /********************************************************************/
- void CDataSocket::OnSend(int nErrorCode)
- {
- CAsyncSocket::OnSend(nErrorCode);
- switch(m_nStatus)
- {
- case XFERMODE_LIST:
- {
- while (m_nTotalBytesTransfered < m_nTotalBytesSend)
- {
- DWORD dwRead;
- int dwBytes;
- CString strData;
-
- dwRead = m_strData.GetLength();
-
- if (dwRead <= PACKET_SIZE)
- {
- strData = m_strData;
- }
- else
- {
- strData = m_strData.Left(PACKET_SIZE);
- dwRead = strData.GetLength();
- }
-
- if ((dwBytes = Send(strData, dwRead)) == SOCKET_ERROR)
- {
- if (GetLastError() == WSAEWOULDBLOCK)
- {
- Sleep(0);
- break;
- }
- else
- {
- TCHAR szError[256];
- wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
- // close the data connection.
- Close();
- m_nTotalBytesSend = 0;
- m_nTotalBytesTransfered = 0;
- // change status
- m_nStatus = XFERMODE_IDLE;
- m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- }
- }
- else
- {
- m_nTotalBytesTransfered += dwBytes;
- m_strData = m_strData.Mid(dwBytes);
-
- ((CConnectThread *)AfxGetThread())->IncSentBytes(dwBytes);
- }
- }
- if (m_nTotalBytesTransfered == m_nTotalBytesSend)
- {
- // close the data connection.
- Close();
- m_nTotalBytesSend = 0;
- m_nTotalBytesTransfered = 0;
- // change status
- m_nStatus = XFERMODE_IDLE;
- // tell the client the transfer is complete.
- m_pConnectSocket->SendResponse("226 Transfer complete");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- }
- break;
- }
- case XFERMODE_SEND:
- {
- while (m_nTotalBytesTransfered < m_nTotalBytesSend)
- {
- // allocate space to store data
- byte data[PACKET_SIZE];
-
- m_File.Seek(m_nTotalBytesTransfered, CFile::begin);
- DWORD dwRead = m_File.Read(data, PACKET_SIZE);
-
- int dwBytes;
- if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
- {
- if (GetLastError() == WSAEWOULDBLOCK)
- {
- Sleep(0);
- break;
- }
- else
- {
- TCHAR szError[256];
- wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
- // close file.
- m_File.Close();
- m_File.m_hFile = NULL;
- // close the data connection.
- Close();
- m_nTotalBytesSend = 0;
- m_nTotalBytesTransfered = 0;
- // change status
- m_nStatus = XFERMODE_IDLE;
- m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // download failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_DOWNLOADFAILED);
- }
- }
- else
- {
- m_nTotalBytesTransfered += dwBytes;
-
- ((CConnectThread *)AfxGetThread())->IncSentBytes(dwBytes);
- }
- }
- if (m_nTotalBytesTransfered == m_nTotalBytesSend)
- {
- // close file.
- m_File.Close();
- m_File.m_hFile = NULL;
- // close the data connection.
- Close();
- m_nTotalBytesSend = 0;
- m_nTotalBytesTransfered = 0;
- // change status
- m_nStatus = XFERMODE_IDLE;
- // tell the client the transfer is complete.
- m_pConnectSocket->SendResponse("226 Transfer complete");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // download successfull
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_DOWNLOADSUCCEEDED);
- }
- break;
- }
- // default:
- // break;
- }
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::OnConnect */
- /* Description : Called by the framework to notify connecting */
- /* socket that its connection attempt is completed */
- /* */
- /********************************************************************/
- void CDataSocket::OnConnect(int nErrorCode)
- {
- if (nErrorCode)
- {
- m_nStatus = XFERMODE_ERROR;
- m_pConnectSocket->SendResponse("425 Can't open data connection.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- }
- else
- {
- switch (m_nTransferType)
- {
- case 0: // List Directory
- m_nStatus = XFERMODE_LIST;
- m_bConnected = TRUE;
- OnSend(0);
- break;
- case 1: // Send File
- if (PrepareSendFile(m_strData))
- {
- m_nStatus = XFERMODE_SEND;
- m_bConnected = TRUE;
- }
- else
- {
- Close();
- }
- break;
- case 2: // Receive File
- if (PrepareReceiveFile(m_strData))
- {
- m_nStatus = XFERMODE_RECEIVE;
- m_bConnected = TRUE;
- }
- else
- {
- Close();
- m_pConnectSocket->SendResponse("450 can't access file.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
- }
- break;
- }
- }
- CAsyncSocket::OnConnect(nErrorCode);
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::OnClose */
- /* Description : Called by the framework to notify this socket */
- /* that the connected socket is closed. */
- /* */
- /********************************************************************/
- void CDataSocket::OnClose(int nErrorCode)
- {
- TRACE0("CDataSocket() OnClose()\n");
- if (m_pConnectSocket)
- {
- // shutdown sends
- ShutDown(1);
- if (m_nStatus == XFERMODE_RECEIVE)
- {
- while(Receive() != 0)
- {
- // receive remaining data
- }
- }
- else
- {
- m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
- }
- }
- m_nStatus = XFERMODE_IDLE;
- m_bConnected = FALSE;
- CAsyncSocket::OnClose(nErrorCode);
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::OnAccept */
- /* Description : Notify this listening socket that it can accept */
- /* pending connection requests. */
- /* */
- /********************************************************************/
- void CDataSocket::OnAccept(int nErrorCode)
- {
- // Accept the connection using a temp CSocket object.
- CAsyncSocket tmpSocket;
- Accept(tmpSocket);
-
- SOCKET socket = tmpSocket.Detach();
- Close();
- Attach(socket);
- m_bConnected = TRUE;
- if (!m_bInitialized)
- SetTransferType(m_nTransferType);
-
- CAsyncSocket::OnAccept(nErrorCode);
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::GetStatus */
- /* Description : Get socket status. */
- /* */
- /********************************************************************/
- int CDataSocket::GetStatus()
- {
- return m_nStatus;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::PrepareSendFile */
- /* Description : Prepare socket to send a file. */
- /* */
- /********************************************************************/
- BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
- {
- // close file if it's already open
- if (m_File.m_hFile != NULL)
- {
- m_File.Close();
- }
- // open source file
- if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
- {
- return FALSE;
- }
- m_nTotalBytesSend = m_File.GetLength();
- if (m_dwRestartOffset < m_nTotalBytesSend)
- m_nTotalBytesTransfered = m_dwRestartOffset;
- else
- m_nTotalBytesTransfered = 0;
- return TRUE;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::PrepareReceiveFile */
- /* Description : Prepare socket to receive a file. */
- /* */
- /********************************************************************/
- BOOL CDataSocket::PrepareReceiveFile(LPCTSTR lpszFilename)
- {
- // close file if it's already open
- if (m_File.m_hFile != NULL)
- {
- m_File.Close();
- }
- // open destination file
- if (!m_File.Open(lpszFilename, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate | CFile::shareDenyWrite))
- {
- return FALSE;
- }
- m_nTotalBytesReceive = 0;
- m_nTotalBytesTransfered = 0;
- if (m_dwRestartOffset)
- {
- m_File.SetLength(m_dwRestartOffset);
- m_File.SeekToEnd();
- }
- return TRUE;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::OnReceive */
- /* Description : Called by the framework to notify this socket */
- /* that there is data in the buffer that can be */
- /* retrieved by calling the Receive member function.*/
- /* */
- /********************************************************************/
- void CDataSocket::OnReceive(int nErrorCode)
- {
- CAsyncSocket::OnReceive(nErrorCode);
-
- Receive();
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::Receive */
- /* Description : Receive data from a socket */
- /* */
- /********************************************************************/
- int CDataSocket::Receive()
- {
- int nRead = 0;
-
- if (m_nStatus == XFERMODE_RECEIVE)
- {
- if (m_File.m_hFile == NULL)
- return 0;
- byte data[PACKET_SIZE];
- nRead = CAsyncSocket::Receive(data, PACKET_SIZE);
- switch(nRead)
- {
- case 0:
- {
- m_File.Close();
- m_File.m_hFile = NULL;
- Close();
- // tell the client the transfer is complete.
- m_pConnectSocket->SendResponse("226 Transfer complete");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload succesfull
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADSUCCEEDED);
- break;
- }
- case SOCKET_ERROR:
- {
- if (GetLastError() != WSAEWOULDBLOCK)
- {
- m_File.Close();
- m_File.m_hFile = NULL;
- Close();
- m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
- }
- break;
- }
- default:
- {
- ((CConnectThread *)AfxGetThread())->IncReceivedBytes(nRead);
- TRY
- {
- m_File.Write(data, nRead);
- }
- CATCH_ALL(e)
- {
- m_File.Close();
- m_File.m_hFile = NULL;
- Close();
- m_pConnectSocket->SendResponse("450 Can't access file.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
- return 0;
- }
- END_CATCH_ALL;
- break;
- }
- }
- }
- return nRead;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::SetData */
- /* Description : Set data that is initially send to client. */
- /* */
- /********************************************************************/
- void CDataSocket::SetData(LPCTSTR lpszData)
- {
- m_strData = lpszData;
- m_nTotalBytesSend = m_strData.GetLength();
- m_nTotalBytesTransfered = 0;
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::SetTransferType */
- /* Description : Set transfer type: */
- /* 0 = LIST DIR, 1 = SEND FILE, 2 = RECEIVE FILE */
- /* */
- /********************************************************************/
- void CDataSocket::SetTransferType(int nType, BOOL bWaitForAccept)
- {
- m_nTransferType = nType;
- if (bWaitForAccept && !m_bConnected)
- {
- m_bInitialized = FALSE;
- return;
- }
- if (m_bConnected && m_nTransferType != -1)
- m_pConnectSocket->SendResponse("150 Connection accepted");
- m_bInitialized = TRUE;
- switch(m_nTransferType)
- {
- case 0: // List Directory
- m_nStatus = XFERMODE_LIST;
- OnSend(0);
- break;
- case 1: // Send File
- if (PrepareSendFile(m_strData))
- {
- m_nStatus = XFERMODE_SEND;
- m_bConnected = TRUE;
- OnSend(0);
- }
- else
- {
- Close();
- }
- break;
- case 2: // Receive File
- if (PrepareReceiveFile(m_strData))
- {
- m_nStatus = XFERMODE_RECEIVE;
- m_bConnected = TRUE;
- OnSend(0);
- }
- else
- {
- Close();
- m_pConnectSocket->SendResponse("450 Can't access file.");
- // destroy this socket
- AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
- // upload failed
- ((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
- }
- break;
- default:
- m_bInitialized = FALSE;
- break;
- }
- }
- /********************************************************************/
- /* */
- /* Function name : CDataSocket::SetRestartOffset */
- /* Description : Set offset of where to restart file transfer. */
- /* */
- /********************************************************************/
- void CDataSocket::SetRestartOffset(DWORD dwOffset)
- {
- m_dwRestartOffset = dwOffset;
- }
|