?? ftpserver.cpp
字號:
// 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 + -