SocketBase.cpp
资源名称:warftpd.zip [点击查看]
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:80k
源码类别:
Ftp客户端
开发平台:
Visual C++
- // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
- // Copyright 1996 by Jarle Aase. All rights reserved.
- // See the "War Software Series Licende Agreement" for details concerning
- // use and distribution.
- // ---
- // This source code, executables and programs containing source code or
- // binaries or proprietetary technology from the War Software Series are
- // NOT alloed used, viewed or tested by any governmental agencies in
- // any countries. This includes the government, departments, police,
- // military etc.
- // ---
- // This file is intended for use with Tab space = 2
- // Created and maintained in MSVC Developer Studio
- // ---
- // NAME : SocketBase.cpp
- // PURPOSE : Basic socket handeling
- // PROGRAM :
- // DATE : Sept. 19 1996
- // AUTHOR : Jarle Aase
- // ---
- // REVISION HISTORY
- //
- #include "stdafx.h"
- #include "telnet.h"
- #include "ftp.h"
- #include "WarSoftware.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////
- // CSockHandler
- // Maintanance class for sockets
- CSocketException::CSocketException()
- {
- };
- void CSocketException::Throw(CSock *pSock, LPCSTR Module, int ErrorNum, LPCSTR Format, ...)
- {
- CWarString cBuf;
- CSocketException *pExc = new CSocketException;
- if (Format == NULL)
- pExc->m_ErrorText = GetLastErrorText(ErrorNum);
- else
- {
- va_list argList;
- va_start(argList, Format);
- cBuf.FormatVaList(Format, argList);
- va_end(argList);
- pExc->m_ErrorText = cBuf;
- }
- pExc->m_FromModule = Module;
- pExc->m_ErrorNum = ErrorNum;
- pExc->m_pSock = pSock;
- if (CSock::m_Log)
- CSock::m_Log->LogMsg(LOGF_DEBUG,"CSocketException::Throw(%s) - from module %s err=%d msg=%s",
- pSock->m_SocketName, Module, ErrorNum, cBuf);
- throw pExc;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // CSock
- // Base class for all async socket communication
- IMPLEMENT_DYNAMIC(CSock, CAsyncSocket);
- DWORD CSock::m_SequenceCounter = 0;
- CLog *CSock::m_Log = NULL;
- DWORD CSock::m_NumSocketsInUse = 0;
- CCriticalSection CSock::m_GlobalLock;
- LPSTR CSock::DaemonTypes[4] = { "FTP", "FTPData", "Telnet", "RemoteAdmin" };
- int CSock::m_OverlappedCnt = 0;
- CLinkedList CSock::m_SocketList;
- CWnd *CSock::m_DNSwin = NULL;
- CWarTimer CSock::m_Housekeeping;
- CSock::CSock()
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_GlobalLock.Lock();
- m_State = PRELOGIN;
- m_SocketID = ++m_SequenceCounter;
- ++m_NumSocketsInUse;
- m_SocketName = "CSock";
- m_ClearToSend = FALSE;
- m_ClearToReceive = FALSE;
- m_BytesSent = 0;
- m_BytesReceived = 0;
- m_Type = LT_INVALID;
- m_IsConnected = FALSE;
- m_SocketList.AddFirst((LPVOID)this);
- m_Father = NULL;
- m_SuspendOnClose = FALSE;
- m_GlobalLock.Unlock();
- m_AsyncSelectMask = FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT | FD_CLOSE;
- m_DestructorIsActive = FALSE;
- m_SuspendDelete = 0;
- m_MaxIdleTime = 0;
- m_MaxOnlineTime = 0;
- // EXT module
- PrcExt(CAPIHandler::OnNewSocket,0,0,(LPARAM)this);
- }
- CSock::~CSock()
- {
- m_DestructorIsActive = TRUE;
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- if (m_hSocket != INVALID_SOCKET)
- {
- AsyncSelect(0);
- Close();
- }
- m_GlobalLock.Lock();
- --m_NumSocketsInUse;
- m_SocketList.DeletePtr((LPVOID)this);
- m_GlobalLock.Unlock();
- PrcSockExt(iOnSocketIsDestroyed,0,0,(LPARAM)this);
- if (m_Log)
- LogMsg(LOGF_DEBUG,"~CSock() - socket destroyed. %d sockets left in use.", m_NumSocketsInUse );
- #ifdef _DEBUG
- if (m_SuspendDelete && m_Log)
- LogMsg(LOGF_DEBUG,"~CSock() - Warning - socket was suspended from deletion (%d).",
- m_SuspendDelete);
- #endif
- }
- void CSock::SetIdleTime(int limit)
- {
- m_MaxIdleTime = limit;
- }
- void CSock::SetLogonTime(int limit)
- {
- m_MaxOnlineTime = limit;
- }
- void CSock::SetDNSWin(CWnd *pWnd)
- {
- m_DNSwin = pWnd;
- }
- BOOL CSock::IsOkToDelete(BOOL IgnoreSuspend)
- {
- return TRUE;
- }
- void CSock::InitiateDNSLookup()
- {
- CDNSLookup *pLookup = new CDNSLookup();
- pLookup->Create(this);
- }
- void CSock::OnDNSLookup(int nErrorCode, CDNSLookup *pDNS)
- {
- int err;
- if (nErrorCode)
- {
- LogMsg(LOGF_DEBUG,"OnDNSLookup() failed. Error code %d", nErrorCode);
- }
- else
- {
- ASSERT(AfxIsValidString(((struct hostent *)&(pDNS->m_Buf))->h_name));
- m_DNSName = ((struct hostent *)&(pDNS->m_Buf))->h_name;
- }
- if (err = PrcSockExt(iOnVerifyIPAddress, nErrorCode, 0, (LPARAM)pDNS))
- {
- if (err == CFuncList::AbortError)
- CSocketException::Throw(this, "CSock::OnDNSLookup", -1, "Plugin said NO!");
- if (err == CFuncList::OkAllDone)
- return;
- }
- m_AsyncSelectMask |= (FD_READ | FD_WRITE);
- AsyncSelect(m_AsyncSelectMask);
- }
- void CSock::OnFileCompletion(int nErrorCode)
- {
- ;
- }
- // Called by listening sockets to delete all children before a service shuts down
- void CSock::KillAllChildren()
- {
- CLinkedListItem *Item = m_SocketList.First(), *CurrItem;
- while(Item)
- {
- CurrItem = Item;
- CSock *Soc = (CSock *)m_SocketList.Ptr(Item);
- Item = m_SocketList.Next(Item);
- ASSERT(AfxIsValidAddress(Soc,sizeof(CSock)));
- if (Soc->m_Father == this)
- {
- Soc->SayGoodbye();
- m_SocketList.DeleteItem(CurrItem);
- delete Soc;
- }
- }
- }
- // Override to say goodbye
- void CSock::SayGoodbye()
- {
- return;
- }
- CUserFsys *CSock::GetFsys()
- {
- return NULL;
- }
- // Get the local IP number
- BOOL CSock::GetHostIpNumber(CString& cIpName)
- {
- SOCKADDR_IN sockAddr;
- LPHOSTENT lphost;
- char LogicName[64];
- cIpName = "localhost";
- if (gethostname(LogicName,sizeof(LogicName) -1))
- return FALSE;
- memset(&sockAddr,0,sizeof(sockAddr));
- sockAddr.sin_family = AF_INET;
- sockAddr.sin_addr.s_addr = inet_addr(LogicName);
- if (sockAddr.sin_addr.s_addr == INADDR_NONE)
- {
- lphost = gethostbyname(LogicName);
- if (lphost != NULL)
- {
- sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
- }
- else
- return FALSE;
- }
- cIpName = inet_ntoa(sockAddr.sin_addr);
- return TRUE;
- }
- // Elapsed time in seconds
- float CSock::GetLapTime()
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- return (float)m_StartTime.TimeDiff() / (float)1000;
- }
- // Bytes/Second
- float CSock::GetCPS()
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- return (float)(m_BytesSent + m_BytesReceived) / GetLapTime();
- }
- // Total kb/s for all sockets
- float CSock::GetTotalCPS()
- {
- CLinkedListItem *Item;
- CSock *pSock;
- float Rval = (float)0.0;
- for(Item = m_SocketList.First(); Item; Item = m_SocketList.Next(Item))
- {
- pSock = (CSock *)m_SocketList.Ptr(Item);
- ASSERT(AfxIsValidAddress(pSock, sizeof(CSock)));
- if ((pSock->m_hSocket != INVALID_SOCKET) && !pSock->m_Timer.TimeOut(3000))
- Rval += pSock->GetCPS();
- }
- return Rval;
- }
- CSock *CSock::GetFromID(DWORD ID)
- {
- CLinkedListItem *Item = m_SocketList.First();
- CSock *pSock;
- while(Item)
- {
- pSock = (CSock *)m_SocketList.Ptr(Item);
- Item = m_SocketList.Next(Item);
- if (pSock->m_SocketID == ID)
- return pSock;
- }
- return NULL;
- }
- static BOOL IsProcessingIdle;
- BOOL CSock::OnIdle( LONG lCount )
- {
- int Cnt;
- IsProcessingIdle = TRUE;
- while(Cnt = m_OverlappedCnt)
- {
- SleepEx(0, TRUE);
- if (Cnt == m_OverlappedCnt)
- break;
- }
- IsProcessingIdle = FALSE;
- CLinkedListItem *Item, *NextItem;
- CSock *pSock;
- for (Item = m_SocketList.First(); Item; Item = NextItem)
- {
- NextItem = m_SocketList.Next(Item);
- pSock = (CSock *)m_SocketList.Ptr(Item);
- pSock->PrcSockExt(CSock::iOnIdle, 0, lCount, 0);
- if (m_Housekeeping.TimeOut(5000))
- {
- // Check timeout on all sockets
- if (pSock->m_MaxIdleTime && pSock->m_State == HOLD)
- pSock->m_Timer.Reset(); // Avoid dumping held sockets
- if (pSock->m_MaxIdleTime && pSock->m_Timer.TimeOut(pSock->m_MaxIdleTime))
- {
- pSock->LogMsg(LOGF_INOUT,"Idle time of %d seconds expired.", pSock->m_MaxIdleTime / 1000);
- if (!pSock->OnHandleWinsockErr(SOCKERR_IDLETIME))
- delete pSock;
- }
- else if (pSock->m_MaxOnlineTime && pSock->m_Timer.TimeOut(pSock->m_MaxOnlineTime))
- {
- pSock->LogMsg(LOGF_INOUT,"Login time limit of %d minutes expired.", pSock->m_MaxOnlineTime / 60000);
- if (!pSock->OnHandleWinsockErr(SOCKERR_LOGINTIME))
- delete pSock;
- }
- // NOTE: Do _NOT_ access pSock now. It might be deleted!
- }
- }
- if (m_Housekeeping.TimeOut(5000))
- m_Housekeeping.Reset();
- return m_OverlappedCnt != 0;
- }
- void CSock::SetName(LPCSTR Name)
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_SocketName = Name;
- }
- void CSock::IncXferCnt(BOOL Add)
- {
- // Override to update server status
- }
- void CSock::SetLog(CLog *LogPtr)
- {
- m_Log = LogPtr;
- }
- void CSock::LogMsg(int flag, LPCSTR Format, ...)
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- if (!ShouldLog(m_Log, flag))
- return;
- {
- CString cBuf;
- ASSERT(AfxIsValidString(Format, FALSE));
- cBuf.Format("%s: %s", m_SocketName, Format);
- va_list argList;
- va_start(argList, Format);
- m_Log->LogMsgV(flag, cBuf, argList);
- va_end(argList);
- }
- }
- void CSock::LogLastError(int flag, int eval, LPCSTR msg)
- {
- //ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- char *p = "";
- if (!eval)
- eval = GetLastError();
- switch(eval)
- {
- case WSAEFAULT: p = "WSAEFAULT. Argument to small or not in a valid part of the process address space."; break;
- case WSAEWOULDBLOCK: p = "WSAEWOULDBLOCK The socket is marked as nonblocking and no connections are present to be accepted."; break;
- case WSANOTINITIALISED: p = "WSANOTINITIALISED A successful AfxSocketInit must occur before using this API."; break;
- case WSAENETDOWN: p = "WSAENETDOWN The Windows Sockets implementation detected that the network subsystem failed."; break;
- case WSAEADDRINUSE: p = "WSAEADDRINUSE An attempt has been made to listen on an address in use."; break;
- case WSAEINPROGRESS: p = "WSAEINPROGRESS A blocking Windows Sockets operation is in progress."; break;
- case WSAEINVAL: p = "WSAEINVAL Generic error message. Check with Winsock manual pages."; break;
- case WSAEISCONN: p = "WSAEISCONN The socket is already connected."; break;
- case WSAEMFILE: p = "WSAEMFILE No more file descriptors are available."; break;
- case WSAENOBUFS: p = "WSAENOBUFS No buffer space is available."; break;
- case WSAENOTSOCK: p = "WSAENOTSOCK The descriptor is not a socket."; break;
- case WSAEOPNOTSUPP: p = "WSAEOPNOTSUPP The referenced socket is not of a type that supports the Listen operation."; break;
- case WSAEAFNOSUPPORT: p= "WSAEAFNOSUPPORT The specified address family is not supported."; break;
- case WSAEPROTOTYPE: p = "WSAEPROTOTYPE The specified port is the wrong type for this socket."; break;
- case WSAENETRESET: p = "WSAENETRESET Connection has timed out when SO_KEEPALIVE is set."; break;
- case WSAENOPROTOOPT: p = "WSAENOPROTOOPT The option is unknown or unsupported. In particular, SO_BROADCAST is not supported on sockets of type SOCK_STREAM, while SO_DONTLINGER, SO_KEEPALIVE, SO_LINGER, and SO_OOBINLINE are not supported on sockets of type SOCK_DGRAM."; break;
- case WSAENOTCONN: p = "WSAENOTCONN Connection has been reset when SO_KEEPALIVE is set."; break;
- case WSAEPROTONOSUPPORT: p = "WSAEPROTONOSUPPORT The specified port is not supported."; break;
- case WSAESOCKTNOSUPPORT: p = "WSAESOCKTNOSUPPORT The specified socket type is not supported in this address family."; break;
- case WSAEHOSTDOWN: p = "WSAEHOSTDOWN"; break;
- case WSAEHOSTUNREACH: p = "WSAEHOSTUNREACH"; break;
- case WSAEADDRNOTAVAIL: p = "WSAEADDRNOTAVAIL"; break;
- case WSAESHUTDOWN: p = "WSAESHUTDOWN"; break;
- }
- LogMsg(flag,"%s - Socket error %d %s", msg, eval, p);
- }
- void CSock::OnAccept( int nErrorCode )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_Timer.Reset();
- LogMsg(LOGF_WINSOCK,"OnAccept(%d)", nErrorCode);
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnAccept()", nErrorCode, NULL);
- }
- // Called from derived class that know what dataclass we must
- // use.
- BOOL CSock::DoAccept(CSock *NewSocket )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- UINT MyPort;
- CString cBuf;
- NewSocket->m_Type = m_Type;
- ASSERT(m_Type != LT_INVALID);
- if (!Accept(*NewSocket))
- {
- NewSocket->LogLastError(LOGF_WARNINGS,0,"CLSock::DoAccept(): Accept() failed.");
- return FALSE;
- }
- // Set IO flags
- if (!NewSocket->AsyncSelect(m_AsyncSelectMask))
- {
- NewSocket->LogLastError(LOGF_WARNINGS,0,"CLSock::DoAccept(): AsyncSelect() failed.");
- return FALSE;
- }
- if (!NewSocket->GetSockName(NewSocket->m_HostName,MyPort))
- {
- NewSocket->LogLastError(LOGF_WARNINGS,0, "CLSock::DoAccept: GetSockName() failed.");
- }
- else
- {
- LogMsg(LOGF_DEBUG,"Connected to Local IP: %s", (LPCSTR)NewSocket->m_HostName);
- }
- NewSocket->GetPeerName(NewSocket->m_PeerName,MyPort);
- NewSocket->m_DNSName = NewSocket->m_PeerName;
- // OnConnect is never called by the framework on accepted sockets.
- // We use OnAccept() for one-time class member initializtion, so we
- // call it here.
- NewSocket->_OnConnect(0);
- return TRUE;
- }
- void CSock::OnClose( int nErrorCode )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- AsyncSelect(0); // We don't want more messages...
- m_Timer.Reset();
- LogMsg(LOGF_WINSOCK,"OnClose(%d)", nErrorCode);
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnClose()", nErrorCode, NULL);
- if (!m_SuspendOnClose)
- Close();
- }
- BOOL CSock::OnHandleWinsockErr(int nErrorCode )
- {
- LogMsg(LOGF_DEBUG,"CSock::OnHandleWinsockErr(%d)", "No default handler for this error.", nErrorCode);
- delete this;
- return TRUE; // Deleted
- }
- void CSock::_OnConnect( int nErrorCode )
- {
- ASSERT(FALSE); // Must be overridden
- }
- void CSock::OnConnect( int nErrorCode )
- {
- PrcSockExt(iOnConnect, nErrorCode, NULL, NULL);
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_Timer.Reset();
- ASSERT(m_IsConnected == FALSE);
- m_AsyncSelectMask &= ~FD_CONNECT;
- AsyncSelect(m_AsyncSelectMask);
- LogMsg(LOGF_WINSOCK,"OnConnect(%d)", nErrorCode);
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnConnect",nErrorCode,NULL);
- m_ConnectTime.Reset();
- m_IsConnected = TRUE;
- BOOL True = TRUE;
- if (!SetSockOpt(SO_KEEPALIVE,(LPVOID)&True,sizeof(True)))
- LogLastError(LOGF_DEBUG,0,"OnConnect() - Failed to SetSockOpt(SO_KEEPALIVE).");
- }
- void CSock::OnOutOfBandData( int nErrorCode )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_Timer.Reset();
- LogMsg(LOGF_WINSOCK,"OnOutOfBandData(%d)", nErrorCode);
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnOutOfBandData",nErrorCode,NULL);
- }
- void CSock::OnReceive( int nErrorCode )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- CAsyncSocket::OnReceive(nErrorCode);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- PrcSockExt(iOnReceive, nErrorCode, 0, 0);
- // Turn off READ notifications (MFC BUG workaround)
- AsyncSelect(m_AsyncSelectMask & ~FD_READ);
- m_Timer.Reset();
- m_ClearToReceive = TRUE;
- LogMsg(LOGF_WINSOCK,"OnReceive(%d)", nErrorCode);
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnReceive",nErrorCode,NULL);
- }
- void CSock::OnSend( int nErrorCode )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- CAsyncSocket::OnSend(nErrorCode);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- PrcSockExt(iOnSend, nErrorCode, 0, 0);
- m_Timer.Reset();
- LogMsg(LOGF_WINSOCK,"OnSend(%d)", nErrorCode);
- m_ClearToSend = TRUE;
- if (nErrorCode)
- CSocketException::Throw(this, "CSock::OnSend",nErrorCode,NULL);
- }
- BOOL CSock::Accept( CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr, int* lpSockAddrLen)
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- m_Timer.Reset();
- LogMsg(LOGF_WINSOCK,"Accept()");
- return CAsyncSocket::Accept(rConnectedSocket, lpSockAddr, lpSockAddrLen);
- }
- void CSock::Close( )
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- LogMsg(LOGF_WINSOCK,"Close()");
- m_IsConnected = FALSE;
- m_ClearToReceive = FALSE;
- m_ClearToSend = FALSE;
- if (m_hSocket != INVALID_SOCKET)
- {
- AsyncSelect(0);
- CAsyncSocket::Close();
- }
- }
- // We return 0 on the WSAEWOULDBLOCK event
- // We throw an exception on EOF.
- int CSock::Receive( void* lpBuf, int nBufLen, int nFlags)
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- int Rval = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags);
- int err;
- if (Rval == SOCKET_ERROR)
- {
- if ((err = GetLastError()) == WSAEWOULDBLOCK)
- {
- LogMsg(LOGF_WINSOCK,"Receive() (Waiting for data)");
- m_ClearToReceive = FALSE;
- // Turn on read notification (MFC bug workaround)
- AsyncSelect(m_AsyncSelectMask);
- Rval = 0;
- }
- else
- CSocketException::Throw(this, "CSock::Receive()", err, NULL);
- }
- else if (Rval == 0)
- CSocketException::Throw(this, "CSock::Receive()", 0, "EOF. 0 bytes read.");
- LogMsg(LOGF_WINSOCK,"Receive() (%d bytes)", Rval);
- m_BytesReceived += Rval;
- m_LastReceive.Reset();
- m_Timer.Reset();
- if (m_StartTime.m_TimerVal == m_ConnectTime.m_TimerVal)
- m_StartTime.Reset(); // Start of transmission timer
- return Rval;
- }
- // Note: We call OnClose() to destroy the object on errors and
- // termination.
- // We return 0 on the WSAEWOULDBLOCK event
- // We return -1 on fatal error, after the object is deleted.
- int CSock::Send( const void* lpBuf, int nBufLen, int nFlags)
- {
- ASSERT(m_hSocket != INVALID_SOCKET);
- ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
- if (nBufLen <= 0)
- return 0;
- int Rval = CAsyncSocket::Send(lpBuf, nBufLen, nFlags);
- int err;
- if (Rval == SOCKET_ERROR)
- {
- if ((err = GetLastError()) == WSAEWOULDBLOCK)
- {
- LogMsg(LOGF_WINSOCK,"Send() (Waiting for data)");
- m_ClearToSend = FALSE;
- Rval = 0;
- }
- else
- {
- CSocketException::Throw(this, "CSock::Send()", err, NULL,
- err, GetLastErrorText(err));
- }
- }
- else if (Rval == 0)
- {
- LogMsg(LOGF_WINSOCK,"*** Send(%d) (%d bytes sent)", nBufLen, Rval);
- }
- else
- {
- LogMsg(LOGF_WINSOCK,"Send(%d) (%d bytes sent)", nBufLen, Rval);
- m_BytesSent += Rval;
- }
- m_LastSend.Reset();
- m_Timer.Reset();
- if (m_StartTime.m_TimerVal == m_ConnectTime.m_TimerVal)
- m_StartTime.Reset(); // Start of transmission timer
- return Rval;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // CBufferSock
- IMPLEMENT_DYNAMIC(CBufferSock, CSock);
- CBufferSock::CBufferSock()
- {
- m_BufferSize = m_MaxBufferSize = BUFFERSOCK_DEFUALT_BUFFER_SIZE;
- m_MaxSendLen = m_BufferSize;
- m_OutBuf = new char[m_BufferSize];
- m_BufferUsed = 0;
- }
- CBufferSock::~CBufferSock()
- {
- if (m_OutBuf)
- delete m_OutBuf;
- }
- void CBufferSock::TrashOutputBuffer()
- {
- m_BufferUsed = 0;
- }
- BOOL CBufferSock::DoOverlapped()
- {
- return TRUE; // Currently no default processing
- }
- int CBufferSock::Send( const void* lpBuf, int nBufLen, int nFlags)
- {
- // All data must be sent with SendBuffer!
- ASSERT(FALSE);
- return -1;
- }
- void CBufferSock::OnSend( int nErrorCode )
- {
- CSock::OnSend(nErrorCode);
- if (nErrorCode)
- return;
- DoSend();
- }
- // Send if we have queued data!
- BOOL CBufferSock::DoSend()
- {
- int BytesSent;
- ASSERT(m_ClearToSend);
- // Send as much as possible
- while(m_BufferUsed && m_ClearToSend)
- {
- BytesSent = CSock::Send(m_OutBuf, min((int)m_BufferUsed,m_MaxSendLen));
- m_BufferUsed -= BytesSent;
- ASSERT(m_BufferUsed >= 0);
- if (m_BufferUsed)
- memmove(m_OutBuf,m_OutBuf + BytesSent, m_BufferUsed);
- }
- return TRUE;
- }
- // Prepere to send a databuffer
- // Returns -1 on fatal error after object is deleted.
- long CBufferSock::SendBuffer(LPCSTR Buffer, DWORD Size)
- {
- int BytesSent = 0;
- int BytesQueued;
- long BytesToQueue;
- if (BufferSock_BufferFree() < Size)
- {
- if (m_MaxBufferSize < (m_BufferUsed + Size))
- m_MaxBufferSize = m_BufferUsed + Size + 16;
- if (BufferSock_BufferFree() < m_MaxBufferSize)
- {
- LogMsg(LOGF_DEBUG,
- "CBufferSock::SendBuffer(): Reallocating buffer to %d bytes", m_MaxBufferSize);
- // Allocate more space
- LPSTR p = new char[m_BufferSize = m_MaxBufferSize];
- memcpy(p,m_OutBuf,m_BufferUsed);
- delete m_OutBuf;
- m_OutBuf = p;
- }
- if (BufferSock_BufferFree() == 0)
- return 0;
- }
- if (!m_BufferUsed && m_ClearToSend)
- {
- // Optimize - just send what we can at once
- BytesSent = CSock::Send(Buffer, min((int)Size,m_MaxSendLen));
- }
- if ((BytesToQueue = (Size - BytesSent)) == 0)
- return BytesSent; // Nothing left to queue...
- ASSERT(BytesToQueue > 0);
- #ifdef _DEBUG
- int FreeBytes = BufferSock_BufferFree();
- int NeededBytes = BytesToQueue + m_BufferUsed;
- int UsedBytes = m_BufferUsed;
- int BufSize = m_BufferSize;
- ASSERT(FreeBytes >= BytesToQueue);
- #endif // _DEBUG
- memcpy(m_OutBuf,Buffer + BytesSent,
- BytesQueued = BytesToQueue);
- m_BufferUsed += BytesQueued;
- return BytesQueued + BytesSent;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // CTextSock
- IMPLEMENT_DYNAMIC(CTextSock, CBufferSock);
- int CTextSock::m_LoginCounter = 0;
- HANDLE CTextSock::m_SvrEvents = INVALID_HANDLE_VALUE;
- CLinkedList CTextSock::m_UserConnections;
- CTextSock::CTextSock()
- {
- m_InsertOffset = 0;
- m_Virgin = TRUE;
- m_LocalEcho = FALSE;
- m_HandleBackspace = FALSE;
- m_SuspendExpandMacros = TRUE;
- m_BufferSize = TEXTSOCK_DEFUALT_BUFFER_SIZE - 4; // Make space for trailing 0
- m_BufferUsed = 0;
- m_InBuf = new char[TEXTSOCK_DEFUALT_BUFFER_SIZE];
- m_SavedIndex = 0;
- m_HaveIAC = FALSE;
- m_HaveCR = FALSE;
- m_User = 0;
- m_RootDir.Empty();
- m_HomeDir.Empty();
- m_CWD.Empty();
- m_Events = new CDaemonEvent(this, 1024);
- m_LoginNum = ++m_LoginCounter;
- m_IsLoggedIn = FALSE;
- m_LoginName = "Prelogin";
- m_StateSave = -1;
- m_SuspendEvents = FALSE;
- m_FileHandle = INVALID_HANDLE_VALUE;
- m_UserConnections.AddLast((LPVOID)this);
- PrcExt(CAPIHandler::OnNewTextSocket,0,0,(LPARAM)this);
- }
- CTextSock::~CTextSock()
- {
- NotifyLogin(ENL_DEL);
- PrcExt(CAPIHandler::OnLogout,0,0,(LPARAM)this);
- if (m_IsLoggedIn)
- LogMsg(LOGF_INOUT,"Logged out");
- if (m_InBuf)
- delete m_InBuf;
- if (m_Events)
- delete m_Events;
- m_UserConnections.DeletePtr((LPVOID)this);
- }
- BOOL CTextSock::InitSvrEvents()
- {
- if (m_SvrEvents != INVALID_HANDLE_VALUE)
- return TRUE;
- if ((m_SvrEvents = CDaemonEvent::DsRegister(
- EVT_CONN, NULL, WhoSendAll)) == INVALID_HANDLE_VALUE)
- {
- m_Log->LogMsg(LOGF_ERROR,"InitSvrEvents() - Unable to register LOGIN event.");
- return FALSE;
- }
- return TRUE;
- }
- // Send a file over the control connection
- BOOL CTextSock::SendFile(LPCSTR Path, LPCSTR Name)
- {
- char FullPath[MAX_PATH];
- LPTSTR Unused;
- DWORD Length;
- if (!SearchPath(Path, Name, NULL, MAX_PATH, FullPath, &Unused))
- {
- LogMsg(LOGF_WARNINGS,"Failed to locate file '%s' (%s)", Name, GetLastErrorText());
- return FALSE;
- }
- if (m_FileHandle != INVALID_HANDLE_VALUE)
- {
- LogMsg(LOGF_WARNINGS,"CTextSock::SendFile(%s) - File transfer already in progress.",
- Name);
- return FALSE;
- }
- if ((m_FileHandle = ::CreateFile(
- FullPath,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL)) == INVALID_HANDLE_VALUE)
- {
- LogMsg(LOGF_WARNINGS,"Failed to open file '%s' (%s)", FullPath, GetLastErrorText());
- return FALSE;
- }
- m_SuspendEvents = TRUE;
- Length = GetFileSize(m_FileHandle, NULL);
- LogMsg(LOGF_FILEACC,"CTextSock::SendFile(%s) Sending file over the control connection...",
- FullPath);
- SendMsg(280,"Sending file "%s" over the control connection. (%d bytes)",
- FullPath, Length);
- while(Length)
- {
- char buf[1024];
- DWORD BytesRead;
- ReadFile(m_FileHandle, buf, 1024, &BytesRead, NULL);
- Length -= BytesRead;
- SendBuffer(buf, BytesRead);
- if (Length && !BytesRead)
- CSocketException::Throw(this, "CTextSock::SendFile()", -1, "ReadFile() failed.");
- }
- CloseHandle(m_FileHandle);
- m_FileHandle = INVALID_HANDLE_VALUE;
- m_SuspendEvents = FALSE;
- DoSend();
- return TRUE;
- }
- BOOL CTextSock::TerminateSvrEvents()
- {
- if (m_SvrEvents)
- {
- CDaemonEvent::DsClose(m_SvrEvents);
- m_SvrEvents = INVALID_HANDLE_VALUE;
- return TRUE;
- }
- return FALSE;
- }
- void CTextSock::NotifyLogin(DWORD Flags, LPCSTR InfoTxt, CDaemonEvent *pCliEv)
- {
- if (!this)
- return;
- CString cMsg;
- if (InfoTxt)
- m_Info = InfoTxt;
- cMsg.Format("%d %d, %u %d 1%s1 1%s1 1%s1",
- m_LoginNum, m_User, Flags, m_State, m_LoginName, m_Info, m_DNSName);
- if (m_SvrEvents != INVALID_HANDLE_VALUE)
- {
- if (pCliEv)
- pCliEv->Event(m_SvrEvents, cMsg);
- else
- CDaemonEvent::DsEvent(m_SvrEvents, cMsg, TRUE);
- }
- m_StateSave = m_State;
- }
- void CTextSock::WhoSendAll(LPVOID pOrigin, CDaemonEvent *pCliEv)
- {
- CString cBuf;
- CLinkedListItem *Item = m_UserConnections.First();
- while(Item)
- {
- CTextSock *pInfo = (CTextSock *)m_UserConnections.Ptr(Item);
- Item = m_UserConnections.Next(Item);
- pInfo->NotifyLogin(ENL_NEW, NULL, pCliEv);
- }
- }
- // Override to say goodbye
- void CTextSock::SayGoodbye()
- {
- SendMsg(421, "Service is shutting down. Goodbye.");
- return;
- }
- BOOL CTextSock::OnCommand(LPCSTR Text)
- {
- if (m_State == GOTNAME)
- LogMsg(LOGF_DEBUG,"CTextSock::OnCommand(Shhh: Dont tell anyone about the password!)");
- else
- LogMsg(LOGF_DEBUG,"CTextSock::OnCommand(%s)", Text);
- return TRUE;
- }
- void CTextSock::OnClose(int nErrorCode)
- {
- CSock::OnClose(nErrorCode);
- CSocketException::Throw(this, "CTextSock::OnClose()", nErrorCode, "Connection is closed.");
- }
- void CTextSock::OnConnect( int nErrorCode )
- {
- BOOL bVal;
- CSock::OnConnect(nErrorCode);
- if (nErrorCode)
- return;
- bVal = TRUE; SetSockOpt(SO_KEEPALIVE,&bVal,sizeof(bVal));
- bVal = TRUE; SetSockOpt(TCP_NODELAY,&bVal,sizeof(bVal),IPPROTO_TCP);
- bVal = TRUE; SetSockOpt(SO_OOBINLINE,&bVal,sizeof(bVal));
- if ((m_Type == LT_TELNET) || (m_Type == LT_REMOTE))
- {
- LogMsg(LOGF_DEBUG,"Turning local echo on");
- m_LocalEcho = TRUE;
- m_HandleBackspace = TRUE;
- }
- SetName("prelogin");
- NotifyLogin(ENL_NEW, "Login");
- // Perform reverse DNS lookup before doing any communications.
- m_AsyncSelectMask &= ~FD_READ | FD_WRITE;
- m_ClearToSend = FALSE;
- m_ClearToReceive = FALSE;
- AsyncSelect(m_AsyncSelectMask);
- InitiateDNSLookup();
- }
- void CTextSock::SetName(LPCSTR Name)
- {
- CString cBuf;
- cBuf.Format("%05d %s %s %s",
- m_LoginNum,
- SafeStringIndex(CSock::DaemonTypes, m_Type, LT_INVALID),
- m_PeerName,
- MapStringValid(Name));
- CSock::SetName(cBuf);
- }
- // Try to get a line of text terminated with CRLF.
- // Telnet codes are passed to ProcessTelnetNegotiation()
- // If this is the first time the function is called we call Virgin()
- // If Virgin() dont turn off the m_Virgin flag we continue to call it
- void CTextSock::OnReceive( int nErrorCode )
- {
- int BytesReceived = 0;
- int BytesToGo;
- unsigned char *p;
- char buf[2];
- buf[1] = 0;
- CSock::OnReceive(nErrorCode);
- ASSERT(nErrorCode == 0);
- if (m_Virgin)
- Virgin();
- ASSERT(m_ClearToReceive);
- while(m_ClearToReceive)
- {
- // Fill up buffer
- while(BufferText_BufferFree()
- && (BytesReceived = Receive(m_InBuf + m_BufferUsed, BufferText_BufferFree())) > 0)
- {
- m_BufferUsed += BytesReceived;
- }
- ASSERT(BytesReceived >= 0);
- // Process what we've got. Most likely there is nothing more to receive,
- // and we have one or more complete commands.
- // But the buffer can also be full..
- ASSERT(m_BufferUsed >= 0);
- BytesToGo = m_BufferUsed - m_SavedIndex;
- p = (unsigned char *)(m_InBuf + m_SavedIndex);
- while(BytesToGo--)
- {
- ASSERT(m_BufferUsed > 0);
- ASSERT(BytesToGo >= 0);
- if (m_HaveIAC)
- {
- if (*p == IAC)
- {
- // Just keep one of them and continue
- memmove(p-1,p,BytesToGo);
- --m_BufferUsed;
- }
- else if (++m_HaveIAC == 3)
- {
- ProcessTelnetNegotiation(p[-1],p[0]);
- m_HaveIAC = 0;
- // Remove the 3 bytes
- memmove(p - 2, p + 1, BytesToGo);
- m_BufferUsed -= 3;
- p -= 3;
- }
- p++;
- continue;
- }
- if (m_HaveCR)
- {
- if (*p == 'n')
- {
- // We have a valid line :-)
- if (m_LocalEcho)
- {
- // Special case - we can't echo this below because of the IAC parsing below
- if (Send("n") < 0)
- CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 1", GetLastError(), NULL);
- }
- *p = 0;
- OnCommand(m_InBuf);
- memmove(m_InBuf, p, BytesToGo);
- m_BufferUsed -= ((LPSTR)p - m_InBuf) +1;
- p = (unsigned char *)m_InBuf;
- continue;
- }
- }
- if (*p == IAC)
- {
- m_HaveIAC = 1;
- ++p;
- continue;
- }
- if (m_LocalEcho)
- {
- buf[0] = (m_LocalEcho == 1) || (*p == 'r')
- ? *p : (char)m_LocalEcho;
- if (Send(buf) < 0)
- CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 2", GetLastError(), NULL);
- }
- switch(*p)
- {
- case 'r':
- m_HaveCR = TRUE;
- memmove(p, p+1, BytesToGo);
- --m_BufferUsed;
- continue;
- case 'b':
- if (m_HandleBackspace)
- {
- if (m_LocalEcho)
- {
- if (Send(" b") < 0)
- CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 3", GetLastError(), NULL);
- }
- goto skip_ch;
- }
- default:
- if (*p < 32) // Ignore control characters
- {
- // Garbage. Trash the character.
- skip_ch:
- memmove(p, p+1, BytesToGo);
- --m_BufferUsed;
- }
- else
- ++p;
- }
- m_HaveCR = FALSE;
- }
- } // while m_ClearToReceive
- m_SavedIndex = m_BufferUsed;
- ASSERT(m_BufferUsed >= 0);
- ASSERT(BytesToGo == -1);
- if (!BufferText_BufferFree())
- {
- LogMsg(LOGF_WARNINGS,"CTextSock::OnReceive(): Input buffer overflow (line loo long). Trashing buffer.");
- m_BufferUsed = 0;
- }
- if (m_StateSave != m_State)
- NotifyLogin(ENL_STATE);
- }
- void CTextSock::Virgin()
- {
- m_Virgin = FALSE;
- }
- // Return TRUE if everything is all right...
- BOOL CTextSock::ProcessTelnetNegotiation(int ch1, int ch2)
- {
- // Simple I WILL NOT! Telnet negitiation
- ch1 &= 0377;
- char buf[8];
- switch (ch1)
- {
- case WILL:
- case WONT:
- sprintf(buf,"%c%c%c", IAC, DONT, 0377&ch2);
- if (Send(buf) < 0)
- CSocketException::Throw(this,
- "CTextSock::ProcessTelnetNegotiation() - Send() 1", GetLastError(), NULL);
- break;
- case DO:
- if (ch2 == TELOPT_ECHO)
- {
- m_LocalEcho = 1;
- LogMsg(LOGF_DEBUG,"Turning local echo on");
- sprintf(buf,"%c%c%c", IAC, WILL, 0377&ch2);
- if (Send(buf) < 0)
- CSocketException::Throw(this,
- "CTextSock::ProcessTelnetNegotiation() - Send() 2", GetLastError(), NULL);
- break;
- }
- case DONT:
- if (ch2 == TELOPT_ECHO)
- {
- m_LocalEcho = 0;
- LogMsg(LOGF_DEBUG,"Turning local echo off");
- }
- sprintf(buf,"%c%c%c", IAC, WONT, 0377&ch2);
- if (Send(buf) < 0)
- CSocketException::Throw(this,
- "CTextSock::ProcessTelnetNegotiation() - Send() 3", GetLastError(), NULL);
- break;
- }
- return TRUE;
- }
- // Send an unformatted text string
- BOOL CTextSock::Send(LPCSTR Text)
- {
- return SendBuffer(Text, strlen(Text)) >= 0;
- }
- // Check the error and (eventually) say goodbye
- // This implementation output FTP server codes. Override to
- // handle incompatible server types
- BOOL CTextSock::OnHandleWinsockErr(int nErrorCode )
- {
- switch(nErrorCode)
- {
- case SOCKERR_IDLETIME:
- SendMsg(421, "Idle time of %d seconds expired. Goodbye.", m_MaxIdleTime / 1000);
- break;
- case SOCKERR_LOGINTIME:
- SendMsg(421, "Login time limit of %d minutes expired. Goodbye.", m_MaxIdleTime / 60000);
- break;
- }
- return CSock::OnHandleWinsockErr(nErrorCode);
- }
- BOOL CTextSock::DoSend()
- {
- BOOL Rval;
- TRY
- {
- Rval = m_Events->Process();
- if (Rval)
- Rval = CBufferSock::DoSend();
- }
- CATCH(CUserException, e)
- {
- CSocketException::Throw(this, "CTextSock::DoSend()", -1, "m_Events->Process() failed.");
- }
- END_CATCH
- return Rval;
- }
- BOOL CTextSock::SendMsg(int Rcode, LPCSTR Format, ...)
- {
- if (!this)
- return TRUE; // Fake OK.
- CWarString cBuf;
- ASSERT(AfxIsValidString(Format, FALSE));
- va_list argList;
- va_start(argList, Format);
- cBuf.FormatVaList(Format,argList);
- va_end(argList);
- return SendCtrlMsg(Rcode, cBuf);
- }
- // Send one or more lines with standard Internet result codes.
- // InsertPendingText() will call SendCtrlMsg recursively if there is
- // data to insert before the Text message.
- // ExpandMacros() is used to expand macros prior to sending the buffer
- BOOL CTextSock::SendCtrlMsg(int Rcode, LPCSTR Text, BOOL More, BOOL CrLf)
- {
- LPCSTR From;
- LPSTR To;
- int Ofset, LineLength, err;
- SNDCTLMSG cmsg;
- cmsg.Rcode = Rcode;
- cmsg.Text = Text;
- cmsg.More = More;
- cmsg.CrLf = CrLf;
- if (err = PrcSockExt(iSendCtrlMsg, 0, 0, (LPARAM)&cmsg))
- {
- if (err == CFuncList::OkAllDone)
- return DoSend();
- else
- return TRUE;
- }
- m_LastRcode = Rcode;
- #ifdef _DEBUG
- // Get a pointer to the variable for the debugger...
- DWORD *DBm_BufferUsed = (DWORD *)&(CBufferSock::m_BufferUsed);
- #endif
- InsertPendingText();
- // We manipulate the CBufferSock output buffers directly to save some memory and
- // fragmentation.
- for(To = &m_OutBuf[CBufferSock::m_BufferUsed] + m_InsertOffset, From = Text;;)
- {
- if (!m_SuspendExpandMacros && (*From == '['))
- {
- // Parse out the macro
- CString Macro("");
- LPCSTR p = From;
- while(*(++p) && (*p != ']'))
- Macro += *p;
- if (ExpandMacro(&To, Macro, &m_OutBuf[CBufferSock::m_BufferSize - 127] - To ))
- {
- From += (Macro.GetLength() + 2);
- //To = &m_OutBuf[CBufferSock::m_BufferUsed];
- continue;
- }
- }
- if (To >= &m_OutBuf[CBufferSock::m_BufferSize - 16])
- {
- // Realloc
- LPSTR p = m_OutBuf;
- int Buflen = To - p;
- m_OutBuf = new char[(CBufferSock::m_BufferSize += BUFFERSOCK_DEFUALT_BUFFER_SIZE)];
- memcpy(m_OutBuf, p, Buflen);
- delete p;
- To = m_OutBuf + Buflen;
- }
- if (*From == 'r')
- {
- ++From;
- continue;
- }
- if (!*From || (*From == 'n'))
- {
- // Send the line
- //Ofset = (More || *From) ? 5 : 4;
- Ofset = 4;
- LineLength = To - &m_OutBuf[CBufferSock::m_BufferUsed];
- //if (Rcode)
- if (Rcode && (!More || (*From == 'n')))
- {
- // Make space for header
- memmove(&m_OutBuf[CBufferSock::m_BufferUsed + Ofset],
- &m_OutBuf[CBufferSock::m_BufferUsed],
- LineLength);
- // Insert header 123[-]<SP>
- itoa(Rcode, &m_OutBuf[CBufferSock::m_BufferUsed], 10);
- m_OutBuf[CBufferSock::m_BufferUsed + Ofset - 1] = ' ';
- if (More || *From)
- m_OutBuf[CBufferSock::m_BufferUsed + 3] = '-';
- }
- else
- Ofset = 0;
- // Adjust buffer length counter
- CBufferSock::m_BufferUsed += Ofset + LineLength;
- if ((!More && CrLf) || (*From == 'n'))
- {
- // Insert trailing CRLF
- m_OutBuf[CBufferSock::m_BufferUsed++] = 'r';
- m_OutBuf[CBufferSock::m_BufferUsed++] = 'n';
- }
- m_OutBuf[CBufferSock::m_BufferUsed] = 0; // Not needed, but OK in the debugger :-)
- // Prepere To for the next line.
- To = &m_OutBuf[CBufferSock::m_BufferUsed];
- if (!*From)
- break;
- ++From;
- }
- else
- {
- *To++ = *From++;
- //CBufferSock::m_BufferUsed++;
- }
- }
- return DoSend();
- }
- void CTextSock::InsertPendingText()
- {
- }
- enum // Macro Table
- {
- MT_USER, MT_ORIGIN, MT_ULCNT, MT_DLCNT, MT_ULRSTR, MT_DLRAT, MT_ULRAT,
- MT_CREDIT, MT_CTYPE, MT_ULCNTR,
- MT_IDLE, MT_UQRESTR, MT_PRGNAM, MT_PRGVER, MT_PRGCPYR, MT_SYSNAME,
- MT_OSNAME, MT_EMAIL, MT_FRESTR,
- MT_CONLINE, MT_CAONLINE,
- MT_DNSNAME, MT_LOCALIP, MT_OPONLINE
- };
- MACROTABLE BaseMacros[] =
- {
- {"user", MT_USER, "Username of the current user."},
- {"origin", MT_ORIGIN, "IP address of the current user."},
- {"ulcount", MT_ULCNT, "Upload counter of the current user."},
- {"dlcount", MT_DLCNT, "Download counter of the current user"},
- {"dlratio", MT_DLRAT, "Download ratio (files to get for each n upload)."},
- {"ulratio", MT_ULRAT, "Upload ratio (files to upload for each n get)."},
- {"credit", MT_CREDIT, "Credit - bytes/files available for download."},
- {"ulctype", MT_CTYPE, "Up/Download ratio type - file(s) or Kb."},
- {"udrestrictions", MT_ULRSTR, "Are Upload/Download restrictions enabled?"},
- {"ulcounttrash", MT_ULCNTR, "Will the upload counter be reset at logout?"},
- {"idletime", MT_IDLE, "Idle time limit in minutes."},
- {"uniquefileoption",MT_UQRESTR, "Is upload of existing files denied?"},
- {"programname", MT_PRGNAM, "Name of the FTP daemon software."},
- {"programversion", MT_PRGVER, "Version of the FTP daemon software."},
- {"prgcopyright", MT_PRGCPYR, "Copyright notification of the FTP daemon software"},
- {"systemname", MT_SYSNAME, "The name you have chosen for your site."},
- {"osname", MT_OSNAME, "The name of the operating system (Win95, NT etc...)"},
- {"email", MT_EMAIL, "Email address of the system administrator."},
- {"restrictions", MT_FRESTR, "File system restrictions appliy/do not apply."},
- {"usersonline", MT_CONLINE, "Users currently online."},
- {"anonsonline", MT_CAONLINE,"Anonymous users currently online."},
- {"dnsname", MT_DNSNAME, "DNS name of the current user"},
- {"localip", MT_LOCALIP, "Logged on to local IP number"},
- {"oponline", MT_OPONLINE,"Operators online"},
- {"", 0, ""}
- };
- // On overrides: Call base class first
- // That way we can expand macros on all layers...
- BOOL CTextSock::ExpandMacro(LPSTR *To, LPCSTR MacroName, int AvailBytes)
- {
- // if (CBaseClass::ExpandMacros(To, MacroName, AvailBytes))
- // return TRUE;
- // TODO: Add expansion here and return TRUE if the macro was expanded
- // We do all the trivial macros, like file paths, dates, program name etc..
- CString Macro("");
- if (*MacroName == '%')
- ExpandStringMacros(MacroName, Macro, NULL);
- else if (*MacroName == '$')
- {
- for(MACROTABLE *pMT = BaseMacros; *pMT->Name; pMT++)
- {
- if (!stricmp(pMT->Name, MacroName + 1))
- {
- switch(pMT->Symb)
- {
- case MT_USER: Macro = m_LoginName; break;
- case MT_ORIGIN: Macro = m_PeerName; break;
- case MT_LOCALIP: Macro = m_HostName; break;
- case MT_DNSNAME: Macro = m_DNSName; break;
- case MT_CAONLINE:
- Macro.Format("%d", CDaemonStatus::GetStat()->m_AnonUserConnections);
- break;
- case MT_CONLINE:
- Macro.Format("%d", CDaemonStatus::GetStat()->m_UserConnections);
- break;
- case MT_OPONLINE:
- Macro.Format("%d", CDaemonStatus::GetStat()->m_OperatorConnections);
- break;
- case MT_FRESTR:
- Macro = m_IsLoggedInAnonymously ? "apply" : "Does not apply";
- break;
- case MT_SYSNAME: Macro = CDaemonStatus::GetStat()->m_ServerName; break;
- case MT_EMAIL: Macro = CDaemonStatus::GetStat()->m_ServerEmail; break;
- case MT_OSNAME: Macro = OsName(); break;
- case MT_PRGCPYR: Macro = CProgramInfo::m_COPYRIGHT; break;
- case MT_PRGVER: Macro = CProgramInfo::m_VERSION; break;
- case MT_PRGNAM: Macro = CProgramInfo::m_PROGRAM; break;
- default:
- Macro.Format("(Macro '%s' is not yet available)", MacroName);
- break;
- }
- break;
- }
- }
- }
- int Len = Macro.GetLength();
- if (Len && (Len < AvailBytes))
- {
- memcpy(*To, Macro, Len);
- *To = *To + Len;
- return TRUE;
- }
- return FALSE; // Failed or macro not found..
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // CFTPDataSock
- IMPLEMENT_DYNAMIC(CFTPDataSock, CBufferSock);
- CFTPDataSock::CFTPDataSock()
- {
- m_Flags = 0;
- m_pFile = NULL;
- m_HaveToldUserThatTransfereIsComplete = FALSE;
- //if (m_UseOverlappedIO = IsNT())
- m_UseOverlappedIO = atoi(COptions::GetOption(COPTION_ADVANCEDOPTIONS, ADVANCEDOPTIONS_OVERLAPPEDIO)) != 0;
- if (m_UseOverlappedIO)
- {
- m_Overlapped = new CFTPOverlapped;
- m_Overlapped->m_Origin = this;
- m_Overlapped->m_pFile = NULL;
- }
- else
- m_Overlapped = NULL;
- m_ListeningSock = NULL;
- m_OriginD = NULL;
- m_OriginC = NULL;
- m_CurrentPosition = 0;
- m_DataBuffers[0] = NULL;
- m_DataBuffers[1] = NULL;
- m_OverlappedIOReady = TRUE;
- m_OverlappedIOUsed = 0;
- m_OverlappedIOToggle = 1;
- m_EOF = FALSE;
- #ifdef _DEBUG
- dm_OverlappedCnt = 0;
- #endif
- PrcExt(CAPIHandler::OnNewFTPDataSocket,0,0,(LPARAM)this);
- }
- CFTPDataSock::~CFTPDataSock()
- {
- m_DestructorIsActive = TRUE;
- if (m_OriginD)
- {
- ASSERT(AfxIsValidAddress(m_OriginD, sizeof(CTextSock)));
- ;
- }
- if (m_OriginC)
- {
- ASSERT(AfxIsValidAddress(m_OriginC, sizeof(CRemoteInterface)));
- ;
- }
- ASSERT(AfxIsValidAddress(m_PtrToOriginsPtrToMe, sizeof(CFTPDataSock **)));
- CString cBuf;
- LogMsg(LOGF_DEBUG,"~CFTPDataSock() - Closing data connection.");
- if (m_ListeningSock)
- delete m_ListeningSock;
- if (m_Overlapped)
- {
- if (m_OverlappedIOReady)
- {
- delete m_Overlapped;
- m_Overlapped = NULL;
- }
- else
- m_Overlapped->m_KillMe = TRUE;
- }
- if (m_pFile)
- {
- if (!m_HaveToldUserThatTransfereIsComplete)
- {
- int err = GetLastError();
- try
- {
- OnFileCompletion(err ? err : -1);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::~CFTPDataSock() - Caught exception '%s' from %s. Ignored.",
- pExc->m_ErrorText, pExc->m_FromModule);
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::~CFTPDataSock() - Caught unknown exception - ignored");
- }
- }
- // If we have pending overlapped data, dont close.
- if (!(m_Overlapped && m_Overlapped->m_KillMe))
- {
- if (m_pFile->m_CallbackPending)
- {
- LogMsg(LOGF_DEBUG,"~CFTPDataSock() - File is in callback state. Leaving it open.");
- m_pFile->m_IsZombie = TRUE;
- }
- else
- {
- m_pFile->Destroy();
- m_pFile = NULL;
- LogMsg(LOGF_DEBUG,"~CFTPDataSock() - File closed.");
- }
- }
- else
- LogMsg(LOGF_DEBUG,"~CFTPDataSock() - Leaving file open (overlapped data pending).");
- }
- if (m_PtrToOriginsPtrToMe && (*m_PtrToOriginsPtrToMe == this))
- *m_PtrToOriginsPtrToMe = NULL; // Release us from origin.
- }
- BOOL CFTPDataSock::IsOkToDelete(BOOL IgnoreSuspend)
- {
- if (!IgnoreSuspend && m_SuspendDelete)
- {
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::IsOkToDelete() - NOT ok to delete.. m_SuspendDelete=%d.",
- m_SuspendDelete);
- return FALSE;
- }
- if (!m_OverlappedIOReady || m_DestructorIsActive)
- {
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::IsOkToDelete() - NOT ok to delete.. m_OverlappedIOReady=%d m_DestructorIsActive=%d",
- m_OverlappedIOReady, m_DestructorIsActive);
- return FALSE;
- }
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::IsOkToDelete() - YES. FTP Data socket can be killed.");
- return TRUE;
- }
- BOOL CFTPDataSock::OnHandleWinsockErr(int nErrorCode )
- {
- // Normally called from within an excpetrion handler
- SuspendDelete();
- if (!m_HaveToldUserThatTransfereIsComplete)
- {
- try
- {
- OnFileCompletion(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::OnHandleWinsockErr(%d) 1 - Caught exception '%s' from %s. Ignored.",
- nErrorCode, pExc->m_ErrorText, pExc->m_FromModule);
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::OnHandleWinsockErr(%d) - Caught unknown exception", nErrorCode);
- return TRUE; // Can't do anthing..
- }
- }
- ReleaseSuspendDelete();
- if (m_OriginD)
- {
- m_OriginD->NotifyLogin(ENL_UPDATE);
- m_OriginD->m_State = PROCESS;
- }
- if (IsOkToDelete())
- delete this;
- else
- {
- if (m_IsConnected)
- {
- SuspendDelete();
- try
- {
- Close();
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::OnHandleWinsockErr(%d) 2 - Caught exception '%s' from %s. Ignored.",
- nErrorCode, pExc->m_ErrorText, pExc->m_FromModule);
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::OnHandleWinsockErr(%d) 2 - Caught unknown exception", nErrorCode);
- return TRUE; // Can't do anthing..
- }
- ReleaseSuspendDelete();
- }
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::OnHandleWinsockErr(%d) - Data socket not ready for delete. Delete is pending.",
- nErrorCode);
- }
- return TRUE; // We have handled the stuff
- }
- // Create the data socket. This is called on PASV and before any
- // file transmission. If the datasocket is NULL, create it.
- // If passive mode, initiate the listening socket.
- // FTP Client version
- BOOL CFTPDataSock::Create(CRemoteInterface *Origin, CFTPDataSock ** Ptr,
- int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr,
- BOOL Passive, DWORD Flags)
- {
- return Create(Origin, NULL, Ptr, FTPmode, FTPstru, FTPform, FTPtype, Sockaddr, Passive, Flags);
- }
- // FTP Server version
- BOOL CFTPDataSock::Create(CTextSock *Origin, CFTPDataSock ** Ptr,
- int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr,
- BOOL Passive, DWORD Flags)
- {
- return Create(NULL, Origin, Ptr, FTPmode, FTPstru, FTPform, FTPtype, Sockaddr, Passive);
- }
- // Actual implementation..
- BOOL CFTPDataSock::Create(CRemoteInterface *OriginC, CTextSock *OriginD, CFTPDataSock ** Ptr,
- int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr,
- BOOL Passive, DWORD Flags)
- {
- ASSERT(!OriginC || !OriginD);
- ASSERT(((int)(OriginC) | (int)(OriginD)) != 0);
- CFTPDataSock *me = this;
- if (me == NULL)
- {
- me = new CFTPDataSock;
- }
- else
- {
- if (me->m_pFile)
- {
- me->LogMsg(LOGF_WARNINGS,"User tries to start a new transfere without closing the old one.");
- if (me->m_OriginD)
- me->m_OriginD->SendMsg(425, "Can't build data connection. Use ABOR to stop the current transfer.");
- CSocketException::Throw(me,
- "CFTPDataSock::Create()", GetLastError(), "User tries to start a new transfere without closing the old one.");
- }
- }
- me->m_PtrToOriginsPtrToMe = Ptr;
- *me->m_PtrToOriginsPtrToMe = me;
- me->m_OriginC = OriginC;
- me->m_OriginD = OriginD;
- me->m_OriginB = OriginD ? (CSock *)OriginD : (CSock *)OriginC;
- me->m_FTPmode = FTPmode;
- me->m_FTPtype = FTPtype;
- me->m_FTPstru = FTPstru;
- me->m_FTPform = FTPform;
- me->m_Flags = Flags;
- memcpy(&me->m_Sockaddr,Sockaddr,sizeof(struct sockaddr));
- me->m_SocketName.Format("%s::*noname*", me->m_OriginD
- ? me->m_OriginD->m_SocketName
- : me->m_OriginC->m_SocketName);
- if (Passive)
- {
- me->LogMsg(LOGF_DEBUG,"Create() - Setting up listening socket for passive mode.");
- if (me->m_ListeningSock)
- delete me->m_ListeningSock;
- me->m_ListeningSock = new CFTPPassiveSock;
- if (!me->m_ListeningSock->Create(me, 0))
- {
- me->LogMsg(LOGF_WARNINGS,"Create() - Failed to create listening socket for passive mode.");
- CSocketException::Throw(me,
- "CFTPDataSock::Create()", GetLastError(), NULL);
- }
- }
- return TRUE;
- }
- BOOL CFTPDataSock::SendFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp,
- FLEN StartOffset, FLEN FileLength)
- {
- m_SendMode = TRUE;
- m_AsyncSelectMask = FD_WRITE | FD_CONNECT | FD_CLOSE;
- return XmitFile(FileName, VisualFileName, IsTmp, StartOffset, FileLength);
- }
- BOOL CFTPDataSock::ReceiveFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp,
- FLEN StartOffset, FLEN FileLength)
- {
- m_SendMode = FALSE;
- m_SuspendOnClose = TRUE; // We want to see the receive() 0 bytes EOS..
- m_AsyncSelectMask = FD_READ | FD_CONNECT | FD_CLOSE;
- return XmitFile(FileName, VisualFileName, IsTmp, StartOffset, FileLength);
- }
- BOOL CFTPDataSock::XmitFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp,
- FLEN StartOffset, FLEN FileLength)
- {
- ASSERT(m_OriginB != NULL);
- CString cBuf;
- int err;
- LPCSTR p = strrchr(VisualFileName,'//');
- if (p)
- ++p;
- else
- p = VisualFileName;
- m_SocketName.Format("%s::%s%s", m_OriginD
- ? m_OriginD->m_SocketName
- : m_OriginC->m_SocketName,
- m_SendMode ? "<<" : ">>", p);
- m_OriginB->m_State = m_SendMode ? GETFILE : PUTFILE;
- m_FileName = FileName;
- m_VisualFileName = VisualFileName;
- m_IsTmpFile = IsTmp;
- m_FileLength = FileLength;
- m_StartOffset = StartOffset;
- if (m_OriginD && (err = m_OriginD->PrcSockExt(iOnVerifyTransferRequest, m_SendMode, (WPARAM)this, (LPARAM)FileName)))
- {
- if (err == CFuncList::AbortError)
- {
- LogMsg(LOGF_FILEACC,"Plugin denied file transfer.");
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", -1, "Plugin said NO!");
- }
- if (err == CFuncList::OkAllDone)
- return TRUE;
- }
- // If a file system is in use, the object is created by the calling function
- if (!m_pFile)
- m_pFile = new CWarFile;
- ASSERT(m_pFile->IsOpen() == FALSE);
- if (!m_pFile->Create(
- FileName,
- m_SendMode ? GENERIC_READ : (IsTmp && m_OriginC) ? GENERIC_READ | GENERIC_WRITE : GENERIC_WRITE,
- m_SendMode ? FILE_SHARE_READ : 0,
- NULL,
- (m_SendMode || StartOffset) ? OPEN_EXISTING : CREATE_ALWAYS,
- (m_UseOverlappedIO ? FILE_FLAG_OVERLAPPED : 0)
- | (IsTmp ? FILE_FLAG_DELETE_ON_CLOSE : 0)
- | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL,
- m_Flags,
- (LPARAM)m_SocketID,
- CallbackFileIsCreated))
- {
- err = GetLastError();
- if (err == WAIT_IO_COMPLETION)
- return TRUE;
- LogMsg(LOGF_DEBUG,"XmitFile() - Failed to open file %s. %s.", FileName, GetLastErrorText(err));
- if (m_OriginD)
- m_OriginD->SendMsg(553, "Open error %s", GetLastErrorText(err));
- m_HaveToldUserThatTransfereIsComplete = TRUE;
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", err, NULL);
- }
- if (m_pFile->CallbackIsPending())
- return TRUE;
- return XmitFileCallback(TRUE);
- }
- // Called by CWarFile callback after the file is opened (or open failed)
- void CFTPDataSock::CallbackFileIsCreated(CWarFile *pFile, BOOL Success, LPARAM lParam)
- {
- CFTPDataSock *pSock = (CFTPDataSock *)GetFromID(lParam);
- pFile->m_CallbackPending = FALSE;
- if (pSock)
- {
- ASSERT(pFile->m_IsZombie == FALSE);
- try
- {
- pSock->XmitFileCallback(Success);
- }
- catch(CSocketException *pExc)
- {
- pExc->m_pSock->LogMsg(LOGF_DEBUG,"CFTPDataSock::CallbackFileIsCreated() - Caught ecxeption.");
- pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum);
- delete pExc;
- return;
- }
- catch(...)
- {
- CLog::GetLog()->LogMsg(LOGF_ERROR,"CFTPDataSock::CallbackFileIsCreated() - Caught unknown ecxeption.");
- pFile->Destroy();
- return;
- }
- }
- else
- {
- pFile->Destroy();
- }
- }
- // Continue to initiate transfer
- BOOL CFTPDataSock::XmitFileCallback(BOOL Success)
- {
- if (!Success)
- {
- int err = GetLastError();
- LogMsg(LOGF_DEBUG,"XmitFileCallback() - Failed to open file %s. %s.", m_FileName, GetLastErrorText(err));
- if (m_OriginD)
- m_OriginD->SendMsg(553, "Open error %s", GetLastErrorText(err));
- m_HaveToldUserThatTransfereIsComplete = TRUE;
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", err, NULL);
- }
- // Get file lenght
- if (!m_FileLength)
- {
- if ((m_FileLength = m_pFile->Seek(0, FILE_END)) == INVALID_FLEN_VALUE)
- {
- int Err = GetLastError();
- LogMsg(LOGF_DEBUG,"XmitFile() - Failed seek to end of file %s. %s.", m_FileName, GetLastErrorText(Err));
- if (m_OriginD)
- m_OriginD->SendMsg(451, "Seek error %s", GetLastErrorText(Err));
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 2", Err, NULL);
- }
- if (m_StartOffset == FLEN_MAX)
- {
- // Append
- ASSERT(m_SendMode == FALSE);
- m_CurrentPosition = m_FileLength;
- }
- else if ((m_CurrentPosition = m_pFile->Seek(m_StartOffset, FILE_BEGIN)) == INVALID_FLEN_VALUE)
- {
- int err = GetLastError();
- LogMsg(LOGF_DEBUG,"XmitFile() - Failed to move to offset %i. %s.",
- (unsigned)m_StartOffset, GetLastErrorText(err));
- if (m_OriginD)
- m_OriginD->SendMsg(451, "Seek error %s", GetLastErrorText(err));
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 3", err, NULL);
- }
- }
- if (m_StartOffset != m_CurrentPosition)
- {
- LogMsg(LOGF_DEBUG,"SendFile(): Aborting due to illegal restart marker %u", (unsigned)m_StartOffset);
- if (m_OriginD)
- m_OriginD->SendMsg(550, "Cannot resume on this file.");
- CSocketException::Throw(this, "CFTPDataSock::XmitFile() 4", -1, "Illegal restart marker.");
- }
- return DoConnect();
- }
- BOOL CFTPDataSock::DoConnect()
- {
- CString cBuf;
- if (m_FileLength)
- cBuf.Format(" (%u bytes)", (unsigned)m_FileLength);
- else
- cBuf.Empty();
- if (m_IsConnected)
- {
- ASSERT(m_ListeningSock != NULL);
- if (m_OriginD)
- m_OriginD->SendMsg(125, "Using existing data connection (%s mode) for %s%s.",
- m_FTPtype == TYPE_A ? "ASCII" : "BINARY",
- m_VisualFileName, cBuf);
- }
- else
- {
- if (m_OriginD)
- m_OriginD->SendMsg(150, "Opening %s mode data connection for %s%s.",
- m_FTPtype == TYPE_A ? "ASCII" : "BINARY",
- m_VisualFileName, m_SendMode ? cBuf : "");
- }
- if (!m_ListeningSock)
- {
- SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
- LogMsg(LOGF_DEBUG,"Trying to connect to %d.%d.%d.%d port %d (%lX,%d)",
- s_in->sin_addr.S_un.S_un_b.s_b1,
- s_in->sin_addr.S_un.S_un_b.s_b2,
- s_in->sin_addr.S_un.S_un_b.s_b3,
- s_in->sin_addr.S_un.S_un_b.s_b4,
- ntohs(s_in->sin_port),
- s_in->sin_addr.s_addr,
- ntohs(s_in->sin_port));
- if (!CSock::Create() || !Connect(&m_Sockaddr, sizeof(struct sockaddr)))
- {
- int err;
- if (err = GetLastError() != WSAEWOULDBLOCK)
- {
- CString cBuf;
- LogLastError(LOGF_DEBUG, 0, "DoConnect - Connect failed");
- if (m_OriginD)
- m_OriginD->SendMsg(425, "Can't build data connection. %s.", GetLastErrorText(err));
- m_HaveToldUserThatTransfereIsComplete = TRUE;
- CSocketException::Throw(this, "CFTPDataSock::DoConnect()", err, NULL);
- }
- }
- }
- m_State = m_SendMode ? PUTFILE : GETFILE;
- if (m_SendMode && m_ClearToSend)
- DoSend();
- if (m_OriginD)
- m_OriginD->NotifyLogin(ENL_UPDATE, strrchr(m_SocketName, ':') + 1);
- return TRUE;
- }
- void CFTPDataSock::OnConnect( int nErrorCode )
- {
- try
- {
- _OnConnect(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnConnect(%d %d) - Caught ecxeption.",
- nErrorCode, pExc->m_ErrorNum);
- ASSERT(pExc->m_pSock == this);
- if (!OnHandleWinsockErr(pExc->m_ErrorNum))
- delete this;
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::OnConnect(%d) - Caught unknown ecxeption.", nErrorCode);
- }
- return;
- }
- void CFTPDataSock::_OnConnect( int nErrorCode )
- {
- if (nErrorCode)
- {
- if (m_OriginD)
- m_OriginD->SendMsg(425, "Can't build data connection. Error code %d.", nErrorCode);
- LogMsg(LOGF_WARNINGS,"OnConnect() - Can't build data connection. Error code %d.", nErrorCode);
- m_HaveToldUserThatTransfereIsComplete = TRUE;
- }
- CSock::OnConnect(nErrorCode);
- ASSERT(nErrorCode == 0);
- if (m_OriginD)
- m_OriginD->IncXferCnt(TRUE);
- if (m_UseOverlappedIO)
- {
- m_BufferSize = atoi(COptions::GetOption(COPTION_ADVANCEDOPTIONS, ADVANCEDOPTIONS_OVERLAPPEDIO));
- m_BufferSize = CAdvancedOptions::GetOvlMap(m_BufferSize);
- LogMsg(LOGF_DEBUG,
- " CFTPDataSock::_OnConnect() - Overlapped IO is enabled. Buffer size is 2 x %d bytes",
- m_BufferSize);
- delete m_OutBuf;
- ASSERT(m_BufferSize > MAX_PATH);
- ASSERT(AfxIsValidAddress(m_Overlapped,sizeof(CFTPOverlapped)));
- m_DataBuffers[0] = m_OutBuf = new char[m_BufferSize];
- m_DataBuffers[1] = m_Overlapped->m_Buffer = new char[m_BufferSize];
- }
- AsyncSelect(m_AsyncSelectMask);
- if (m_SendMode && m_pFile->IsOpen())
- DoSend();
- return;
- }
- void CFTPDataSock::OnReceive( int nErrorCode )
- {
- try
- {
- _OnReceive(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnReceive(%d %d) - Caught ecxeption.",
- nErrorCode, pExc->m_ErrorNum);
- ASSERT(pExc->m_pSock == this);
- if (!OnHandleWinsockErr(pExc->m_ErrorNum))
- delete this;
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::OnReceive(%d) - Caught unknown ecxeption.", nErrorCode);
- }
- return;
- }
- void CFTPDataSock::_OnReceive( int nErrorCode )
- {
- CBufferSock::OnReceive(nErrorCode);
- ASSERT(nErrorCode == 0);
- m_OriginB->m_Timer.Reset();
- if (!m_pFile->IsOpen())
- {
- LogMsg(LOGF_WARNINGS,"OnReceive(): Data received before opening file.");
- return;
- }
- ASSERT(m_ClearToReceive);
- if (m_UseOverlappedIO)
- DoOverlapped();
- else
- {
- int BytesRead = 0;
- while((BytesRead = Receive(m_OutBuf, m_BufferSize)) > 0)
- {
- // CSock::Receive() handles WASWOULDBLOCK, EOF and errors
- DWORD BytesWritten = 0;
- if (!m_pFile->Write(
- m_OutBuf + BytesWritten,
- BytesRead - BytesWritten,
- &BytesWritten,
- NULL))
- {
- int err = GetLastError();
- CString cBuf;
- LogMsg(LOGF_DEBUG,"_OnReceive() - WriteFile() failed. Error %s.", GetLastErrorText(err));
- CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 1", err, NULL);
- }
- if (BytesWritten < (DWORD)BytesRead)
- {
- // Probarbly disk full...
- LogMsg(LOGF_WARNINGS,"_OnReceive() - WriteFile(%d) only wrote %d bytes. Aborting..",
- BytesRead, BytesWritten);
- CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 2", -1, "Failed to write");
- }
- m_CurrentPosition += BytesRead;
- m_BufferUsed = 0;
- if (m_FileLength < m_CurrentPosition)
- m_FileLength = m_CurrentPosition;
- }
- ASSERT(BytesRead != -1);
- if (!m_IsConnected)
- {
- OnFileCompletion(0);
- CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 3", 0, "File received OK");
- }
- }
- }
- BOOL CFTPDataSock::DoSend()
- {
- if (!m_pFile->IsOpen())
- {
- LogMsg(LOGF_DEBUG,"DoSend(): File not open yet. Nothing sent to network.");
- return TRUE;
- }
- if (!m_SendMode)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::DoSend() - Called without send mode enabled. Ignoring.");
- return TRUE;
- }
- if (m_ClearToSend)
- CBufferSock::DoSend(); // Try to empty the current output buffer
- else
- return TRUE; // No need to continue, we are waiting for OnSend()
- if (m_UseOverlappedIO)
- DoOverlapped();
- else
- {
- DWORD BytesRead = 0;
- while(!m_EOF && BufferSock_BufferFree())
- {
- ASSERT(BufferSock_BufferFree() > 0);
- if (!m_EOF && !m_pFile->Read(
- m_OutBuf + m_BufferUsed,
- BufferSock_BufferFree(),
- &BytesRead,
- NULL))
- {
- if (GetLastError() == ERROR_HANDLE_EOF)
- m_EOF = TRUE;
- else
- {
- CString cBuf;
- int Err = GetLastError();
- LogMsg(LOGF_DEBUG,"DoSend() - ReadFile() failed. Error %s.", GetLastErrorText(Err));
- CSocketException::Throw(this, "CFTPDataSock::_DoSend()", Err, NULL);
- }
- }
- if (BytesRead == 0)
- m_EOF = TRUE;
- m_CurrentPosition += BytesRead;
- m_BufferUsed += BytesRead;
- if (m_ClearToSend)
- CBufferSock::DoSend();
- }
- }
- if (m_EOF && m_ClearToSend)
- {
- ASSERT(m_BufferUsed == 0);
- OnFileCompletion(0); // File sent OK
- CSocketException::Throw(this, "CFTPDataSock::_DoSend()", 0, "File sent OK");
- }
- return TRUE;
- }
- void CFTPDataSock::OnSend( int nErrorCode )
- {
- try
- {
- m_OriginB->m_Timer.Reset();
- CBufferSock::OnSend(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnSend(%d %d) - Caught exception.",
- nErrorCode, pExc->m_ErrorNum);
- ASSERT(pExc->m_pSock == this);
- if (!OnHandleWinsockErr(pExc->m_ErrorNum))
- delete this;
- delete pExc;
- }
- return;
- }
- BOOL CFTPDataSock::DoOverlapped()
- {
- ASSERT(AfxIsValidAddress(this, sizeof(CFTPDataSock)));
- ASSERT(m_UseOverlappedIO);
- ASSERT(AfxIsValidAddress(m_Overlapped,sizeof(CFTPOverlapped)));
- ASSERT(m_BufferSize >= MAX_PATH);
- ASSERT(AfxIsValidAddress(m_Overlapped->m_Buffer,m_BufferSize));
- ASSERT(AfxIsValidAddress(m_DataBuffers[0],m_BufferSize));
- ASSERT(AfxIsValidAddress(m_DataBuffers[0],m_BufferSize));
- //ASSERT(IsNT());
- if (m_SendMode)
- {
- if (m_OverlappedIOReady)
- {
- if (m_BufferUsed)
- {
- ASSERT(m_ClearToSend == FALSE);
- return TRUE; // We have to wait until the send buffer is ready
- }
- // Toggle the buffers
- m_OutBuf = m_DataBuffers[m_OverlappedIOToggle];
- m_Overlapped->m_Buffer = m_DataBuffers[!m_OverlappedIOToggle];
- m_OverlappedIOToggle = m_OverlappedIOToggle == FALSE;
- m_BufferUsed = m_OverlappedIOUsed;
- m_OverlappedIOUsed = 0;
- if (m_EOF && (m_BufferUsed == 0))
- CSocketException::Throw(this, "CFTPDataSock::DoOverlapped()", 0, "File xmitted OK");
- else if (!m_EOF)
- ReadWriteOverlapped();
- // Send data to network
- if (m_BufferUsed && m_ClearToSend)
- CBufferSock::DoSend();
- }
- }
- else // receive
- {
- if (m_ClearToReceive)
- {
- // Fill receive buffer
- try
- {
- int BytesRead = 0;
- while(BufferSock_BufferFree()
- && ((BytesRead = Receive(m_OutBuf + m_BufferUsed, BufferSock_BufferFree())) > 0))
- {
- m_BufferUsed += BytesRead;
- }
- }
- catch(CSocketException *pExc)
- {
- if (pExc->m_ErrorNum)
- throw pExc; // We can only handle EOF.
- // End of transmission.
- Close();
- delete pExc;
- }
- }
- if (m_OverlappedIOReady && (!m_IsConnected || !BufferSock_BufferFree()))
- {
- // Toggle the buffers
- m_OutBuf = m_DataBuffers[m_OverlappedIOToggle];
- m_Overlapped->m_Buffer = m_DataBuffers[!m_OverlappedIOToggle];
- m_OverlappedIOToggle = m_OverlappedIOToggle == FALSE;
- if (!m_BufferUsed && !m_IsConnected)
- CSocketException::Throw(this, "CFTPDataSock::DoOverlapped() 1", 0, "File xmitted OK");
- if (m_BufferUsed)
- ReadWriteOverlapped();
- m_BufferUsed = 0;
- m_OverlappedIOUsed = 0;
- }
- }
- return TRUE;
- }
- // Call overlapped IO operation
- BOOL CFTPDataSock::ReadWriteOverlapped()
- {
- ASSERT(m_OverlappedIOReady == TRUE);
- BOOL IOResult;
- m_Overlapped->m_pFile = m_pFile;
- m_Overlapped->m_OverlappedData.Offset = LODWORD(m_CurrentPosition);
- m_Overlapped->m_OverlappedData.OffsetHigh = HIDWORD(m_CurrentPosition);
- m_Overlapped->m_OverlappedData.hEvent = (HANDLE)m_Overlapped;
- if (m_SendMode)
- {
- LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - ReadFileEx(%d bytes) %08X", m_BufferSize, m_Overlapped);
- IOResult = m_pFile->ReadEx(
- m_Overlapped->m_Buffer,
- m_BufferSize,
- &m_Overlapped->m_OverlappedData,
- OnOverlappedIO);
- }
- else
- {
- LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - ReadFileEx(%d bytes) %08X", m_BufferUsed, m_Overlapped);
- IOResult = m_pFile->WriteEx(
- m_Overlapped->m_Buffer,
- m_BufferUsed,
- &m_Overlapped->m_OverlappedData,
- OnOverlappedIO);
- }
- if (!IOResult)
- {
- if (m_SendMode && (GetLastError() == ERROR_HANDLE_EOF))
- m_EOF = TRUE;
- else
- {
- int err = GetLastError();
- CString cBuf;
- LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - Read/WriteFile() failed. %s", GetLastErrorText(err));
- CSocketException::Throw(this, "CFTPDataSock::ReadWriteOverlapped()", err, NULL);
- }
- }
- else
- {
- // ReadFileEx was successful
- m_OverlappedIOReady = FALSE;
- ++m_OverlappedCnt;
- ASSERT(++dm_OverlappedCnt == 1);
- }
- return TRUE;
- }
- // Always called from an exception handler.
- void CFTPDataSock::OnFileCompletion(int nErrorCode)
- {
- if (m_IsConnected)
- {
- Close();
- if (m_OriginD)
- {
- m_OriginD->IncXferCnt(FALSE);
- m_OriginB->m_State = PROCESS;
- }
- }
- // If we have pending overlapped IO we will wait for that to complete.
- if (!IsOkToDelete(TRUE) && !nErrorCode)
- {
- LogMsg(LOGF_DEBUG,
- "CFTPDataSock::OnFileCompletion(OK) - Transfer is OK. Awaiting pending overlapped IO.");
- return;
- }
- if (m_OriginD)
- m_OriginD->NotifyLogin(ENL_UPDATE, "");
- if (nErrorCode)
- {
- CString cBuf;
- if (m_OriginD && (nErrorCode == -1))
- m_OriginD->SendMsg(426, "Transfere aborted.");
- else if (m_OriginD)
- m_OriginD->SendMsg(426, "Error %s. Transfere aborted.", GetLastErrorText(nErrorCode));
- LogMsg(LOGF_FILEACC,"OnFileCompletion() - Transfere aborted. Error %d.", nErrorCode);
- }
- else
- {
- int err;
- if (m_OriginD && (err = m_OriginD->PrcSockExt(iOnVerifyUploadedFile, m_SendMode, 0,(LPARAM)this)))
- {
- if (err == CFuncList::AbortError)
- {
- LogMsg(LOGF_FILEACC,"Plugin denied file after successful upload.");
- CSocketException::Throw(this, "CFTPDataSock::OnFileCompletion()", -1, "Plugin said NO!");
- }
- if (err == CFuncList::OkAllDone)
- return;
- }
- if (m_OriginD)
- m_OriginD->SendMsg(226, "Transfer complete. %u bytes in %.2f sec. (%.3f Kb/s)",
- m_BytesSent + m_BytesReceived,
- GetLapTime(),
- GetCPS() / (float)1024);
- LogMsg(m_IsTmpFile ? LOGF_DEBUG : LOGF_FILEACC,"OnFileCompletion() - Transfere complete. %u bytes in %.2f sec. (%.3f Kb/s)",
- m_BytesSent + m_BytesReceived,
- GetLapTime(),
- GetCPS() / (float)1024);
- }
- m_HaveToldUserThatTransfereIsComplete = TRUE;
- if (m_OriginC)
- {
- SuspendDelete();
- m_OriginC->OnFileCompletion(nErrorCode);
- ReleaseSuspendDelete();
- }
- }
- void CFTPDataSock::OnClose( int nErrorCode )
- {
- try
- {
- _OnClose(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnClose(%d %d) - Caught ecxeption.",
- nErrorCode, pExc->m_ErrorNum);
- ASSERT(pExc->m_pSock == this);
- if (nErrorCode == WSAECONNABORTED)
- {
- LogMsg(LOGF_WARNINGS,"CFTPDataSock::OnClose(WSAECONNABORTED) - Error message is ignored.");
- nErrorCode = 0;
- }
- if (!nErrorCode && m_SuspendOnClose)
- {
- // We want 0 on receive to confirm that the file is received OK.
- ASSERT(m_IsConnected == TRUE);
- ASSERT(m_SendMode == FALSE);
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnClose() - OnClose(0) is not allowed right now. Calling OnReceive().");
- OnReceive(0);
- return;
- }
- if (!OnHandleWinsockErr(pExc->m_ErrorNum))
- delete this;
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPDataSock::OnClose(%d) - Caught unknown ecxeption.", nErrorCode);
- }
- return;
- }
- void CFTPDataSock::_OnClose( int nErrorCode )
- {
- CSock::OnClose(nErrorCode);
- m_OriginB->m_Timer.Reset();
- if (m_SendMode)
- {
- // This should never be called during send.
- LogMsg(LOGF_WARNINGS,"OnClose(%d) called during FTP data send.", nErrorCode);
- CSocketException::Throw(this,
- "CFTPDataSock::_OnClose(%d)", nErrorCode ? nErrorCode : -1, "On close during send.",
- nErrorCode);
- }
- else // receive
- {
- CSocketException::Throw(this,
- "CFTPDataSock::_OnClose(%d)", nErrorCode, "On close during receive.",
- nErrorCode);
- }
- }
- VOID WINAPI CFTPDataSock::OnOverlappedIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered,
- LPOVERLAPPED lpOverlapped)
- {
- CFTPOverlapped *Overlap = (CFTPOverlapped *)lpOverlapped->hEvent;
- ASSERT(AfxIsValidAddress(Overlap,sizeof(CFTPOverlapped)));
- ASSERT(IsProcessingIdle);
- try
- {
- m_OverlappedCnt--;
- ASSERT(m_OverlappedCnt >= 0);
- ASSERT(--Overlap->m_Origin->dm_OverlappedCnt == 0);
- m_Log->LogMsg(LOGF_DEBUG,"OnOverlappedIO(%08X) - Err=%d, %u bytes, Killme=%d",
- Overlap,
- dwErrorCode, dwNumberOfBytesTransfered, Overlap->m_KillMe);
- if (Overlap->m_KillMe)
- {
- // Transfere is aborted. Data socket is dead.
- CSock::m_Log->LogMsg(LOGF_DEBUG,"OnOverlappedIO() - Deleting dead overlapped data and closing file.");
- ASSERT(Overlap->m_pFile->IsOpen());
- Overlap->m_pFile->Close();
- if (Overlap->m_pFile->m_IsZombie && !Overlap->m_pFile->m_CallbackPending)
- {
- Overlap->m_pFile->Destroy();
- Overlap->m_pFile = NULL;
- }
- delete Overlap;
- return;
- }
- Overlap->m_Origin->m_OverlappedIOReady = TRUE;
- Overlap->m_Origin->m_OverlappedIOUsed = (int)dwNumberOfBytesTransfered;
- Overlap->m_Origin->m_CurrentPosition += dwNumberOfBytesTransfered;
- if (Overlap->m_Origin->m_FileLength < Overlap->m_Origin->m_CurrentPosition)
- Overlap->m_Origin->m_FileLength = Overlap->m_Origin->m_CurrentPosition;
- if (dwErrorCode)
- {
- if (Overlap->m_Origin->m_SendMode && (dwErrorCode == ERROR_HANDLE_EOF))
- {
- Overlap->m_Origin->m_EOF == TRUE;
- }
- else
- {
- CString cBuf;
- Overlap->m_Origin->LogMsg(LOGF_DEBUG,"OnOverlappedIO() - Error %s.",
- GetLastErrorText((int)dwErrorCode));
- CSocketException::Throw(Overlap->m_Origin, "CFTPDataSock::OnOverlappedIO", dwErrorCode, NULL);
- }
- }
- Overlap->m_Origin->DoOverlapped();
- // Check for end of transmission in send mode
- if (Overlap->m_Origin->m_SendMode && Overlap->m_Origin->m_EOF && Overlap->m_Origin->m_ClearToSend)
- {
- ASSERT(Overlap->m_Origin->m_BufferUsed == 0);
- CSocketException::Throw(Overlap->m_Origin, "CFTPDataSock::OnOverlappedIO", 0, "File xmitted OK");
- }
- }
- catch(CSocketException *pExc)
- {
- Overlap->m_Origin->m_OverlappedIOReady = TRUE;
- if (!pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum))
- delete pExc->m_pSock;
- delete pExc;
- }
- catch(...)
- {
- CLog::GetLog()->LogMsg(LOGF_ERROR,"CFTPDataSock::OnOverlappedIO(%d) - Caught unknown ecxeption.", dwErrorCode);
- }
- return;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // FTP Data listening sock
- CFTPPassiveSock::CFTPPassiveSock()
- {
- m_Origin = NULL;
- m_HasAccepted = FALSE;
- m_Type = LT_FTP_DATA;
- }
- CFTPPassiveSock::~CFTPPassiveSock()
- {
- ASSERT(m_Origin->m_ListeningSock == this);
- if (m_Origin && (m_Origin->m_ListeningSock == this))
- m_Origin->m_ListeningSock = NULL;
- }
- BOOL CFTPPassiveSock::Create(CFTPDataSock *Origin, int Port)
- {
- ASSERT(AfxIsValidAddress(Origin, sizeof(CFTPDataSock)));
- CString cBuf;
- m_Origin = Origin;
- m_SocketName = m_Origin->m_SocketName;
- m_SocketName += "::Passive";
- BOOL True = TRUE;
- int AddrLen = sizeof(SOCKADDR);
- SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
- ASSERT(AfxIsValidAddress(s_in,sizeof(SOCKADDR_IN)));
- // Get the local IP address the user is connected to
- UINT Dummy;
- if (!m_Origin->m_OriginB->GetSockName(&m_Sockaddr, &AddrLen) ||
- !m_Origin->m_OriginB->GetSockName(cBuf, Dummy))
- {
- LogLastError(LOGF_DEBUG,m_Origin->m_OriginB->GetLastError(),"Create() - m_OriginB->GetSockName() failed.");
- delete this;
- return FALSE;
- }
- s_in->sin_port = htons(Port);
- s_in->sin_family = AF_INET;
- // Create the socket
- if (!CSock::Create(Port, SOCK_STREAM, FD_ACCEPT, cBuf))
- {
- LogLastError(LOGF_DEBUG,0,"Create() failed.");
- delete this;
- return FALSE;
- }
- AsyncSelect(FD_ACCEPT);
- // Get the actual IP and port number
- if (!GetSockName(&m_Sockaddr, &AddrLen))
- {
- LogLastError(LOGF_DEBUG,0,"Create() - GetSockName() failed.");
- delete this;
- return FALSE;
- }
- if (!Listen())
- {
- LogLastError(LOGF_DEBUG,0,"Create() - Listen(1) failed.");
- delete this;
- return FALSE;
- }
- LogMsg(LOGF_DEBUG,"Create() - Listening to %d.%d.%d.%d.%d.%d (%d).",
- s_in->sin_addr.S_un.S_un_b.s_b1,
- s_in->sin_addr.S_un.S_un_b.s_b2,
- s_in->sin_addr.S_un.S_un_b.s_b3,
- s_in->sin_addr.S_un.S_un_b.s_b4,
- ((ntohs(s_in->sin_port) >> 8) & 0xff),
- (ntohs(s_in->sin_port) & 0xff),
- ntohs(s_in->sin_port));
- if (m_Origin->m_OriginC)
- {
- // Prepere the PORT command for the FTP Client
- m_Origin->m_OriginC->m_PreperedCommand.Format("PORT %d,%d,%d,%d,%d,%d",
- s_in->sin_addr.S_un.S_un_b.s_b1,
- s_in->sin_addr.S_un.S_un_b.s_b2,
- s_in->sin_addr.S_un.S_un_b.s_b3,
- s_in->sin_addr.S_un.S_un_b.s_b4,
- ((ntohs(s_in->sin_port) >> 8) & 0xff),
- (ntohs(s_in->sin_port) & 0xff));
- }
- else
- {
- if (m_Origin->m_OriginD)
- m_Origin->m_OriginD->SendMsg(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
- s_in->sin_addr.S_un.S_un_b.s_b1,
- s_in->sin_addr.S_un.S_un_b.s_b2,
- s_in->sin_addr.S_un.S_un_b.s_b3,
- s_in->sin_addr.S_un.S_un_b.s_b4,
- ((ntohs(s_in->sin_port) >> 8) & 0xff),
- (ntohs(s_in->sin_port) & 0xff));
- }
- return TRUE;
- }
- void CFTPPassiveSock::OnAccept( int nErrorCode )
- {
- try
- {
- _OnAccept(nErrorCode);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CFTPDataSock::OnAccept(%d %d) - Caught ecxeption.",
- nErrorCode, pExc->m_ErrorNum);
- if (!OnHandleWinsockErr(pExc->m_ErrorNum))
- {
- LogLastError(LOGF_WARNINGS,pExc->m_ErrorNum,"_OnAccept() - DoAccept() failed.");
- if (m_Origin->m_OriginD)
- m_Origin->m_OriginD->SendMsg(425, "Can't build data connection. %s.",
- GetLastErrorText(pExc->m_ErrorNum));
- m_Origin->m_HaveToldUserThatTransfereIsComplete = TRUE;
- int ErrNo = pExc->m_ErrorNum;
- delete pExc;
- CSocketException::Throw(m_Origin, "CFTPPassiveSock::OnAccept()", ErrNo, "Failed to build data connection.");
- }
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CFTPPassiveSock::OnAccept(%d) - Caught unknown ecxeption.", nErrorCode);
- }
- return;
- }
- void CFTPPassiveSock::_OnAccept( int nErrorCode )
- {
- CSock::OnAccept(nErrorCode);
- ASSERT(nErrorCode == 0);
- if (!DoAccept(m_Origin))
- {
- CString cBuf;
- int Err = GetLastError();
- LogLastError(LOGF_WARNINGS,Err,"_OnAccept() - DoAccept() failed.");
- if (m_Origin->m_OriginD)
- m_Origin->m_OriginD->SendMsg(425, "Can't build data connection. %s.", GetLastErrorText(Err));
- CSocketException::Throw(this, "CFTPPassiveSock::_OnAccept()", Err, NULL);
- }
- LogMsg(LOGF_DEBUG,"OnAccept() - Data socket is connected to remote host.");
- m_HasAccepted = TRUE;
- return;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // FTP data Overlapped IO support
- CFTPOverlapped::CFTPOverlapped()
- {
- m_Buffer = NULL;
- m_KillMe = FALSE;
- }
- CFTPOverlapped::~CFTPOverlapped()
- {
- if (m_Buffer)
- delete m_Buffer;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // CDaemonEvent
- // Class to pass events from a module to a remote process.
- CRegisteredEvents::CRegisteredEvents()
- {
- m_Event = 0;
- }
- CRegisteredEvents::~CRegisteredEvents()
- {
- LPVOID p;
- while((p = m_ClientEventObjects.GetAndDeleteFirst()) != NULL)
- delete p;
- }
- CLinkedList CDaemonEvent::m_DsEventRegister;
- CDaemonEvent::CDaemonEvent(CTextSock *Socket, int MaxQueueItems)
- {
- m_MaxQueueItems = MaxQueueItems;
- m_Client = Socket;
- m_EventTypes = 0;
- m_ClosePending = FALSE;
- }
- CDaemonEvent::~CDaemonEvent()
- {
- CLinkedListItem *Item;
- m_EventQueue.KillAll();
- Item = m_DsEventRegister.First();
- CRegisteredEvents *pEv;
- while(Item)
- {
- pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
- if (pEv->m_Event & m_EventTypes)
- {
- pEv->m_ClientEventObjects.DeletePtr((LPVOID)this);
- }
- Item = m_DsEventRegister.Next(Item);
- }
- }
- CRegisteredEvents *CDaemonEvent::FindRegisteredEvent(int EventType)
- {
- CLinkedListItem *Item = m_DsEventRegister.First();
- CRegisteredEvents *pEv = NULL;
- while(Item)
- {
- pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
- if (pEv->m_Event & EventType)
- return pEv;
- Item = m_DsEventRegister.Next(Item);
- }
- return NULL;
- }
- HANDLE CDaemonEvent::DsRegister(int EventType, LPVOID pOrigin,
- void (* DsNotify)(LPVOID pOrigin, CDaemonEvent *pCliEv))
- {
- ASSERT(FindRegisteredEvent(EventType) == NULL);
- CRegisteredEvents *pReg = new CRegisteredEvents;
- pReg->m_Event = EventType;
- pReg->m_DsNotify = DsNotify;
- pReg->m_pOrigin = pOrigin;
- m_DsEventRegister.AddLast((LPVOID)pReg);
- return pReg;
- }
- BOOL CDaemonEvent::DsClose(HANDLE h)
- {
- if (h == INVALID_HANDLE_VALUE)
- return FALSE;
- CRegisteredEvents *pEv = (CRegisteredEvents *)h;
- ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
- m_DsEventRegister.DeletePtr(pEv);
- delete pEv;
- return TRUE;
- }
- // Send an event to all clients
- BOOL CDaemonEvent::DsEvent(HANDLE h, LPCSTR EventMsg, BOOL Priority)
- {
- ASSERT(AfxIsValidString(EventMsg));
- CRegisteredEvents *pEv = (CRegisteredEvents *)h;
- ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
- CLinkedListItem *Item = pEv->m_ClientEventObjects.First();
- CString MyCs;
- MyCs.Empty();
- while(Item)
- {
- CDaemonEvent *pClientEvent = (CDaemonEvent *)pEv->m_ClientEventObjects.Ptr(Item);
- ASSERT(AfxIsValidAddress(pClientEvent, sizeof(CDaemonEvent)));
- Item = pEv->m_ClientEventObjects.Next(Item);
- if (MyCs.IsEmpty())
- MyCs.Format("%s%05d %03d %srn", OOB_HDR, strlen(EventMsg), pEv->m_Event, EventMsg);
- pClientEvent->Event(h, EventMsg, Priority, &MyCs);
- }
- return TRUE;
- }
- // Send an event to the object event (one client)
- BOOL CDaemonEvent::Event(HANDLE h, LPCSTR EventMsg, BOOL Priority, CString *MyCs)
- {
- ASSERT(AfxIsValidAddress(this, sizeof(CDaemonEvent)));
- ASSERT(AfxIsValidString(EventMsg));
- CRegisteredEvents *pEv = (CRegisteredEvents *)h;
- ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
- if (m_EventQueue.GetItemCount() >= m_MaxQueueItems)
- {
- // Flooded.
- CString *cs;
- while(cs = (CString *)m_EventQueue.GetAndDeleteFirst())
- delete cs;
- cs = new CString("00000 000 rn"); // Close header.
- m_EventQueue.AddFirst((LPVOID)cs);
- m_ClosePending = TRUE;
- }
- else
- {
- CString cBuf;
- if (!MyCs)
- {
- MyCs = &cBuf;
- MyCs->Format("%s%05d %03d %srn", OOB_HDR, strlen(EventMsg), pEv->m_Event, EventMsg);
- }
- if (Priority)
- m_EventQueue.AddFirst((LPVOID) new CString( *MyCs));
- else
- m_EventQueue.AddLast((LPVOID) new CString (*MyCs));
- TRY
- {
- Process();
- }
- CATCH (CUserException, e)
- {
- Close();
- }
- END_CATCH
- }
- return TRUE;
- }
- BOOL CDaemonEvent::Register(int EventType)
- {
- if (m_EventTypes & EventType)
- return TRUE;
- CLinkedListItem *Item = m_DsEventRegister.First();
- CRegisteredEvents *pEv;
- while(Item)
- {
- pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
- if (pEv->m_Event & EventType)
- {
- m_EventTypes |= EventType;
- pEv->m_ClientEventObjects.AddFirst((LPVOID)this);
- if (pEv->m_DsNotify)
- pEv->m_DsNotify(pEv->m_pOrigin, this);
- }
- Item = m_DsEventRegister.Next(Item);
- }
- return TRUE;
- }
- BOOL CDaemonEvent::Process()
- {
- while(!m_Client->m_SuspendEvents && m_Client->m_ClearToSend && m_EventQueue.GetItemCount())
- {
- CString *cs = (CString *)m_EventQueue.FirstPtr();
- ASSERT(AfxIsValidString(*cs));
- int nBytes = m_Client->CAsyncSocket::Send(*cs, cs->GetLength());
- if (nBytes == SOCKET_ERROR)
- {
- if (m_Client->GetLastError() != WSAEWOULDBLOCK)
- AfxThrowUserException();
- if (m_Client->m_ClearToSend)
- {
- try
- {
- m_Client->Close();
- }
- catch(CSocketException *pExc)
- {
- if (!pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum))
- delete pExc->m_pSock;
- delete pExc;
- }
- catch(...)
- {
- CLog::GetLog()->LogMsg(LOGF_ERROR,"CDaemonEvent::Process() - caught unknown exception.");
- return FALSE;
- }
- }
- return FALSE;
- }
- if (nBytes != cs->GetLength())
- {
- ASSERT(cs->GetLength() > 0);
- LPSTR p = cs->GetBuffer(1);
- memmove(p, p + nBytes, cs->GetLength() - nBytes);
- p[cs->GetLength() - nBytes] = 0;
- cs->ReleaseBuffer();
- }
- else
- {
- m_EventQueue.GetAndDeleteFirst();
- delete cs;
- }
- }
- if (m_ClosePending)
- Close();
- return m_Client->m_ClearToSend;
- }
- BOOL CDaemonEvent::Close()
- {
- return Close(-1);
- }
- BOOL CDaemonEvent::Close(int Events)
- {
- CLinkedListItem *Item = m_DsEventRegister.First();
- CRegisteredEvents *pEv;
- while(Item)
- {
- pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
- if (pEv->m_Event & (m_EventTypes & Events))
- {
- pEv->m_ClientEventObjects.DeletePtr((LPVOID)this);
- }
- Item = m_DsEventRegister.Next(Item);
- }
- m_EventTypes &= ~Events;
- m_ClosePending = FALSE;
- CString *cs;
- while(cs = (CString *)m_EventQueue.GetAndDeleteFirst())
- delete cs;
- return TRUE;
- }
- /////////////////////////////////////////////////////////////////////////
- // CDNSLookup
- CLinkedList CDNSLookup::m_List;
- CDNSLookup::CDNSLookup()
- {
- m_ID = 0;
- m_ReqHandle = 0;
- m_QueryName.Empty();
- m_LParam = NULL;
- memset(m_Buf,0,MAXGETHOSTSTRUCT);
- }
- BOOL CDNSLookup::Create(CSock *pOrigin, LPCSTR Name, LPARAM LParam)
- {
- if (Name == NULL)
- Name = pOrigin->m_PeerName;
- m_ID = pOrigin->m_SocketID;
- m_LParam = LParam;
- m_QueryName = Name;
- long inaddr = inet_addr(Name);
- char addr[4];
- memcpy(addr,&inaddr, 4);
- ASSERT(pOrigin->m_DNSwin != NULL);
- if (!pOrigin->m_DNSwin)
- {
- pOrigin->LogMsg(LOGF_ERROR,"CDNSLookup(%s) - APPLICATION ERROR: No DNS window.", Name);
- goto error;
- }
- if (inaddr == INADDR_NONE)
- {
- m_ReqHandle = WSAAsyncGetHostByName(
- pOrigin->m_DNSwin->m_hWnd,
- WMU_TX_DNS,
- Name,
- m_Buf,
- MAXGETHOSTSTRUCT);
- }
- else
- {
- m_ReqHandle = WSAAsyncGetHostByAddr(
- pOrigin->m_DNSwin->m_hWnd,
- WMU_TX_DNS,
- addr,
- 4,
- PF_INET,
- m_Buf,
- MAXGETHOSTSTRUCT);
- }
- if (!m_ReqHandle)
- {
- pOrigin->LogMsg(LOGF_ERROR,"CDNSLookup(%s) - WSAAsyncGetHostByAddr failed.",
- pOrigin->m_PeerName);
- error:
- pOrigin->OnDNSLookup(-1, this);
- delete this;
- return FALSE;
- }
- m_List.AddLast((LPVOID)this);
- return TRUE;
- }
- CDNSLookup::~CDNSLookup()
- {
- m_List.DeletePtr((LPVOID)this);
- }
- void CDNSLookup::DNSlookupCallback(WPARAM Handle, LPARAM Status)
- {
- CLinkedListItem *Item = m_List.First();
- CDNSLookup *pItem;
- CSock *pSock;
- while(Item)
- {
- pItem = (CDNSLookup *)m_List.Ptr(Item);
- Item = m_List.Next(Item);
- if (pItem->m_ReqHandle == (HANDLE)Handle)
- {
- pSock = CSock::GetFromID(pItem->m_ID);
- if (pSock)
- pSock->OnDNSLookup(HIWORD(Status), pItem);
- delete pItem;
- break;
- }
- }
- }