基于c++、vs2017实现的ftp服务端,以tcp多线程的方式,用抓包工具的话,需要看tcp而非ftp,怎么将tcp封成ftp格式,目前没空,就没折腾了
#ifndef COMMONMETHOD_H
#define COMMONMETHOD_H
#include <string>
#include <vector>
/** str字符串中是否存在fmt字符串(不区分大小写) */
bool StringFind(const char *str, const char *fmt);
/** 获取文件最近修改时间:path-文件路径,fmt-时间格式 */
std::string GetFileMtime(const char *path, const char *fmt);
/** 字符串分割:ss-源字符串,split-分割字符串:返回分割后字符串集合 */
std::vector<std::string> StringSplit(const std::string &ss, const std::string &split);
/** 创建目录:menu-目录:成功返回0 */
int CreateMenu(const char *menu);
/** 获取目录所在磁盘剩余可用空间:menu-目录,FreeSpace-剩余可用空间:成功返回0 */
int GetMenuDiskFreeSpace(const std::string &menu, unsigned long long &FreeSpace);
#endif
#include "CommonMethod.h"
#include <algorithm>
#include <time.h>
#include <regex>
#include <io.h>
#include <direct.h>
#include <Windows.h>
#pragma warning(disable:4996)
bool StringFind(const char *str, const char *fmt)
{
std::string ss_str = str;
transform(ss_str.begin(), ss_str.end(), ss_str.begin(), ::tolower);//将ss_str字符串转换为小写
std::string ss_fmt = fmt;
transform(ss_fmt.begin(), ss_fmt.end(), ss_fmt.begin(), ::tolower);//将ss_fmt字符串转换为小写
return (ss_str.find(ss_fmt) != std::string::npos);
}
std::string GetFileMtime(const char *path, const char *fmt)
{
struct _stat st = { 0 };
if (_stat(path, &st) == 0)
{
char ct[128] = { 0 };
strftime(ct, sizeof(ct), fmt, localtime(&st.st_mtime));
return ct;
}
return "";
}
std::vector<std::string> StringSplit(const std::string &ss, const std::string &split)
{
std::vector<std::string> svss;
if (ss != "")
{
std::regex reg(split);
std::sregex_token_iterator pos(ss.begin(), ss.end(), reg, -1);
decltype(pos) end;
for (; pos != end; ++pos)
{
svss.push_back(pos->str());
}
}
return svss;
}
int CreateMenu(const char *menu)
{
std::vector<std::string> svss = StringSplit(menu, "/");
std::string ss = "";
for (unsigned int i = 0; i < svss.size(); i++)
{
ss = ss + svss.at(i) + "/";
if (_access(ss.c_str(), 0) == 0)
{
continue;
}
if (_mkdir(ss.c_str()) != 0)
{
return -1;
}
}
return 0;
}
int GetMenuDiskFreeSpace(const std::string &menu, unsigned long long &FreeSpace)
{
std::string ssDisk = "";
if (menu.find_first_of(":") == std::string::npos)
{
char buf[MAX_PATH] = { 0 };
if (getcwd(buf, sizeof(buf)) == nullptr)
{
return -1;
}
ssDisk = buf;
ssDisk = ssDisk.substr(0, ssDisk.find_first_of(":")) + ":";
}
else
ssDisk = menu.substr(0, menu.find_first_of(":")) + ":";
WCHAR wc[8] = { 0 };
swprintf(wc, L"%S", ssDisk.c_str());
LPCWSTR ls = wc;
DWORD64 lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes;
if (GetDiskFreeSpaceEx(ls, (PULARGE_INTEGER)&lpFreeBytesAvailableToCaller, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&FreeSpace) == false)
{
return -2;
}
return 0;
}
#ifndef TCPCOMMON_H
#define TCPCOMMON_H
/** 发送tcp数据(不适用于在结束之前可能遇到'\0'的字符串):TcpSocket-tcp套接字,data-数据,timeout-超时:返回0-成功,-1-select失败,-2-select超时,-3-发送失败 */
int SendTcpData(int TcpSocket, const char *data, long timeout = 1);
/** 发送tcp数据:TcpSocket-tcp套接字,data-数据,DataLen-数据长度,timeout-超时:返回0-成功,-1-select失败,-2-select超时,-3-发送失败 */
int SendTcpDataL(int TcpSocket, const char *data, int DataLen, long timeout = 1);
/** 创建tcp服务端:port-端口,ClientCnt-客户端数量:成功返回套接字,失败返回-1 */
int CreateTcpServer(const int &port, int ClientCnt);
/** 创建自动端口tcp服务端:port-端口(输出):成功返回套接字,失败返回-1 */
int CreateAutoPortTcpServer(unsigned short &port);
/** 接收tcp数据:TcpSocket-套接字,data-数据,DataLen-希望读取长度,RecvLen-实际读取长度,timeout-超时:返回0-成功,1-对端关闭,-1-参数错误,-2-select超时,-3-select失败,-4-接收失败 */
int RecvTcpData(int TcpSocket, char *data, int DataLen, int &RecvLen, long timeout = 1);
#endif
#include "TcpCommon.h"
#include <WinSock2.h>
int SendTcpData(int TcpSocket, const char *data, long timeout)
{
int DataLen = strlen(data);
fd_set __writefds;
timeval tv = { timeout, 0 };
int ir = 0;
int SendLen = 0;
while (true)
{
FD_ZERO(&__writefds);
FD_SET(TcpSocket, &__writefds);
ir = select(TcpSocket + 1, NULL, &__writefds, NULL, &tv);
if (ir < 0)
{
return -1;
}
else if (ir == 0)
{
return -2;
}
ir = send(TcpSocket, data + SendLen, DataLen - SendLen, 0);
if (ir == -1)
{
return -3;
}
SendLen += ir;
if (SendLen == DataLen)
break;
}
return 0;
}
int SendTcpDataL(int TcpSocket, const char *data, int DataLen, long timeout)
{
fd_set __writefds;
timeval tv = { timeout, 0 };
int ir = 0;
int SendLen = 0;
while (true)
{
FD_ZERO(&__writefds);
FD_SET(TcpSocket, &__writefds);
ir = select(TcpSocket + 1, NULL, &__writefds, NULL, &tv);
if (ir < 0)
{
return -1;
}
else if (ir == 0)
{
return -2;
}
ir = send(TcpSocket, data + SendLen, DataLen - SendLen, 0);
if (ir == -1)
{
return -3;
}
SendLen += ir;
if (SendLen == DataLen)
break;
}
return 0;
}
int CreateTcpServer(const int &port, int ClientCnt)
{
int FdServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (FdServer < 0)
{
return -1;
}
int opt = 1;
if (setsockopt(FdServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) == -1)
{
closesocket(FdServer);
return -1;
}
sockaddr_in server_addr = { 0 };
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(FdServer, (sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
closesocket(FdServer);
return -1;
}
if (listen(FdServer, ClientCnt) < 0)
{
closesocket(FdServer);
return -1;
}
return FdServer;
}
int CreateAutoPortTcpServer(unsigned short &port)
{
int FdServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (FdServer < 0)
{
return -1;
}
sockaddr_in server_addr = { 0 };
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = 0;
if (bind(FdServer, (sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
closesocket(FdServer);
return -1;
}
sockaddr sa = { 0 };
int sal = sizeof(sockaddr);
if (getsockname(FdServer, &sa, &sal) != 0)
{
closesocket(FdServer);
return -1;
}
port = ntohs(((sockaddr_in *)&sa)->sin_port);
if (listen(FdServer, 1) < 0)
{
closesocket(FdServer);
return -1;
}
return FdServer;
}
int RecvTcpData(int TcpSocket, char *data, int DataLen, int &RecvLen, long timeout)
{
RecvLen = 0;
if ((TcpSocket == -1) || (data == nullptr) || (DataLen <= 0))
{
return -1;
}
fd_set __readfds;
timeval tv = { timeout, 0 };
int ir = 0;
while (true)
{
FD_ZERO(&__readfds);
FD_SET(TcpSocket, &__readfds);
ir = select(TcpSocket + 1, &__readfds, NULL, NULL, &tv);
if (ir == 0)
{
return -2;
}
else if (ir < 0)
{
return -3;
}
else
{
ir = recv(TcpSocket, data + RecvLen, DataLen - RecvLen, 0);
if (ir < 0)
{
return -4;
}
else if (ir == 0)
{
return 1;
}
RecvLen += ir;
if (RecvLen == DataLen)
break;
}
}
return 0;
}
#ifndef FtpConnectingClient_H
#define FtpConnectingClient_H
#include <thread>
/** 传输模式 */
enum TransferMode
{
/** 十进制 */
ascii = 'A',
/** 二进制 */
image = 'I'
};
/** 连接中的客户端 */
class FtpConnectingClient
{
public:
FtpConnectingClient();
~FtpConnectingClient();
/** 开启:ConnSock-客户端套接字,RootDirectory-根目录,LocalIp-本机ip:返回0-成功,-1-发送220消息失败,-2-创建线程失败 */
int start(int ClientSock, const std::string &RootDirectory, const std::string &LocalIp);
/** 获取是否处于可以停止的状态 */
bool GetCanBeStopped();
private:
/** 客户端套接字 */
int _ClientSock;
/** 线程退出标识 */
bool _ThreadExit;
/** 线程 */
std::thread _thread;
/** 是否处于可以停止的状态 */
bool _CanBeStopped;
/** 用户名 */
std::string _user;
/** 密码 */
std::string _pass;
/** 传输模式 */
TransferMode _TransferMode;
/** 根目录 */
std::string _RootDirectory;
/** 本机IP */
std::string _LocalIp;
/** 客户端上传文件时候附加的文件大小 */
long _AlloSize;
/** 停止 */
void stop();
/** 线程函数 */
void ThreadFunc();
};
#endif
#include "FtpConnectingClient.h"
#include <WinSock2.h>
#include <list>
#include "TcpCommon.h"
#include "CommonMethod.h"
#include <algorithm>
#include <WS2tcpip.h>
#pragma warning(disable:4996)
FtpConnectingClient::FtpConnectingClient()
{
_ClientSock = -1;
_ThreadExit = true;
_CanBeStopped = true;
_user = "";
_pass = "";
_TransferMode = ascii;
_RootDirectory = "";
_LocalIp = "";
_AlloSize = 0;
}
FtpConnectingClient::~FtpConnectingClient()
{
stop();
}
int FtpConnectingClient::start(int ClientSock, const std::string &RootDirectory, const std::string &LocalIp)
{
printf("FtpConnectingClient::start:ClientSock=%d,RootDirectory=%s\n", ClientSock, RootDirectory.c_str());
_ClientSock = ClientSock;
int ir = SendTcpData(_ClientSock, "220 GTLI FTP Service\r\n");
if (ir != 0)
{
printf("FtpConnectingClient::start:SendTcpData 220 fail:ir=%d\n", ir);
return -1;
}
_RootDirectory = RootDirectory;
_LocalIp = LocalIp;
_CanBeStopped = false;
_ThreadExit = false;
_thread = std::thread(&FtpConnectingClient::ThreadFunc, this);
if (_thread.joinable() == false)
{
_ThreadExit = true;
_CanBeStopped = true;
return -2;
}
return 0;
}
void FtpConnectingClient::stop()
{
_CanBeStopped = true;
_ThreadExit = true;
if (_thread.joinable() == true)
{
_thread.join();
}
closesocket(_ClientSock);
}
bool FtpConnectingClient::GetCanBeStopped()
{
return _CanBeStopped;
}
/** 从USER请求中解析出用户名 */
static void AnalyzeUserFromUserRequest(const char *UserRequest, std::string &user)
{
user = "";
std::string _UserRequest = UserRequest;
std::string::size_type ssst_space = _UserRequest.find_first_of(' ');
std::string::size_type ssst_line = _UserRequest.find_first_of("\r\n");
if ((ssst_space != std::string::npos) && (ssst_line != std::string::npos) && (ssst_space < ssst_line))
{
user = _UserRequest.substr(ssst_space + 1, ssst_line - ssst_space - 1);
}
}
/** 用户登录验证 */
static bool UserCheck(const std::string &user, const std::string &pass)
{
if (user == "anonymous")
{
return true;
}
return false;
}
/** 获取文件大小:path-路径,TransferMode-传输模式:返回<=0表示失败 */
static long GetFileSize(const char *path, TransferMode TransferMode)
{
long lr = -1;
FILE *fr = fopen(path, TransferMode == ascii ? "r" : "rb");
if(fr != nullptr)
{
if (fseek(fr, 0, SEEK_END) == 0)
{
lr = ftell(fr);
}
fclose(fr);
}
return lr;
}
void FtpConnectingClient::ThreadFunc()
{
printf("FtpConnectingClient::ThreadFunc:thread %d begin\n", std::this_thread::get_id());
fd_set fs;
timeval tv = { 1, 0 };
char CBuf[2048] = { 0 };
int PasvFdServer = -1;
unsigned short PasvPort = 0;
while (_ThreadExit == false)
{
FD_ZERO(&fs);
FD_SET(_ClientSock, &fs);
int sr = select(_ClientSock + 1, &fs, NULL, NULL, &tv);
if (sr < 0)
{
printf("FtpConnectingClient::ThreadFunc:select fail:sr=%d\n", sr);
_CanBeStopped = true;
break;
}
else if (sr > 0)
{
memset(CBuf, 0, sizeof(CBuf));
int rr = recv(_ClientSock, CBuf, sizeof(CBuf), 0);
if (rr == 0)//客户端关闭了连接
{
printf("FtpConnectingClient::ThreadFunc:recv 0 bytes,perhaps the client has shut down itself\n");
_CanBeStopped = true;
break;
}
else if (rr < 0)
{
printf("FtpConnectingClient::ThreadFunc:failed to receive message\n");
_CanBeStopped = true;
break;
}
else
{
printf("FtpConnectingClient::ThreadFunc:recv msg:%s\n", CBuf);
if (StringFind(CBuf, "USER") == true)
{
AnalyzeUserFromUserRequest(CBuf, _user);
int ir = SendTcpData(_ClientSock, "331 Password required\r\n");
if (ir != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 331 fail:ir=%d\n", ir);
_CanBeStopped = true;
break;
}
}
else if (StringFind(CBuf, "PASS") == true)
{
AnalyzeUserFromUserRequest(CBuf, _pass);
if (UserCheck(_user, _pass) == false)
{
int ir1 = SendTcpData(_ClientSock, "530 user or password error.\r\n");
if (ir1 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 530 fail:ir1=%d\n", ir1);
_CanBeStopped = true;
break;
}
}
else
{
int ir2 = SendTcpData(_ClientSock, "230 User logged in.\r\n");
if (ir2 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 230 fail:ir2=%d\n", ir2);
_CanBeStopped = true;
break;
}
}
}
else if (StringFind(CBuf, "QUIT") == true)
{
int ir3 = SendTcpData(_ClientSock, "221 Goodbye.\r\n");
if (ir3 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 221 fail:ir3=%d\n", ir3);
}
_CanBeStopped = true;
break;
}
else if (StringFind(CBuf, "HELP") == true)
{
std::list<std::string> slss;
slss.push_back("214-The following commands are recognized (* ==>'s unimplemented).\r\n");
slss.push_back(" USER \r\n");
slss.push_back(" PASS \r\n");
slss.push_back(" QUIT \r\n");
slss.push_back(" HELP \r\n");
slss.push_back(" TYPE \r\n");
slss.push_back(" SIZE \r\n");
slss.push_back(" MDTM \r\n");
slss.push_back(" PASV \r\n");
slss.push_back(" RETR \r\n");
slss.push_back(" MKD \r\n");
slss.push_back(" ALLO \r\n");
slss.push_back(" STOR \r\n");
slss.push_back("214 HELP command successful.\r\n");
for (std::list<std::string>::iterator it = slss.begin(); it != slss.end(); it++)
{
int ir4 = SendTcpData(_ClientSock, (*it).c_str());
if (ir4 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 214 fail:ir4=%d\n", ir4);
_CanBeStopped = true;
break;
}
}
if (_CanBeStopped == true)
{
break;
}
}
else if (StringFind(CBuf, "TYPE") == true)
{
std::string ssType = "";
AnalyzeUserFromUserRequest(CBuf, ssType);
_TransferMode = ascii;
if (ssType.at(0) == ascii || ssType.at(0) == image)
{
_TransferMode = (TransferMode)ssType.at(0);
}
std::string ssSend = "200 Type set to ";
ssSend += (char)_TransferMode;
ssSend.append(".\r\n");
int ir5 = SendTcpData(_ClientSock, ssSend.c_str());
if (ir5 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 200 fail:ir5=%d\n", ir5);
_CanBeStopped = true;
break;
}
}
else if (StringFind(CBuf, "SIZE") == true)
{
std::string ssPath = "";
AnalyzeUserFromUserRequest(CBuf, ssPath);
ssPath = _RootDirectory + ssPath;
std::replace(ssPath.begin(), ssPath.end(), '\\', '/');
long FileSize = GetFileSize(ssPath.c_str(), _TransferMode);
if (FileSize <= 0)
{
int ir6 = SendTcpData(_ClientSock, "550 failed to obtain file size.\r\n");
if (ir6 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 550 fail:ir6=%d\n", ir6);
_CanBeStopped = true;
break;
}
}
else
{
std::string ssSend = "213 " + std::to_string(FileSize) + "\r\n";
int ir7 = SendTcpData(_ClientSock, ssSend.c_str());
if (ir7 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData SIZE 213 fail:ir7=%d\n", ir7);
_CanBeStopped = true;
break;
}
}
}
else if (StringFind(CBuf, "MDTM") == true)
{
std::string ssPath = "";
AnalyzeUserFromUserRequest(CBuf, ssPath);
ssPath = _RootDirectory + ssPath;
std::replace(ssPath.begin(), ssPath.end(), '\\', '/');
std::string ssSend = "213 " + GetFileMtime(ssPath.c_str(), "%Y%m%d%H%M%S") + "\r\n";
int ir8 = SendTcpData(_ClientSock, ssSend.c_str());
if (ir8 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData MDTM 213 fail:ir8=%d\n", ir8);
_CanBeStopped = true;
break;
}
}
else if (StringFind(CBuf, "PASV") == true)
{
if (PasvFdServer == -1)
{
PasvFdServer = CreateAutoPortTcpServer(PasvPort);
}
if (PasvFdServer == -1)
{
int ir9 = SendTcpData(_ClientSock, "425 Can not open data connection\r\n");
if (ir9 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData PASV 425 fail:ir9=%d\n", ir9);
_CanBeStopped = true;
break;
}
}
else
{
printf("FtpConnectingClient::ThreadFunc:PasvFdServer=%d,PasvPort=%hu\n", PasvFdServer, PasvPort);
std::string ssLocalIp = _LocalIp;
std::replace(ssLocalIp.begin(), ssLocalIp.end(), '.', ',');
char cSend[128] = { 0 };
sprintf(cSend, "227 Entering Passive Mode(%s,%d,%d).\r\n", ssLocalIp.c_str(), PasvPort / 256, PasvPort % 256);
int ir10 = SendTcpData(_ClientSock, cSend);
if (ir10 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData MDTM 213 fail:ir10=%d\n", ir10);
_CanBeStopped = true;
break;
}
}
}
else if (StringFind(CBuf, "RETR") == true)
{
if (PasvFdServer == -1)
{
int ir11 = SendTcpData(_ClientSock, "425 Can not open data connection\r\n");
if (ir11 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData RETR 425 fail:ir11=%d\n", ir11);
_CanBeStopped = true;
break;
}
}
else
{
int ir12 = SendTcpData(_ClientSock, "125 Data connection already open; Transfer starting.\r\n");
if (ir12 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 125 fail:ir12=%d\n", ir12);
_CanBeStopped = true;
break;
}
fd_set fsrErtrAccept;
timeval tvrErtrAccept = { 1, 0 };
int ErtrFdClient = -1;
unsigned int uiErtrAcceptInx = 0;
while (_ThreadExit == false)
{
FD_ZERO(&fsrErtrAccept);
FD_SET(PasvFdServer, &fsrErtrAccept);
int sr1 = select(PasvFdServer + 1, &fsrErtrAccept, NULL, NULL, &tvrErtrAccept);
if (sr1 < 0)
{
printf("FtpConnectingClient::ThreadFunc:select fail:sr1=%d\n", sr1);
_CanBeStopped = true;
break;
}
else if (sr1 > 0)
{
sockaddr_in saiErtrFdClient;
int ilErtrFdClient = sizeof(sockaddr_in);
ErtrFdClient = accept(PasvFdServer, (sockaddr *)&saiErtrFdClient, &ilErtrFdClient);
if (ErtrFdClient == -1)
{
printf("FtpConnectingClient::ThreadFunc:accept fail\n");
_CanBeStopped = true;
}
else
{
char ErtrClientIp[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, (void *)&(saiErtrFdClient.sin_addr), ErtrClientIp, sizeof(ErtrClientIp));
printf("FtpConnectingClient::ThreadFunc:ClientIp=%s,ClientPort=%hu,FdClient=%d\n", ErtrClientIp, saiErtrFdClient.sin_port, ErtrFdClient);
}
break;
}
else
{
uiErtrAcceptInx++;
if (uiErtrAcceptInx >= 10)
{
printf("FtpConnectingClient::ThreadFunc:accept timeout\n");
_CanBeStopped = true;
break;
}
}
}
if (_ThreadExit == false)
{
if (_CanBeStopped == true)
{
int ir27 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir27 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir27=%d\n", ir27);
}
break;
}
std::string ssPath = "";
AnalyzeUserFromUserRequest(CBuf, ssPath);
ssPath = _RootDirectory + ssPath;
std::replace(ssPath.begin(), ssPath.end(), '\\', '/');
FILE *frPasv = fopen(ssPath.c_str(), _TransferMode == ascii ? "r" : "rb");
if (frPasv == nullptr)
{
int ir15 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir15 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir15=%d\n", ir15);
}
closesocket(ErtrFdClient);
ErtrFdClient = -1;
_CanBeStopped = true;
break;
}
char c_buf_pasv[1024] = { 0 };
while (_ThreadExit == false)
{
memset(c_buf_pasv, 0, sizeof(c_buf_pasv));
size_t stfr = fread(c_buf_pasv, 1, sizeof(c_buf_pasv), frPasv);
if (stfr != sizeof(c_buf_pasv))
{
if (feof(frPasv) == 0)//文件未结束
{
printf("FtpConnectingClient::ThreadFunc:fread fail\n");
_CanBeStopped = true;
}
else
{
if (stfr > 0)
{
int ir16 = SendTcpDataL(ErtrFdClient, c_buf_pasv, stfr);
if (ir16 != 0)
{
printf("FtpConnectingClient::ThreadFunc:send c_buf_pasv fail:ir16=%d,stfr=%llu\n", ir16, stfr);
_CanBeStopped = true;
}
}
}
break;
}
int ir17 = SendTcpDataL(ErtrFdClient, c_buf_pasv, stfr);
if (ir17 != 0)
{
printf("FtpConnectingClient::ThreadFunc:send c_buf_pasv fail:ir17=%d,stfr=%llu\n", ir17, stfr);
_CanBeStopped = true;
break;
}
if (feof(frPasv) != 0)//文件结束
{
break;
}
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
fclose(frPasv);
frPasv = nullptr;
closesocket(ErtrFdClient);
ErtrFdClient = -1;
if (_ThreadExit == false)
{
if (_CanBeStopped == true)
{
int ir26 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir26 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir26=%d\n", ir26);
}
break;
}
int ir13 = SendTcpData(_ClientSock, "226 Transfer complete.\r\n");
if (ir13 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 226 fail:ir13=%d\n", ir13);
_CanBeStopped = true;
break;
}
}
else
{
int ir31 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir31 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir31=%d\n", ir31);
}
}
}
else
{
if (ErtrFdClient != -1)
{
closesocket(ErtrFdClient);
ErtrFdClient = -1;
}
int ir30 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir30 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir30=%d\n", ir30);
}
}
}
}
else if (StringFind(CBuf, "MKD") == true)
{
std::string ssRequestMenu = "";
AnalyzeUserFromUserRequest(CBuf, ssRequestMenu);
std::string ssMenu = _RootDirectory + ssRequestMenu;
std::replace(ssMenu.begin(), ssMenu.end(), '\\', '/');
if (CreateMenu(ssMenu.c_str()) != 0)
{
int ir17 = SendTcpData(_ClientSock, "550 Requested action not taken.File unavailable\r\n");
if (ir17 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 550 fail:ir17=%d\n", ir17);
_CanBeStopped = true;
break;
}
}
else
{
char cSend[128] = { 0 };
sprintf(cSend, "257 \"%s\" created\r\n", ssRequestMenu.c_str());
int ir18 = SendTcpData(_ClientSock, cSend);
if (ir18 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 257 fail:ir18=%d\n", ir18);
_CanBeStopped = true;
break;
}
}
}
else if (StringFind(CBuf, "ALLO") == true)
{
std::string ssAlloSize = "";
AnalyzeUserFromUserRequest(CBuf, ssAlloSize);
_AlloSize = atol(ssAlloSize.c_str());
if (_AlloSize <= 0)
{
int ir19 = SendTcpData(_ClientSock, "500 Syntax error, command unrecognized\r\n");
if (ir19 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 500 fail:ir19=%d\n", ir19);
_CanBeStopped = true;
break;
}
}
else
{
unsigned long long FreeSpace = 0;
if (GetMenuDiskFreeSpace(_RootDirectory.c_str(), FreeSpace) != 0)
{
_AlloSize = 0;
int ir20 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir20 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir20=%d\n", ir20);
_CanBeStopped = true;
break;
}
}
else
{
if (FreeSpace < (_AlloSize + 1024 * 1024 * 1024))
{
_AlloSize = 0;
int ir21 = SendTcpData(_ClientSock, "452 Requested action not taken.Insufficient storage space in system\r\n");
if (ir21 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 452 fail:ir21=%d\n", ir21);
_CanBeStopped = true;
break;
}
}
else
{
int ir22 = SendTcpData(_ClientSock, "200 ALLO command successful.\r\n");
if (ir22 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 200 fail:ir22=%d\n", ir22);
_AlloSize = 0;
_CanBeStopped = true;
break;
}
}
}
}
}
else if (StringFind(CBuf, "STOR") == true)
{
int ir26 = SendTcpData(_ClientSock, "125 Data connection already open; Transfer starting.\r\n");
if (ir26 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 125 fail:ir26=%d\n", ir26);
_CanBeStopped = true;
break;
}
fd_set fswStorAccept;
timeval tvwStorAccept = { 1, 0 };
int StorFdClient = -1;
unsigned int uiStorAcceptInx = 0;
while (_ThreadExit == false)
{
FD_ZERO(&fswStorAccept);
FD_SET(PasvFdServer, &fswStorAccept);
int sr2 = select(PasvFdServer + 1, &fswStorAccept, NULL, NULL, &tvwStorAccept);
if (sr2 < 0)
{
printf("FtpConnectingClient::ThreadFunc:select fail:sr2=%d\n", sr2);
_CanBeStopped = true;
break;
}
else if (sr2 > 0)
{
sockaddr_in saiStorFdClient;
int ilStorFdClient = sizeof(sockaddr_in);
StorFdClient = accept(PasvFdServer, (sockaddr *)&saiStorFdClient, &ilStorFdClient);
if (StorFdClient == -1)
{
printf("FtpConnectingClient::ThreadFunc:accept fail\n");
_CanBeStopped = true;
}
else
{
char StorClientIp[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, (void *)&(saiStorFdClient.sin_addr), StorClientIp, sizeof(StorClientIp));
printf("FtpConnectingClient::ThreadFunc:ClientIp=%s,ClientPort=%hu,FdClient=%d\n", StorClientIp, saiStorFdClient.sin_port, StorFdClient);
}
break;
}
else
{
uiStorAcceptInx++;
if (uiStorAcceptInx >= 10)
{
printf("FtpConnectingClient::ThreadFunc:accept timeout\n");
_CanBeStopped = true;
break;
}
}
}
if (_ThreadExit == false)
{
if (_CanBeStopped == true)
{
int ir28 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir28 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir28=%d\n", ir28);
}
break;
}
std::string ssStorPath = "";
AnalyzeUserFromUserRequest(CBuf, ssStorPath);
ssStorPath = _RootDirectory + ssStorPath;
std::replace(ssStorPath.begin(), ssStorPath.end(), '\\', '/');
std::string ssStorMenu = ssStorPath.substr(0, ssStorPath.find_last_of('/'));
CreateMenu(ssStorMenu.c_str());
FILE *fwStor = fopen(ssStorPath.c_str(), _TransferMode == ascii ? "w" : "wb");
if (fwStor == nullptr)
{
int ir24 = SendTcpData(_ClientSock, "550 The system cannot find the path specified. \r\n");
if (ir24 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 550 fail:ir24=%d\n", ir24);
}
closesocket(StorFdClient);
StorFdClient = -1;
_CanBeStopped = true;
break;
}
long lRecvStorSize = 0;
char c_buf_stor[1024] = { 0 };
while (_ThreadExit == false)
{
memset(c_buf_stor, 0, sizeof(c_buf_stor));
int RecvStorSize = 0;
int RecvCode = RecvTcpData(StorFdClient, c_buf_stor, sizeof(c_buf_stor), RecvStorSize);
if (RecvStorSize > 0)
{
if (fwrite(c_buf_stor, 1, RecvStorSize, fwStor) != RecvStorSize)
{
printf("FtpConnectingClient::ThreadFunc:fwrite fail\n");
_CanBeStopped = true;
break;
}
}
if (RecvCode < 0)
{
printf("FtpConnectingClient::ThreadFunc:RecvTcpData fail:RecvCode=%d\n", RecvCode);
_CanBeStopped = true;
break;
}
else if (RecvCode == 1)
{
if (_AlloSize > 0)
{
if (lRecvStorSize != _AlloSize)
{
printf("FtpConnectingClient::ThreadFunc:RecvTcpData fail:RecvCode=%d\n", RecvCode);
_CanBeStopped = true;
}
}
break;
}
lRecvStorSize += RecvStorSize;
if (_AlloSize > 0)
{
if (lRecvStorSize == _AlloSize)
{
break;
}
else if (lRecvStorSize > _AlloSize)
{
printf("FtpConnectingClient::ThreadFunc:recv len error\n");
_CanBeStopped = true;
break;
}
}
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
fclose(fwStor);
fwStor = nullptr;
closesocket(StorFdClient);
StorFdClient = -1;
if (_ThreadExit == false)
{
if (_CanBeStopped == true)
{
remove(ssStorPath.c_str());
int ir29 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir29 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir29=%d\n", ir29);
}
break;
}
int ir25 = SendTcpData(_ClientSock, "226 Transfer complete.\r\n");
if (ir25 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 226 fail:ir25=%d\n", ir25);
_CanBeStopped = true;
break;
}
}
else
{
int ir33 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir33 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir33=%d\n", ir33);
}
}
}
else
{
if (StorFdClient != -1)
{
closesocket(StorFdClient);
StorFdClient = -1;
}
int ir32 = SendTcpData(_ClientSock, "451 Requested action aborted. Local error in processing\r\n");
if (ir32 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 451 fail:ir32=%d\n", ir32);
}
}
}
else
{
int ir14 = SendTcpData(_ClientSock, "500 Syntax error, command unrecognized\r\n");
if (ir14 != 0)
{
printf("FtpConnectingClient::ThreadFunc:SendTcpData 500 fail:ir14=%d\n", ir14);
}
_CanBeStopped = true;
break;
}
}
}
}
if (PasvFdServer != -1)
{
closesocket(PasvFdServer);
PasvFdServer = -1;
}
printf("FtpConnectingClient::ThreadFunc:thread %d end\n", std::this_thread::get_id());
}
#ifndef FTPSERVER_H
#define FTPSERVER_H
#include <thread>
/** ftp服务端 */
class FtpServer
{
public:
FtpServer();
~FtpServer();
/** 开启:RootDirectory-根目录,ControlPort-控制端口,MaxClientCnt-最大客户端数量:返回0-成功,-1-初始化套接字库失败,-2-创建线程失败 */
int start(const char *RootDirectory, unsigned short ControlPort = 21, int MaxClientCnt = 10);
/** 停止 */
void stop();
private:
/** 根目录 */
std::string m_RootDirectory;
/** 控制端口 */
unsigned short m_ControlPort;
/** 最大客户端数量 */
int m_MaxClientCnt;
/** 线程退出标识 */
bool m_ThreadExit;
/** 线程 */
std::thread m_thread;
/** 线程函数 */
void ThreadFunc();
};
#endif
#include "FtpServer.h"
#include <WinSock2.h>
#include <vector>
#include "FtpConnectingClient.h"
#include <algorithm>
#include <WS2tcpip.h>
#include "TcpCommon.h"
#pragma comment(lib, "Ws2_32.lib")
FtpServer::FtpServer()
{
m_RootDirectory = "";
m_ControlPort = 0;
m_MaxClientCnt = 0;
m_ThreadExit = true;
}
FtpServer::~FtpServer()
{
stop();
}
int FtpServer::start(const char *RootDirectory, unsigned short ControlPort, int MaxClientCnt)
{
printf("FtpServer::start:RootDirectory=%s,ControlPort=%hu,MaxClientCnt=%d\n", RootDirectory, ControlPort, MaxClientCnt);
WSADATA _wsa;
if (WSAStartup(MAKEWORD(2, 2), &_wsa) != 0)
{
return -1;
}
m_RootDirectory = RootDirectory;
std::replace(m_RootDirectory.begin(), m_RootDirectory.end(), '\\', '/');
if (m_RootDirectory.at(m_RootDirectory.length() - 1) == '/')
{
m_RootDirectory = m_RootDirectory.substr(0, m_RootDirectory.length() - 1);
}
printf("FtpServer::start:m_RootDirectory=%s\n", m_RootDirectory.c_str());
m_ControlPort = ControlPort;
m_MaxClientCnt = MaxClientCnt;
m_ThreadExit = false;
m_thread = std::thread(&FtpServer::ThreadFunc, this);
if (m_thread.joinable() == false)
{
m_ThreadExit = true;
WSACleanup();
return -2;
}
return 0;
}
void FtpServer::stop()
{
m_ThreadExit = true;
if (m_thread.joinable() == true)
{
m_thread.join();
}
WSACleanup();
}
void FtpServer::ThreadFunc()
{
printf("FtpServer::ThreadFunc:thread %d begin\n", std::this_thread::get_id());
int FdServerControl = CreateTcpServer(m_ControlPort, m_MaxClientCnt);
if (FdServerControl != -1)
{
printf("FtpServer::ThreadFunc:CreateTcpServer success:FdServerControl=%d\n", FdServerControl);
}
else
{
printf("FtpServer::ThreadFunc:CreateTcpServer fail\n");
}
fd_set fs;
timeval tv = { 1, 0 };
std::vector<FtpConnectingClient *> svcc;
while (m_ThreadExit == false)
{
if (FdServerControl == -1)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
FdServerControl = CreateTcpServer(m_ControlPort, m_MaxClientCnt);
if (FdServerControl != -1)
{
printf("FtpServer::ThreadFunc:CreateTcpServer success:FdServerControl=%d\n", FdServerControl);
}
else
{
printf("FtpServer::ThreadFunc:CreateTcpServer fail\n");
}
continue;
}
for (std::vector<FtpConnectingClient *>::iterator it = svcc.begin(); it != svcc.end(); it++)
{
FtpConnectingClient *cc = *it;
if (cc->GetCanBeStopped() == true)
{
svcc.erase(it);
delete cc;
cc = nullptr;
break;
}
}
FD_ZERO(&fs);
FD_SET(FdServerControl, &fs);
int sr = select(FdServerControl + 1, &fs, NULL, NULL, &tv);
if (sr < 0)
{
printf("FtpServer::ThreadFunc:select fail\n");
while (svcc.size() > 0)
{
FtpConnectingClient *cc = svcc.front();
svcc.erase(svcc.begin());
delete cc;
cc = nullptr;
}
closesocket(FdServerControl);
FdServerControl = -1;
}
else if (sr > 0)
{
sockaddr_in client_address;
int address_len = sizeof(sockaddr_in);
int FdClientControl = accept(FdServerControl, (sockaddr *)&client_address, &address_len);
if (FdClientControl != -1)
{
if (svcc.size() >= m_MaxClientCnt)
{
printf("FtpServer::ThreadFunc:the link has reached the limit\n");
closesocket(FdClientControl);
}
else
{
char LocalIp[INET6_ADDRSTRLEN] = { 0 };
sockaddr sa = { 0 };
int sal = sizeof(sockaddr);
if (getsockname(FdClientControl, &sa, &sal) != 0)
{
printf("FtpServer::ThreadFunc:get local ip fail\n");
closesocket(FdClientControl);
}
else
{
inet_ntop(AF_INET, (void *)&((sockaddr_in *)&sa)->sin_addr, LocalIp, sizeof(LocalIp));
printf("FtpServer::ThreadFunc:LocalIp=%s\n", LocalIp);
char ClientIp[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, (void *)&(client_address.sin_addr), ClientIp, sizeof(ClientIp));
printf("FtpServer::ThreadFunc:ClientIp=%s,ClientPort=%hu\n", ClientIp, client_address.sin_port);
FtpConnectingClient *cc = new FtpConnectingClient();
if (cc->start(FdClientControl, m_RootDirectory, LocalIp) != 0)
{
printf("FtpServer::ThreadFunc:cc->start fail\n");
delete cc;
cc = nullptr;
}
else
{
svcc.push_back(cc);
}
}
}
}
else
{
printf("FtpServer::ThreadFunc:accept fail\n");
}
}
}
if (FdServerControl != -1)
{
while (svcc.size() > 0)
{
FtpConnectingClient *cc = svcc.front();
svcc.erase(svcc.begin());
delete cc;
cc = nullptr;
}
closesocket(FdServerControl);
}
printf("FtpServer::ThreadFunc:thread %d end\n", std::this_thread::get_id());
}
#include "FtpServer.h"
int main()
{
FtpServer fs;
fs.start("E:\\ft_server_test\\", 3001, 1);
getchar();
fs.stop();
return 0;
}