// FileZilla Server - a Windows ftp server // Copyright (C) 2002-2004 - Tim Kosse // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // TransferSocket.cpp: Implementierungsdatei // #include "stdafx.h" #include "TransferSocket.h" #include "ControlSocket.h" #include "options.h" #include "ServerThread.h" #include "AsyncGssSocketLayer.h" #include "AsyncSslSocketLayer.h" #include "Permissions.h" #include "iputils.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CTransferSocket CTransferSocket::CTransferSocket(CControlSocket *pOwner) : m_pSslLayer() , m_sslContext() { ASSERT(pOwner); m_pOwner = pOwner; m_status = 0; m_nMode = TRANSFERMODE_NOTSET; m_nBufferPos = NULL; m_pBuffer = NULL; m_pDirListing = NULL; m_bAccepted = FALSE; m_bSentClose = FALSE; m_bReady = FALSE; m_bStarted = FALSE; GetSystemTime(&m_LastActiveTime); m_wasActiveSinceCheck = false; m_nRest = 0; m_pGssLayer = 0; m_hFile = INVALID_HANDLE_VALUE; m_nBufSize = (int)m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_BUFFERSIZE); m_useZlib = false; memset(&m_zlibStream, 0, sizeof(m_zlibStream)); m_zlibBytesIn = 0; m_zlibBytesOut = 0; m_pBuffer2 = 0; m_currentFileOffset = 0; m_waitingForSslHandshake = false; m_premature_send = false; } void CTransferSocket::Init(t_dirlisting *pDir, int nMode) { ASSERT(nMode==TRANSFERMODE_LIST || nMode==TRANSFERMODE_NLST); ASSERT(pDir); m_bReady = TRUE; m_status = 0; if (m_pBuffer) delete [] m_pBuffer; m_pBuffer = 0; if (m_pBuffer2) delete [] m_pBuffer2; m_pBuffer2 = 0; m_pDirListing = pDir; m_nMode = nMode; if (m_hFile != INVALID_HANDLE_VALUE) CloseHandle(m_hFile); m_nBufferPos = 0; } void CTransferSocket::Init(const CStdString& filename, int nMode, _int64 rest) { ASSERT(nMode == TRANSFERMODE_SEND || nMode == TRANSFERMODE_RECEIVE); m_bReady = TRUE; m_Filename = filename; m_nRest = rest; m_nMode = nMode; if (m_pBuffer) delete [] m_pBuffer; m_pBuffer = 0; if (m_pBuffer2) delete [] m_pBuffer2; m_pBuffer2 = 0; } CTransferSocket::~CTransferSocket() { delete [] m_pBuffer; delete [] m_pBuffer2; if (m_hFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } RemoveAllLayers(); delete m_pGssLayer; delete m_pSslLayer; CPermissions::DestroyDirlisting(m_pDirListing); if (m_useZlib) { if (m_nMode == TRANSFERMODE_RECEIVE) inflateEnd(&m_zlibStream); else deflateEnd(&m_zlibStream); } } //Die folgenden Zeilen nicht bearbeiten. Sie werden vom Klassen-Assistenten benötigt. #if 0 BEGIN_MESSAGE_MAP(CTransferSocket, CAsyncSocketEx) //{{AFX_MSG_MAP(CTransferSocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ///////////////////////////////////////////////////////////////////////////// // Member-Funktion CTransferSocket void CTransferSocket::OnSend(int nErrorCode) { CAsyncSocketEx::OnSend(nErrorCode); if (nErrorCode) { if (m_hFile != INVALID_HANDLE_VALUE) CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(1); return; } if (m_nMode == TRANSFERMODE_LIST || m_nMode == TRANSFERMODE_NLST) { //Send directory listing if (!m_bStarted) if (!InitTransfer(TRUE)) return; if (m_useZlib) { if (!m_pBuffer) { m_pBuffer = new char[m_nBufSize]; m_nBufferPos = 0; m_zlibStream.next_in = (Bytef *)m_pBuffer; // Make sure next_in is not 0 in all cases m_zlibStream.next_out = (Bytef *)m_pBuffer; m_zlibStream.avail_out = m_nBufSize; } while (true) { int numsend; if (!m_zlibStream.avail_in) { if (m_pDirListing) { m_zlibStream.next_in = (Bytef *)m_pDirListing->buffer; m_zlibStream.avail_in = m_pDirListing->len; } } if (!m_zlibStream.avail_out) { if (m_nBufferPos >= m_nBufSize) { m_nBufferPos = 0; m_zlibStream.next_out = (Bytef *)m_pBuffer; m_zlibStream.avail_out = m_nBufSize; } } int res = Z_OK; if (m_zlibStream.avail_out) { m_zlibStream.total_in = 0; m_zlibStream.total_out = 0; res = deflate(&m_zlibStream, (m_pDirListing && m_pDirListing->pNext) ? 0 : Z_FINISH); m_currentFileOffset += m_zlibStream.total_in; m_zlibBytesIn += m_zlibStream.total_in; m_zlibBytesOut += m_zlibStream.total_out; if (res == Z_STREAM_END) { if (m_pDirListing && m_pDirListing->pNext) { ShutDown(); EndTransfer(6); return; } if (!(m_nBufSize - m_nBufferPos - m_zlibStream.avail_out)) break; } else if (res != Z_OK) { ShutDown(); EndTransfer(6); return; } if (!m_zlibStream.avail_in && m_pDirListing) { t_dirlisting *pPrev = m_pDirListing; m_pDirListing = m_pDirListing->pNext; delete pPrev; } } numsend = m_nBufSize; unsigned int len = m_nBufSize - m_nBufferPos - m_zlibStream.avail_out; if (!len) continue; if (len < m_nBufSize) numsend = len; int nLimit = m_pOwner->GetSpeedLimit(download); if (nLimit != -1 && GetState() != aborted && numsend > nLimit) numsend = nLimit; if (!numsend) return; int numsent = Send(m_pBuffer + m_nBufferPos, numsend); if (numsent == SOCKET_ERROR) { if (GetLastError() != WSAEWOULDBLOCK) EndTransfer(1); return; } if (nLimit != -1 && GetState() != aborted) m_pOwner->m_SlQuotas[download].nTransferred += numsent; ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent); m_wasActiveSinceCheck = true; m_nBufferPos += numsent; if (!m_zlibStream.avail_in && !m_pDirListing && m_zlibStream.avail_out && m_zlibStream.avail_out + m_nBufferPos == m_nBufSize && res == Z_STREAM_END) { break; } //Check if there are other commands in the command queue. MSG msg; if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE)) { TriggerEvent(FD_WRITE); return; } } } else { while (m_pDirListing && m_pDirListing->len) { int numsend = m_nBufSize; if ((m_pDirListing->len - m_nBufferPos) < m_nBufSize) numsend = m_pDirListing->len - m_nBufferPos; int nLimit = m_pOwner->GetSpeedLimit(download); if (nLimit != -1 && GetState() != aborted && numsend > nLimit) numsend = nLimit; if (!numsend) return; int numsent = Send(m_pDirListing->buffer + m_nBufferPos, numsend); if (numsent == SOCKET_ERROR) { int error = GetLastError(); if (error != WSAEWOULDBLOCK) EndTransfer(1); return; } if (nLimit != -1 && GetState() != aborted) m_pOwner->m_SlQuotas[download].nTransferred += numsent; ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent); m_wasActiveSinceCheck = true; if (numsent < numsend) m_nBufferPos += numsent; else m_nBufferPos += numsend; m_currentFileOffset += numsent; ASSERT(m_nBufferPos <= m_pDirListing->len); if (m_nBufferPos == m_pDirListing->len) { t_dirlisting *pPrev = m_pDirListing; m_pDirListing = m_pDirListing->pNext; delete pPrev; m_nBufferPos = 0; if (!m_pDirListing) break; } //Check if there are other commands in the command queue. MSG msg; if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE)) { TriggerEvent(FD_WRITE); return; } } } if (m_waitingForSslHandshake) { // Don't yet issue a shutdown return; } if (m_pGssLayer || m_pSslLayer) { if (!ShutDown() && GetLastError() == WSAEWOULDBLOCK) return; } else ShutDown(); EndTransfer(0); } else if (m_nMode == TRANSFERMODE_SEND) { //Send file if (!m_bStarted) if (!InitTransfer(TRUE)) return; if (m_useZlib) { if (!m_pBuffer2) { m_pBuffer2 = new char[m_nBufSize]; m_zlibStream.next_in = (Bytef *)m_pBuffer2; } while (true) { int numsend; if (!m_zlibStream.avail_in) { if (m_hFile != INVALID_HANDLE_VALUE) { DWORD numread; if (!ReadFile(m_hFile, m_pBuffer2, m_nBufSize, &numread, 0)) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(3); // TODO: Better reason return; } m_currentFileOffset += numread; m_zlibStream.next_in = (Bytef *)m_pBuffer2; m_zlibStream.avail_in = numread; if (numread < m_nBufSize) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; if (m_waitingForSslHandshake) return; } } } if (!m_zlibStream.avail_out) { if (m_nBufferPos >= m_nBufSize) { m_nBufferPos = 0; m_zlibStream.next_out = (Bytef *)m_pBuffer; m_zlibStream.avail_out = m_nBufSize; } } int res = Z_OK; if (m_zlibStream.avail_out) { m_zlibStream.total_in = 0; m_zlibStream.total_out = 0; res = deflate(&m_zlibStream, (m_hFile != INVALID_HANDLE_VALUE) ? 0 : Z_FINISH); m_zlibBytesIn += m_zlibStream.total_in; m_zlibBytesOut += m_zlibStream.total_out; if (res == Z_STREAM_END) { if (m_hFile != INVALID_HANDLE_VALUE) { EndTransfer(6); return; } if (!(m_nBufSize - m_nBufferPos - m_zlibStream.avail_out)) break; } else if (res != Z_OK) { EndTransfer(6); return; } } numsend = m_nBufSize; unsigned int len = m_nBufSize - m_nBufferPos - m_zlibStream.avail_out; if (!len) continue; if (len < m_nBufSize) numsend = len; int nLimit = m_pOwner->GetSpeedLimit(download); if (nLimit != -1 && GetState() != aborted && numsend > nLimit) numsend = nLimit; if (!numsend) return; int numsent = Send(m_pBuffer + m_nBufferPos, numsend); if (numsent == SOCKET_ERROR) { if (GetLastError() != WSAEWOULDBLOCK) EndTransfer(1); return; } if (nLimit != -1 && GetState() != aborted) m_pOwner->m_SlQuotas[download].nTransferred += numsent; ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent); m_wasActiveSinceCheck = true; m_nBufferPos += numsent; if (!m_zlibStream.avail_in && m_hFile == INVALID_HANDLE_VALUE && m_zlibStream.avail_out && m_zlibStream.avail_out + m_nBufferPos == m_nBufSize && res == Z_STREAM_END) { break; } //Check if there are other commands in the command queue. MSG msg; if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE)) { TriggerEvent(FD_WRITE); return; } } } else { while (m_hFile != INVALID_HANDLE_VALUE || m_nBufferPos) { DWORD numread; if (m_nBufSize - m_nBufferPos && m_hFile != INVALID_HANDLE_VALUE) { if (!ReadFile(m_hFile, m_pBuffer+m_nBufferPos, m_nBufSize-m_nBufferPos, &numread, 0)) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(3); //TODO: Better reason return; } if (!numread) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; if (!m_nBufferPos) { if (m_waitingForSslHandshake) return; if (m_pGssLayer || m_pSslLayer) if (!ShutDown() && GetLastError() == WSAEWOULDBLOCK) return; EndTransfer(0); return; } } else m_currentFileOffset += numread; numread += m_nBufferPos; m_nBufferPos = 0; } else numread = m_nBufferPos; m_nBufferPos = 0; if (numread < m_nBufSize) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } int numsend = numread; int nLimit = m_pOwner->GetSpeedLimit(download); if (nLimit != -1 && GetState() != aborted && numsend > nLimit) numsend = nLimit; if (!numsend) { m_nBufferPos = numread; return; } int numsent = Send(m_pBuffer, numsend); if (numsent==SOCKET_ERROR) { if (GetLastError()!=WSAEWOULDBLOCK) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(1); return; } m_nBufferPos=numread; return; } else if ((unsigned int)numsentm_SlQuotas[download].nTransferred += numsent; ((CServerThread *)m_pOwner->m_pOwner)->IncSendCount(numsent); m_wasActiveSinceCheck = true; //Check if there are other commands in the command queue. MSG msg; if (PeekMessage(&msg,0, 0, 0, PM_NOREMOVE)) { TriggerEvent(FD_WRITE); return; } } } if (m_waitingForSslHandshake) { // Don't yet issue a shutdown return; } if (m_pGssLayer || m_pSslLayer) { if (!ShutDown() && GetLastError() == WSAEWOULDBLOCK) return; } else ShutDown(); Sleep(0); //Give the system the possibility to relay the data //If not using Sleep(0), GetRight for example can't receive the last chunk. EndTransfer(0); } else if (m_nMode == TRANSFERMODE_NOTSET) { m_premature_send = true; } } void CTransferSocket::OnConnect(int nErrorCode) { if (nErrorCode) { if (m_hFile!=INVALID_HANDLE_VALUE) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(2); return; } int size = (int)m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_BUFFERSIZE2); if (size > 0) { if (m_nMode == TRANSFERMODE_RECEIVE) SetSockOpt(SO_RCVBUF, &size, sizeof(int)); else SetSockOpt(SO_SNDBUF, &size, sizeof(int)); } if (m_pGssLayer) VERIFY(AddLayer(m_pGssLayer)); if (m_sslContext) { if (!m_pSslLayer) m_pSslLayer = new CAsyncSslSocketLayer(); VERIFY(AddLayer(m_pSslLayer)); int code = m_pSslLayer->InitSSLConnection(false, m_sslContext); if (code == SSL_FAILURE_LOADDLLS) m_pOwner->SendStatus(_T("Failed to load SSL libraries"), 1); else if (code == SSL_FAILURE_INITSSL) m_pOwner->SendStatus(_T("Failed to initialize SSL library"), 1); if (code) { EndTransfer(2); return; } m_waitingForSslHandshake = true; } if (!m_bStarted) InitTransfer(FALSE); CAsyncSocketEx::OnConnect(nErrorCode); } void CTransferSocket::OnClose(int nErrorCode) { if (nErrorCode) { if (m_hFile) { FlushFileBuffers(m_hFile); CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(1); return; } if (m_bReady) { if (m_nMode==TRANSFERMODE_RECEIVE) { //Receive all data still waiting to be recieve _int64 pos=0; do { if (m_hFile != INVALID_HANDLE_VALUE) pos=GetPosition64(m_hFile); OnReceive(0); if (m_hFile != INVALID_HANDLE_VALUE) if (pos == GetPosition64(m_hFile)) break; //Leave loop when no data was written to file } while (m_hFile != INVALID_HANDLE_VALUE); //Or file was closed if (m_hFile != INVALID_HANDLE_VALUE) { FlushFileBuffers(m_hFile); CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(0); } else EndTransfer((m_nMode == TRANSFERMODE_RECEIVE) ? 0 : 1); } CAsyncSocketEx::OnClose(nErrorCode); } int CTransferSocket::GetStatus() { return m_status; } void CTransferSocket::OnAccept(int nErrorCode) { CAsyncSocketEx tmp; Accept(tmp); SOCKET socket=tmp.Detach(); Close(); Attach(socket); m_bAccepted = TRUE; int size = (int)m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_BUFFERSIZE2); if (size > 0) { if (m_nMode == TRANSFERMODE_RECEIVE) SetSockOpt(SO_RCVBUF, &size, sizeof(int)); else SetSockOpt(SO_SNDBUF, &size, sizeof(int)); } if (m_pGssLayer) VERIFY(AddLayer(m_pGssLayer)); if (m_sslContext) { if (!m_pSslLayer) m_pSslLayer = new CAsyncSslSocketLayer(); VERIFY(AddLayer(m_pSslLayer)); int code = m_pSslLayer->InitSSLConnection(false, m_sslContext); if (code == SSL_FAILURE_LOADDLLS) m_pOwner->SendStatus(_T("Failed to load SSL libraries"), 1); else if (code == SSL_FAILURE_INITSSL) m_pOwner->SendStatus(_T("Failed to initialize SSL library"), 1); if (code) { EndTransfer(2); return; } m_waitingForSslHandshake = true; } if (m_bReady) if (!m_bStarted) InitTransfer(FALSE); CAsyncSocketEx::OnAccept(nErrorCode); } void CTransferSocket::OnReceive(int nErrorCode) { CAsyncSocketEx::OnReceive(nErrorCode); bool obeySpeedLimit = true; if (nErrorCode == WSAESHUTDOWN) obeySpeedLimit = false; else if (nErrorCode) { if (m_hFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(3); return; } else if (GetState() == closed) obeySpeedLimit = false; if (m_nMode == TRANSFERMODE_RECEIVE) { if (!m_bStarted) if (!InitTransfer(FALSE)) return; m_wasActiveSinceCheck = true; int len = m_nBufSize; int nLimit = -1; if (obeySpeedLimit) { nLimit = m_pOwner->GetSpeedLimit(upload); if (nLimit != -1 && GetState() != aborted && len > nLimit) len = nLimit; } if (!len) return; int numread = Receive(m_pBuffer, len); if (numread == SOCKET_ERROR) { const int error = GetLastError(); if (m_pSslLayer && error == WSAESHUTDOWN) { // Don't do anything at this point, we should get OnClose soon return; } else if (error != WSAEWOULDBLOCK) { if (m_hFile!=INVALID_HANDLE_VALUE) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(1); } return; } if (!numread) { if (m_hFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; } EndTransfer(0); return; } ((CServerThread *)m_pOwner->m_pOwner)->IncRecvCount(numread); if (nLimit != -1 && GetState() != aborted) m_pOwner->m_SlQuotas[upload].nTransferred += numread; if (m_useZlib) { if (!m_pBuffer2) m_pBuffer2 = new char[m_nBufSize]; m_zlibStream.next_in = (Bytef *)m_pBuffer; m_zlibStream.avail_in = numread; m_zlibStream.next_out = (Bytef *)m_pBuffer2; m_zlibStream.avail_out = m_nBufSize; m_zlibStream.total_in = 0; m_zlibStream.total_out = 0; int res = inflate(&m_zlibStream, 0); m_zlibBytesIn += m_zlibStream.total_in; m_zlibBytesOut += m_zlibStream.total_out; while (res == Z_OK) { DWORD numwritten; if (!WriteFile(m_hFile, m_pBuffer2, m_nBufSize - m_zlibStream.avail_out, &numwritten, 0) || numwritten != m_nBufSize - m_zlibStream.avail_out) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(3); // TODO: Better reason return; } m_currentFileOffset += numwritten; m_zlibStream.next_out = (Bytef *)m_pBuffer2; m_zlibStream.avail_out = m_nBufSize; res = inflate(&m_zlibStream, 0); } if (res == Z_STREAM_END) { DWORD numwritten; if (!WriteFile(m_hFile, m_pBuffer2, m_nBufSize - m_zlibStream.avail_out, &numwritten, 0) || numwritten != m_nBufSize - m_zlibStream.avail_out) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(3); // TODO: Better reason return; } m_currentFileOffset += numwritten; } else if (res != Z_OK && res != Z_BUF_ERROR) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(6); return; } } else { DWORD numwritten; if (!WriteFile(m_hFile, m_pBuffer, numread, &numwritten, 0) || numwritten!=(unsigned int)numread) { CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; EndTransfer(3); //TODO: Better reason return; } m_currentFileOffset += numwritten; } } } void CTransferSocket::PasvTransfer() { if (m_bAccepted) if (!m_bStarted) InitTransfer(FALSE); if (m_premature_send) { m_premature_send = false; OnSend(0); } } BOOL CTransferSocket::InitTransfer(BOOL bCalledFromSend) { int optAllowServerToServer, optStrictFilter; if (m_nMode == TRANSFERMODE_RECEIVE) { optAllowServerToServer = OPTION_INFXP; optStrictFilter = OPTION_NOINFXPSTRICT; } else { optAllowServerToServer = OPTION_OUTFXP; optStrictFilter = OPTION_NOOUTFXPSTRICT; } if (!m_pOwner->m_pOwner->m_pOptions->GetOptionVal(optAllowServerToServer)) { //Check if the IP of the remote machine is valid CStdString OwnerIP, TransferIP; UINT port = 0; SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); if (!m_pOwner->GetSockName(OwnerIP, port)) { EndTransfer(5); return FALSE; } if (!GetSockName(TransferIP, port)) { EndTransfer(5); return FALSE; } if (!IsLocalhost(OwnerIP) && !IsLocalhost(TransferIP)) { if (GetFamily() == AF_INET6) { OwnerIP = GetIPV6LongForm(OwnerIP); TransferIP = GetIPV6LongForm(TransferIP); } if (!m_pOwner->m_pOwner->m_pOptions->GetOptionVal(optStrictFilter)) { if (GetFamily() == AF_INET6) { // Assume a /64 OwnerIP = OwnerIP.Left(20); TransferIP = TransferIP.Left(20); } else { // Assume a /24 OwnerIP = OwnerIP.Left(OwnerIP.ReverseFind('.')); TransferIP = TransferIP.Left(TransferIP.ReverseFind('.')); } } if (OwnerIP != TransferIP) { EndTransfer(5); return FALSE; } } } if (m_nMode == TRANSFERMODE_RECEIVE) AsyncSelect(FD_READ|FD_CLOSE); else AsyncSelect(FD_WRITE|FD_CLOSE); if (m_bAccepted) { CStdString str = _T("150 Connection accepted"); if (m_nRest) str.Format(_T("150 Connection accepted, restarting at offset %I64d"), m_nRest); m_pOwner->Send(str); } m_bStarted = TRUE; if (m_nMode == TRANSFERMODE_SEND) { ASSERT(m_Filename != _T("")); int shareMode = FILE_SHARE_READ; if (m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_SHAREDWRITE)) shareMode |= FILE_SHARE_WRITE; m_hFile = CreateFile(m_Filename, GENERIC_READ, shareMode, 0, OPEN_EXISTING, 0, 0); if (m_hFile == INVALID_HANDLE_VALUE) { EndTransfer(3); return FALSE; } DWORD low=(DWORD)(m_nRest&0xFFFFFFFF); LONG high=(LONG)(m_nRest>>32); if ((low = SetFilePointer(m_hFile, low, &high, FILE_BEGIN)) == 0xFFFFFFFF && GetLastError() != NO_ERROR) { high = 0; low = SetFilePointer(m_hFile, 0, &high, FILE_END); if (low == 0xFFFFFFFF && GetLastError() != NO_ERROR) { EndTransfer(3); return FALSE; } } m_currentFileOffset = (((__int64)high) << 32) + low; if (!m_pBuffer) { m_pBuffer = new char[m_nBufSize]; m_nBufferPos = 0; if (m_useZlib) { m_zlibStream.next_out = (Bytef *)m_pBuffer; m_zlibStream.avail_out = m_nBufSize; } } } else if (m_nMode == TRANSFERMODE_RECEIVE) { unsigned int buflen = 0; int varlen = sizeof(buflen); if (GetSockOpt(SO_RCVBUF, &buflen, &varlen)) { if (buflen < m_nBufSize) { buflen = m_nBufSize; SetSockOpt(SO_RCVBUF, &buflen, varlen); } } if (m_hFile == INVALID_HANDLE_VALUE) { ASSERT(m_Filename != _T("")); int shareMode = FILE_SHARE_READ; if (m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_SHAREDWRITE)) shareMode |= FILE_SHARE_WRITE; m_hFile = CreateFile(m_Filename, GENERIC_WRITE, shareMode, 0, OPEN_ALWAYS, 0, 0); if (m_hFile == INVALID_HANDLE_VALUE) { EndTransfer(3); return FALSE; } DWORD low = (DWORD)(m_nRest&0xFFFFFFFF); LONG high = (LONG)(m_nRest>>32); low = SetFilePointer(m_hFile, low, &high, FILE_BEGIN); if (low == 0xFFFFFFFF && GetLastError() != NO_ERROR) { EndTransfer(3); return FALSE; } SetEndOfFile(m_hFile); m_currentFileOffset = (((__int64)high) << 32) + low; } if (!m_pBuffer) m_pBuffer = new char[m_nBufSize]; } GetSystemTime(&m_LastActiveTime); return TRUE; } BOOL CTransferSocket::CheckForTimeout() { if (!m_bReady) return FALSE; _int64 timeout = m_pOwner->m_pOwner->m_pOptions->GetOptionVal(OPTION_TIMEOUT); SYSTEMTIME sCurrentTime; GetSystemTime(&sCurrentTime); FILETIME fCurrentTime; SystemTimeToFileTime(&sCurrentTime, &fCurrentTime); FILETIME fLastTime; if (m_wasActiveSinceCheck) { m_wasActiveSinceCheck = false; GetSystemTime(&m_LastActiveTime); return TRUE; } SystemTimeToFileTime(&m_LastActiveTime, &fLastTime); _int64 elapsed = ((_int64)(fCurrentTime.dwHighDateTime - fLastTime.dwHighDateTime) << 32) + fCurrentTime.dwLowDateTime - fLastTime.dwLowDateTime; if (timeout && elapsed > (timeout*10000000)) { EndTransfer(4); return TRUE; } else if (!m_bStarted && elapsed > (10 * 10000000)) { EndTransfer(2); return TRUE; } else if (!timeout) return FALSE; return TRUE; } BOOL CTransferSocket::Started() const { return m_bStarted; } int CTransferSocket::GetMode() const { return m_nMode; } void CTransferSocket::UseGSS(CAsyncGssSocketLayer *pGssLayer) { m_pGssLayer = new CAsyncGssSocketLayer; m_pGssLayer->InitTransferChannel(pGssLayer); } bool CTransferSocket::UseSSL(void* sslContext) { if (m_pSslLayer) return false; m_sslContext = sslContext; return true; } int CTransferSocket::OnLayerCallback(std::list& callbacks) { for (std::list::iterator iter = callbacks.begin(); iter != callbacks.end(); iter++) { if (m_pGssLayer && iter->pLayer == m_pGssLayer) { if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == GSS_SHUTDOWN_COMPLETE) { Sleep(0); //Give the system the possibility to relay the data //If not using Sleep(0), GetRight for example can't receive the last chunk. EndTransfer(0); do { delete [] iter->str; iter++; } while (iter != callbacks.end()); return 0; } } else if (m_pSslLayer && iter->pLayer == m_pSslLayer) { if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_INFO && iter->nParam2 == SSL_INFO_SHUTDOWNCOMPLETE) { Sleep(0); //Give the system the possibility to relay the data //If not using Sleep(0), GetRight for example can't receive the last chunk. EndTransfer(0); do { delete [] iter->str; iter++; } while (iter != callbacks.end()); return 0; } else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_VERBOSE_WARNING) { if (iter->str) { CStdString str = "Data connection SSL warning: "; str += iter->str; m_pOwner->SendStatus(str, 1); } } /* Verbose info for debugging else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_VERBOSE_INFO) { if (iter->str) { CStdString str = "SSL info: "; str += iter->str; m_pOwner->SendStatus(str, 0); } }*/ else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_INFO_ESTABLISHED) { delete [] iter->str; m_waitingForSslHandshake = false; m_pOwner->SendStatus(_T("SSL connection for data connection established"), 0); return 0; } } delete [] iter->str; } return 0; } bool CTransferSocket::InitZLib(int level) { int res; if (m_nMode == TRANSFERMODE_RECEIVE) res = inflateInit2(&m_zlibStream, 15); else res = deflateInit2(&m_zlibStream, level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); if (res == Z_OK) m_useZlib = true; return res == Z_OK; } bool CTransferSocket::GetZlibStats(_int64 &bytesIn, _int64 &bytesOut) const { bytesIn = m_zlibBytesIn; bytesOut = m_zlibBytesOut; return true; } void CTransferSocket::EndTransfer(int status) { Close(); if (m_bSentClose) return; m_bSentClose = TRUE; m_status = status; m_pOwner->m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_TRANSFERMSG, m_pOwner->m_userid); }