📄 ftpserver.cpp
字号:
// 取得登陆用户名
sprintf(szUser,"%s",pSI->buffRecv+strlen("USER")+1);
strtok( szUser,"\r\n");
// 响应信息
sprintf(pSI->buffSend,"%s",szUserOK );
if( SendResponse(pSI) == -1 ) return -1;
// if( RecvRequest(pSI) == -1 ) return -1;
return USER_OK;
}
if( strstr(strupr(pSI->buffRecv),"PASS") || strstr(pSI->buffRecv,"pass") ) {
sprintf(szPwd,"%s",pSI->buffRecv+strlen("PASS")+1 );
strtok( szPwd,"\r\n");
// 用户名跟口令都正确吗?
if( stricmp( szPwd,DEFAULT_PASS) || stricmp(szUser,DEFAULT_USER) ) {
sprintf(pSI->buffSend,"530 User %s cannot log in.\r\n",szUser );
printf("User %s cannot log in\n",szUser );
nRetVal = LOGIN_FAILED;
} else {
sprintf(pSI->buffSend,"%s",szLoggedIn);
printf("User %s logged in\n",szUser );
nRetVal = LOGGED_IN;
}
if( SendResponse( pSI ) == -1 ) return -1;
}
return nRetVal;
}
char* ConvertCommaAddress( char* szAddress, WORD wPort )
{
char szPort[10];
sprintf( szPort,"%d,%d",wPort/256,wPort%256 );
char szIpAddr[20];
sprintf( szIpAddr,"%s,",szAddress );
int idx = 0;
while( szIpAddr[idx] ) {
if( szIpAddr[idx] == '.' )
szIpAddr[idx] = ',';
idx ++;
}
sprintf( szAddress,"%s%s",szIpAddr,szPort );
return szAddress;
}
int ConvertDotAddress( char* szAddress, LPDWORD pdwIpAddr, LPWORD pwPort )
{
int idx = 0,i = 0, iCount = 0;
char szIpAddr[MAX_ADDR_LEN]; ZeroMemory( szIpAddr,sizeof(szIpAddr) );
char szPort[MAX_ADDR_LEN]; ZeroMemory( szPort, sizeof(szPort) );
*pdwIpAddr = 0; *pwPort = 0;
while( szAddress[idx] ) {
if( szAddress[idx] == ',' ) {
iCount ++;
szAddress[idx] ='.';
}
if( iCount < 4 )
szIpAddr[idx] = szAddress[idx];
else
szPort[i++] = szAddress[idx];
idx++;
}
if( iCount != 5 ) return -1;
*pdwIpAddr = inet_addr( szIpAddr );
if( *pdwIpAddr == INADDR_NONE ) return -1;
char *pToken = strtok( szPort+1,"." );
if( pToken == NULL ) return -1;
*pwPort = (WORD)(atoi(pToken) * 256);
pToken = strtok(NULL,".");
if( pToken == NULL ) return -1;
*pwPort += (WORD)atoi(pToken);
return 0;
}
UINT FileListToString( char* buff, UINT nBuffSize,BOOL bDetails )
{
FILE_INFO fi[MAX_FILE_NUM];
int nFiles = GetFileList( fi, MAX_FILE_NUM, "*.*" );
char szTemp[128];
sprintf( buff,"%s","" );
if( bDetails ) {
for( int i=0; i<nFiles; i++) {
if( strlen(buff)>nBuffSize-128 ) break;
if(!strcmp(fi[i].szFileName,".")) continue;
if(!strcmp(fi[i].szFileName,"..")) continue;
// 时间
SYSTEMTIME st;
FileTimeToSystemTime(&(fi[i].ftLastWriteTime), &st);
char *szNoon = "AM";
if( st.wHour > 12 ) { st.wHour -= 12; szNoon = "PM"; }
if( st.wYear >= 2000 ) st.wYear -= 2000;
else st.wYear -= 1900;
sprintf( szTemp,"%02u-%02u-%02u %02u:%02u%s ",
st.wMonth,st.wDay,st.wYear,st.wHour,st.wMonth,szNoon );
strcat( buff,szTemp );
if( fi[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ){
strcat(buff,"<DIR>");
strcat(buff," ");
} else {
strcat(buff," ");
// 文件大小
sprintf( szTemp,"% 9d ",fi[i].nFileSizeLow );
strcat( buff,szTemp );
}
// 文件名
strcat( buff,fi[i].szFileName );
strcat( buff,"\r\n");
}
} else {
for( int i=0; i<nFiles; i++) {
if( strlen(buff) + strlen( fi[i].szFileName ) + 2 < nBuffSize ) {
strcat( buff, fi[i].szFileName );
strcat( buff, "\r\n");
} else break;
}
}
return strlen( buff );
}
DWORD ReadFileToBuffer( const char* szFile, char *buff, DWORD nFileSize )
{
DWORD idx = 0;
DWORD dwBytesLeft = nFileSize;
DWORD dwNumOfBytesRead = 0;
char lpFileName[MAX_PATH];
GetCurrentDirectory( MAX_PATH,lpFileName );
strcat( lpFileName,"\\" );
strcat(lpFileName,szFile );
HANDLE hFile = CreateFile( lpFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( hFile != INVALID_HANDLE_VALUE ) {
while( dwBytesLeft > 0 ) {
if( !ReadFile( hFile,&buff[idx],dwBytesLeft,&dwNumOfBytesRead,NULL ) ) {
printf("读文件出错.\n");
CloseHandle( hFile );
return 0;
}
idx += dwNumOfBytesRead;
dwBytesLeft -= dwNumOfBytesRead;
}
CloseHandle( hFile );
}
return idx;
}
DWORD WriteToFile( SOCKET s , const char* szFile )
{
DWORD idx = 0;
DWORD dwNumOfBytesWritten = 0;
DWORD nBytesLeft = DATA_BUFSIZE;
char buf[DATA_BUFSIZE];
char lpFileName[MAX_PATH];
GetCurrentDirectory( MAX_PATH,lpFileName );
strcat( lpFileName,"\\" );
strcat(lpFileName,szFile );
HANDLE hFile = CreateFile( lpFileName,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( hFile == INVALID_HANDLE_VALUE ) {
printf("打开文件出错.\n");
return 0;
}
while( TRUE ) {
int nBytesRecv = 0;
idx = 0; nBytesLeft = DATA_BUFSIZE;
while( nBytesLeft > 0 ) {
nBytesRecv = recv( s,&buf[idx],nBytesLeft,0 );
if( nBytesRecv == SOCKET_ERROR ) {
printf("Failed to send buffer to socket %d\n",WSAGetLastError() );
return -1;
}
if( nBytesRecv == 0 ) break;
idx += nBytesRecv;
nBytesLeft -= nBytesRecv;
}
nBytesLeft = idx; // 要写入文件中的字节数
idx = 0; // 索引清0,指向开始位置
while( nBytesLeft > 0 ) {
// 移动文件指针到文件末尾
if( !SetEndOfFile(hFile) ) return 0;
if( !WriteFile( hFile,&buf[idx],nBytesLeft,&dwNumOfBytesWritten,NULL ) ) {
printf("写文件出错.\n");
CloseHandle( hFile );
return 0;
}
idx += dwNumOfBytesWritten;
nBytesLeft -= dwNumOfBytesWritten;
}
// 如果没有数据可接收,退出循环
if( nBytesRecv == 0 ) break;
}
CloseHandle( hFile );
return idx;
}
int CombindFileNameSize( const char* szFileName,char* szFileNS )
{
// 假定文件的大小不超过4GB,只处理低位
int nFileSize = -1;
FILE_INFO fi[1];
int nFiles = GetFileList( fi,1,szFileName );
if( nFiles != 1 ) return -1;
sprintf( szFileNS, "%s<%d bytes>",szFileName,fi[0].nFileSizeLow );
nFileSize = fi[0].nFileSizeLow;
return nFileSize;
}
int DataConn( SOCKET& s, DWORD dwIp, WORD wPort, int nMode )
{
// 创建一个socket
s = socket( AF_INET,SOCK_STREAM,0 );
if( s == INVALID_SOCKET ) {
printf("Failed to get a socket %d\n", WSAGetLastError());
return -1;
}
struct sockaddr_in inetAddr;
inetAddr.sin_family = AF_INET;
if( nMode == MODE_PASV ) {
inetAddr.sin_port = htons( wPort );
inetAddr.sin_addr.s_addr = dwIp;
} else {
inetAddr.sin_port = htons( DATA_FTP_PORT );
inetAddr.sin_addr.s_addr = inet_addr( GetLocalAddress() );
}
BOOL optval = TRUE;
if( setsockopt(s,SOL_SOCKET,SO_REUSEADDR,
(char*)&optval,sizeof(optval) ) == SOCKET_ERROR ) {
printf("Failed to setsockopt %d.\n",WSAGetLastError() );
closesocket(s);
return -1;
}
if( bind( s,(struct sockaddr*)&inetAddr,sizeof(inetAddr)) == SOCKET_ERROR ) {
printf("Failed to bind a socket %d.\n",WSAGetLastError() );
closesocket(s);
return -1;
}
if( MODE_PASV == nMode ) {
if( listen( s,SOMAXCONN ) == SOCKET_ERROR ) {
printf("Failed to listen a socket %d.\n",WSAGetLastError() );
closesocket(s);
return -1;
}
} else if( MODE_PORT == nMode ) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons( wPort );
addr.sin_addr.s_addr = dwIp;
if( connect( s, (const sockaddr*)&addr,sizeof(addr) ) == SOCKET_ERROR ) {
printf("Failed to connect a socket %d\n",WSAGetLastError() );
closesocket( s );
return -1;
}
}
return 0;
}
int DataSend( SOCKET s, char* buff,int nBufSize )
{
int nBytesLeft = nBufSize;
int idx = 0, nBytes = 0;
while( nBytesLeft > 0 ) {
nBytes = send( s,&buff[idx],nBytesLeft,0);
if( nBytes == SOCKET_ERROR ) {
printf("Failed to send buffer to socket %d\n",WSAGetLastError() );
closesocket( s );
return -1;
}
nBytesLeft -= nBytes;
idx += nBytes;
}
return idx;
}
int DataRecv( SOCKET s, const char* szFileName )
{
return WriteToFile( s, szFileName );
}
SOCKET DataAccept( SOCKET& s )
{
SOCKET sAccept = accept( s ,NULL,NULL );
if( sAccept != INVALID_SOCKET ) {
closesocket( s );
}
return sAccept;
}
int ParseCommand( LPSOCKET_INFO pSI )
{
int nRetVal = 0;
static SOCKET sAccept = INVALID_SOCKET;
static SOCKET s = INVALID_SOCKET;
static BOOL bPasv = FALSE;
char szCmd[MAX_REQ_LEN];
char szCurrDir[MAX_PATH];
strcpy( szCmd, pSI->buffRecv );
if( strtok( szCmd," \r\n") == NULL ) return -1;
strupr( szCmd );
const char* szOpeningAMode = "150 Opening ASCII mode data connection for ";
static DWORD dwIpAddr = 0;
static WORD wPort = 0;
// ?PORT n1,n2,n3,n4,n5,n6
if( strstr(szCmd,"PORT") ) {
if( ConvertDotAddress( pSI->buffRecv+strlen("PORT")+1,&dwIpAddr,&wPort) == -1 )
return -1;
const char* szPortCmdOK = "200 PORT Command successful.\r\n";
sprintf(pSI->buffSend,"%s",szPortCmdOK );
if( SendResponse( pSI ) == -1 ) return -1;
bPasv = FALSE;
return CMD_OK;
}
if( strstr( szCmd,"PASV") ) {
if( DataConn( s, htonl(INADDR_ANY), PORT_BIND, MODE_PASV ) == -1 )
return -1;
char *szCommaAddress = ConvertCommaAddress( GetLocalAddress(),PORT_BIND );
sprintf( pSI->buffSend,"227 Entering Passive Mode (%s).\r\n",szCommaAddress );
if( SendResponse( pSI ) == -1 )
return -1;
// sAccept = accept( s ,NULL,NULL );
// if( sAccept != INVALID_SOCKET ) {
// closesocket( s );
// }
bPasv = TRUE;
return PASSIVE_MODE;
}
// if( RecvRequest(pSI) == -1 ) return -1;
if( strstr( szCmd, "NLST") || strstr( szCmd,"LIST") ) {
if( bPasv ) sAccept = DataAccept( s );
if( !bPasv )
sprintf(pSI->buffSend,"%s/bin/ls.\r\n",szOpeningAMode );
else {
strcpy(pSI->buffSend,"125 Data connection already open; Transfer starting.\r\n");
}
if( SendResponse( pSI ) == -1 )
return -1;
// 取得文件列表信息,并转换成字符串
BOOL bDetails = strstr(szCmd,"LIST")?TRUE:FALSE;
char buff[DATA_BUFSIZE];
UINT nStrLen = FileListToString( buff,sizeof(buff),bDetails);
if( !bPasv ) {
if( DataConn( s,dwIpAddr,wPort,MODE_PORT ) == -1 )
return -1;
if( DataSend( s, buff,nStrLen ) == -1 )
return -1;
closesocket(s);
} else {
DataSend( sAccept,buff,nStrLen );
closesocket( sAccept );
}
sprintf( pSI->buffSend,"%s","226 Transfer complete.\r\n" );
if( SendResponse( pSI ) == -1 )
return -1;
return TRANS_COMPLETE;
}
if( strstr( szCmd, "RETR") ) {
if( bPasv ) sAccept = DataAccept(s);
char szFileNS[MAX_PATH];
char *szFile = strtok( NULL," \r\n" );
int nFileSize = CombindFileNameSize( szFile,szFileNS );
if( nFileSize == -1 ) {
sprintf( pSI->buffSend,"550 %s: 系统找不到指定的文件.\r\n",szFile);
if( SendResponse( pSI ) == -1 )
return -1;
if( !bPasv ) closesocket( sAccept );
else closesocket( s );
return CANNOT_FIND;
}
else
sprintf(pSI->buffSend,"%s%s.\r\n",szOpeningAMode,szFileNS);
if( SendResponse( pSI ) == -1 )
return -1;
char* buff = new char[nFileSize];
if( NULL = buff ) {
printf("Not enough memory error!\n");
return -1;
}
if( ReadFileToBuffer( szFile,buff, nFileSize ) == (DWORD)nFileSize ) {
// 处理Data FTP连接
Sleep( 10 );
if( bPasv ) {
DataSend( sAccept,buff,nFileSize );
closesocket( sAccept );
} else {
if( DataConn( s,dwIpAddr,wPort,MODE_PORT ) == -1 )
return -1;
DataSend( s, buff, nFileSize );
closesocket( s );
}
}
if( buff != NULL )
delete[] buff;
sprintf( pSI->buffSend,"%s","226 Transfer complete.\r\n" );
if( SendResponse( pSI ) == -1 )
return -1;
return TRANS_COMPLETE;
}
if( strstr( szCmd, "STOR") ) {
if( bPasv ) sAccept = DataAccept(s);
char *szFile = strtok( NULL," \r\n" );
if( NULL == szFile ) return -1;
sprintf(pSI->buffSend,"%s%s.\r\n",szOpeningAMode,szFile);
if( SendResponse( pSI ) == -1 )
return -1;
// char buff[DATA_BUFSIZE];
// 处理Data FTP连接
if( bPasv )
DataRecv( sAccept,szFile );
else {
if( DataConn( s,dwIpAddr,wPort,MODE_PORT ) == -1 )
return -1;
DataRecv( s, szFile );
}
sprintf( pSI->buffSend,"%s","226 Transfer complete.\r\n" );
if( SendResponse( pSI ) == -1 )
return -1;
return TRANS_COMPLETE;
}
if( strstr( szCmd,"QUIT" ) ) {
sprintf( pSI->buffSend,"%s","221 Good bye,欢迎下次再来.\r\n" );
if( SendResponse( pSI ) == -1 )
return -1;
return FTP_QUIT;
}
if( strstr( szCmd,"XPWD" ) || strstr( szCmd,"PWD") ) {
GetCurrentDirectory( MAX_PATH,szCurrDir );
sprintf( pSI->buffSend,"257 \"%s\" is current directory.\r\n",
RelativeDirectory(szCurrDir) );
if( SendResponse( pSI ) == -1 ) return -1;
return CURR_DIR;
}
if( strstr( szCmd,"CWD" ) || strstr(szCmd,"CDUP") ) {
char *szDir = strtok( NULL,"\r\n" );
if( szDir == NULL ) szDir = "\\";
char szSetDir[MAX_PATH];
if( strstr(szCmd,"CDUP") ) {
strcpy(szSetDir,"..");
} else {
strcpy(szSetDir,AbsoluteDirectory( szDir ) );
}
if( !SetCurrentDirectory( szSetDir ) ) {
sprintf(szCurrDir,"\\%s",szSetDir);
sprintf( pSI->buffSend,"550 %s No such file or Directory.\r\n",
RelativeDirectory(szCurrDir) );
nRetVal = CANNOT_FIND;
} else {
GetCurrentDirectory( MAX_PATH,szCurrDir );
sprintf( pSI->buffSend,"250 Directory changed to /%s.\r\n",
RelativeDirectory(szCurrDir) );
nRetVal = DIR_CHANGED;
}
if( SendResponse( pSI ) == -1 ) return -1;
return nRetVal;
}
if( strstr( szCmd,"SYST" ) ) {
sprintf( pSI->buffSend,"%s","215 Windows_NT Version 4.0\r\n");
if( SendResponse( pSI ) == -1 ) return -1;
return OS_TYPE;
}
if( strstr( szCmd,"TYPE") ) {
char *szType = strtok(NULL,"\r\n");
if( szType == NULL ) szType = "A";
sprintf(pSI->buffSend,"200 Type set to %s.\r\n",szType );
if( SendResponse( pSI ) == -1 )
return -1;
return CMD_OK;
}
if( strstr( szCmd,"REST" ) ) {
sprintf( pSI->buffSend,"504 Reply marker must be 0.\r\n");
if( SendResponse( pSI ) == -1 )
return -1;
return REPLY_MARKER;
}
if( strstr( szCmd,"NOOP") ) {
sprintf( pSI->buffSend,"200 NOOP command successful.\r\n");
if( SendResponse( pSI ) == -1 )
return -1;
return CMD_OK;
}
// 其余都是无效的命令
sprintf(pSI->buffSend,"500 '%s' command not understand.\r\n",szCmd );
if( SendResponse( pSI ) == -1 ) return -1;
return nRetVal;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -