SocketBase.cpp
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:80k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
  2. // Copyright 1996 by Jarle Aase. All rights reserved.
  3. // See the "War Software Series Licende Agreement" for details concerning 
  4. // use and distribution.
  5. // ---
  6. // This source code, executables and programs containing source code or
  7. // binaries or proprietetary technology from the War Software Series are
  8. // NOT alloed used, viewed or tested by any governmental agencies in
  9. // any countries. This includes the government, departments, police, 
  10. // military etc.
  11. // ---
  12. // This file is intended for use with Tab space = 2
  13. // Created and maintained in MSVC Developer Studio
  14. // ---
  15. // NAME : SocketBase.cpp
  16. // PURPOSE : Basic socket handeling
  17. // PROGRAM : 
  18. // DATE : Sept. 19 1996
  19. // AUTHOR : Jarle Aase
  20. // ---
  21. // REVISION HISTORY
  22. // 
  23. #include "stdafx.h"
  24. #include "telnet.h"
  25. #include "ftp.h"
  26. #include "WarSoftware.h"
  27. #ifdef _DEBUG
  28. #define new DEBUG_NEW
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32. ///////////////////////////////////////////////////////////////////////////////////////
  33. // CSockHandler
  34. // Maintanance class for sockets
  35. CSocketException::CSocketException()
  36. {
  37. };
  38. void CSocketException::Throw(CSock *pSock, LPCSTR Module, int ErrorNum, LPCSTR Format, ...)
  39. {
  40. CWarString cBuf;
  41. CSocketException *pExc = new CSocketException;
  42. if (Format == NULL)
  43. pExc->m_ErrorText = GetLastErrorText(ErrorNum);
  44. else
  45. {
  46. va_list argList;
  47. va_start(argList, Format);
  48. cBuf.FormatVaList(Format, argList);
  49. va_end(argList);
  50. pExc->m_ErrorText = cBuf;
  51. }
  52. pExc->m_FromModule = Module;
  53. pExc->m_ErrorNum = ErrorNum;
  54. pExc->m_pSock = pSock;
  55. if (CSock::m_Log)
  56. CSock::m_Log->LogMsg(LOGF_DEBUG,"CSocketException::Throw(%s) - from module %s err=%d msg=%s",
  57. pSock->m_SocketName, Module, ErrorNum, cBuf);
  58. throw pExc;
  59. }
  60. ///////////////////////////////////////////////////////////////////////////////////////
  61. // CSock
  62. // Base class for all async socket communication
  63. IMPLEMENT_DYNAMIC(CSock, CAsyncSocket);
  64. DWORD CSock::m_SequenceCounter = 0;
  65. CLog *CSock::m_Log = NULL;
  66. DWORD CSock::m_NumSocketsInUse = 0;
  67. CCriticalSection CSock::m_GlobalLock;
  68. LPSTR CSock::DaemonTypes[4] = { "FTP", "FTPData", "Telnet", "RemoteAdmin" };
  69. int CSock::m_OverlappedCnt = 0;
  70. CLinkedList CSock::m_SocketList;
  71. CWnd *CSock::m_DNSwin = NULL;
  72. CWarTimer CSock::m_Housekeeping;
  73. CSock::CSock()
  74. {
  75. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  76. m_GlobalLock.Lock();
  77. m_State = PRELOGIN;
  78. m_SocketID = ++m_SequenceCounter; 
  79. ++m_NumSocketsInUse;
  80. m_SocketName = "CSock";
  81. m_ClearToSend = FALSE;
  82. m_ClearToReceive = FALSE;
  83. m_BytesSent = 0;
  84. m_BytesReceived = 0;
  85. m_Type = LT_INVALID;
  86. m_IsConnected = FALSE;
  87. m_SocketList.AddFirst((LPVOID)this);
  88. m_Father = NULL;
  89. m_SuspendOnClose = FALSE;
  90. m_GlobalLock.Unlock();
  91. m_AsyncSelectMask = FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT | FD_CLOSE;
  92. m_DestructorIsActive = FALSE;
  93. m_SuspendDelete = 0;
  94. m_MaxIdleTime = 0;
  95. m_MaxOnlineTime = 0;
  96. // EXT module
  97. PrcExt(CAPIHandler::OnNewSocket,0,0,(LPARAM)this);
  98. }
  99. CSock::~CSock()
  100. {
  101. m_DestructorIsActive = TRUE;
  102. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  103. if (m_hSocket != INVALID_SOCKET)
  104. {
  105. AsyncSelect(0);
  106. Close();
  107. }
  108. m_GlobalLock.Lock();
  109. --m_NumSocketsInUse;
  110. m_SocketList.DeletePtr((LPVOID)this);
  111. m_GlobalLock.Unlock();
  112. PrcSockExt(iOnSocketIsDestroyed,0,0,(LPARAM)this);
  113. if (m_Log)
  114. LogMsg(LOGF_DEBUG,"~CSock() - socket destroyed. %d sockets left in use.", m_NumSocketsInUse );
  115. #ifdef _DEBUG
  116. if (m_SuspendDelete && m_Log)
  117. LogMsg(LOGF_DEBUG,"~CSock() - Warning - socket was suspended from deletion (%d).",
  118. m_SuspendDelete);
  119. #endif
  120. }
  121. void CSock::SetIdleTime(int limit)
  122. {
  123. m_MaxIdleTime = limit;
  124. }
  125. void CSock::SetLogonTime(int limit)
  126. {
  127. m_MaxOnlineTime = limit;
  128. }
  129. void CSock::SetDNSWin(CWnd *pWnd)
  130. {
  131. m_DNSwin = pWnd;
  132. }
  133. BOOL CSock::IsOkToDelete(BOOL IgnoreSuspend)
  134. {
  135. return TRUE;
  136. }
  137. void CSock::InitiateDNSLookup()
  138. {
  139. CDNSLookup *pLookup =  new CDNSLookup();
  140. pLookup->Create(this);
  141. }
  142. void CSock::OnDNSLookup(int nErrorCode, CDNSLookup *pDNS)
  143. {
  144. int err;
  145. if (nErrorCode)
  146. {
  147. LogMsg(LOGF_DEBUG,"OnDNSLookup() failed. Error code %d", nErrorCode);
  148. }
  149. else
  150. {
  151. ASSERT(AfxIsValidString(((struct hostent *)&(pDNS->m_Buf))->h_name));
  152. m_DNSName = ((struct hostent *)&(pDNS->m_Buf))->h_name;
  153. }
  154. if (err = PrcSockExt(iOnVerifyIPAddress, nErrorCode, 0, (LPARAM)pDNS))
  155. {
  156. if (err == CFuncList::AbortError)
  157. CSocketException::Throw(this, "CSock::OnDNSLookup", -1, "Plugin said NO!");
  158. if (err == CFuncList::OkAllDone)
  159. return;
  160. }
  161. m_AsyncSelectMask |= (FD_READ | FD_WRITE);
  162. AsyncSelect(m_AsyncSelectMask);
  163. }
  164. void CSock::OnFileCompletion(int nErrorCode)
  165. {
  166. ;
  167. }
  168. // Called by listening sockets to delete all children before a service shuts down
  169. void CSock::KillAllChildren()
  170. {
  171. CLinkedListItem *Item = m_SocketList.First(), *CurrItem;
  172. while(Item)
  173. {
  174. CurrItem = Item;
  175. CSock *Soc = (CSock *)m_SocketList.Ptr(Item);
  176. Item = m_SocketList.Next(Item);
  177. ASSERT(AfxIsValidAddress(Soc,sizeof(CSock)));
  178. if (Soc->m_Father == this)
  179. {
  180. Soc->SayGoodbye();
  181. m_SocketList.DeleteItem(CurrItem);
  182. delete Soc;
  183. }
  184. }
  185. }
  186. // Override to say goodbye
  187. void CSock::SayGoodbye()
  188. {
  189. return;
  190. }
  191. CUserFsys *CSock::GetFsys()
  192. {
  193. return NULL;
  194. }
  195. // Get the local IP number
  196. BOOL CSock::GetHostIpNumber(CString& cIpName)
  197. {
  198. SOCKADDR_IN sockAddr;
  199. LPHOSTENT lphost;
  200. char LogicName[64];
  201. cIpName = "localhost";
  202. if (gethostname(LogicName,sizeof(LogicName) -1))
  203. return FALSE;
  204. memset(&sockAddr,0,sizeof(sockAddr));
  205. sockAddr.sin_family = AF_INET;
  206. sockAddr.sin_addr.s_addr = inet_addr(LogicName);
  207. if (sockAddr.sin_addr.s_addr == INADDR_NONE)
  208. {
  209. lphost = gethostbyname(LogicName);
  210. if (lphost != NULL)
  211. {
  212. sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  213. }
  214. else
  215. return FALSE;
  216. }
  217. cIpName = inet_ntoa(sockAddr.sin_addr);
  218. return TRUE;
  219. }
  220. // Elapsed time in seconds
  221. float CSock::GetLapTime()
  222. {
  223. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  224. return (float)m_StartTime.TimeDiff() / (float)1000;
  225. }
  226. // Bytes/Second
  227. float CSock::GetCPS()
  228. {
  229. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  230. return (float)(m_BytesSent + m_BytesReceived) / GetLapTime();
  231. }
  232. // Total kb/s for all sockets
  233. float CSock::GetTotalCPS()
  234. {
  235. CLinkedListItem *Item;
  236. CSock *pSock;
  237. float Rval = (float)0.0;
  238. for(Item = m_SocketList.First(); Item; Item = m_SocketList.Next(Item))
  239. {
  240. pSock = (CSock *)m_SocketList.Ptr(Item);
  241. ASSERT(AfxIsValidAddress(pSock, sizeof(CSock)));
  242. if ((pSock->m_hSocket != INVALID_SOCKET) && !pSock->m_Timer.TimeOut(3000))
  243. Rval += pSock->GetCPS();
  244. }
  245. return Rval;
  246. }
  247. CSock *CSock::GetFromID(DWORD ID)
  248. {
  249. CLinkedListItem *Item = m_SocketList.First();
  250. CSock *pSock;
  251. while(Item)
  252. {
  253. pSock = (CSock *)m_SocketList.Ptr(Item);
  254. Item = m_SocketList.Next(Item);
  255. if (pSock->m_SocketID == ID)
  256. return pSock;
  257. }
  258. return NULL;
  259. }
  260. static BOOL IsProcessingIdle;
  261. BOOL CSock::OnIdle( LONG lCount )
  262. {
  263. int Cnt;
  264. IsProcessingIdle = TRUE;
  265. while(Cnt = m_OverlappedCnt)
  266. {
  267. SleepEx(0, TRUE);
  268. if (Cnt == m_OverlappedCnt)
  269. break;
  270. }
  271. IsProcessingIdle = FALSE;
  272. CLinkedListItem *Item, *NextItem;
  273. CSock *pSock;
  274. for (Item = m_SocketList.First(); Item; Item = NextItem)
  275. {
  276. NextItem = m_SocketList.Next(Item);
  277. pSock = (CSock *)m_SocketList.Ptr(Item);
  278. pSock->PrcSockExt(CSock::iOnIdle, 0, lCount, 0);
  279. if (m_Housekeeping.TimeOut(5000))
  280. {
  281. // Check timeout on all sockets
  282. if (pSock->m_MaxIdleTime && pSock->m_State == HOLD)
  283. pSock->m_Timer.Reset(); // Avoid dumping held sockets
  284. if (pSock->m_MaxIdleTime && pSock->m_Timer.TimeOut(pSock->m_MaxIdleTime))
  285. {
  286. pSock->LogMsg(LOGF_INOUT,"Idle time of %d seconds expired.", pSock->m_MaxIdleTime / 1000);
  287. if (!pSock->OnHandleWinsockErr(SOCKERR_IDLETIME))
  288. delete pSock;
  289. }
  290. else if (pSock->m_MaxOnlineTime && pSock->m_Timer.TimeOut(pSock->m_MaxOnlineTime))
  291. {
  292. pSock->LogMsg(LOGF_INOUT,"Login time limit of %d minutes expired.", pSock->m_MaxOnlineTime / 60000);
  293. if (!pSock->OnHandleWinsockErr(SOCKERR_LOGINTIME))
  294. delete pSock;
  295. }
  296. // NOTE: Do _NOT_ access pSock now. It might be deleted!
  297. }
  298. }
  299. if (m_Housekeeping.TimeOut(5000))
  300. m_Housekeeping.Reset();
  301. return m_OverlappedCnt != 0;
  302. }
  303. void CSock::SetName(LPCSTR Name)
  304. {
  305. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  306. m_SocketName = Name;
  307. }
  308. void CSock::IncXferCnt(BOOL Add)
  309. {
  310. // Override to update server status
  311. }
  312. void CSock::SetLog(CLog *LogPtr)
  313. {
  314. m_Log = LogPtr;
  315. }
  316. void CSock::LogMsg(int flag, LPCSTR Format, ...)
  317. {
  318. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  319. if (!ShouldLog(m_Log, flag))
  320. return;
  321. {
  322. CString cBuf;
  323. ASSERT(AfxIsValidString(Format, FALSE));
  324. cBuf.Format("%s: %s", m_SocketName, Format);
  325. va_list argList;
  326. va_start(argList, Format);
  327. m_Log->LogMsgV(flag, cBuf, argList);
  328. va_end(argList);
  329. }
  330. }
  331. void CSock::LogLastError(int flag, int eval, LPCSTR msg)
  332. {
  333. //ASSERT(m_hSocket != INVALID_SOCKET);
  334. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  335. char *p = "";
  336. if (!eval)
  337. eval = GetLastError();
  338. switch(eval)
  339. {
  340. case WSAEFAULT: p = "WSAEFAULT. Argument to small or not in a valid part of the process address space."; break;
  341. case WSAEWOULDBLOCK: p = "WSAEWOULDBLOCK   The socket is marked as nonblocking and no connections are present to be accepted."; break;
  342. case WSANOTINITIALISED: p = "WSANOTINITIALISED   A successful AfxSocketInit must occur before using this API."; break;
  343. case WSAENETDOWN: p = "WSAENETDOWN   The Windows Sockets implementation detected that the network subsystem failed."; break;
  344. case WSAEADDRINUSE: p = "WSAEADDRINUSE   An attempt has been made to listen on an address in use."; break;
  345. case WSAEINPROGRESS: p = "WSAEINPROGRESS   A blocking Windows Sockets operation is in progress."; break;
  346. case WSAEINVAL: p = "WSAEINVAL   Generic error message. Check with Winsock manual pages."; break;
  347. case WSAEISCONN: p = "WSAEISCONN   The socket is already connected."; break;
  348. case WSAEMFILE: p = "WSAEMFILE   No more file descriptors are available."; break;
  349. case WSAENOBUFS: p = "WSAENOBUFS   No buffer space is available."; break;
  350. case WSAENOTSOCK: p = "WSAENOTSOCK   The descriptor is not a socket."; break;
  351. case WSAEOPNOTSUPP: p = "WSAEOPNOTSUPP   The referenced socket is not of a type that supports the Listen operation."; break;
  352. case WSAEAFNOSUPPORT: p= "WSAEAFNOSUPPORT   The specified address family is not supported."; break;
  353. case WSAEPROTOTYPE: p = "WSAEPROTOTYPE   The specified port is the wrong type for this socket."; break;
  354. case WSAENETRESET: p = "WSAENETRESET   Connection has timed out when SO_KEEPALIVE is set."; break;
  355. 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;
  356. case WSAENOTCONN: p = "WSAENOTCONN   Connection has been reset when SO_KEEPALIVE is set."; break;
  357. case WSAEPROTONOSUPPORT: p = "WSAEPROTONOSUPPORT   The specified port is not supported."; break;
  358. case WSAESOCKTNOSUPPORT: p = "WSAESOCKTNOSUPPORT   The specified socket type is not supported in this address family."; break;
  359. case WSAEHOSTDOWN: p = "WSAEHOSTDOWN"; break;
  360. case WSAEHOSTUNREACH: p = "WSAEHOSTUNREACH"; break;
  361. case WSAEADDRNOTAVAIL: p = "WSAEADDRNOTAVAIL"; break;
  362. case WSAESHUTDOWN: p = "WSAESHUTDOWN"; break;
  363. }
  364. LogMsg(flag,"%s - Socket error %d %s", msg, eval, p);
  365. }
  366. void CSock::OnAccept( int nErrorCode )
  367. {
  368. ASSERT(m_hSocket != INVALID_SOCKET);
  369. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  370. m_Timer.Reset();
  371. LogMsg(LOGF_WINSOCK,"OnAccept(%d)", nErrorCode);
  372. if (nErrorCode)
  373. CSocketException::Throw(this, "CSock::OnAccept()", nErrorCode, NULL);
  374. }
  375. // Called from derived class that know what dataclass we must
  376. // use.
  377. BOOL CSock::DoAccept(CSock *NewSocket )
  378. {
  379. ASSERT(m_hSocket != INVALID_SOCKET);
  380. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  381. UINT MyPort;
  382. CString cBuf;
  383. NewSocket->m_Type = m_Type;
  384. ASSERT(m_Type != LT_INVALID);
  385. if (!Accept(*NewSocket))
  386. {
  387. NewSocket->LogLastError(LOGF_WARNINGS,0,"CLSock::DoAccept(): Accept() failed.");
  388. return FALSE;
  389. }
  390. // Set IO flags
  391. if (!NewSocket->AsyncSelect(m_AsyncSelectMask))
  392. {
  393. NewSocket->LogLastError(LOGF_WARNINGS,0,"CLSock::DoAccept(): AsyncSelect() failed.");
  394. return FALSE;
  395. }
  396. if (!NewSocket->GetSockName(NewSocket->m_HostName,MyPort))
  397. {
  398. NewSocket->LogLastError(LOGF_WARNINGS,0, "CLSock::DoAccept: GetSockName() failed.");
  399. }
  400. else
  401. {
  402. LogMsg(LOGF_DEBUG,"Connected to Local IP: %s", (LPCSTR)NewSocket->m_HostName);
  403. }
  404. NewSocket->GetPeerName(NewSocket->m_PeerName,MyPort);
  405. NewSocket->m_DNSName = NewSocket->m_PeerName;
  406. // OnConnect is never called by the framework on accepted sockets.
  407. // We use OnAccept() for one-time class member initializtion, so we
  408. // call it here.
  409. NewSocket->_OnConnect(0);
  410. return TRUE;
  411. }
  412. void CSock::OnClose( int nErrorCode )
  413. {
  414. ASSERT(m_hSocket != INVALID_SOCKET);
  415. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  416. AsyncSelect(0); // We don't want more messages...
  417. m_Timer.Reset();
  418. LogMsg(LOGF_WINSOCK,"OnClose(%d)", nErrorCode);
  419. if (nErrorCode)
  420. CSocketException::Throw(this, "CSock::OnClose()", nErrorCode, NULL);
  421. if (!m_SuspendOnClose)
  422. Close();
  423. }
  424. BOOL CSock::OnHandleWinsockErr(int nErrorCode )
  425. {
  426. LogMsg(LOGF_DEBUG,"CSock::OnHandleWinsockErr(%d)", "No default handler for this error.", nErrorCode);
  427. delete this;
  428. return TRUE; // Deleted
  429. }
  430. void CSock::_OnConnect( int nErrorCode )
  431. {
  432. ASSERT(FALSE); // Must be overridden
  433. }
  434. void CSock::OnConnect( int nErrorCode )
  435. {
  436. PrcSockExt(iOnConnect, nErrorCode, NULL, NULL);
  437. ASSERT(m_hSocket != INVALID_SOCKET);
  438. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  439. m_Timer.Reset();
  440. ASSERT(m_IsConnected == FALSE);
  441. m_AsyncSelectMask &= ~FD_CONNECT;
  442. AsyncSelect(m_AsyncSelectMask);
  443. LogMsg(LOGF_WINSOCK,"OnConnect(%d)", nErrorCode);
  444. if (nErrorCode)
  445. CSocketException::Throw(this, "CSock::OnConnect",nErrorCode,NULL);
  446. m_ConnectTime.Reset();
  447. m_IsConnected = TRUE;
  448. BOOL True = TRUE;
  449. if (!SetSockOpt(SO_KEEPALIVE,(LPVOID)&True,sizeof(True)))
  450. LogLastError(LOGF_DEBUG,0,"OnConnect() - Failed to SetSockOpt(SO_KEEPALIVE).");
  451. }
  452. void CSock::OnOutOfBandData( int nErrorCode )
  453. {
  454. ASSERT(m_hSocket != INVALID_SOCKET);
  455. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  456. m_Timer.Reset();
  457. LogMsg(LOGF_WINSOCK,"OnOutOfBandData(%d)", nErrorCode);
  458. if (nErrorCode)
  459. CSocketException::Throw(this, "CSock::OnOutOfBandData",nErrorCode,NULL);
  460. }
  461. void CSock::OnReceive( int nErrorCode )
  462. {
  463. ASSERT(m_hSocket != INVALID_SOCKET);
  464. CAsyncSocket::OnReceive(nErrorCode);
  465. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  466. PrcSockExt(iOnReceive, nErrorCode, 0, 0);
  467. // Turn off READ notifications (MFC BUG workaround)
  468. AsyncSelect(m_AsyncSelectMask & ~FD_READ);
  469. m_Timer.Reset();
  470. m_ClearToReceive = TRUE;
  471. LogMsg(LOGF_WINSOCK,"OnReceive(%d)", nErrorCode);
  472. if (nErrorCode)
  473. CSocketException::Throw(this, "CSock::OnReceive",nErrorCode,NULL);
  474. }
  475. void CSock::OnSend( int nErrorCode )
  476. {
  477. ASSERT(m_hSocket != INVALID_SOCKET);
  478. CAsyncSocket::OnSend(nErrorCode);
  479. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  480. PrcSockExt(iOnSend, nErrorCode, 0, 0);
  481. m_Timer.Reset();
  482. LogMsg(LOGF_WINSOCK,"OnSend(%d)", nErrorCode);
  483. m_ClearToSend = TRUE;
  484. if (nErrorCode)
  485. CSocketException::Throw(this, "CSock::OnSend",nErrorCode,NULL);
  486. }
  487. BOOL CSock::Accept( CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr, int* lpSockAddrLen)
  488. {
  489. ASSERT(m_hSocket != INVALID_SOCKET);
  490. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  491. m_Timer.Reset();
  492. LogMsg(LOGF_WINSOCK,"Accept()");
  493. return CAsyncSocket::Accept(rConnectedSocket, lpSockAddr, lpSockAddrLen);
  494. }
  495. void CSock::Close( )
  496. {
  497. ASSERT(m_hSocket != INVALID_SOCKET);
  498. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  499. LogMsg(LOGF_WINSOCK,"Close()");
  500. m_IsConnected = FALSE;
  501. m_ClearToReceive = FALSE;
  502. m_ClearToSend = FALSE;
  503. if (m_hSocket != INVALID_SOCKET)
  504. {
  505. AsyncSelect(0);
  506. CAsyncSocket::Close();
  507. }
  508. }
  509. // We return 0 on the WSAEWOULDBLOCK event
  510. // We throw an exception on EOF.
  511. int CSock::Receive( void* lpBuf, int nBufLen, int nFlags)
  512. {
  513. ASSERT(m_hSocket != INVALID_SOCKET);
  514. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  515. int Rval = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags);
  516. int err;
  517. if (Rval == SOCKET_ERROR)
  518. {
  519. if ((err = GetLastError()) == WSAEWOULDBLOCK)
  520. {
  521. LogMsg(LOGF_WINSOCK,"Receive() (Waiting for data)");
  522. m_ClearToReceive = FALSE;
  523. // Turn on read notification (MFC bug workaround)
  524. AsyncSelect(m_AsyncSelectMask);
  525. Rval = 0;
  526. }
  527. else
  528. CSocketException::Throw(this, "CSock::Receive()", err, NULL);
  529. }
  530. else if (Rval == 0)
  531. CSocketException::Throw(this, "CSock::Receive()", 0, "EOF. 0 bytes read.");
  532. LogMsg(LOGF_WINSOCK,"Receive() (%d bytes)", Rval);
  533. m_BytesReceived += Rval;
  534. m_LastReceive.Reset();
  535. m_Timer.Reset();
  536. if (m_StartTime.m_TimerVal == m_ConnectTime.m_TimerVal)
  537. m_StartTime.Reset(); // Start of transmission timer
  538. return Rval;
  539. }
  540. // Note: We call OnClose() to destroy the object on errors and
  541. // termination.
  542. // We return 0 on the WSAEWOULDBLOCK event
  543. // We return -1 on fatal error, after the object is deleted.
  544. int CSock::Send( const void* lpBuf, int nBufLen, int nFlags)
  545. {
  546. ASSERT(m_hSocket != INVALID_SOCKET);
  547. ASSERT(AfxIsValidAddress(this,sizeof(CSock)));
  548. if (nBufLen <= 0)
  549. return 0;
  550. int Rval = CAsyncSocket::Send(lpBuf, nBufLen, nFlags);
  551. int err;
  552. if (Rval == SOCKET_ERROR)
  553. {
  554. if ((err = GetLastError()) == WSAEWOULDBLOCK)
  555. {
  556. LogMsg(LOGF_WINSOCK,"Send() (Waiting for data)");
  557. m_ClearToSend = FALSE;
  558. Rval = 0;
  559. }
  560. else
  561. {
  562. CSocketException::Throw(this, "CSock::Send()", err, NULL, 
  563. err, GetLastErrorText(err));
  564. }
  565. }
  566. else if (Rval == 0)
  567. {
  568. LogMsg(LOGF_WINSOCK,"*** Send(%d) (%d bytes sent)", nBufLen, Rval);
  569. }
  570. else
  571. {
  572. LogMsg(LOGF_WINSOCK,"Send(%d) (%d bytes sent)", nBufLen, Rval);
  573. m_BytesSent += Rval;
  574. }
  575. m_LastSend.Reset();
  576. m_Timer.Reset();
  577. if (m_StartTime.m_TimerVal == m_ConnectTime.m_TimerVal)
  578. m_StartTime.Reset(); // Start of transmission timer
  579. return Rval;
  580. }
  581. ///////////////////////////////////////////////////////////////////////////////////////
  582. // CBufferSock
  583. IMPLEMENT_DYNAMIC(CBufferSock, CSock);
  584. CBufferSock::CBufferSock()
  585. {
  586. m_BufferSize = m_MaxBufferSize = BUFFERSOCK_DEFUALT_BUFFER_SIZE;
  587. m_MaxSendLen = m_BufferSize;
  588. m_OutBuf = new char[m_BufferSize];
  589. m_BufferUsed = 0;
  590. }
  591. CBufferSock::~CBufferSock()
  592. {
  593. if (m_OutBuf)
  594. delete m_OutBuf;
  595. }
  596. void CBufferSock::TrashOutputBuffer()
  597. {
  598. m_BufferUsed = 0;
  599. }
  600. BOOL CBufferSock::DoOverlapped()
  601. {
  602. return TRUE; // Currently no default processing
  603. }
  604. int CBufferSock::Send( const void* lpBuf, int nBufLen, int nFlags)
  605. {
  606. // All data must be sent with SendBuffer!
  607. ASSERT(FALSE);
  608. return -1;
  609. }
  610. void CBufferSock::OnSend( int nErrorCode )
  611. {
  612. CSock::OnSend(nErrorCode);
  613. if (nErrorCode)
  614. return;
  615. DoSend();
  616. }
  617. // Send if we have queued data!
  618. BOOL CBufferSock::DoSend()
  619. {
  620. int BytesSent;
  621. ASSERT(m_ClearToSend);
  622. // Send as much as possible
  623. while(m_BufferUsed && m_ClearToSend)
  624. {
  625. BytesSent = CSock::Send(m_OutBuf, min((int)m_BufferUsed,m_MaxSendLen));
  626. m_BufferUsed -= BytesSent;
  627. ASSERT(m_BufferUsed >= 0);
  628. if (m_BufferUsed)
  629. memmove(m_OutBuf,m_OutBuf + BytesSent, m_BufferUsed);
  630. }
  631. return TRUE;
  632. }
  633. // Prepere to send a databuffer
  634. // Returns -1 on fatal error after object is deleted.
  635. long CBufferSock::SendBuffer(LPCSTR Buffer, DWORD Size)
  636. {
  637. int BytesSent = 0;
  638. int BytesQueued;
  639. long BytesToQueue;
  640. if (BufferSock_BufferFree() < Size)
  641. {
  642. if (m_MaxBufferSize < (m_BufferUsed + Size))
  643. m_MaxBufferSize = m_BufferUsed + Size + 16;
  644. if (BufferSock_BufferFree() < m_MaxBufferSize)
  645. {
  646. LogMsg(LOGF_DEBUG,
  647. "CBufferSock::SendBuffer(): Reallocating buffer to %d bytes", m_MaxBufferSize);
  648. // Allocate more space
  649. LPSTR p = new char[m_BufferSize = m_MaxBufferSize];
  650. memcpy(p,m_OutBuf,m_BufferUsed);
  651. delete m_OutBuf;
  652. m_OutBuf = p;
  653. }
  654. if (BufferSock_BufferFree() == 0)
  655. return 0;
  656. }
  657. if (!m_BufferUsed && m_ClearToSend)
  658. {
  659. // Optimize - just send what we can at once
  660. BytesSent = CSock::Send(Buffer, min((int)Size,m_MaxSendLen));
  661. }
  662. if ((BytesToQueue = (Size - BytesSent)) == 0)
  663. return BytesSent; // Nothing left to queue...
  664. ASSERT(BytesToQueue > 0);
  665. #ifdef _DEBUG
  666. int FreeBytes = BufferSock_BufferFree();
  667. int NeededBytes = BytesToQueue + m_BufferUsed;
  668. int UsedBytes = m_BufferUsed;
  669. int BufSize = m_BufferSize;
  670. ASSERT(FreeBytes >= BytesToQueue);
  671. #endif // _DEBUG
  672. memcpy(m_OutBuf,Buffer + BytesSent, 
  673. BytesQueued = BytesToQueue);
  674. m_BufferUsed += BytesQueued;
  675. return BytesQueued + BytesSent;
  676. }
  677. ///////////////////////////////////////////////////////////////////////////////////////
  678. // CTextSock
  679. IMPLEMENT_DYNAMIC(CTextSock, CBufferSock);
  680. int CTextSock::m_LoginCounter = 0;
  681. HANDLE CTextSock::m_SvrEvents = INVALID_HANDLE_VALUE;
  682. CLinkedList CTextSock::m_UserConnections;
  683. CTextSock::CTextSock()
  684. {
  685. m_InsertOffset = 0;
  686. m_Virgin = TRUE;
  687. m_LocalEcho = FALSE;
  688. m_HandleBackspace = FALSE;
  689. m_SuspendExpandMacros = TRUE;
  690. m_BufferSize = TEXTSOCK_DEFUALT_BUFFER_SIZE - 4; // Make space for trailing 0
  691. m_BufferUsed = 0;
  692. m_InBuf = new char[TEXTSOCK_DEFUALT_BUFFER_SIZE];
  693. m_SavedIndex = 0;
  694. m_HaveIAC = FALSE;
  695. m_HaveCR = FALSE;
  696. m_User = 0;
  697. m_RootDir.Empty();
  698. m_HomeDir.Empty();
  699. m_CWD.Empty();
  700. m_Events = new CDaemonEvent(this, 1024);
  701. m_LoginNum = ++m_LoginCounter;
  702. m_IsLoggedIn = FALSE;
  703. m_LoginName = "Prelogin";
  704. m_StateSave = -1;
  705. m_SuspendEvents = FALSE;
  706. m_FileHandle = INVALID_HANDLE_VALUE;
  707. m_UserConnections.AddLast((LPVOID)this);
  708. PrcExt(CAPIHandler::OnNewTextSocket,0,0,(LPARAM)this);
  709. }
  710. CTextSock::~CTextSock()
  711. {
  712. NotifyLogin(ENL_DEL);
  713. PrcExt(CAPIHandler::OnLogout,0,0,(LPARAM)this);
  714. if (m_IsLoggedIn)
  715. LogMsg(LOGF_INOUT,"Logged out");
  716. if (m_InBuf)
  717. delete m_InBuf;
  718. if (m_Events)
  719. delete m_Events;
  720. m_UserConnections.DeletePtr((LPVOID)this);
  721. }
  722. BOOL CTextSock::InitSvrEvents()
  723. {
  724. if (m_SvrEvents != INVALID_HANDLE_VALUE)
  725. return TRUE;
  726. if ((m_SvrEvents = CDaemonEvent::DsRegister(
  727. EVT_CONN, NULL, WhoSendAll)) == INVALID_HANDLE_VALUE)
  728. {
  729. m_Log->LogMsg(LOGF_ERROR,"InitSvrEvents() - Unable to register LOGIN event.");
  730. return FALSE;
  731. }
  732. return TRUE;
  733. }
  734. // Send a file over the control connection
  735. BOOL CTextSock::SendFile(LPCSTR Path, LPCSTR Name)
  736. {
  737. char FullPath[MAX_PATH];
  738. LPTSTR Unused;
  739. DWORD Length;
  740. if (!SearchPath(Path, Name, NULL, MAX_PATH, FullPath, &Unused))
  741. {
  742. LogMsg(LOGF_WARNINGS,"Failed to locate file '%s' (%s)", Name, GetLastErrorText());
  743. return FALSE;
  744. }
  745. if (m_FileHandle != INVALID_HANDLE_VALUE)
  746. {
  747. LogMsg(LOGF_WARNINGS,"CTextSock::SendFile(%s) - File transfer already in progress.",
  748. Name);
  749. return FALSE;
  750. }
  751. if ((m_FileHandle = ::CreateFile(
  752. FullPath,
  753. GENERIC_READ,
  754. FILE_SHARE_READ,
  755. NULL,
  756. OPEN_EXISTING,
  757. FILE_FLAG_SEQUENTIAL_SCAN,
  758. NULL)) == INVALID_HANDLE_VALUE)
  759. {
  760. LogMsg(LOGF_WARNINGS,"Failed to open file '%s' (%s)", FullPath, GetLastErrorText());
  761. return FALSE;
  762. }
  763. m_SuspendEvents = TRUE;
  764. Length = GetFileSize(m_FileHandle, NULL);
  765. LogMsg(LOGF_FILEACC,"CTextSock::SendFile(%s) Sending file over the control connection...",
  766. FullPath);
  767. SendMsg(280,"Sending file "%s" over the control connection. (%d bytes)", 
  768. FullPath, Length);
  769. while(Length)
  770. {
  771. char buf[1024];
  772. DWORD BytesRead;
  773. ReadFile(m_FileHandle, buf, 1024, &BytesRead, NULL);
  774. Length -= BytesRead;
  775. SendBuffer(buf, BytesRead);
  776. if (Length && !BytesRead)
  777. CSocketException::Throw(this, "CTextSock::SendFile()", -1, "ReadFile() failed.");
  778. }
  779. CloseHandle(m_FileHandle);
  780. m_FileHandle = INVALID_HANDLE_VALUE;
  781. m_SuspendEvents = FALSE;
  782. DoSend();
  783. return TRUE;
  784. }
  785. BOOL CTextSock::TerminateSvrEvents()
  786. {
  787. if (m_SvrEvents)
  788. {
  789. CDaemonEvent::DsClose(m_SvrEvents);
  790. m_SvrEvents = INVALID_HANDLE_VALUE;
  791. return TRUE;
  792. }
  793. return FALSE;
  794. }
  795. void CTextSock::NotifyLogin(DWORD Flags, LPCSTR InfoTxt, CDaemonEvent *pCliEv)
  796. {
  797. if (!this)
  798. return;
  799. CString cMsg;
  800. if (InfoTxt)
  801. m_Info = InfoTxt;
  802. cMsg.Format("%d %d, %u %d 1%s1 1%s1 1%s1", 
  803. m_LoginNum, m_User, Flags, m_State, m_LoginName, m_Info, m_DNSName);
  804. if (m_SvrEvents != INVALID_HANDLE_VALUE)
  805. {
  806. if (pCliEv)
  807. pCliEv->Event(m_SvrEvents, cMsg);
  808. else 
  809. CDaemonEvent::DsEvent(m_SvrEvents, cMsg, TRUE);
  810. }
  811. m_StateSave = m_State;
  812. }
  813. void CTextSock::WhoSendAll(LPVOID pOrigin, CDaemonEvent *pCliEv)
  814. {
  815. CString cBuf;
  816. CLinkedListItem *Item = m_UserConnections.First();
  817. while(Item)
  818. {
  819. CTextSock *pInfo = (CTextSock *)m_UserConnections.Ptr(Item);
  820. Item = m_UserConnections.Next(Item);
  821. pInfo->NotifyLogin(ENL_NEW, NULL, pCliEv);
  822. }
  823. }
  824. // Override to say goodbye
  825. void CTextSock::SayGoodbye()
  826. {
  827. SendMsg(421, "Service is shutting down. Goodbye.");
  828. return;
  829. }
  830. BOOL CTextSock::OnCommand(LPCSTR Text)
  831. {
  832. if (m_State == GOTNAME)
  833. LogMsg(LOGF_DEBUG,"CTextSock::OnCommand(Shhh: Dont tell anyone about the password!)");
  834. else
  835. LogMsg(LOGF_DEBUG,"CTextSock::OnCommand(%s)", Text);
  836. return TRUE;
  837. }
  838. void CTextSock::OnClose(int nErrorCode)
  839. {
  840. CSock::OnClose(nErrorCode);
  841. CSocketException::Throw(this, "CTextSock::OnClose()", nErrorCode, "Connection is closed.");
  842. }
  843. void CTextSock::OnConnect( int nErrorCode )
  844. {
  845. BOOL bVal;
  846. CSock::OnConnect(nErrorCode);
  847. if (nErrorCode)
  848. return;
  849. bVal = TRUE; SetSockOpt(SO_KEEPALIVE,&bVal,sizeof(bVal));
  850. bVal = TRUE; SetSockOpt(TCP_NODELAY,&bVal,sizeof(bVal),IPPROTO_TCP);
  851. bVal = TRUE; SetSockOpt(SO_OOBINLINE,&bVal,sizeof(bVal));
  852. if ((m_Type == LT_TELNET) || (m_Type == LT_REMOTE))
  853. {
  854. LogMsg(LOGF_DEBUG,"Turning local echo on");
  855. m_LocalEcho = TRUE;
  856. m_HandleBackspace = TRUE;
  857. }
  858. SetName("prelogin");
  859. NotifyLogin(ENL_NEW, "Login");
  860. // Perform reverse DNS lookup before doing any communications.
  861. m_AsyncSelectMask &= ~FD_READ | FD_WRITE;
  862. m_ClearToSend = FALSE;
  863. m_ClearToReceive = FALSE;
  864. AsyncSelect(m_AsyncSelectMask);
  865. InitiateDNSLookup();
  866. }
  867. void CTextSock::SetName(LPCSTR Name)
  868. {
  869. CString cBuf;
  870. cBuf.Format("%05d %s %s %s", 
  871. m_LoginNum,
  872. SafeStringIndex(CSock::DaemonTypes, m_Type, LT_INVALID),
  873. m_PeerName,
  874. MapStringValid(Name));
  875. CSock::SetName(cBuf);
  876. }
  877. // Try to get a line of text terminated with CRLF. 
  878. // Telnet codes are passed to ProcessTelnetNegotiation()
  879. // If this is the first time the function is called we call Virgin()
  880. // If Virgin() dont turn off the m_Virgin flag we continue to call it
  881. void CTextSock::OnReceive( int nErrorCode )
  882. {
  883. int BytesReceived = 0;
  884. int BytesToGo;
  885. unsigned char *p;
  886. char buf[2];
  887. buf[1] = 0;
  888. CSock::OnReceive(nErrorCode);
  889. ASSERT(nErrorCode == 0);
  890. if (m_Virgin)
  891. Virgin();
  892. ASSERT(m_ClearToReceive);
  893. while(m_ClearToReceive)
  894. {
  895. // Fill up buffer
  896. while(BufferText_BufferFree() 
  897. && (BytesReceived = Receive(m_InBuf + m_BufferUsed, BufferText_BufferFree())) > 0)
  898. {
  899. m_BufferUsed += BytesReceived;
  900. }
  901. ASSERT(BytesReceived >= 0);
  902. // Process what we've got. Most likely there is nothing more to receive,
  903. // and we have one or more complete commands.
  904. // But the buffer can also be full..
  905. ASSERT(m_BufferUsed >= 0);
  906. BytesToGo = m_BufferUsed - m_SavedIndex;
  907. p = (unsigned char *)(m_InBuf + m_SavedIndex);
  908. while(BytesToGo--)
  909. {
  910. ASSERT(m_BufferUsed > 0);
  911. ASSERT(BytesToGo >= 0);
  912. if (m_HaveIAC)
  913. {
  914. if (*p == IAC)
  915. {
  916. // Just keep one of them and continue
  917. memmove(p-1,p,BytesToGo);
  918. --m_BufferUsed;
  919. }
  920. else if (++m_HaveIAC == 3)
  921. {
  922. ProcessTelnetNegotiation(p[-1],p[0]);
  923. m_HaveIAC = 0;
  924. // Remove the 3 bytes
  925. memmove(p - 2, p + 1, BytesToGo);
  926. m_BufferUsed -= 3;
  927. p -= 3;
  928. }
  929. p++;
  930. continue;
  931. }
  932. if (m_HaveCR)
  933. {
  934. if (*p == 'n')
  935. {
  936. // We have a valid line :-)
  937. if (m_LocalEcho)
  938. {
  939. // Special case - we can't echo this below because of the IAC parsing below
  940. if (Send("n") < 0)
  941. CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 1", GetLastError(), NULL);
  942. }
  943. *p = 0;
  944. OnCommand(m_InBuf);
  945. memmove(m_InBuf, p, BytesToGo);
  946. m_BufferUsed -= ((LPSTR)p - m_InBuf) +1;
  947. p = (unsigned char *)m_InBuf;
  948. continue;
  949. }
  950. }
  951. if (*p == IAC)
  952. {
  953. m_HaveIAC = 1;
  954. ++p;
  955. continue;
  956. }
  957. if (m_LocalEcho)
  958. {
  959. buf[0] = (m_LocalEcho == 1) || (*p == 'r')
  960. ? *p : (char)m_LocalEcho;
  961. if (Send(buf) < 0)
  962. CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 2", GetLastError(), NULL);
  963. }
  964. switch(*p)
  965. {
  966. case 'r':
  967. m_HaveCR = TRUE;
  968. memmove(p, p+1, BytesToGo);
  969. --m_BufferUsed;
  970. continue;
  971. case 'b':
  972. if (m_HandleBackspace)
  973. {
  974. if (m_LocalEcho)
  975. {
  976. if (Send(" b") < 0)
  977. CSocketException::Throw(this, "CTextSock::OnReceive() - Send() 3", GetLastError(), NULL);
  978. }
  979. goto skip_ch;
  980. }
  981. default:
  982. if (*p < 32) // Ignore control characters
  983. {
  984. // Garbage. Trash the character.
  985. skip_ch:
  986. memmove(p, p+1, BytesToGo);
  987. --m_BufferUsed;
  988. }
  989. else
  990. ++p;
  991. }
  992. m_HaveCR = FALSE;
  993. }
  994. } // while m_ClearToReceive
  995. m_SavedIndex = m_BufferUsed;
  996. ASSERT(m_BufferUsed >= 0);
  997. ASSERT(BytesToGo == -1);
  998. if (!BufferText_BufferFree())
  999. {
  1000. LogMsg(LOGF_WARNINGS,"CTextSock::OnReceive(): Input buffer overflow (line loo long). Trashing buffer.");
  1001. m_BufferUsed = 0;
  1002. }
  1003. if (m_StateSave != m_State)
  1004. NotifyLogin(ENL_STATE);
  1005. }
  1006. void CTextSock::Virgin()
  1007. {
  1008. m_Virgin = FALSE;
  1009. }
  1010. // Return TRUE if everything is all right...
  1011. BOOL CTextSock::ProcessTelnetNegotiation(int ch1, int ch2)
  1012. {
  1013. // Simple I WILL NOT! Telnet negitiation
  1014. ch1 &= 0377;
  1015. char buf[8];
  1016. switch (ch1)
  1017. {
  1018. case WILL:
  1019. case WONT:
  1020. sprintf(buf,"%c%c%c", IAC, DONT, 0377&ch2);
  1021. if (Send(buf) < 0)
  1022. CSocketException::Throw(this, 
  1023. "CTextSock::ProcessTelnetNegotiation() - Send() 1", GetLastError(), NULL);
  1024. break;
  1025. case DO:
  1026. if (ch2 == TELOPT_ECHO)
  1027. {
  1028. m_LocalEcho = 1;
  1029. LogMsg(LOGF_DEBUG,"Turning local echo on");
  1030. sprintf(buf,"%c%c%c", IAC, WILL, 0377&ch2);
  1031. if (Send(buf) < 0)
  1032. CSocketException::Throw(this, 
  1033. "CTextSock::ProcessTelnetNegotiation() - Send() 2", GetLastError(), NULL);
  1034. break;
  1035. }
  1036. case DONT:
  1037. if (ch2 == TELOPT_ECHO)
  1038. {
  1039. m_LocalEcho = 0;
  1040. LogMsg(LOGF_DEBUG,"Turning local echo off");
  1041. }
  1042. sprintf(buf,"%c%c%c", IAC, WONT, 0377&ch2);
  1043. if (Send(buf) < 0)
  1044. CSocketException::Throw(this, 
  1045. "CTextSock::ProcessTelnetNegotiation() - Send() 3", GetLastError(), NULL);
  1046. break;
  1047. }
  1048. return TRUE;
  1049. }
  1050. // Send an unformatted text string
  1051. BOOL CTextSock::Send(LPCSTR Text)
  1052. {
  1053. return SendBuffer(Text, strlen(Text)) >= 0;
  1054. }
  1055. // Check the error and (eventually) say goodbye
  1056. // This implementation output FTP server codes. Override to
  1057. // handle incompatible server types
  1058. BOOL CTextSock::OnHandleWinsockErr(int nErrorCode )
  1059. {
  1060. switch(nErrorCode)
  1061. {
  1062. case SOCKERR_IDLETIME:
  1063. SendMsg(421, "Idle time of %d seconds expired. Goodbye.", m_MaxIdleTime / 1000);
  1064. break;
  1065. case SOCKERR_LOGINTIME:
  1066. SendMsg(421, "Login time limit of %d minutes expired. Goodbye.", m_MaxIdleTime / 60000);
  1067. break;
  1068. }
  1069. return CSock::OnHandleWinsockErr(nErrorCode);
  1070. }
  1071. BOOL CTextSock::DoSend()
  1072. {
  1073. BOOL Rval;
  1074. TRY
  1075. {
  1076. Rval = m_Events->Process();
  1077. if (Rval)
  1078. Rval = CBufferSock::DoSend();
  1079. }
  1080. CATCH(CUserException, e)
  1081. {
  1082. CSocketException::Throw(this, "CTextSock::DoSend()", -1, "m_Events->Process() failed.");
  1083. }
  1084. END_CATCH
  1085. return Rval;
  1086. }
  1087. BOOL CTextSock::SendMsg(int Rcode, LPCSTR Format, ...)
  1088. {
  1089. if (!this)
  1090. return TRUE; // Fake OK.
  1091. CWarString cBuf;
  1092. ASSERT(AfxIsValidString(Format, FALSE));
  1093. va_list argList;
  1094. va_start(argList, Format);
  1095. cBuf.FormatVaList(Format,argList);
  1096. va_end(argList);
  1097. return SendCtrlMsg(Rcode, cBuf);
  1098. }
  1099. // Send one or more lines with standard Internet result codes.
  1100. // InsertPendingText() will call SendCtrlMsg recursively if there is
  1101. // data to insert before the Text message.
  1102. // ExpandMacros() is used to expand macros prior to sending the buffer
  1103. BOOL CTextSock::SendCtrlMsg(int Rcode, LPCSTR Text, BOOL More, BOOL CrLf)
  1104. {
  1105. LPCSTR From;
  1106. LPSTR To;
  1107. int Ofset, LineLength, err;
  1108. SNDCTLMSG cmsg;
  1109. cmsg.Rcode = Rcode;
  1110. cmsg.Text = Text;
  1111. cmsg.More = More;
  1112. cmsg.CrLf = CrLf;
  1113. if (err = PrcSockExt(iSendCtrlMsg, 0, 0, (LPARAM)&cmsg))
  1114. {
  1115. if (err == CFuncList::OkAllDone)
  1116. return DoSend();
  1117. else
  1118. return TRUE;
  1119. }
  1120. m_LastRcode = Rcode;
  1121. #ifdef _DEBUG
  1122. // Get a pointer to the variable for the debugger...
  1123. DWORD *DBm_BufferUsed = (DWORD *)&(CBufferSock::m_BufferUsed);
  1124. #endif
  1125. InsertPendingText();
  1126. // We manipulate the CBufferSock output buffers directly to save some memory and
  1127. // fragmentation. 
  1128. for(To = &m_OutBuf[CBufferSock::m_BufferUsed] + m_InsertOffset, From = Text;;)
  1129. {
  1130. if (!m_SuspendExpandMacros && (*From == '['))
  1131. {
  1132. // Parse out the macro
  1133. CString Macro("");
  1134. LPCSTR p = From;
  1135. while(*(++p) && (*p != ']'))
  1136. Macro += *p;
  1137. if (ExpandMacro(&To, Macro, &m_OutBuf[CBufferSock::m_BufferSize - 127] - To ))
  1138. {
  1139. From += (Macro.GetLength() + 2);
  1140. //To = &m_OutBuf[CBufferSock::m_BufferUsed];
  1141. continue;
  1142. }
  1143. }
  1144. if (To >= &m_OutBuf[CBufferSock::m_BufferSize - 16])
  1145. {
  1146. // Realloc
  1147. LPSTR p = m_OutBuf;
  1148. int Buflen = To - p;
  1149. m_OutBuf = new char[(CBufferSock::m_BufferSize += BUFFERSOCK_DEFUALT_BUFFER_SIZE)];
  1150. memcpy(m_OutBuf, p, Buflen);
  1151. delete p;
  1152. To = m_OutBuf + Buflen;
  1153. }
  1154. if (*From == 'r')
  1155. {
  1156. ++From;
  1157. continue;
  1158. }
  1159. if (!*From || (*From == 'n'))
  1160. {
  1161. // Send the line
  1162. //Ofset = (More || *From) ? 5 : 4;
  1163. Ofset = 4;
  1164. LineLength = To - &m_OutBuf[CBufferSock::m_BufferUsed];
  1165. //if (Rcode)
  1166. if (Rcode && (!More || (*From == 'n')))
  1167. {
  1168. // Make space for header
  1169. memmove(&m_OutBuf[CBufferSock::m_BufferUsed + Ofset], 
  1170. &m_OutBuf[CBufferSock::m_BufferUsed], 
  1171. LineLength);
  1172. // Insert header 123[-]<SP>
  1173. itoa(Rcode, &m_OutBuf[CBufferSock::m_BufferUsed], 10);
  1174. m_OutBuf[CBufferSock::m_BufferUsed + Ofset - 1] = ' ';
  1175. if (More || *From)
  1176. m_OutBuf[CBufferSock::m_BufferUsed + 3] = '-';
  1177. }
  1178. else
  1179. Ofset = 0;
  1180. // Adjust buffer length counter
  1181. CBufferSock::m_BufferUsed += Ofset + LineLength;
  1182. if ((!More && CrLf) || (*From == 'n'))
  1183. {
  1184. // Insert trailing CRLF
  1185. m_OutBuf[CBufferSock::m_BufferUsed++] = 'r';
  1186. m_OutBuf[CBufferSock::m_BufferUsed++] = 'n';
  1187. }
  1188. m_OutBuf[CBufferSock::m_BufferUsed] = 0; // Not needed, but OK in the debugger :-)
  1189. // Prepere To for the next line.
  1190. To = &m_OutBuf[CBufferSock::m_BufferUsed];
  1191. if (!*From)
  1192. break;
  1193. ++From;
  1194. }
  1195. else
  1196. {
  1197. *To++ = *From++;
  1198. //CBufferSock::m_BufferUsed++;
  1199. }
  1200. }
  1201. return DoSend();
  1202. }
  1203. void CTextSock::InsertPendingText()
  1204. {
  1205. }
  1206. enum // Macro Table 
  1207. {
  1208. MT_USER, MT_ORIGIN, MT_ULCNT, MT_DLCNT, MT_ULRSTR, MT_DLRAT, MT_ULRAT, 
  1209. MT_CREDIT, MT_CTYPE, MT_ULCNTR,
  1210. MT_IDLE, MT_UQRESTR, MT_PRGNAM, MT_PRGVER, MT_PRGCPYR, MT_SYSNAME, 
  1211. MT_OSNAME, MT_EMAIL, MT_FRESTR,
  1212. MT_CONLINE, MT_CAONLINE,
  1213. MT_DNSNAME, MT_LOCALIP, MT_OPONLINE
  1214. };
  1215. MACROTABLE BaseMacros[] = 
  1216. {
  1217. {"user", MT_USER, "Username of the current user."},
  1218. {"origin", MT_ORIGIN, "IP address of the current user."},
  1219. {"ulcount", MT_ULCNT, "Upload counter of the current user."},
  1220. {"dlcount", MT_DLCNT, "Download counter of the current user"},
  1221. {"dlratio", MT_DLRAT, "Download ratio (files to get for each n upload)."},
  1222. {"ulratio", MT_ULRAT, "Upload ratio (files to upload for each n get)."},
  1223. {"credit", MT_CREDIT, "Credit - bytes/files available for download."},
  1224. {"ulctype", MT_CTYPE, "Up/Download ratio type - file(s) or Kb."},
  1225. {"udrestrictions", MT_ULRSTR, "Are Upload/Download restrictions enabled?"},
  1226. {"ulcounttrash", MT_ULCNTR, "Will the upload counter be reset at logout?"},
  1227. {"idletime", MT_IDLE, "Idle time limit in minutes."},
  1228. {"uniquefileoption",MT_UQRESTR, "Is upload of existing files denied?"},
  1229. {"programname", MT_PRGNAM, "Name of the FTP daemon software."},
  1230. {"programversion", MT_PRGVER, "Version of the FTP daemon software."},
  1231. {"prgcopyright", MT_PRGCPYR, "Copyright notification of the FTP daemon software"},
  1232. {"systemname", MT_SYSNAME, "The name you have chosen for your site."},
  1233. {"osname", MT_OSNAME, "The name of the operating system (Win95, NT etc...)"},
  1234. {"email", MT_EMAIL, "Email address of the system administrator."},
  1235. {"restrictions", MT_FRESTR, "File system restrictions appliy/do not apply."},
  1236. {"usersonline", MT_CONLINE, "Users currently online."},
  1237. {"anonsonline", MT_CAONLINE,"Anonymous users currently online."},
  1238. {"dnsname",         MT_DNSNAME, "DNS name of the current user"},
  1239. {"localip", MT_LOCALIP, "Logged on to local IP number"},
  1240. {"oponline", MT_OPONLINE,"Operators online"},
  1241. {"", 0, ""}
  1242. };
  1243. // On overrides: Call base class first
  1244. // That way we can expand macros on all layers...
  1245. BOOL CTextSock::ExpandMacro(LPSTR *To, LPCSTR MacroName, int AvailBytes)
  1246. {
  1247. // if (CBaseClass::ExpandMacros(To, MacroName, AvailBytes))
  1248. // return TRUE;
  1249. // TODO: Add expansion here and return TRUE if the macro was expanded
  1250. // We do all the trivial macros, like file paths, dates, program name etc..
  1251. CString Macro("");
  1252. if (*MacroName == '%')
  1253. ExpandStringMacros(MacroName, Macro, NULL);
  1254. else if (*MacroName == '$')
  1255. {
  1256. for(MACROTABLE *pMT = BaseMacros; *pMT->Name; pMT++)
  1257. {
  1258. if (!stricmp(pMT->Name, MacroName + 1))
  1259. {
  1260. switch(pMT->Symb)
  1261. {
  1262. case MT_USER: Macro = m_LoginName; break;
  1263. case MT_ORIGIN: Macro = m_PeerName; break;
  1264. case MT_LOCALIP: Macro = m_HostName; break;
  1265. case MT_DNSNAME: Macro = m_DNSName; break;
  1266. case MT_CAONLINE:
  1267. Macro.Format("%d", CDaemonStatus::GetStat()->m_AnonUserConnections);
  1268. break;
  1269. case MT_CONLINE:
  1270. Macro.Format("%d", CDaemonStatus::GetStat()->m_UserConnections);
  1271. break;
  1272. case MT_OPONLINE:
  1273. Macro.Format("%d", CDaemonStatus::GetStat()->m_OperatorConnections);
  1274. break;
  1275. case MT_FRESTR:
  1276. Macro = m_IsLoggedInAnonymously ? "apply" : "Does not apply";
  1277. break;
  1278. case MT_SYSNAME: Macro = CDaemonStatus::GetStat()->m_ServerName; break;
  1279. case MT_EMAIL: Macro = CDaemonStatus::GetStat()->m_ServerEmail; break;
  1280. case MT_OSNAME: Macro = OsName(); break;
  1281. case MT_PRGCPYR: Macro = CProgramInfo::m_COPYRIGHT; break;
  1282. case MT_PRGVER: Macro = CProgramInfo::m_VERSION; break;
  1283. case MT_PRGNAM: Macro = CProgramInfo::m_PROGRAM; break; 
  1284. default:
  1285. Macro.Format("(Macro '%s' is not yet available)", MacroName);
  1286. break;
  1287. }
  1288. break;
  1289. }
  1290. }
  1291. }
  1292. int Len = Macro.GetLength();
  1293. if (Len && (Len < AvailBytes))
  1294. {
  1295. memcpy(*To, Macro, Len);
  1296. *To = *To + Len;
  1297. return TRUE;
  1298. }
  1299. return FALSE; // Failed or macro not found..
  1300. }
  1301. ///////////////////////////////////////////////////////////////////////////////////////
  1302. // CFTPDataSock
  1303. IMPLEMENT_DYNAMIC(CFTPDataSock, CBufferSock);
  1304. CFTPDataSock::CFTPDataSock()
  1305. {
  1306. m_Flags = 0;
  1307. m_pFile = NULL;
  1308. m_HaveToldUserThatTransfereIsComplete = FALSE;
  1309. //if (m_UseOverlappedIO = IsNT())
  1310. m_UseOverlappedIO = atoi(COptions::GetOption(COPTION_ADVANCEDOPTIONS, ADVANCEDOPTIONS_OVERLAPPEDIO)) != 0;
  1311. if (m_UseOverlappedIO)
  1312. {
  1313. m_Overlapped = new CFTPOverlapped;
  1314. m_Overlapped->m_Origin = this;
  1315. m_Overlapped->m_pFile = NULL;
  1316. }
  1317. else
  1318. m_Overlapped = NULL;
  1319. m_ListeningSock = NULL;
  1320. m_OriginD = NULL;
  1321. m_OriginC = NULL;
  1322. m_CurrentPosition = 0;
  1323. m_DataBuffers[0] = NULL;
  1324. m_DataBuffers[1] = NULL;
  1325. m_OverlappedIOReady = TRUE;
  1326. m_OverlappedIOUsed = 0;
  1327. m_OverlappedIOToggle = 1;
  1328. m_EOF = FALSE;
  1329. #ifdef _DEBUG
  1330. dm_OverlappedCnt = 0;
  1331. #endif
  1332. PrcExt(CAPIHandler::OnNewFTPDataSocket,0,0,(LPARAM)this);
  1333. }
  1334. CFTPDataSock::~CFTPDataSock()
  1335. {
  1336. m_DestructorIsActive = TRUE;
  1337. if (m_OriginD)
  1338. {
  1339. ASSERT(AfxIsValidAddress(m_OriginD, sizeof(CTextSock)));
  1340. ;
  1341. }
  1342. if (m_OriginC)
  1343. {
  1344. ASSERT(AfxIsValidAddress(m_OriginC, sizeof(CRemoteInterface)));
  1345. ;
  1346. }
  1347. ASSERT(AfxIsValidAddress(m_PtrToOriginsPtrToMe, sizeof(CFTPDataSock **)));
  1348. CString cBuf;
  1349. LogMsg(LOGF_DEBUG,"~CFTPDataSock() - Closing data connection.");
  1350. if (m_ListeningSock)
  1351. delete m_ListeningSock;
  1352. if (m_Overlapped)
  1353. {
  1354. if (m_OverlappedIOReady)
  1355. {
  1356. delete m_Overlapped;
  1357. m_Overlapped = NULL;
  1358. }
  1359. else
  1360. m_Overlapped->m_KillMe = TRUE;
  1361. }
  1362. if (m_pFile)
  1363. {
  1364. if (!m_HaveToldUserThatTransfereIsComplete)
  1365. {
  1366. int err = GetLastError();
  1367. try
  1368. {
  1369. OnFileCompletion(err ? err : -1);
  1370. }
  1371. catch(CSocketException *pExc)
  1372. {
  1373. LogMsg(LOGF_DEBUG,"CFTPDataSock::~CFTPDataSock() - Caught exception '%s' from %s. Ignored.", 
  1374. pExc->m_ErrorText, pExc->m_FromModule);
  1375. delete pExc;
  1376. }
  1377. catch(...)
  1378. {
  1379. LogMsg(LOGF_ERROR,"CFTPDataSock::~CFTPDataSock() - Caught unknown exception - ignored");
  1380. }
  1381. }
  1382. // If we have pending overlapped data, dont close.
  1383. if (!(m_Overlapped && m_Overlapped->m_KillMe))
  1384. {
  1385. if (m_pFile->m_CallbackPending)
  1386. {
  1387. LogMsg(LOGF_DEBUG,"~CFTPDataSock() - File is in callback state. Leaving it open.");
  1388. m_pFile->m_IsZombie = TRUE;
  1389. }
  1390. else
  1391. {
  1392. m_pFile->Destroy();
  1393. m_pFile = NULL;
  1394. LogMsg(LOGF_DEBUG,"~CFTPDataSock() - File closed.");
  1395. }
  1396. }
  1397. else
  1398. LogMsg(LOGF_DEBUG,"~CFTPDataSock() - Leaving file open (overlapped data pending).");
  1399. }
  1400. if (m_PtrToOriginsPtrToMe && (*m_PtrToOriginsPtrToMe == this))
  1401. *m_PtrToOriginsPtrToMe = NULL; // Release us from origin.
  1402. }
  1403. BOOL CFTPDataSock::IsOkToDelete(BOOL IgnoreSuspend)
  1404. {
  1405. if (!IgnoreSuspend && m_SuspendDelete)
  1406. {
  1407. LogMsg(LOGF_DEBUG,
  1408. "CFTPDataSock::IsOkToDelete() - NOT ok to delete.. m_SuspendDelete=%d.",
  1409. m_SuspendDelete);
  1410. return FALSE;
  1411. }
  1412. if (!m_OverlappedIOReady || m_DestructorIsActive)
  1413. {
  1414. LogMsg(LOGF_DEBUG,
  1415. "CFTPDataSock::IsOkToDelete() - NOT ok to delete.. m_OverlappedIOReady=%d m_DestructorIsActive=%d",
  1416. m_OverlappedIOReady, m_DestructorIsActive);
  1417. return FALSE;
  1418. }
  1419. LogMsg(LOGF_DEBUG,
  1420. "CFTPDataSock::IsOkToDelete() - YES. FTP Data socket can be killed.");
  1421. return TRUE;
  1422. }
  1423. BOOL CFTPDataSock::OnHandleWinsockErr(int nErrorCode )
  1424. {
  1425. // Normally called from within an excpetrion handler
  1426. SuspendDelete();
  1427. if (!m_HaveToldUserThatTransfereIsComplete)
  1428. {
  1429. try
  1430. {
  1431. OnFileCompletion(nErrorCode);
  1432. }
  1433. catch(CSocketException *pExc)
  1434. {
  1435. LogMsg(LOGF_DEBUG,
  1436. "CFTPDataSock::OnHandleWinsockErr(%d) 1 - Caught exception '%s' from %s. Ignored.", 
  1437. nErrorCode, pExc->m_ErrorText, pExc->m_FromModule);
  1438. delete pExc;
  1439. }
  1440. catch(...)
  1441. {
  1442. LogMsg(LOGF_ERROR,"CFTPDataSock::OnHandleWinsockErr(%d) - Caught unknown exception", nErrorCode);
  1443. return TRUE; // Can't do anthing.. 
  1444. }
  1445. }
  1446. ReleaseSuspendDelete();
  1447. if (m_OriginD)
  1448. {
  1449. m_OriginD->NotifyLogin(ENL_UPDATE);
  1450. m_OriginD->m_State = PROCESS;
  1451. }
  1452. if (IsOkToDelete())
  1453. delete this;
  1454. else
  1455. {
  1456. if (m_IsConnected)
  1457. {
  1458. SuspendDelete();
  1459. try
  1460. {
  1461. Close();
  1462. }
  1463. catch(CSocketException *pExc)
  1464. {
  1465. LogMsg(LOGF_DEBUG,
  1466. "CFTPDataSock::OnHandleWinsockErr(%d) 2 - Caught exception '%s' from %s. Ignored.", 
  1467. nErrorCode, pExc->m_ErrorText, pExc->m_FromModule);
  1468. delete pExc;
  1469. }
  1470. catch(...)
  1471. {
  1472. LogMsg(LOGF_ERROR,"CFTPDataSock::OnHandleWinsockErr(%d) 2 - Caught unknown exception", nErrorCode);
  1473. return TRUE; // Can't do anthing.. 
  1474. }
  1475. ReleaseSuspendDelete();
  1476. }
  1477. LogMsg(LOGF_DEBUG,
  1478. "CFTPDataSock::OnHandleWinsockErr(%d) - Data socket not ready for delete. Delete is pending.",
  1479. nErrorCode);
  1480. }
  1481. return TRUE; // We have handled the stuff
  1482. }
  1483. // Create the data socket. This is called on PASV and before any
  1484. // file transmission. If the datasocket is NULL, create it.
  1485. // If passive mode, initiate the listening socket.
  1486. // FTP Client version
  1487. BOOL CFTPDataSock::Create(CRemoteInterface *Origin, CFTPDataSock ** Ptr, 
  1488. int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr, 
  1489. BOOL Passive, DWORD Flags)
  1490. {
  1491. return Create(Origin, NULL, Ptr, FTPmode, FTPstru, FTPform, FTPtype, Sockaddr, Passive, Flags);
  1492. }
  1493. // FTP Server version
  1494. BOOL CFTPDataSock::Create(CTextSock *Origin, CFTPDataSock ** Ptr, 
  1495. int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr, 
  1496. BOOL Passive, DWORD Flags)
  1497. {
  1498. return Create(NULL, Origin, Ptr, FTPmode, FTPstru, FTPform, FTPtype, Sockaddr, Passive);
  1499. }
  1500. // Actual implementation..
  1501. BOOL CFTPDataSock::Create(CRemoteInterface *OriginC, CTextSock *OriginD, CFTPDataSock ** Ptr, 
  1502. int FTPmode, int FTPstru, int FTPform, int FTPtype, sockaddr *Sockaddr, 
  1503. BOOL Passive, DWORD Flags)
  1504. {
  1505. ASSERT(!OriginC || !OriginD);
  1506. ASSERT(((int)(OriginC) | (int)(OriginD)) != 0);
  1507. CFTPDataSock *me = this;
  1508. if (me == NULL)
  1509. {
  1510. me = new CFTPDataSock;
  1511. }
  1512. else
  1513. {
  1514. if (me->m_pFile)
  1515. {
  1516. me->LogMsg(LOGF_WARNINGS,"User tries to start a new transfere without closing the old one.");
  1517. if (me->m_OriginD)
  1518. me->m_OriginD->SendMsg(425, "Can't build data connection. Use ABOR to stop the current transfer.");
  1519. CSocketException::Throw(me, 
  1520. "CFTPDataSock::Create()", GetLastError(), "User tries to start a new transfere without closing the old one.");
  1521. }
  1522. }
  1523. me->m_PtrToOriginsPtrToMe = Ptr;
  1524. *me->m_PtrToOriginsPtrToMe = me;
  1525. me->m_OriginC = OriginC;
  1526. me->m_OriginD = OriginD;
  1527. me->m_OriginB = OriginD ? (CSock *)OriginD : (CSock *)OriginC;
  1528. me->m_FTPmode = FTPmode;
  1529. me->m_FTPtype = FTPtype;
  1530. me->m_FTPstru = FTPstru;
  1531. me->m_FTPform = FTPform;
  1532. me->m_Flags = Flags;
  1533. memcpy(&me->m_Sockaddr,Sockaddr,sizeof(struct sockaddr));
  1534. me->m_SocketName.Format("%s::*noname*", me->m_OriginD 
  1535. ? me->m_OriginD->m_SocketName
  1536. : me->m_OriginC->m_SocketName);
  1537. if (Passive)
  1538. {
  1539. me->LogMsg(LOGF_DEBUG,"Create() - Setting up listening socket for passive mode.");
  1540. if (me->m_ListeningSock)
  1541. delete me->m_ListeningSock;
  1542. me->m_ListeningSock = new CFTPPassiveSock;
  1543. if (!me->m_ListeningSock->Create(me, 0))
  1544. {
  1545. me->LogMsg(LOGF_WARNINGS,"Create() - Failed to create listening socket for passive mode.");
  1546. CSocketException::Throw(me,
  1547. "CFTPDataSock::Create()", GetLastError(), NULL);
  1548. }
  1549. }
  1550. return TRUE;
  1551. }
  1552. BOOL CFTPDataSock::SendFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp, 
  1553. FLEN StartOffset, FLEN FileLength)
  1554. {
  1555. m_SendMode = TRUE;
  1556. m_AsyncSelectMask = FD_WRITE | FD_CONNECT | FD_CLOSE;
  1557. return XmitFile(FileName, VisualFileName, IsTmp, StartOffset, FileLength); 
  1558. }
  1559. BOOL CFTPDataSock::ReceiveFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp, 
  1560. FLEN StartOffset, FLEN FileLength)
  1561. {
  1562. m_SendMode = FALSE;
  1563. m_SuspendOnClose = TRUE; // We want to see the receive() 0 bytes EOS..
  1564. m_AsyncSelectMask = FD_READ | FD_CONNECT | FD_CLOSE;
  1565. return XmitFile(FileName, VisualFileName, IsTmp, StartOffset, FileLength); 
  1566. }
  1567. BOOL CFTPDataSock::XmitFile(LPCSTR FileName, LPCSTR VisualFileName, BOOL IsTmp, 
  1568. FLEN StartOffset, FLEN FileLength)
  1569. {
  1570. ASSERT(m_OriginB != NULL);
  1571. CString cBuf;
  1572. int err;
  1573. LPCSTR p = strrchr(VisualFileName,'//');
  1574. if (p)
  1575. ++p;
  1576. else
  1577. p = VisualFileName;
  1578. m_SocketName.Format("%s::%s%s", m_OriginD 
  1579. ? m_OriginD->m_SocketName
  1580. : m_OriginC->m_SocketName, 
  1581. m_SendMode ? "<<" : ">>",  p);
  1582. m_OriginB->m_State = m_SendMode ? GETFILE : PUTFILE;
  1583. m_FileName = FileName;
  1584. m_VisualFileName = VisualFileName;
  1585. m_IsTmpFile = IsTmp;
  1586. m_FileLength = FileLength;
  1587. m_StartOffset = StartOffset;
  1588. if (m_OriginD && (err = m_OriginD->PrcSockExt(iOnVerifyTransferRequest, m_SendMode, (WPARAM)this, (LPARAM)FileName)))
  1589. {
  1590. if (err == CFuncList::AbortError)
  1591. {
  1592. LogMsg(LOGF_FILEACC,"Plugin denied file transfer.");
  1593. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", -1, "Plugin said NO!");
  1594. }
  1595. if (err == CFuncList::OkAllDone)
  1596. return TRUE;
  1597. }
  1598. // If a file system is in use, the object is created by the calling function
  1599. if (!m_pFile)
  1600. m_pFile = new CWarFile; 
  1601. ASSERT(m_pFile->IsOpen() == FALSE);
  1602. if (!m_pFile->Create(
  1603. FileName,
  1604. m_SendMode ? GENERIC_READ : (IsTmp && m_OriginC) ? GENERIC_READ | GENERIC_WRITE : GENERIC_WRITE,
  1605. m_SendMode ? FILE_SHARE_READ : 0,
  1606. NULL,
  1607. (m_SendMode || StartOffset) ? OPEN_EXISTING : CREATE_ALWAYS,
  1608. (m_UseOverlappedIO ? FILE_FLAG_OVERLAPPED : 0)
  1609. | (IsTmp ? FILE_FLAG_DELETE_ON_CLOSE : 0)
  1610. | FILE_FLAG_SEQUENTIAL_SCAN,
  1611. NULL,
  1612. m_Flags,
  1613. (LPARAM)m_SocketID,
  1614. CallbackFileIsCreated))
  1615. {
  1616. err = GetLastError();
  1617. if (err == WAIT_IO_COMPLETION)
  1618. return TRUE;
  1619. LogMsg(LOGF_DEBUG,"XmitFile() - Failed to open file %s. %s.", FileName, GetLastErrorText(err));
  1620. if (m_OriginD)
  1621. m_OriginD->SendMsg(553, "Open error %s", GetLastErrorText(err));
  1622. m_HaveToldUserThatTransfereIsComplete = TRUE;
  1623. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", err, NULL);
  1624. }
  1625. if (m_pFile->CallbackIsPending())
  1626. return TRUE;
  1627. return XmitFileCallback(TRUE);
  1628. }
  1629. // Called by CWarFile callback after the file is opened (or open failed)
  1630. void CFTPDataSock::CallbackFileIsCreated(CWarFile *pFile, BOOL Success, LPARAM lParam)
  1631. {
  1632. CFTPDataSock *pSock = (CFTPDataSock *)GetFromID(lParam);
  1633. pFile->m_CallbackPending = FALSE;
  1634. if (pSock)
  1635. {
  1636. ASSERT(pFile->m_IsZombie == FALSE);
  1637. try
  1638. {
  1639. pSock->XmitFileCallback(Success);
  1640. }
  1641. catch(CSocketException *pExc)
  1642. {
  1643. pExc->m_pSock->LogMsg(LOGF_DEBUG,"CFTPDataSock::CallbackFileIsCreated() - Caught ecxeption.");
  1644. pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum);
  1645. delete pExc;
  1646. return;
  1647. }
  1648. catch(...)
  1649. {
  1650. CLog::GetLog()->LogMsg(LOGF_ERROR,"CFTPDataSock::CallbackFileIsCreated() - Caught unknown ecxeption.");
  1651. pFile->Destroy();
  1652. return;
  1653. }
  1654. }
  1655. else
  1656. {
  1657. pFile->Destroy();
  1658. }
  1659. }
  1660. // Continue to initiate transfer
  1661. BOOL CFTPDataSock::XmitFileCallback(BOOL Success)
  1662. {
  1663. if (!Success)
  1664. {
  1665. int err = GetLastError();
  1666. LogMsg(LOGF_DEBUG,"XmitFileCallback() - Failed to open file %s. %s.", m_FileName, GetLastErrorText(err));
  1667. if (m_OriginD)
  1668. m_OriginD->SendMsg(553, "Open error %s", GetLastErrorText(err));
  1669. m_HaveToldUserThatTransfereIsComplete = TRUE;
  1670. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 1", err, NULL);
  1671. }
  1672. // Get file lenght
  1673. if (!m_FileLength)
  1674. {
  1675. if ((m_FileLength = m_pFile->Seek(0, FILE_END)) == INVALID_FLEN_VALUE)
  1676. {
  1677. int Err = GetLastError();
  1678. LogMsg(LOGF_DEBUG,"XmitFile() - Failed seek to end of file %s. %s.", m_FileName, GetLastErrorText(Err));
  1679. if (m_OriginD)
  1680. m_OriginD->SendMsg(451, "Seek error %s", GetLastErrorText(Err));
  1681. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 2", Err, NULL);
  1682. }
  1683. if (m_StartOffset == FLEN_MAX)
  1684. {
  1685. // Append
  1686. ASSERT(m_SendMode == FALSE);
  1687. m_CurrentPosition = m_FileLength;
  1688. }
  1689. else if ((m_CurrentPosition = m_pFile->Seek(m_StartOffset, FILE_BEGIN)) == INVALID_FLEN_VALUE)
  1690. {
  1691. int err = GetLastError();
  1692. LogMsg(LOGF_DEBUG,"XmitFile() - Failed to move to offset %i. %s.", 
  1693. (unsigned)m_StartOffset, GetLastErrorText(err));
  1694. if (m_OriginD)
  1695. m_OriginD->SendMsg(451, "Seek error %s", GetLastErrorText(err));
  1696. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 3", err, NULL);
  1697. }
  1698. }
  1699. if (m_StartOffset != m_CurrentPosition)
  1700. {
  1701. LogMsg(LOGF_DEBUG,"SendFile(): Aborting due to illegal restart marker %u", (unsigned)m_StartOffset);
  1702. if (m_OriginD)
  1703. m_OriginD->SendMsg(550, "Cannot resume on this file.");
  1704. CSocketException::Throw(this, "CFTPDataSock::XmitFile() 4", -1, "Illegal restart marker.");
  1705. }
  1706. return DoConnect();
  1707. }
  1708. BOOL CFTPDataSock::DoConnect()
  1709. {
  1710. CString cBuf;
  1711. if (m_FileLength)
  1712. cBuf.Format(" (%u bytes)", (unsigned)m_FileLength);
  1713. else
  1714. cBuf.Empty();
  1715. if (m_IsConnected)
  1716. {
  1717. ASSERT(m_ListeningSock != NULL);
  1718. if (m_OriginD)
  1719. m_OriginD->SendMsg(125, "Using existing data connection (%s mode) for %s%s.", 
  1720. m_FTPtype == TYPE_A ? "ASCII" : "BINARY", 
  1721. m_VisualFileName, cBuf);
  1722. }
  1723. else 
  1724. {
  1725. if (m_OriginD)
  1726. m_OriginD->SendMsg(150, "Opening %s mode data connection for %s%s.", 
  1727. m_FTPtype == TYPE_A ? "ASCII" : "BINARY", 
  1728. m_VisualFileName, m_SendMode ? cBuf : "");
  1729. }
  1730. if (!m_ListeningSock)
  1731. {
  1732. SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
  1733. LogMsg(LOGF_DEBUG,"Trying to connect to %d.%d.%d.%d port %d (%lX,%d)",
  1734. s_in->sin_addr.S_un.S_un_b.s_b1,
  1735. s_in->sin_addr.S_un.S_un_b.s_b2,
  1736. s_in->sin_addr.S_un.S_un_b.s_b3,
  1737. s_in->sin_addr.S_un.S_un_b.s_b4,
  1738. ntohs(s_in->sin_port),
  1739. s_in->sin_addr.s_addr, 
  1740. ntohs(s_in->sin_port));
  1741. if (!CSock::Create() || !Connect(&m_Sockaddr, sizeof(struct sockaddr)))
  1742. {
  1743. int err;
  1744. if (err = GetLastError() != WSAEWOULDBLOCK)
  1745. {
  1746. CString cBuf;
  1747. LogLastError(LOGF_DEBUG, 0, "DoConnect - Connect failed");
  1748. if (m_OriginD)
  1749. m_OriginD->SendMsg(425, "Can't build data connection. %s.", GetLastErrorText(err));
  1750. m_HaveToldUserThatTransfereIsComplete = TRUE;
  1751. CSocketException::Throw(this, "CFTPDataSock::DoConnect()", err, NULL);
  1752. }
  1753. }
  1754. }
  1755. m_State = m_SendMode ? PUTFILE : GETFILE;
  1756. if (m_SendMode && m_ClearToSend)
  1757. DoSend();
  1758. if (m_OriginD)
  1759. m_OriginD->NotifyLogin(ENL_UPDATE, strrchr(m_SocketName, ':') + 1);
  1760. return TRUE;
  1761. }
  1762. void CFTPDataSock::OnConnect( int nErrorCode )
  1763. {
  1764. try
  1765. {
  1766. _OnConnect(nErrorCode);
  1767. }
  1768. catch(CSocketException *pExc)
  1769. {
  1770. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnConnect(%d %d) - Caught ecxeption.", 
  1771. nErrorCode, pExc->m_ErrorNum);
  1772. ASSERT(pExc->m_pSock == this);
  1773. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  1774. delete this; 
  1775. delete pExc;
  1776. }
  1777. catch(...)
  1778. {
  1779. LogMsg(LOGF_ERROR,"CFTPDataSock::OnConnect(%d) - Caught unknown ecxeption.", nErrorCode);
  1780. }
  1781. return;
  1782. }
  1783. void CFTPDataSock::_OnConnect( int nErrorCode )
  1784. {
  1785. if (nErrorCode)
  1786. {
  1787. if (m_OriginD)
  1788. m_OriginD->SendMsg(425, "Can't build data connection. Error code %d.", nErrorCode);
  1789. LogMsg(LOGF_WARNINGS,"OnConnect() - Can't build data connection. Error code %d.", nErrorCode);
  1790. m_HaveToldUserThatTransfereIsComplete = TRUE;
  1791. }
  1792. CSock::OnConnect(nErrorCode);
  1793. ASSERT(nErrorCode == 0);
  1794. if (m_OriginD)
  1795. m_OriginD->IncXferCnt(TRUE);
  1796. if (m_UseOverlappedIO)
  1797. {
  1798. m_BufferSize = atoi(COptions::GetOption(COPTION_ADVANCEDOPTIONS, ADVANCEDOPTIONS_OVERLAPPEDIO));
  1799. m_BufferSize = CAdvancedOptions::GetOvlMap(m_BufferSize);
  1800. LogMsg(LOGF_DEBUG,
  1801. " CFTPDataSock::_OnConnect() - Overlapped IO is enabled. Buffer size is 2 x %d bytes",
  1802. m_BufferSize);
  1803. delete m_OutBuf;
  1804. ASSERT(m_BufferSize > MAX_PATH);
  1805. ASSERT(AfxIsValidAddress(m_Overlapped,sizeof(CFTPOverlapped)));
  1806. m_DataBuffers[0] = m_OutBuf = new char[m_BufferSize];
  1807. m_DataBuffers[1] = m_Overlapped->m_Buffer = new char[m_BufferSize];
  1808. }
  1809. AsyncSelect(m_AsyncSelectMask);
  1810. if (m_SendMode && m_pFile->IsOpen())
  1811. DoSend();
  1812. return;
  1813. }
  1814. void CFTPDataSock::OnReceive( int nErrorCode )
  1815. {
  1816. try
  1817. {
  1818. _OnReceive(nErrorCode);
  1819. }
  1820. catch(CSocketException *pExc)
  1821. {
  1822. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnReceive(%d %d) - Caught ecxeption.", 
  1823. nErrorCode, pExc->m_ErrorNum);
  1824. ASSERT(pExc->m_pSock == this);
  1825. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  1826. delete this; 
  1827. delete pExc;
  1828. }
  1829. catch(...)
  1830. {
  1831. LogMsg(LOGF_ERROR,"CFTPDataSock::OnReceive(%d) - Caught unknown ecxeption.", nErrorCode);
  1832. }
  1833. return;
  1834. }
  1835. void CFTPDataSock::_OnReceive( int nErrorCode )
  1836. {
  1837. CBufferSock::OnReceive(nErrorCode);
  1838. ASSERT(nErrorCode == 0);
  1839. m_OriginB->m_Timer.Reset();
  1840. if (!m_pFile->IsOpen())
  1841. {
  1842. LogMsg(LOGF_WARNINGS,"OnReceive(): Data received before opening file.");
  1843. return;
  1844. }
  1845. ASSERT(m_ClearToReceive);
  1846. if (m_UseOverlappedIO)
  1847. DoOverlapped();
  1848. else
  1849. {
  1850. int BytesRead = 0;
  1851. while((BytesRead = Receive(m_OutBuf, m_BufferSize)) > 0)
  1852. {
  1853. // CSock::Receive() handles WASWOULDBLOCK, EOF and errors
  1854. DWORD BytesWritten = 0;
  1855. if (!m_pFile->Write(
  1856. m_OutBuf + BytesWritten,
  1857. BytesRead - BytesWritten,
  1858. &BytesWritten,
  1859. NULL))
  1860. {
  1861. int err = GetLastError();
  1862. CString cBuf;
  1863. LogMsg(LOGF_DEBUG,"_OnReceive() - WriteFile() failed. Error %s.", GetLastErrorText(err));
  1864. CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 1", err, NULL);
  1865. }
  1866. if (BytesWritten < (DWORD)BytesRead)
  1867. {
  1868. // Probarbly disk full...
  1869. LogMsg(LOGF_WARNINGS,"_OnReceive() - WriteFile(%d) only wrote %d bytes. Aborting..",
  1870. BytesRead, BytesWritten);
  1871. CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 2", -1, "Failed to write");
  1872. }
  1873. m_CurrentPosition += BytesRead;
  1874. m_BufferUsed = 0;
  1875. if (m_FileLength < m_CurrentPosition)
  1876. m_FileLength = m_CurrentPosition;
  1877. }
  1878. ASSERT(BytesRead != -1);
  1879. if (!m_IsConnected)
  1880. {
  1881. OnFileCompletion(0);
  1882. CSocketException::Throw(this, "CFTPDataSock::_OnReceive() 3", 0, "File received OK");
  1883. }
  1884. }
  1885. }
  1886. BOOL CFTPDataSock::DoSend()
  1887. {
  1888. if (!m_pFile->IsOpen())
  1889. {
  1890. LogMsg(LOGF_DEBUG,"DoSend(): File not open yet. Nothing sent to network.");
  1891. return TRUE;
  1892. }
  1893. if (!m_SendMode)
  1894. {
  1895. LogMsg(LOGF_DEBUG,"CFTPDataSock::DoSend() - Called without send mode enabled. Ignoring.");
  1896. return TRUE;
  1897. }
  1898. if (m_ClearToSend)
  1899. CBufferSock::DoSend(); // Try to empty the current output buffer
  1900. else
  1901. return TRUE; // No need to continue, we are waiting for OnSend()
  1902. if (m_UseOverlappedIO)
  1903. DoOverlapped();
  1904. else
  1905. {
  1906. DWORD BytesRead = 0;
  1907. while(!m_EOF && BufferSock_BufferFree())
  1908. {
  1909. ASSERT(BufferSock_BufferFree() > 0);
  1910. if (!m_EOF && !m_pFile->Read(
  1911. m_OutBuf + m_BufferUsed,
  1912. BufferSock_BufferFree(),
  1913. &BytesRead,
  1914. NULL))
  1915. {
  1916. if (GetLastError() == ERROR_HANDLE_EOF)
  1917. m_EOF = TRUE;
  1918. else
  1919. {
  1920. CString cBuf;
  1921. int Err = GetLastError();
  1922. LogMsg(LOGF_DEBUG,"DoSend() - ReadFile() failed. Error %s.", GetLastErrorText(Err));
  1923. CSocketException::Throw(this, "CFTPDataSock::_DoSend()", Err, NULL);
  1924. }
  1925. }
  1926. if (BytesRead == 0)
  1927. m_EOF = TRUE;
  1928. m_CurrentPosition += BytesRead;
  1929. m_BufferUsed += BytesRead;
  1930. if (m_ClearToSend)
  1931. CBufferSock::DoSend();
  1932. }
  1933. }
  1934. if (m_EOF && m_ClearToSend)
  1935. {
  1936. ASSERT(m_BufferUsed == 0);
  1937. OnFileCompletion(0); // File sent OK
  1938. CSocketException::Throw(this, "CFTPDataSock::_DoSend()", 0, "File sent OK");
  1939. }
  1940. return TRUE;
  1941. }
  1942. void CFTPDataSock::OnSend( int nErrorCode )
  1943. {
  1944. try
  1945. {
  1946. m_OriginB->m_Timer.Reset();
  1947. CBufferSock::OnSend(nErrorCode);
  1948. }
  1949. catch(CSocketException *pExc)
  1950. {
  1951. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnSend(%d %d) - Caught exception.", 
  1952. nErrorCode, pExc->m_ErrorNum);
  1953. ASSERT(pExc->m_pSock == this);
  1954. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  1955. delete this;
  1956. delete pExc;
  1957. }
  1958. return;
  1959. }
  1960. BOOL CFTPDataSock::DoOverlapped()
  1961. {
  1962. ASSERT(AfxIsValidAddress(this, sizeof(CFTPDataSock)));
  1963. ASSERT(m_UseOverlappedIO);
  1964. ASSERT(AfxIsValidAddress(m_Overlapped,sizeof(CFTPOverlapped)));
  1965. ASSERT(m_BufferSize >= MAX_PATH);
  1966. ASSERT(AfxIsValidAddress(m_Overlapped->m_Buffer,m_BufferSize));
  1967. ASSERT(AfxIsValidAddress(m_DataBuffers[0],m_BufferSize));
  1968. ASSERT(AfxIsValidAddress(m_DataBuffers[0],m_BufferSize));
  1969. //ASSERT(IsNT());
  1970. if (m_SendMode)
  1971. {
  1972. if (m_OverlappedIOReady)
  1973. {
  1974. if (m_BufferUsed)
  1975. {
  1976. ASSERT(m_ClearToSend == FALSE);
  1977. return TRUE; // We have to wait until the send buffer is ready
  1978. }
  1979. // Toggle the buffers
  1980. m_OutBuf = m_DataBuffers[m_OverlappedIOToggle];
  1981. m_Overlapped->m_Buffer = m_DataBuffers[!m_OverlappedIOToggle];
  1982. m_OverlappedIOToggle = m_OverlappedIOToggle == FALSE;
  1983. m_BufferUsed = m_OverlappedIOUsed;
  1984. m_OverlappedIOUsed = 0;
  1985. if (m_EOF && (m_BufferUsed == 0))
  1986. CSocketException::Throw(this, "CFTPDataSock::DoOverlapped()", 0, "File xmitted OK");
  1987. else if (!m_EOF)
  1988. ReadWriteOverlapped();
  1989. // Send data to network
  1990. if (m_BufferUsed && m_ClearToSend)
  1991. CBufferSock::DoSend();
  1992. }
  1993. }
  1994. else // receive
  1995. {
  1996. if (m_ClearToReceive)
  1997. {
  1998. // Fill receive buffer
  1999. try
  2000. {
  2001. int BytesRead = 0;
  2002. while(BufferSock_BufferFree()
  2003. && ((BytesRead = Receive(m_OutBuf + m_BufferUsed, BufferSock_BufferFree())) > 0))
  2004. {
  2005. m_BufferUsed += BytesRead;
  2006. }
  2007. }
  2008. catch(CSocketException *pExc)
  2009. {
  2010. if (pExc->m_ErrorNum)
  2011. throw pExc; // We can only handle EOF.
  2012. // End of transmission.
  2013. Close();
  2014. delete pExc;
  2015. }
  2016. }
  2017. if (m_OverlappedIOReady && (!m_IsConnected || !BufferSock_BufferFree()))
  2018. {
  2019. // Toggle the buffers
  2020. m_OutBuf = m_DataBuffers[m_OverlappedIOToggle];
  2021. m_Overlapped->m_Buffer = m_DataBuffers[!m_OverlappedIOToggle];
  2022. m_OverlappedIOToggle = m_OverlappedIOToggle == FALSE;
  2023. if (!m_BufferUsed && !m_IsConnected)
  2024. CSocketException::Throw(this, "CFTPDataSock::DoOverlapped() 1", 0, "File xmitted OK");
  2025. if (m_BufferUsed)
  2026. ReadWriteOverlapped();
  2027. m_BufferUsed = 0;
  2028. m_OverlappedIOUsed = 0;
  2029. }
  2030. }
  2031. return TRUE;
  2032. }
  2033. // Call overlapped IO operation
  2034. BOOL CFTPDataSock::ReadWriteOverlapped()
  2035. {
  2036. ASSERT(m_OverlappedIOReady == TRUE);
  2037. BOOL IOResult;
  2038. m_Overlapped->m_pFile = m_pFile;
  2039. m_Overlapped->m_OverlappedData.Offset = LODWORD(m_CurrentPosition);
  2040. m_Overlapped->m_OverlappedData.OffsetHigh = HIDWORD(m_CurrentPosition);
  2041. m_Overlapped->m_OverlappedData.hEvent = (HANDLE)m_Overlapped;
  2042. if (m_SendMode)
  2043. {
  2044. LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - ReadFileEx(%d bytes) %08X", m_BufferSize, m_Overlapped);
  2045. IOResult = m_pFile->ReadEx(
  2046. m_Overlapped->m_Buffer,
  2047. m_BufferSize,
  2048. &m_Overlapped->m_OverlappedData,
  2049. OnOverlappedIO);
  2050. }
  2051. else
  2052. {
  2053. LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - ReadFileEx(%d bytes) %08X", m_BufferUsed, m_Overlapped);
  2054. IOResult = m_pFile->WriteEx(
  2055. m_Overlapped->m_Buffer,
  2056. m_BufferUsed,
  2057. &m_Overlapped->m_OverlappedData,
  2058. OnOverlappedIO);
  2059. }
  2060. if (!IOResult)
  2061. {
  2062. if (m_SendMode && (GetLastError() == ERROR_HANDLE_EOF))
  2063. m_EOF = TRUE;
  2064. else
  2065. {
  2066. int err = GetLastError();
  2067. CString cBuf;
  2068. LogMsg(LOGF_DEBUG,"ReadWriteOverlapped() - Read/WriteFile() failed. %s", GetLastErrorText(err));
  2069. CSocketException::Throw(this, "CFTPDataSock::ReadWriteOverlapped()", err, NULL);
  2070. }
  2071. }
  2072. else
  2073. {
  2074. // ReadFileEx was successful
  2075. m_OverlappedIOReady = FALSE;
  2076. ++m_OverlappedCnt;
  2077. ASSERT(++dm_OverlappedCnt == 1);
  2078. }
  2079. return TRUE;
  2080. }
  2081. // Always called from an exception handler.
  2082. void CFTPDataSock::OnFileCompletion(int nErrorCode)
  2083. {
  2084. if (m_IsConnected)
  2085. {
  2086. Close();
  2087. if (m_OriginD)
  2088. {
  2089. m_OriginD->IncXferCnt(FALSE);
  2090. m_OriginB->m_State = PROCESS;
  2091. }
  2092. }
  2093. // If we have pending overlapped IO we will wait for that to complete.
  2094. if (!IsOkToDelete(TRUE) && !nErrorCode)
  2095. {
  2096. LogMsg(LOGF_DEBUG,
  2097. "CFTPDataSock::OnFileCompletion(OK) - Transfer is OK. Awaiting pending overlapped IO.");
  2098. return;
  2099. }
  2100. if (m_OriginD)
  2101. m_OriginD->NotifyLogin(ENL_UPDATE, "");
  2102. if (nErrorCode)
  2103. {
  2104. CString cBuf;
  2105. if (m_OriginD && (nErrorCode == -1))
  2106. m_OriginD->SendMsg(426, "Transfere aborted.");
  2107. else if (m_OriginD)
  2108. m_OriginD->SendMsg(426, "Error %s. Transfere aborted.", GetLastErrorText(nErrorCode));
  2109. LogMsg(LOGF_FILEACC,"OnFileCompletion() - Transfere aborted. Error %d.", nErrorCode);
  2110. }
  2111. else
  2112. {
  2113. int err;
  2114. if (m_OriginD && (err = m_OriginD->PrcSockExt(iOnVerifyUploadedFile, m_SendMode, 0,(LPARAM)this)))
  2115. {
  2116. if (err == CFuncList::AbortError)
  2117. {
  2118. LogMsg(LOGF_FILEACC,"Plugin denied file after successful upload.");
  2119. CSocketException::Throw(this, "CFTPDataSock::OnFileCompletion()", -1, "Plugin said NO!");
  2120. }
  2121. if (err == CFuncList::OkAllDone)
  2122. return;
  2123. }
  2124. if (m_OriginD)
  2125. m_OriginD->SendMsg(226, "Transfer complete. %u bytes in %.2f sec. (%.3f Kb/s)",
  2126. m_BytesSent + m_BytesReceived,
  2127. GetLapTime(),
  2128. GetCPS() / (float)1024);
  2129. LogMsg(m_IsTmpFile ? LOGF_DEBUG : LOGF_FILEACC,"OnFileCompletion() - Transfere complete. %u bytes in %.2f sec. (%.3f Kb/s)", 
  2130. m_BytesSent + m_BytesReceived,
  2131. GetLapTime(),
  2132. GetCPS() / (float)1024);
  2133. }
  2134. m_HaveToldUserThatTransfereIsComplete = TRUE;
  2135. if (m_OriginC)
  2136. {
  2137. SuspendDelete();
  2138. m_OriginC->OnFileCompletion(nErrorCode);
  2139. ReleaseSuspendDelete();
  2140. }
  2141. }
  2142. void CFTPDataSock::OnClose( int nErrorCode )
  2143. {
  2144. try
  2145. {
  2146. _OnClose(nErrorCode);
  2147. }
  2148. catch(CSocketException *pExc)
  2149. {
  2150. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnClose(%d %d) - Caught ecxeption.", 
  2151. nErrorCode, pExc->m_ErrorNum);
  2152. ASSERT(pExc->m_pSock == this);
  2153. if (nErrorCode == WSAECONNABORTED)
  2154. {
  2155. LogMsg(LOGF_WARNINGS,"CFTPDataSock::OnClose(WSAECONNABORTED) - Error message is ignored.");
  2156. nErrorCode = 0;
  2157. }
  2158. if (!nErrorCode && m_SuspendOnClose)
  2159. {
  2160. // We want 0 on receive to confirm that the file is received OK.
  2161. ASSERT(m_IsConnected == TRUE);
  2162. ASSERT(m_SendMode == FALSE);
  2163. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnClose() - OnClose(0) is not allowed right now. Calling OnReceive().");
  2164. OnReceive(0);
  2165. return;
  2166. }
  2167. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  2168. delete this; 
  2169. delete pExc;
  2170. }
  2171. catch(...)
  2172. {
  2173. LogMsg(LOGF_ERROR,"CFTPDataSock::OnClose(%d) - Caught unknown ecxeption.", nErrorCode);
  2174. }
  2175. return;
  2176. }
  2177. void CFTPDataSock::_OnClose( int nErrorCode )
  2178. {
  2179. CSock::OnClose(nErrorCode); 
  2180. m_OriginB->m_Timer.Reset();
  2181. if (m_SendMode)
  2182. {
  2183. // This should never be called during send.
  2184. LogMsg(LOGF_WARNINGS,"OnClose(%d) called during FTP data send.", nErrorCode);
  2185. CSocketException::Throw(this, 
  2186. "CFTPDataSock::_OnClose(%d)", nErrorCode ? nErrorCode : -1, "On close during send.",
  2187. nErrorCode);
  2188. }
  2189. else // receive
  2190. {
  2191. CSocketException::Throw(this, 
  2192. "CFTPDataSock::_OnClose(%d)", nErrorCode, "On close during receive.",
  2193. nErrorCode);
  2194. }
  2195. }
  2196. VOID WINAPI CFTPDataSock::OnOverlappedIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, 
  2197. LPOVERLAPPED lpOverlapped)
  2198. {
  2199. CFTPOverlapped *Overlap = (CFTPOverlapped *)lpOverlapped->hEvent;
  2200. ASSERT(AfxIsValidAddress(Overlap,sizeof(CFTPOverlapped)));
  2201. ASSERT(IsProcessingIdle);
  2202. try
  2203. {
  2204. m_OverlappedCnt--;
  2205. ASSERT(m_OverlappedCnt >= 0);
  2206. ASSERT(--Overlap->m_Origin->dm_OverlappedCnt == 0);
  2207. m_Log->LogMsg(LOGF_DEBUG,"OnOverlappedIO(%08X) - Err=%d, %u bytes, Killme=%d",
  2208. Overlap,
  2209. dwErrorCode, dwNumberOfBytesTransfered, Overlap->m_KillMe);
  2210. if (Overlap->m_KillMe)
  2211. {
  2212. // Transfere is aborted. Data socket is dead.
  2213. CSock::m_Log->LogMsg(LOGF_DEBUG,"OnOverlappedIO() - Deleting dead overlapped data and closing file.");
  2214. ASSERT(Overlap->m_pFile->IsOpen());
  2215. Overlap->m_pFile->Close();
  2216. if (Overlap->m_pFile->m_IsZombie && !Overlap->m_pFile->m_CallbackPending)
  2217. {
  2218. Overlap->m_pFile->Destroy();
  2219. Overlap->m_pFile = NULL;
  2220. }
  2221. delete Overlap;
  2222. return;
  2223. }
  2224. Overlap->m_Origin->m_OverlappedIOReady = TRUE;
  2225. Overlap->m_Origin->m_OverlappedIOUsed = (int)dwNumberOfBytesTransfered;
  2226. Overlap->m_Origin->m_CurrentPosition += dwNumberOfBytesTransfered;
  2227. if (Overlap->m_Origin->m_FileLength < Overlap->m_Origin->m_CurrentPosition)
  2228. Overlap->m_Origin->m_FileLength = Overlap->m_Origin->m_CurrentPosition;
  2229. if (dwErrorCode)
  2230. {
  2231. if (Overlap->m_Origin->m_SendMode && (dwErrorCode == ERROR_HANDLE_EOF))
  2232. {
  2233. Overlap->m_Origin->m_EOF == TRUE;
  2234. }
  2235. else
  2236. {
  2237. CString cBuf;
  2238. Overlap->m_Origin->LogMsg(LOGF_DEBUG,"OnOverlappedIO() - Error %s.", 
  2239. GetLastErrorText((int)dwErrorCode));
  2240. CSocketException::Throw(Overlap->m_Origin, "CFTPDataSock::OnOverlappedIO", dwErrorCode, NULL);
  2241. }
  2242. }
  2243. Overlap->m_Origin->DoOverlapped();
  2244. // Check for end of transmission in send mode
  2245. if (Overlap->m_Origin->m_SendMode && Overlap->m_Origin->m_EOF && Overlap->m_Origin->m_ClearToSend)
  2246. {
  2247. ASSERT(Overlap->m_Origin->m_BufferUsed == 0);
  2248. CSocketException::Throw(Overlap->m_Origin, "CFTPDataSock::OnOverlappedIO", 0, "File xmitted OK");
  2249. }
  2250. }
  2251. catch(CSocketException *pExc)
  2252. {
  2253. Overlap->m_Origin->m_OverlappedIOReady = TRUE;
  2254. if (!pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum))
  2255. delete pExc->m_pSock; 
  2256. delete pExc;
  2257. }
  2258. catch(...)
  2259. {
  2260. CLog::GetLog()->LogMsg(LOGF_ERROR,"CFTPDataSock::OnOverlappedIO(%d) - Caught unknown ecxeption.", dwErrorCode);
  2261. }
  2262. return;
  2263. }
  2264. ///////////////////////////////////////////////////////////////////////////////
  2265. // FTP Data listening sock
  2266. CFTPPassiveSock::CFTPPassiveSock()
  2267. {
  2268. m_Origin = NULL;
  2269. m_HasAccepted = FALSE;
  2270. m_Type = LT_FTP_DATA;
  2271. }
  2272. CFTPPassiveSock::~CFTPPassiveSock()
  2273. {
  2274. ASSERT(m_Origin->m_ListeningSock == this);
  2275. if (m_Origin && (m_Origin->m_ListeningSock == this))
  2276. m_Origin->m_ListeningSock = NULL;
  2277. }
  2278. BOOL CFTPPassiveSock::Create(CFTPDataSock *Origin, int Port)
  2279. {
  2280. ASSERT(AfxIsValidAddress(Origin, sizeof(CFTPDataSock)));
  2281. CString cBuf;
  2282. m_Origin = Origin;
  2283. m_SocketName = m_Origin->m_SocketName;
  2284. m_SocketName += "::Passive";
  2285. BOOL True = TRUE;
  2286. int AddrLen = sizeof(SOCKADDR);
  2287. SOCKADDR_IN *s_in = (SOCKADDR_IN *)&m_Sockaddr;
  2288. ASSERT(AfxIsValidAddress(s_in,sizeof(SOCKADDR_IN)));
  2289. // Get the local IP address the user is connected to
  2290. UINT Dummy;
  2291. if (!m_Origin->m_OriginB->GetSockName(&m_Sockaddr, &AddrLen) ||
  2292. !m_Origin->m_OriginB->GetSockName(cBuf, Dummy))
  2293. {
  2294. LogLastError(LOGF_DEBUG,m_Origin->m_OriginB->GetLastError(),"Create() - m_OriginB->GetSockName() failed.");
  2295. delete this;
  2296. return FALSE;
  2297. }
  2298. s_in->sin_port = htons(Port); 
  2299. s_in->sin_family = AF_INET;
  2300. // Create the socket
  2301. if (!CSock::Create(Port, SOCK_STREAM, FD_ACCEPT, cBuf))
  2302. {
  2303. LogLastError(LOGF_DEBUG,0,"Create() failed.");
  2304. delete this;
  2305. return FALSE;
  2306. }
  2307. AsyncSelect(FD_ACCEPT);
  2308. // Get the actual IP and port number
  2309. if (!GetSockName(&m_Sockaddr, &AddrLen))
  2310. {
  2311. LogLastError(LOGF_DEBUG,0,"Create() - GetSockName() failed.");
  2312. delete this;
  2313. return FALSE;
  2314. }
  2315. if (!Listen())
  2316. {
  2317. LogLastError(LOGF_DEBUG,0,"Create() - Listen(1) failed.");
  2318. delete this;
  2319. return FALSE;
  2320. }
  2321. LogMsg(LOGF_DEBUG,"Create() - Listening to %d.%d.%d.%d.%d.%d (%d).",
  2322. s_in->sin_addr.S_un.S_un_b.s_b1,
  2323. s_in->sin_addr.S_un.S_un_b.s_b2,
  2324. s_in->sin_addr.S_un.S_un_b.s_b3,
  2325. s_in->sin_addr.S_un.S_un_b.s_b4,
  2326. ((ntohs(s_in->sin_port) >> 8) & 0xff),
  2327. (ntohs(s_in->sin_port) & 0xff),
  2328. ntohs(s_in->sin_port));
  2329. if (m_Origin->m_OriginC)
  2330. {
  2331. // Prepere the PORT command for the FTP Client
  2332. m_Origin->m_OriginC->m_PreperedCommand.Format("PORT %d,%d,%d,%d,%d,%d",
  2333. s_in->sin_addr.S_un.S_un_b.s_b1,
  2334. s_in->sin_addr.S_un.S_un_b.s_b2,
  2335. s_in->sin_addr.S_un.S_un_b.s_b3,
  2336. s_in->sin_addr.S_un.S_un_b.s_b4,
  2337. ((ntohs(s_in->sin_port) >> 8) & 0xff),
  2338. (ntohs(s_in->sin_port) & 0xff));
  2339. }
  2340. else
  2341. {
  2342. if (m_Origin->m_OriginD)
  2343. m_Origin->m_OriginD->SendMsg(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
  2344. s_in->sin_addr.S_un.S_un_b.s_b1,
  2345. s_in->sin_addr.S_un.S_un_b.s_b2,
  2346. s_in->sin_addr.S_un.S_un_b.s_b3,
  2347. s_in->sin_addr.S_un.S_un_b.s_b4,
  2348. ((ntohs(s_in->sin_port) >> 8) & 0xff),
  2349. (ntohs(s_in->sin_port) & 0xff));
  2350. }
  2351. return TRUE;
  2352. }
  2353. void CFTPPassiveSock::OnAccept( int nErrorCode )
  2354. {
  2355. try
  2356. {
  2357. _OnAccept(nErrorCode);
  2358. }
  2359. catch(CSocketException *pExc)
  2360. {
  2361. LogMsg(LOGF_DEBUG,"CFTPDataSock::OnAccept(%d %d) - Caught ecxeption.", 
  2362. nErrorCode, pExc->m_ErrorNum);
  2363. if (!OnHandleWinsockErr(pExc->m_ErrorNum))
  2364. {
  2365. LogLastError(LOGF_WARNINGS,pExc->m_ErrorNum,"_OnAccept() - DoAccept() failed.");
  2366. if (m_Origin->m_OriginD)
  2367. m_Origin->m_OriginD->SendMsg(425, "Can't build data connection. %s.", 
  2368. GetLastErrorText(pExc->m_ErrorNum));
  2369. m_Origin->m_HaveToldUserThatTransfereIsComplete = TRUE;
  2370. int ErrNo = pExc->m_ErrorNum;
  2371. delete pExc;
  2372. CSocketException::Throw(m_Origin, "CFTPPassiveSock::OnAccept()", ErrNo, "Failed to build data connection.");
  2373. }
  2374. }
  2375. catch(...)
  2376. {
  2377. LogMsg(LOGF_ERROR,"CFTPPassiveSock::OnAccept(%d) - Caught unknown ecxeption.", nErrorCode);
  2378. }
  2379. return;
  2380. }
  2381. void CFTPPassiveSock::_OnAccept( int nErrorCode )
  2382. {
  2383. CSock::OnAccept(nErrorCode);
  2384. ASSERT(nErrorCode == 0);
  2385. if (!DoAccept(m_Origin))
  2386. {
  2387. CString cBuf;
  2388. int Err = GetLastError();
  2389. LogLastError(LOGF_WARNINGS,Err,"_OnAccept() - DoAccept() failed.");
  2390. if (m_Origin->m_OriginD)
  2391. m_Origin->m_OriginD->SendMsg(425, "Can't build data connection. %s.", GetLastErrorText(Err));
  2392. CSocketException::Throw(this, "CFTPPassiveSock::_OnAccept()", Err, NULL);
  2393. }
  2394. LogMsg(LOGF_DEBUG,"OnAccept() - Data socket is connected to remote host.");
  2395. m_HasAccepted = TRUE;
  2396. return;
  2397. }
  2398. ///////////////////////////////////////////////////////////////////////////////
  2399. // FTP data Overlapped IO support
  2400. CFTPOverlapped::CFTPOverlapped()
  2401. {
  2402. m_Buffer = NULL;
  2403. m_KillMe = FALSE;
  2404. }
  2405. CFTPOverlapped::~CFTPOverlapped()
  2406. {
  2407. if (m_Buffer)
  2408. delete m_Buffer;
  2409. }
  2410. ///////////////////////////////////////////////////////////////////////////////////////
  2411. // CDaemonEvent
  2412. // Class to pass events from a module to a remote process.
  2413. CRegisteredEvents::CRegisteredEvents()
  2414. {
  2415. m_Event = 0;
  2416. }
  2417. CRegisteredEvents::~CRegisteredEvents()
  2418. {
  2419. LPVOID p;
  2420. while((p = m_ClientEventObjects.GetAndDeleteFirst()) != NULL)
  2421. delete p;
  2422. }
  2423. CLinkedList CDaemonEvent::m_DsEventRegister;
  2424. CDaemonEvent::CDaemonEvent(CTextSock *Socket, int MaxQueueItems)
  2425. {
  2426. m_MaxQueueItems = MaxQueueItems;
  2427. m_Client = Socket;
  2428. m_EventTypes = 0;
  2429. m_ClosePending = FALSE;
  2430. }
  2431. CDaemonEvent::~CDaemonEvent()
  2432. {
  2433. CLinkedListItem *Item;
  2434. m_EventQueue.KillAll();
  2435. Item = m_DsEventRegister.First();
  2436. CRegisteredEvents *pEv;
  2437. while(Item)
  2438. {
  2439. pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
  2440. if (pEv->m_Event & m_EventTypes)
  2441. {
  2442. pEv->m_ClientEventObjects.DeletePtr((LPVOID)this);
  2443. }
  2444. Item = m_DsEventRegister.Next(Item);
  2445. }
  2446. }
  2447. CRegisteredEvents *CDaemonEvent::FindRegisteredEvent(int EventType)
  2448. {
  2449. CLinkedListItem *Item = m_DsEventRegister.First();
  2450. CRegisteredEvents *pEv = NULL;
  2451. while(Item)
  2452. {
  2453. pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
  2454. if (pEv->m_Event & EventType)
  2455. return pEv;
  2456. Item = m_DsEventRegister.Next(Item);
  2457. }
  2458. return NULL;
  2459. }
  2460. HANDLE CDaemonEvent::DsRegister(int EventType, LPVOID pOrigin, 
  2461. void (* DsNotify)(LPVOID pOrigin, CDaemonEvent *pCliEv))
  2462. {
  2463. ASSERT(FindRegisteredEvent(EventType) == NULL);
  2464. CRegisteredEvents *pReg = new CRegisteredEvents;
  2465. pReg->m_Event = EventType;
  2466. pReg->m_DsNotify = DsNotify;
  2467. pReg->m_pOrigin = pOrigin;
  2468. m_DsEventRegister.AddLast((LPVOID)pReg);
  2469. return pReg;
  2470. }
  2471. BOOL CDaemonEvent::DsClose(HANDLE h)
  2472. {
  2473. if (h == INVALID_HANDLE_VALUE)
  2474. return FALSE;
  2475. CRegisteredEvents *pEv = (CRegisteredEvents *)h;
  2476. ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
  2477. m_DsEventRegister.DeletePtr(pEv);
  2478. delete pEv;
  2479. return TRUE;
  2480. }
  2481. // Send an event to all clients
  2482. BOOL CDaemonEvent::DsEvent(HANDLE h, LPCSTR EventMsg, BOOL Priority)
  2483. {
  2484. ASSERT(AfxIsValidString(EventMsg));
  2485. CRegisteredEvents *pEv = (CRegisteredEvents *)h;
  2486. ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
  2487. CLinkedListItem *Item = pEv->m_ClientEventObjects.First();
  2488. CString MyCs;
  2489. MyCs.Empty();
  2490. while(Item)
  2491. {
  2492. CDaemonEvent *pClientEvent = (CDaemonEvent *)pEv->m_ClientEventObjects.Ptr(Item);
  2493. ASSERT(AfxIsValidAddress(pClientEvent, sizeof(CDaemonEvent)));
  2494. Item = pEv->m_ClientEventObjects.Next(Item);
  2495. if (MyCs.IsEmpty())
  2496. MyCs.Format("%s%05d %03d %srn", OOB_HDR, strlen(EventMsg), pEv->m_Event, EventMsg);
  2497. pClientEvent->Event(h, EventMsg, Priority, &MyCs);
  2498. }
  2499. return TRUE;
  2500. }
  2501. // Send an event to the object event (one client)
  2502. BOOL CDaemonEvent::Event(HANDLE h, LPCSTR EventMsg, BOOL Priority, CString *MyCs)
  2503. {
  2504. ASSERT(AfxIsValidAddress(this, sizeof(CDaemonEvent)));
  2505. ASSERT(AfxIsValidString(EventMsg));
  2506. CRegisteredEvents *pEv = (CRegisteredEvents *)h;
  2507. ASSERT(AfxIsValidAddress(pEv,sizeof(CRegisteredEvents)));
  2508. if (m_EventQueue.GetItemCount() >= m_MaxQueueItems)
  2509. {
  2510. // Flooded.
  2511. CString *cs;
  2512. while(cs = (CString *)m_EventQueue.GetAndDeleteFirst())
  2513. delete cs;
  2514. cs = new CString("00000 000 rn"); // Close header.
  2515. m_EventQueue.AddFirst((LPVOID)cs); 
  2516. m_ClosePending = TRUE;
  2517. }
  2518. else
  2519. {
  2520. CString cBuf;
  2521. if (!MyCs)
  2522. {
  2523. MyCs = &cBuf;
  2524. MyCs->Format("%s%05d %03d %srn", OOB_HDR, strlen(EventMsg), pEv->m_Event, EventMsg);
  2525. }
  2526. if (Priority)
  2527. m_EventQueue.AddFirst((LPVOID) new CString( *MyCs));
  2528. else
  2529. m_EventQueue.AddLast((LPVOID) new CString (*MyCs));
  2530. TRY
  2531. {
  2532. Process();
  2533. }
  2534. CATCH (CUserException, e)
  2535. {
  2536. Close();
  2537. }
  2538. END_CATCH
  2539. }
  2540. return TRUE;
  2541. }
  2542. BOOL CDaemonEvent::Register(int EventType)
  2543. {
  2544. if (m_EventTypes & EventType)
  2545. return TRUE;
  2546. CLinkedListItem *Item = m_DsEventRegister.First();
  2547. CRegisteredEvents *pEv;
  2548. while(Item)
  2549. {
  2550. pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
  2551. if (pEv->m_Event & EventType)
  2552. {
  2553. m_EventTypes |= EventType;
  2554. pEv->m_ClientEventObjects.AddFirst((LPVOID)this);
  2555. if (pEv->m_DsNotify)
  2556. pEv->m_DsNotify(pEv->m_pOrigin, this);
  2557. }
  2558. Item = m_DsEventRegister.Next(Item);
  2559. }
  2560. return TRUE;
  2561. }
  2562. BOOL CDaemonEvent::Process()
  2563. {
  2564. while(!m_Client->m_SuspendEvents && m_Client->m_ClearToSend && m_EventQueue.GetItemCount())
  2565. {
  2566. CString *cs = (CString *)m_EventQueue.FirstPtr();
  2567. ASSERT(AfxIsValidString(*cs));
  2568. int nBytes = m_Client->CAsyncSocket::Send(*cs, cs->GetLength());
  2569. if (nBytes == SOCKET_ERROR)
  2570. {
  2571. if (m_Client->GetLastError() != WSAEWOULDBLOCK)
  2572. AfxThrowUserException();
  2573. if (m_Client->m_ClearToSend)
  2574. {
  2575. try
  2576. {
  2577. m_Client->Close();
  2578. }
  2579. catch(CSocketException *pExc)
  2580. {
  2581. if (!pExc->m_pSock->OnHandleWinsockErr(pExc->m_ErrorNum))
  2582. delete pExc->m_pSock;
  2583. delete pExc;
  2584. }
  2585. catch(...)
  2586. {
  2587. CLog::GetLog()->LogMsg(LOGF_ERROR,"CDaemonEvent::Process() - caught unknown exception.");
  2588. return FALSE;
  2589. }
  2590. }
  2591. return FALSE;
  2592. }
  2593. if (nBytes != cs->GetLength())
  2594. {
  2595. ASSERT(cs->GetLength() > 0);
  2596. LPSTR p = cs->GetBuffer(1);
  2597. memmove(p, p + nBytes, cs->GetLength() - nBytes);
  2598. p[cs->GetLength() - nBytes] = 0;
  2599. cs->ReleaseBuffer();
  2600. }
  2601. else
  2602. {
  2603. m_EventQueue.GetAndDeleteFirst();
  2604. delete cs;
  2605. }
  2606. }
  2607. if (m_ClosePending)
  2608. Close();
  2609. return m_Client->m_ClearToSend;
  2610. }
  2611. BOOL CDaemonEvent::Close()
  2612. {
  2613. return Close(-1);
  2614. }
  2615. BOOL CDaemonEvent::Close(int Events)
  2616. {
  2617. CLinkedListItem *Item = m_DsEventRegister.First();
  2618. CRegisteredEvents *pEv;
  2619. while(Item)
  2620. {
  2621. pEv = (CRegisteredEvents *)m_DsEventRegister.Ptr(Item);
  2622. if (pEv->m_Event & (m_EventTypes & Events))
  2623. {
  2624. pEv->m_ClientEventObjects.DeletePtr((LPVOID)this);
  2625. }
  2626. Item = m_DsEventRegister.Next(Item);
  2627. }
  2628. m_EventTypes &= ~Events;
  2629. m_ClosePending = FALSE;
  2630. CString *cs;
  2631. while(cs = (CString *)m_EventQueue.GetAndDeleteFirst())
  2632. delete cs;
  2633. return TRUE;
  2634. }
  2635. /////////////////////////////////////////////////////////////////////////
  2636. // CDNSLookup
  2637. CLinkedList CDNSLookup::m_List;
  2638. CDNSLookup::CDNSLookup()
  2639. {
  2640. m_ID = 0;
  2641. m_ReqHandle = 0;
  2642. m_QueryName.Empty();
  2643. m_LParam = NULL;
  2644. memset(m_Buf,0,MAXGETHOSTSTRUCT);
  2645. }
  2646. BOOL CDNSLookup::Create(CSock *pOrigin, LPCSTR Name, LPARAM LParam)
  2647. {
  2648. if (Name == NULL)
  2649. Name = pOrigin->m_PeerName;
  2650. m_ID = pOrigin->m_SocketID;
  2651. m_LParam = LParam;
  2652. m_QueryName = Name;
  2653. long inaddr = inet_addr(Name);
  2654. char addr[4];
  2655. memcpy(addr,&inaddr, 4);
  2656. ASSERT(pOrigin->m_DNSwin != NULL);
  2657. if (!pOrigin->m_DNSwin)
  2658. {
  2659. pOrigin->LogMsg(LOGF_ERROR,"CDNSLookup(%s) - APPLICATION ERROR: No DNS window.", Name);
  2660. goto error;
  2661. }
  2662. if (inaddr == INADDR_NONE)
  2663. {
  2664. m_ReqHandle = WSAAsyncGetHostByName(
  2665. pOrigin->m_DNSwin->m_hWnd,
  2666. WMU_TX_DNS,
  2667. Name,
  2668. m_Buf,
  2669. MAXGETHOSTSTRUCT);
  2670. }
  2671. else
  2672. {
  2673. m_ReqHandle = WSAAsyncGetHostByAddr(
  2674. pOrigin->m_DNSwin->m_hWnd,
  2675. WMU_TX_DNS,
  2676. addr,
  2677. 4,
  2678. PF_INET,
  2679. m_Buf,
  2680. MAXGETHOSTSTRUCT);
  2681. }
  2682. if (!m_ReqHandle)
  2683. {
  2684. pOrigin->LogMsg(LOGF_ERROR,"CDNSLookup(%s) - WSAAsyncGetHostByAddr failed.",
  2685. pOrigin->m_PeerName);
  2686. error:
  2687. pOrigin->OnDNSLookup(-1, this);
  2688. delete this;
  2689. return FALSE;
  2690. }
  2691. m_List.AddLast((LPVOID)this);
  2692. return TRUE;
  2693. }
  2694. CDNSLookup::~CDNSLookup()
  2695. {
  2696. m_List.DeletePtr((LPVOID)this);
  2697. }
  2698. void CDNSLookup::DNSlookupCallback(WPARAM Handle, LPARAM Status)
  2699. {
  2700. CLinkedListItem *Item = m_List.First();
  2701. CDNSLookup *pItem;
  2702. CSock *pSock;
  2703. while(Item)
  2704. {
  2705. pItem = (CDNSLookup *)m_List.Ptr(Item);
  2706. Item = m_List.Next(Item);
  2707. if (pItem->m_ReqHandle == (HANDLE)Handle)
  2708. {
  2709. pSock = CSock::GetFromID(pItem->m_ID);
  2710. if (pSock)
  2711. pSock->OnDNSLookup(HIWORD(Status), pItem);
  2712. delete pItem;
  2713. break;
  2714. }
  2715. }
  2716. }