⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpserver.cpp

📁 TinyFtpServer 网上的Ftp客户端的工具很多
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// FtpServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string.h>
#include <ws2tcpip.h>
#include <stdlib.h>

#define FTP_PORT        21     // FTP 控制端口
#define DATA_FTP_PORT   20     // FTP 数据端口
#define DATA_BUFSIZE    8192
#define MAX_NAME_LEN    128
#define MAX_PWD_LEN     128
#define MAX_RESP_LEN    1024
#define MAX_REQ_LEN     256
#define MAX_ADDR_LEN    80

#define WSA_RECV         0
#define WSA_SEND         1

#define USER_OK         331
#define LOGGED_IN       230
#define LOGIN_FAILED    530
#define CMD_OK          200
#define OPENING_AMODE   150
#define TRANS_COMPLETE  226
#define CANNOT_FIND     550
#define FTP_QUIT        221
#define CURR_DIR        257
#define DIR_CHANGED     250
#define OS_TYPE         215
#define REPLY_MARKER    504
#define PASSIVE_MODE    227

#define DEFAULT_USER		"tinyle"
#define DEFAULT_PASS		"751022"
#define DEFAULT_HOME_DIR    "C:\\TEMP"
#define DEFAULT_HOME_DIR_U  "/c:/temp"
#define MAX_FILE_NUM        1024

#define MODE_PORT       0
#define MODE_PASV       1

#define PORT_BIND   1821

typedef struct _SOCKET_INFO {
   CHAR   buffRecv[DATA_BUFSIZE];
   CHAR   buffSend[DATA_BUFSIZE];
   WSABUF wsaBuf;
   SOCKET s;
   WSAOVERLAPPED o;
   DWORD dwBytesSend;
   DWORD dwBytesRecv;
   int   nStatus;
} SOCKET_INFO, *LPSOCKET_INFO;

typedef struct _FILE_INFO {
	TCHAR    szFileName[MAX_PATH];
	DWORD    dwFileAttributes; 
    FILETIME ftCreationTime; 
    FILETIME ftLastAccessTime; 
    FILETIME ftLastWriteTime; 
    DWORD    nFileSizeHigh; 
    DWORD    nFileSizeLow; 
} FILE_INFO, *LPFILE_INFO;

DWORD WINAPI ProcessIO( LPVOID lpParam ) ;
BOOL  Welcome( SOCKET s );
int LoginSvr( LPSOCKET_INFO pSocketInfo  );
int SendResponse( LPSOCKET_INFO pSI );
int RecvRequest( LPSOCKET_INFO pSI );

int ParseCommand( LPSOCKET_INFO pSI );

DWORD g_dwEventTotal = 0;
DWORD g_index;
WSAEVENT g_events[WSA_MAXIMUM_WAIT_EVENTS];
LPSOCKET_INFO g_sockets[WSA_MAXIMUM_WAIT_EVENTS];
CRITICAL_SECTION g_cs;  
char  g_szLocalAddr[MAX_ADDR_LEN]; 

