RemoteInterface.cpp
资源名称:warftpd.zip [点击查看]
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:19k
源码类别:
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 : RemoteInterface.cpp
- // PURPOSE : Basic socket handeling
- // PROGRAM :
- // DATE : Nov. 14 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
- ///////////////////////////////////////////////////////////////////////////////
- // Generic Remote connection interface
- // Handles standard Internet server reply codes for the supported protocols
- // The replies include the server reply code.
- CRemoteInterface::CRemoteInterface()
- {
- m_CurrentRequest.Empty();
- m_CurrentReply.Empty();
- CurrentQueueIndex = 0;
- CurrentRequestQueue = NULL;
- CurrentReplyQueue = NULL;
- m_InBuf.Empty();
- m_OutBuf.Empty();
- m_SuspendOnClose = TRUE;
- m_Type = LT_REMOTE;
- m_FileHandle = INVALID_HANDLE_VALUE;
- m_BytesLeftToDownload = 0;
- }
- CRemoteInterface::~CRemoteInterface()
- {
- if (CurrentRequestQueue)
- delete CurrentRequestQueue;
- if (CurrentReplyQueue)
- delete CurrentReplyQueue;
- m_RequestQueue.KillAll();
- }
- // Open a connection to a War daemon
- BOOL CRemoteInterface::OpenRemote(LPCSTR Address, UINT Port, int Service, LPCSTR UserName,
- LPCSTR UserPwd)
- {
- CString cBuf;
- m_ConnectionTimer.Reset();
- char buf[MAX_PATH];
- m_UserName = UserName;
- m_UserPwd = UserPwd;
- switch(Service)
- {
- case LT_REMOTE:
- m_Type = LT_REMOTE;
- break;
- case LT_FTP:
- m_Type = LT_FTP;
- // Handle firewalls
- // Classic proxy
- if (COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLTYPE) == '1')
- {
- m_UserName.Format("%s@%s", UserName, Address);
- strcpy(buf,COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLHOST));
- cBuf = COptions::GetOption(COPTION_CFTPCLIENTFIREWALL, CFTPCLIENTOPTIONS_FIREWALLPORT);
- if (cBuf == "FTP")
- cBuf = "21";
- if ((Port = atoi(cBuf)) == 0)
- {
- LogMsg(LOGF_ERROR,"Port not defined for proxy/firewall");
- return FALSE;
- }
- LogMsg(LOGF_INOUT,"Using classic proxy logon at %s:%d (USER %s).",
- buf, Port,m_UserName);
- Address = buf;
- }
- break;
- default:
- LogMsg(LOGF_ERROR,"OpenRemote() - Create() failed. Unknown daemon type (%d).", Service);
- return FALSE;
- }
- if (!Create())
- {
- LogMsg(LOGF_ERROR,"OpenRemote() - Create() failed. %s.", GetLastErrorText());
- return FALSE;
- }
- LogMsg(LOGF_DEBUG, "Connecting to remote host (%s) %s on port %u",
- SafeStringIndex(CSock::DaemonTypes, m_Type, LT_INVALID), Address, Port);
- AsyncSelect(FD_CONNECT|FD_CLOSE);
- if (!Connect(Address,Port))
- {
- if (GetLastError() != WSAEWOULDBLOCK)
- {
- LogMsg(LOGF_ERROR,"OpenRemote() - Connect() failed. %s.", GetLastErrorText());
- return FALSE;
- }
- return TRUE;
- }
- // Connected without delay.... Don't know if this can happen...
- try
- {
- OnConnect(0);
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CRemoteInterface::OpenRemote() - Caught exception '%s' from module %s",
- pExc->m_ErrorText, pExc->m_ErrorText);
- if (pExc->m_ErrorNum)
- throw pExc;
- delete pExc;
- }
- catch(...)
- {
- LogMsg(LOGF_ERROR,"CRemoteInterface::OpenRemote() - Caught unknown exception");
- return FALSE;
- }
- return TRUE;
- }
- void CRemoteInterface::OnConnect( int nErrorCode )
- {
- CSock::OnConnect(nErrorCode);
- AsyncSelect(m_AsyncSelectMask);
- BOOL bVal = TRUE; SetSockOpt(TCP_NODELAY,&bVal,sizeof(bVal),IPPROTO_TCP);
- }
- void CRemoteInterface::OnSend( int nErrorCode )
- {
- CString cBuf;
- CSock::OnSend(nErrorCode);
- if (nErrorCode)
- {
- LogMsg(LOGF_ERROR,"OnSend() - Connection to server lost. %s", GetLastErrorText());
- OnServerMessage( -1 );
- return;
- }
- DoSend();
- }
- void CRemoteInterface::OnClose( int nErrorCode )
- {
- CSock::OnClose(nErrorCode);
- }
- void CRemoteInterface::OnReceive( int nErrorCode )
- {
- CString cBuf;
- CSock::OnReceive(nErrorCode);
- char buf[1024];
- int nBytes;
- BOOL DoThrow = FALSE;
- if (nErrorCode)
- {
- LogMsg(LOGF_ERROR,"OnReceive() - Connection to server lost. %s", GetLastErrorText());
- OnServerMessage( -1 );
- return;
- }
- again:
- try
- {
- if (m_BytesLeftToDownload)
- {
- DWORD nBytesWritten;
- ASSERT(m_FileHandle != INVALID_HANDLE_VALUE);
- while(m_ClearToReceive && m_BytesLeftToDownload && ((nBytes = Receive(buf, min(sizeof(buf), m_BytesLeftToDownload))) > 0))
- {
- WriteFile(
- m_FileHandle,
- buf,
- nBytes,
- &nBytesWritten,
- NULL);
- m_BytesLeftToDownload -= nBytes;
- }
- }
- else
- {
- nBytes = Receive(buf, sizeof(buf));
- {
- // Q&D patch to strip off Telnet echo off reply code...
- unsigned char *up = (unsigned char *)buf;
- if ((up[0] == IAC) && (up[1] == WONT) && (up[2] == TELOPT_ECHO))
- {
- nBytes -= 3;
- memmove(buf, buf + 3, nBytes);
- }
- buf[nBytes] = 0;
- m_InBuf += buf;
- }
- }
- }
- catch(CSocketException *pExc)
- {
- LogMsg(LOGF_DEBUG,"CRemoteInterface::OnReceive() - Caught exception '%s' from module %s",
- pExc->m_ErrorText, pExc->m_ErrorText);
- if (pExc->m_ErrorNum)
- throw pExc;
- delete pExc;
- DoThrow = TRUE;
- }
- if (m_BytesLeftToDownload || (m_FileHandle != INVALID_HANDLE_VALUE))
- {
- if (!m_BytesLeftToDownload)
- {
- // EOF
- CloseHandle(m_FileHandle);
- m_FileHandle = INVALID_HANDLE_VALUE;
- m_InBuf.Format("200 {local} received file "%s" "%s" (%d bytes) OKrn",
- m_FileName, m_TempFileName, m_BytesToDownload);
- goto have_something;
- }
- }
- else
- {
- have_something:
- if (m_InBuf.GetLength())
- {
- // See if this is the whole message
- LPSTR p = m_InBuf.GetBuffer(1);
- LPSTR pp = p + m_InBuf.GetLength() - 1;
- BOOL GotEol = FALSE;
- if (pp > p)
- {
- if (m_Type == LT_REMOTE)
- GotEol = !strcmp(pp - 1, ": "); // Valid end of line for remote admin
- if (!GotEol)
- GotEol = !strcmp(pp - 1, "rn"); // Valid end of line for all admin's
- m_LastLineInBuf = pp;
- }
- if (GotEol)
- {
- // Parse the lines
- for(pp = strtok(p, "rn"); pp; pp = strtok(NULL,"rn"))
- {
- if (!memcmp(pp, OOB_HDR, 4))
- {
- CurrentServerNotifications.AddLast((LPVOID)strdup(pp + 4));
- }
- else if (isdigit(pp[0]) && isdigit(pp[1]) && isdigit(pp[2]))
- {
- CurrentServerReply.AddLast((LPVOID)strdup(pp));
- }
- else
- {
- if (m_Type == LT_FTP)
- OnClientLogNotify(pp); // Show raw test on the display...
- else
- LogMsg(LOGF_WARNINGS,"Received trash from server: '%s'", pp);
- }
- }
- m_InBuf.Empty();
- // Process the lines
- while(pp = (LPSTR)CurrentServerReply.GetAndDeleteFirst())
- {
- if (!m_InBuf.IsEmpty())
- m_InBuf += 'n';
- int Index = m_InBuf.GetLength();
- OnClientLogNotify(pp);
- m_InBuf += pp;
- m_LastLineInBuf = (LPCSTR)m_InBuf + Index;
- if (m_LastLineInBuf[3] == ' ')
- {
- // Last line of a server reply (nnn<SP>)
- OnServerMessage( 0 );
- m_InBuf.Empty();
- }
- delete pp;
- }
- if (!m_InBuf.IsEmpty())
- m_InBuf += "rn"; // Prepere for next pass
- while(pp = (LPSTR)CurrentServerNotifications.GetAndDeleteFirst())
- {
- OnNotification(0, pp);
- delete pp;
- }
- }
- }
- }
- if (DoThrow)
- CSocketException::Throw(this, "CRemoteInterface::OnReceive",nErrorCode,"Connection is closed by remote host.");
- if (!m_IsConnected)
- {
- OnServerMessage( -1 );
- return;
- }
- if (m_ClearToReceive)
- goto again;
- return;
- }
- void CRemoteInterface::OnServerMessage( int nErrorCode )
- {
- if ( nErrorCode )
- {
- error:
- // Cancel all requests and mark the connection as disconnected
- m_IsConnected = FALSE;
- if (m_State < PROCESS)
- {
- LogMsg(LOGF_DEBUG,"OnServerMessage() - Remote Connection closed.");
- OnOpen(nErrorCode ? nErrorCode : -1);
- return;
- }
- while(m_RequestQueue.GetItemCount())
- NotifyRequest(nErrorCode ? nErrorCode : -1);
- return;
- }
- // Handle direct file download
- if (atoi(m_LastLineInBuf) == 280)
- {
- if (m_BytesLeftToDownload)
- CSocketException::Throw(this, "CRemoteInterface::OnServerMessage",0,"Can not download 2 files at the same time!");
- MySscanf(m_LastLineInBuf,""%C" (%d)",
- &m_FileName, &m_BytesLeftToDownload);
- LogMsg(LOGF_FILEACC,"CRemoteInterface::OnServerMessage() - Downloading file '%s', %d bytes",
- m_FileName, m_BytesLeftToDownload);
- if (m_BytesLeftToDownload)
- {
- char TempName[MAX_PATH];
- if (!GetTempPath(MAX_PATH,TempName))
- strcpy(TempName,".");
- GetTempFileName(TempName, "~tmp_file", 0, m_TempFileName.GetBuffer(MAX_PATH));
- m_TempFileName.ReleaseBuffer();
- if ((m_FileHandle = ::CreateFile(
- m_TempFileName,
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL)) == INVALID_HANDLE_VALUE)
- {
- LogMsg(LOGF_WARNINGS,"CRemoteInterface::OnServerMessage() - Failed to create tmp file '%s' %s",
- m_TempFileName, GetLastErrorText());
- m_BytesLeftToDownload = 0;
- m_LastLineInBuf = "550 (local) Failed to create temp file";
- }
- else
- {
- m_BytesToDownload = m_BytesLeftToDownload;
- return;
- }
- }
- // If null file, let the original message go trough..
- }
- switch(m_State)
- {
- case PRELOGIN: // Send user name.
- if (atoi(m_LastLineInBuf) != 220)
- {
- LogMsg(LOGF_ERROR,"Login refused. (%s)", m_LastLineInBuf);
- if (m_Type == LT_REMOTE)
- AfxMessageBox(m_InBuf);
- goto error;
- }
- switch(m_Type)
- {
- case LT_FTP:
- if (!SendCmd("USER %s", m_UserName))
- goto error;
- break;
- case LT_REMOTE:
- if (!SendCmd("%c%c%c%s", IAC, DONT, TELOPT_ECHO, m_UserName))
- goto error;
- break;
- default:
- ASSERT(FALSE);
- }
- m_State = GOTNAME;
- break;
- case GOTNAME:
- if (atoi(m_LastLineInBuf) == 230)
- {
- m_State = PROCESS;
- OnOpen( 0 );
- break;
- }
- if (atoi(m_LastLineInBuf) != 331)
- {
- LogMsg(LOGF_ERROR,"Login refused. (%s)", m_LastLineInBuf);
- if (m_Type == LT_REMOTE)
- AfxMessageBox(m_InBuf);
- goto error;
- }
- switch(m_Type)
- {
- case LT_FTP:
- if (!SendCmd("PASS %s", m_UserPwd))
- goto error;
- break;
- case LT_REMOTE:
- if (!SendCmd("%s", m_UserPwd))
- goto error;
- break;
- default:
- ASSERT(FALSE);
- }
- m_State = GOTNAME;
- break;
- case HOLD:
- if (NotifyRequest( 0 ))
- {
- m_State = PROCESS;
- ProcessRequest( 0 );
- }
- break;
- default:
- LogMsg(LOGF_ERROR,"Trash received from server. : %s", m_CurrentReply);
- }
- }
- // Process the next request
- BOOL CRemoteInterface::ProcessRequest(int nErrorCode)
- {
- if (m_State != PROCESS)
- {
- LogMsg(LOGF_DEBUG,"ProcessRequest() - Must delay processing until state is PROCESS...");
- return TRUE;
- }
- CRemoteRequest *Req;
- if ((Req = (CRemoteRequest *)m_RequestQueue.FirstPtr()) == NULL)
- return TRUE; // Nothing to process
- switch(Req->m_Type)
- {
- case RQ_SINGLE:
- m_CurrentRequest = Req->m_Request;
- break;
- case RQ_MULTIPLE:
- if (CurrentQueueIndex == 0)
- {
- // Start of new batch..
- CurrentRequestQueue = Req->m_RequestQueue;
- CurrentReplyQueue = new CCmdArgs;
- }
- m_CurrentRequest = Req->m_RequestQueue->Arg(CurrentQueueIndex++);
- break;
- default:
- ASSERT(FALSE);
- }
- if (!SendCmd("%s", m_CurrentRequest))
- {
- OnServerMessage( -1 );
- return FALSE;
- }
- m_State = HOLD;
- return TRUE;
- }
- BOOL CRemoteInterface::NotifyRequest(int nErrorCode)
- {
- CRemoteRequest *Req;
- BOOL DoSuspend = TRUE;
- Req = (CRemoteRequest *)m_RequestQueue.FirstPtr();
- ASSERT(Req != NULL);
- switch(Req->m_Type)
- {
- case RQ_SINGLE:
- m_CurrentReply = m_InBuf;
- *Req->m_ReplyBuf = m_CurrentReply;
- DoSuspend = OnRequest( nErrorCode, Req );
- break;
- case RQ_MULTIPLE:
- ASSERT(CurrentRequestQueue != NULL);
- ASSERT(CurrentReplyQueue != NULL);
- ASSERT(CurrentQueueIndex >= 0);
- CurrentReplyQueue->AddArg(m_InBuf);
- if (CurrentQueueIndex == CurrentRequestQueue->m_argc)
- {
- OnRequestMulti( nErrorCode, Req);
- CurrentRequestQueue = NULL;
- CurrentReplyQueue = NULL;
- CurrentQueueIndex = 0;
- }
- break;
- default:
- ASSERT(FALSE);
- }
- if (DoSuspend)
- {
- m_RequestQueue.GetAndDeleteFirst();
- delete Req;
- }
- else
- Req->m_ReplyBuf->Empty(); // Reuse
- return DoSuspend;
- }
- // Called when a connection to a war deamon is compleated, or has failed
- void CRemoteInterface::OnOpen(int nErrorCode)
- {
- if (!nErrorCode)
- {
- AsyncSelect(m_AsyncSelectMask = FD_READ | FD_WRITE | FD_CLOSE); // Receive all notifications, except OOB
- }
- }
- // Request some action from the daemon
- BOOL CRemoteInterface::Request(LPCSTR Request, CString &cReplyBuf, CWnd *cWnd, int nMsg,
- BOOL (* Func)(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg), LPVOID Arg, HANDLE *CancelHndl)
- {
- CRemoteRequest *Req = new CRemoteRequest;
- Req->m_Type = RQ_SINGLE;
- Req->m_Request = Request;
- Req->m_ReplyBuf = &cReplyBuf;
- Req->m_cWnd = cWnd;
- Req->m_Msg = nMsg;
- Req->m_Func = Func;
- Req->m_FuncArg = Arg;
- Req->m_IsReleased = FALSE;
- if (CancelHndl)
- *CancelHndl = (HANDLE)Req;
- if (!CNotificationWnd::IsSameThread())
- {
- // Since we use sockets, we have to route this to the correct thread.
- // This also simplifies multithread access to the resources.
- BOOL Rval = SendMessage(CNotificationWnd::GetHwnd(), WMU_RCTDREQ, (WPARAM)this, (LPARAM)Req);
- return Rval;
- }
- return CRemoteInterface::Request(Req);
- }
- BOOL CRemoteInterface::Request(CRemoteRequest *Req)
- {
- m_RequestQueue.AddLast((LPVOID)Req);
- return ProcessRequest( 0 );
- }
- // Blocking request. Can not be called from the main therad.
- BOOL CRemoteInterface::Req(HANDLE Remote, LPCSTR RequestText, CString& ReplyBuf, int timeout)
- {
- ASSERT(CNotificationWnd::IsSameThread() == FALSE);
- CRemoteInterface *pRI = (CRemoteInterface *)Remote;
- ASSERT(AfxIsValidAddress(pRI, sizeof(CRemoteInterface)));
- HANDLE h;
- CEvent MyEvent(FALSE, TRUE);
- MyEvent.ResetEvent();
- if (!pRI->Request(RequestText, ReplyBuf, NULL, 0, ReqCallback, (LPVOID)&MyEvent, &h))
- return FALSE;
- CSingleLock MyLock(&MyEvent);
- again:
- if (!MyLock.Lock(timeout))
- {
- try
- {
- if (!pRI->CancelRequest(h))
- goto again;
- return FALSE;
- }
- catch(...)
- {
- CLog::GetLog()->LogMsg(LOGF_ERROR,"CRemoteInterface::Req() - Caught exception. Terminating therad.");
- PostQuitMessage(1);
- }
- }
- return TRUE;
- }
- // Cancel a request. The request is not cancelled to the server, but the notifiications
- // on completion is turned off.
- BOOL CRemoteInterface::CancelRequest(HANDLE h)
- {
- CRemoteRequest *Req = (CRemoteRequest *)h;
- ASSERT(AfxIsValidAddress(Req, sizeof(h)));
- BOOL Rval = TRUE;
- Req->m_Lock.Lock();
- if (Req->m_IsReleased)
- Rval = FALSE;
- else
- {
- Req->m_Func = NULL;
- Req->m_cWnd = NULL;
- }
- Req->m_Lock.Unlock();
- return Rval;
- }
- BOOL CRemoteInterface::ReqCallback(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg)
- {
- CEvent *pEvent = (CEvent *)Arg;
- ASSERT(AfxIsValidAddress(pEvent, sizeof(CEvent)));
- if (nErrorCode)
- AfxThrowUserException();
- pEvent->SetEvent();
- return TRUE;
- }
- // Called when a simple request is completed, or has failed
- BOOL CRemoteInterface::OnRequest(int nErrorCode, CRemoteRequest *Req)
- {
- BOOL Rval = TRUE;
- Req->m_Lock.Lock();
- if (Req->m_cWnd)
- Req->m_cWnd->SendMessage(Req->m_Msg, (WPARAM)nErrorCode, (LPARAM)Req->m_ReplyBuf);
- if (Req->m_Func)
- Rval = Req->m_IsReleased = Req->m_Func(nErrorCode, (LPVOID)Req->m_ReplyBuf, Req->m_FuncArg);
- Req->m_Lock.Unlock();
- return Rval;
- }
- // Process multiple reuests. The requests are stored as in the request list.
- BOOL CRemoteInterface::RequestMulti(CCmdArgs *RequestList, CWnd *cWnd, int nMsg,
- BOOL (* Func)(int nErrorCode, LPVOID ReplyBuf, LPVOID Arg), LPVOID Arg)
- {
- CRemoteRequest *Req = new CRemoteRequest;
- Req->m_Type = RQ_MULTIPLE;
- Req->m_Request.Empty();
- Req->m_RequestQueue = RequestList;
- Req->m_cWnd = cWnd;
- Req->m_Msg = nMsg;
- Req->m_Func = Func;
- Req->m_FuncArg = Arg;
- m_RequestQueue.AddLast((LPVOID)Req);
- return ProcessRequest( 0 );
- }
- // Called when multiple requests has been processed, or failed.
- // The reply buffer is allocated by the framework and must be deleted manually.
- // (this is done if this base function is called).
- // The replies are stored in the same order as they was requested.
- void CRemoteInterface::OnRequestMulti(int nErrorCode, CRemoteRequest *Req)
- {
- if (Req->m_cWnd)
- Req->m_cWnd->SendMessage(Req->m_Msg, (WPARAM)nErrorCode, (LPARAM)CurrentReplyQueue);
- if (Req->m_Func)
- Req->m_Func(nErrorCode, (LPVOID)CurrentReplyQueue, Req->m_FuncArg);
- }
- // Notification messages from the server. These messages are sent as OutOfBand
- // data in the form: <sssss eee msg> where s=message size, e=event msg=message. The message
- // can contain any ascii or binary 8 bit data, including