BOOL  g_bLoggedIn;
///////////////////////////////////////////////////////////////////////////////////////////
// Assistant function
char* GetLocalAddress()
{
    struct in_addr *pinAddr;
    LPHOSTENT	lpHostEnt;
	int			nRet;
	int			nLen;
	char        szLocalAddr[80];
	ZeroMemory( szLocalAddr,sizeof(szLocalAddr) );

	//
	// Get our local name
	//
    nRet = gethostname(szLocalAddr,sizeof(szLocalAddr) );
	if (nRet == SOCKET_ERROR) {
		return NULL;
	}

	//
	// "Lookup" the local name
	//
	lpHostEnt = gethostbyname(szLocalAddr);
    if (NULL == lpHostEnt)	{
		return NULL;
	}

	//
    // Format first address in the list
	//
	pinAddr = ((LPIN_ADDR)lpHostEnt->h_addr);
	nLen = strlen(inet_ntoa(*pinAddr));
	if ((DWORD)nLen > sizeof(szLocalAddr)) {
		WSASetLastError(WSAEINVAL);
		return NULL;
	}

	return inet_ntoa(*pinAddr);
}
int GetFileList( LPFILE_INFO pFI, UINT nArraySize, const char* szPath  )
{
	WIN32_FIND_DATA  wfd;
	int idx = 0;
	CHAR lpFileName[MAX_PATH];
	GetCurrentDirectory( MAX_PATH,lpFileName );
	strcat( lpFileName,"\\" );
	strcat( lpFileName, szPath );
	HANDLE hFile = FindFirstFile( lpFileName, &wfd );
	if ( hFile != INVALID_HANDLE_VALUE ) {
		pFI[idx].dwFileAttributes = wfd.dwFileAttributes;
		lstrcpy( pFI[idx].szFileName, wfd.cFileName );
		pFI[idx].ftCreationTime = wfd.ftCreationTime;
		pFI[idx].ftLastAccessTime = wfd.ftLastAccessTime;
		pFI[idx].ftLastWriteTime  = wfd.ftLastWriteTime;
		pFI[idx].nFileSizeHigh    = wfd.nFileSizeHigh;
		pFI[idx++].nFileSizeLow   = wfd.nFileSizeLow;
		while( FindNextFile( hFile,&wfd ) && idx < (int)nArraySize ) {
			pFI[idx].dwFileAttributes = wfd.dwFileAttributes;
			lstrcpy( pFI[idx].szFileName, wfd.cFileName );
			pFI[idx].ftCreationTime = wfd.ftCreationTime;
			pFI[idx].ftLastAccessTime = wfd.ftLastAccessTime;
			pFI[idx].ftLastWriteTime  = wfd.ftLastWriteTime;
			pFI[idx].nFileSizeHigh    = wfd.nFileSizeHigh;
			pFI[idx++].nFileSizeLow   = wfd.nFileSizeLow;
		}
		FindClose( hFile );
	}

	return idx;
}
char* Back2Slash( char* szPath ) 
{
	int idx = 0;
	if( NULL == szPath ) return NULL;
	strlwr( szPath );
	while( szPath[idx] ) { 
		if( szPath[idx] == '\\' )
			szPath[idx] = '/';
		idx ++;
	}
	return szPath;
}
char* Slash2Back( char* szPath )
{
	int idx = 0;
	if( NULL == szPath ) return NULL;
	strlwr( szPath );
	while( szPath[idx] ) { 
		if( '/' = szPath[idx]  )
			szPath[idx] = '\\';
		idx ++;
	}
	return szPath;
}
char* RelativeDirectory( char* szDir )
{
	int nStrLen = strlen(DEFAULT_HOME_DIR);
	if( !strnicmp( szDir,DEFAULT_HOME_DIR, nStrLen ) ) 
		szDir += nStrLen;

	if( szDir && szDir[0] == '\0' ) szDir = "/";
	
	return Back2Slash(szDir);
}
char* AbsoluteDirectory( char* szDir )
{
	char szTemp[MAX_PATH];
	strcpy( szTemp,DEFAULT_HOME_DIR+2 );
	if( NULL == szDir ) return NULL;
	if( '/' == szDir[0] )
		strcat( szTemp, szDir );
	szDir = szTemp ;
	
	return Slash2Back(szDir);
}
///////////////////////////////////////////////////////////////////////////////////////////
// start main function
void main(void)
{
   WSADATA wsaData;
   SOCKET sListen, sAccept;
   SOCKADDR_IN inetAddr;
   DWORD dwFlags;
   DWORD dwThreadId;
   DWORD dwRecvBytes;
   INT   nRet;

   InitializeCriticalSection(&g_cs);

   if (( nRet = WSAStartup(0x0202,&wsaData)) != 0 ) {
      printf("WSAStartup failed with error %d\n", nRet);
      return;
   }

   // 先取得本地地址
   sprintf( g_szLocalAddr,"%s",GetLocalAddress() );

   if ((sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 
      WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
   {
      printf("Failed to get a socket %d\n", WSAGetLastError());
	  WSACleanup();
      return;
   }

   inetAddr.sin_family = AF_INET;
   inetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   inetAddr.sin_port = htons(FTP_PORT);

   if (bind(sListen, (PSOCKADDR) &inetAddr, sizeof(inetAddr)) == SOCKET_ERROR)
   {
      printf("bind() failed with error %d\n", WSAGetLastError());
      return;
   }

   if (listen(sListen, SOMAXCONN))
   {
      printf("listen() failed with error %d\n", WSAGetLastError());
      return;
   }

   // Setup the listening socket for connections.

   if ((sAccept = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
      WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
   {
      printf("Failed to get a socket %d\n", WSAGetLastError());
      return;
   }

   // Create a manual reset object with an initial state of 
   // nonsignaled
   if ((g_events[0] = WSACreateEvent()) == WSA_INVALID_EVENT)
   {
      printf("WSACreateEvent failed with error %d\n", WSAGetLastError());
      return;
   }

   // Create a thread to service overlapped requests
   if (CreateThread(NULL, 0, ProcessIO, NULL, 0, &dwThreadId) == NULL)
   {
      printf("CreateThread failed with error %d\n", GetLastError());
      return;
   } 

   g_dwEventTotal = 1;

   while(TRUE)
   {
       // Accept inbound connections

      if ((sAccept = accept(sListen, NULL, NULL)) == INVALID_SOCKET)
      {
          printf("accept failed with error %d\n", WSAGetLastError());
          return;
      }

	  if( !Welcome( sAccept ) ) break;
	  if( !SetCurrentDirectory( DEFAULT_HOME_DIR ) ) break;

      EnterCriticalSection(&g_cs);

      // Create a socket information structure to associate with the accepted socket.

      if ((g_sockets[g_dwEventTotal] = (LPSOCKET_INFO) GlobalAlloc(GPTR,
         sizeof(SOCKET_INFO))) == NULL)
      {
         printf("GlobalAlloc() failed with error %d\n", GetLastError());
         return;
      } 

      // Fill in the details of our accepted socket.
	  char buff[DATA_BUFSIZE]; ZeroMemory( buff,DATA_BUFSIZE );
	  g_sockets[g_dwEventTotal]->wsaBuf.buf = buff;  
	  g_sockets[g_dwEventTotal]->wsaBuf.len = DATA_BUFSIZE;
      g_sockets[g_dwEventTotal]->s = sAccept;
      ZeroMemory(&(g_sockets[g_dwEventTotal]->o), sizeof(OVERLAPPED));
      g_sockets[g_dwEventTotal]->dwBytesSend = 0;
      g_sockets[g_dwEventTotal]->dwBytesRecv = 0;
	  g_sockets[g_dwEventTotal]->nStatus     = WSA_RECV;    // 接收
     
     
      if ((g_sockets[g_dwEventTotal]->o.hEvent = g_events[g_dwEventTotal] = 
          WSACreateEvent()) == WSA_INVALID_EVENT)
      {
         printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());
         return;
      }

      // Post a WSARecv request to to begin receiving data on the socket

      dwFlags = 0;
      if (WSARecv(g_sockets[g_dwEventTotal]->s, 
         &(g_sockets[g_dwEventTotal]->wsaBuf), 1, &dwRecvBytes, &dwFlags,
         &(g_sockets[g_dwEventTotal]->o), NULL) == SOCKET_ERROR)
      {
         if (WSAGetLastError() != ERROR_IO_PENDING)
         {
            printf("WSARecv() failed with error %d\n", WSAGetLastError());
            return;
         }
      }

      g_dwEventTotal++;

      LeaveCriticalSection(&g_cs);

      //
      // Signal the first event in the event array to tell the worker thread to
      // service an additional event in the event array
      //
      if (WSASetEvent(g_events[0]) == FALSE)
      {
         printf("WSASetEvent failed with error %d\n", WSAGetLastError());
         return;
      }
   }
}


DWORD WINAPI ProcessIO(LPVOID lpParameter)
{
   
   DWORD dwFlags;
   LPSOCKET_INFO pSI;
   DWORD dwBytesTransferred;
   DWORD i;
  
   // Process asynchronous WSASend, WSARecv requests.

   while(TRUE)
   {
      if ((g_index = WSAWaitForMultipleEvents(g_dwEventTotal, g_events, FALSE,
         WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)
      {
         printf("WSAWaitForMultipleEvents failed %d\n", WSAGetLastError());
         return 0;
      } 

      // If the event triggered was zero then a connection attempt was made
      // on our listening socket.
 
      if ((g_index - WSA_WAIT_EVENT_0) == 0)
      {
         WSAResetEvent(g_events[0]);
         continue;
      }

      pSI = g_sockets[g_index - WSA_WAIT_EVENT_0];
      WSAResetEvent(g_events[g_index - WSA_WAIT_EVENT_0]);

      if (WSAGetOverlappedResult(pSI->s, &(pSI->o), &dwBytesTransferred,
         FALSE, &dwFlags) == FALSE || dwBytesTransferred == 0)
      {
         printf("Closing socket %d\n", pSI->s);

         if (closesocket(pSI->s) == SOCKET_ERROR)
         {
            printf("closesocket() failed with error %d\n", WSAGetLastError());
         }

         GlobalFree(pSI);
         WSACloseEvent(g_events[g_index - WSA_WAIT_EVENT_0]);

         // Cleanup g_sockets and g_events by removing the socket event handle
         // and socket information structure if they are not at the end of the
         // arrays.

         EnterCriticalSection(&g_cs);

         if ((g_index - WSA_WAIT_EVENT_0) + 1 != g_dwEventTotal)
            for (i = g_index - WSA_WAIT_EVENT_0; i < g_dwEventTotal; i++) {
               g_events[i] = g_events[i + 1];
			   g_sockets[i] = g_sockets[i + 1];
            }

         g_dwEventTotal--;

         LeaveCriticalSection(&g_cs);

         continue;
      }
	  //
	  // 已经有数据传递
	  //
	  if( pSI->nStatus == WSA_RECV ) {
		  memcpy( &pSI->buffRecv[pSI->dwBytesRecv],pSI->wsaBuf.buf,dwBytesTransferred);
		  pSI->dwBytesRecv += dwBytesTransferred;
		  printf( "RECV:%s\n",pSI->buffRecv);
		  if( pSI->buffRecv[pSI->dwBytesRecv-2] == '\r'      // 要保证最后是\r\n
				&& pSI->buffRecv[pSI->dwBytesRecv-1] == '\n' 
				&& pSI->dwBytesRecv > 2 )  {                 
		
			 if( !g_bLoggedIn ) {
				if( LoginSvr(pSI) == LOGGED_IN )
					g_bLoggedIn = TRUE;
			 } else {
				  ParseCommand( pSI );
			 }
			 // 初始化缓冲区内容
			 ZeroMemory( pSI->buffRecv,sizeof(pSI->buffRecv) );
			 pSI->dwBytesRecv = 0;
		  }
	  } else {
		  pSI->dwBytesSend += dwBytesTransferred;
	  }
	  //
 	  // 继续接收以后到来的数据
	  //
	  if( RecvRequest( pSI ) == -1 ) 
		  return -1; 
   }
   return 0;
}
// 由于只是简单的出现一个登录信息,直接用send就可以了
// 不必用WSASend来进行I/O Overlapped处理

int SendResponse( LPSOCKET_INFO pSI )
{
	// Post WSASend() request.
    // Since WSASend() is not gauranteed to send all of the bytes requested,
    // continue posting WSASend() calls until all received bytes are sent.

	static DWORD dwSendBytes = 0;

	pSI->nStatus = WSA_SEND;
    
    ZeroMemory(&(pSI->o), sizeof(WSAOVERLAPPED));
    pSI->o.hEvent = g_events[g_index - WSA_WAIT_EVENT_0];

    pSI->wsaBuf.buf = pSI->buffSend + pSI->dwBytesSend;
    pSI->wsaBuf.len = strlen( pSI->buffSend ) - pSI->dwBytesSend;

    if (WSASend(pSI->s, &(pSI->wsaBuf), 1, &dwSendBytes, 0,
        &(pSI->o), NULL) == SOCKET_ERROR) {
        if (WSAGetLastError() != ERROR_IO_PENDING) {
			printf("WSASend() failed with error %d\n", WSAGetLastError());
			return -1;
        }
    }

	return 0;
}
int RecvRequest( LPSOCKET_INFO pSI )
{
	static DWORD dwRecvBytes = 0;
	
	pSI->nStatus = WSA_RECV;
	
	// Now that there are no more bytes to send post another WSARecv() request.
	DWORD dwFlags = 0;
	ZeroMemory(&(pSI->o), sizeof(WSAOVERLAPPED));
	pSI->o.hEvent = g_events[g_index - WSA_WAIT_EVENT_0];

	pSI->wsaBuf.len = DATA_BUFSIZE;
//	pSI->wsaBuf.buf = pSI->buffRecv;

	if (WSARecv(pSI->s, &(pSI->wsaBuf), 1, &dwRecvBytes, &dwFlags,
		&(pSI->o), NULL) == SOCKET_ERROR) {
		if (WSAGetLastError() != ERROR_IO_PENDING) {
		   printf("WSARecv() failed with error %d\n", WSAGetLastError());
		   return -1;
		}
	}

	return 0;
}
//
// Print Welcome message 
//
BOOL Welcome( SOCKET s )
{
	char* szWelcome = "220 欢迎您登录到tinyFtp Server...\r\n";
	if( send( s,szWelcome,strlen(szWelcome),0 ) == SOCKET_ERROR ) {
		printf("Ftp client error:%d\n", WSAGetLastError() );
		return FALSE;
	}
	// 因为刚进来,还没连接,故
	g_bLoggedIn = FALSE;
	return TRUE;
}
int LoginSvr( LPSOCKET_INFO pSocketInfo  )
{
	const char* szUserOK = "331 User name okay, need password.\r\n"; 
	const char* szLoggedIn = "230 User logged in, proceed.\r\n";

	int  nRetVal = 0;
	static char szUser[MAX_NAME_LEN], szPwd[MAX_PWD_LEN];
	LPSOCKET_INFO pSI = pSocketInfo;
	if( strstr(strupr(pSI->buffRecv),"USER") ) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -